kmkarakaya/emlakAsistani
EmlakAsistan
EmlakAsistan is a real-time voice sales assistant for real estate workflows. It uses Gemini Live for audio conversation, keeps UI logic separated from business logic, and stores application data through backend APIs.
Tech Stack
- Frontend: React + Vite + TypeScript + Tailwind
- Backend: Express + TypeScript
- AI: @google/genai (Gemini Live)
- Storage: JSON file persistence under
data/
Architecture (Refactor v2)
The codebase is split to keep UI portable and maintainable:
shared/: framework-agnostic domain types and pricing constantsserver/: backend entry, routes, storage servicesrc/services/: frontend business/services layer (no React dependency)src/hooks/: React binding layer for servicessrc/components/: render-focused UI components
Current key folders:
shared/
types.ts
pricing.ts
server/
index.ts
routes/
config.ts
customers.ts
projects.ts
appointments.ts
services/
storage.ts
src/
services/
hooks/
components/
lib/
App.tsxReliability Guarantees
Voice Session Shutdown (Graceful)
When an operator ends a call, the app performs a graceful shutdown instead of immediately tearing down the session:
- Stop microphone capture first (no new user audio is sent).
- Wait for buffered model audio to drain (with silence + timeout guards).
- Close the Gemini Live session after drain.
This prevents the agent from being cut off mid-sentence in normal conditions and keeps close behavior deterministic.
Additional protections:
- Stale-run guards prevent callback races between old/new sessions.
- Close/error callbacks are suppressed during intentional shutdown.
- Session close is idempotent to avoid double-close side effects.
Appointment Capture and UI Consistency
Appointment recording uses a layered, fail-safe strategy:
- Primary path: Gemini function tool-call (
recordAppointment). - Fallback path: text confirmation detection when a tool-call is missing.
- Deduping: tool-call IDs and normalized fallback hashes avoid duplicate writes.
- Persistence retries: exponential backoff on appointment writes.
Error handling policy:
- Appointment save failures do not crash the active voice call.
- Tool responses report failure back to the model when persistence fails.
UI consistency policy:
- Appointments are inserted into client state after successful save.
- Appointment list is refreshed when the call view closes.
Prerequisites
- Node.js 18+
- npm
Environment Setup
- Copy example env file:
cp .env.example .env- Set your Gemini key in
.env:
GEMINI_API_KEY=your_key_hereRun Locally
npm install
npm run devServer starts on http://localhost:3000.
Deploy to Hugging Face Spaces (Docker)
This repository now includes a production-ready Dockerfile and .dockerignore for Hugging Face Docker Spaces.
- Create a Docker Space in Hugging Face (done).
- Add secret in Space settings:
GEMINI_API_KEY=your_key_here- Push this repository to your Space remote:
git remote add hf https://huggingface.co/spaces/<username>/<space-name>
git push hf mainThe container listens on port 7860, which is the default for Docker Spaces.
Scripts
npm run dev: run backend (serves Vite in middleware mode)npm run start: production mode servernpm run build: production frontend buildnpm run preview: Vite previewnpm run lint: frontend + server type checksnpm run typecheck: frontend TS checknpm run typecheck:server: server TS checknpm run clean: removedist/
API Endpoints
GET /api/configGET /api/config/appPUT /api/config/appPOST /api/config/migrate-local-storageGET /api/customersGET /api/projectsPOST /api/projectsDELETE /api/projects/:projectIdGET /api/appointmentsPOST /api/appointmentsDELETE /api/appointments/:appointmentId
Unknown /api/* routes return JSON 404.
Data and Migration Notes
- Runtime data is persisted in
data/app-storage.json. - Legacy localStorage data is migrated once through backend API on app bootstrap.
- After migration, legacy keys are cleaned from browser storage.
Validation Checklist
npm run lint
npm run buildOptional API smoke checks:
curl http://localhost:3000/api/customers
curl http://localhost:3000/api/projects
curl http://localhost:3000/api/appointments