Skip to main content

No project description provided

Project description

Dubai Real-Estate Lead Qualification Agent

A conversational AI agent built with agents-builder, LangGraph, and Ollama. The agent talks naturally with a prospective buyer, extracts useful details from the full conversation, chooses the next qualification question, and returns a scored lead when enough information is available.

The conversation is not a rigid form. A customer can provide several details in one message, use approximate language, name any Dubai area, or describe a property in their own words.

Install

This project uses the local editable agents-builder checkout at ../agents-builder.

uv sync --group dev --all-extras

Agent Structure

src/real_estate_lead_agent/
├── agent.py      # QualificationAgent and LangGraph wiring
├── nodes.py      # QualificationNode turn processing
├── prompts.py    # Structured qualification prompt
├── models.py     # Lead and LLM output schemas
├── scoring.py    # Deterministic lead scoring
├── integrations/
│   ├── __init__.py       # Generic interface and component loading
│   ├── settings.py       # Discriminated integration settings
│   ├── csv.py            # CSV integration
│   └── google_sheets.py  # Google Sheets integration
├── cli.py        # Interactive agent runner
└── adapters/
    ├── conversation.py # Shared per-session conversation state
    ├── telegram.py     # Telegram bot adapter
    └── web_api.py      # FastAPI web chat adapter

The modules follow the same separation used by the agents-builder agent template: state contracts, prompts, nodes, and graph composition remain independent and directly testable.

Configure Ollama

The default configuration is:

configs/qualification-agent.example.yaml

It follows the Paper Buddy Ollama configuration style:

agent:
  module_path: real_estate_lead_agent.agent.QualificationAgent
  llm_factory:
    module_path: agents_builder.llm.factory.LLMFactory
    roles:
      qualification:
        module_path: agents_builder.llm.llm.OllamaLLM
        model: gpt-oss:120b-cloud
        base_url: https://ollama.com
        kind: ollama
      scoring:
        module_path: agents_builder.llm.llm.OllamaLLM
        model: gpt-oss:120b-cloud
        base_url: https://ollama.com
        kind: ollama
  mcps: []

store:
  kind: memory

integrations:
  - kind: csv
    enabled: true
    path: leads.csv
  - kind: google_sheets
    enabled: false
    spreadsheet_id: your-google-spreadsheet-id
    range: Leads!A:O
    credentials_file: credentials/google-service-account.json

For a local Ollama model, change model and base_url, for example:

model: gpt-oss:20b
base_url: http://localhost:11434

Run The Agent

uv run real-estate-lead-agent

Or provide another config:

uv run real-estate-lead-agent --config configs/qualification-agent.example.yaml

Qualified leads are sent to every enabled integration. The example configuration appends them to leads.csv. Choose an additional CSV destination with:

uv run real-estate-lead-agent --output data/qualified-leads.csv

The command starts the real AI conversation. The agent can understand input such as:

I want a modern two-bedroom apartment near the beach, around 3 million AED,
and I hope to buy in the next two months.

It extracts all available facts, asks one useful follow-up question, and keeps the accumulated lead profile. Once the minimum profile is known, it prints the final lead JSON with lead_score and lead_status, then sends it to the configured integrations.

Run As A Telegram Bot

  1. Open @BotFather, send /newbot, and follow the prompts to create a bot and receive its token.
  2. Create a .env file in the project root. Do not commit it:
TELEGRAM_BOT_TOKEN=your-bot-token
  1. Start the bot with long polling:
uv run real-estate-lead-telegram

To use another agent configuration:

uv run real-estate-lead-telegram --config configs/qualification-agent.example.yaml

Use a different dotenv file with --env-file path/to/.env. An already exported TELEGRAM_BOT_TOKEN takes precedence over the dotenv value.

Open the bot in Telegram and send /start. The bot sends the welcome and first qualification question as two separate messages, in that order, before the user replies. Each Telegram chat gets independent conversation state. /reset starts that chat again, and completed leads are sent to the same enabled CSV or Google Sheets integrations used by the CLI. The final Telegram response confirms how many integrations received the completed lead.

Run As A Web API

Start the FastAPI adapter:

uv run real-estate-lead-web-api \
  --allowed-origin http://localhost:3000

Use --allowed-origin more than once when the widget is hosted on multiple domains. The default bind address is 127.0.0.1:8000; use --host 0.0.0.0 when running inside a container.

The API exposes:

GET  /api/health
POST /api/chat/start
POST /api/chat/message
POST /api/chat/reset
GET  /api/docs

Start a session:

curl -X POST http://localhost:8000/api/chat/start

Send a message using the returned session ID:

curl -X POST http://localhost:8000/api/chat/message \
  -H 'Content-Type: application/json' \
  -d '{
    "session_id": "fb94bb2e-52a0-48ec-9d29-b50a2c23419f",
    "message": "I want a two-bedroom apartment in Dubai Marina"
  }'

The response contains session_id, message, and completed. Sessions are stored in memory by default. Configure the validated store section as kind: redis with redis_url for multi-instance production deployments. See deploy/cloud/gcp/README.md for the Cloud Run and Memorystore deployment procedure.

Google Sheets Integration

Create a Google Cloud service account, enable the Google Sheets API, and share the target spreadsheet with the service account email. Then enable the google_sheets integration and set its spreadsheet ID and range:

integrations:
  - kind: google_sheets
    enabled: true
    spreadsheet_id: 1abc123...
    range: Leads!A:O
    credentials_file: credentials/google-service-account.json

When credentials_file is omitted, Application Default Credentials are used. Each qualified lead is appended as one row in the documented eight-column result order.

Additional providers define an IntegrationSettings subclass with a unique kind and module_path, add it to the discriminated ConfiguredIntegrationSettings union, and implement ResultIntegration[SettingsType].send. Runtime components are loaded with load_class(config.module_path).from_config(config).

The qualification schema contains six fields:

Field
first_name
phone
budget
property_type
location
timeline

The agent asks only about unresolved fields. A field is considered addressed even when the customer does not know the answer, refuses to provide it, or gives an invalid value. In those cases its value is null.

Every final JSON result contains the six lead fields in the documented order, followed by lead_score and lead_status. The CSV uses the same fixed columns; null values are written as empty cells.

Scoring Strategies

The agent uses LLMLeadScorer by default. After qualification, the scoring model receives both the normalized lead and the full customer conversation. It returns a score from 0 to 100, a HOT/WARM/COLD status, and concise reasoning. Reasoning is validated internally but is not added to the final CSV.

A deterministic alternative is also available:

from real_estate_lead_agent import CodeBasedLeadScorer, QualificationAgent

agent = QualificationAgent(config, scorer=CodeBasedLeadScorer())

CodeBasedLeadScorer applies fixed budget, timeline, and completeness rules. Both scorers return the same LeadQualificationResult schema, so JSON and CSV output do not change.

Quality

make ci

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

real_estate_lead_agent-1.0.0.tar.gz (127.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

real_estate_lead_agent-1.0.0-py3-none-any.whl (26.8 kB view details)

Uploaded Python 3

File details

Details for the file real_estate_lead_agent-1.0.0.tar.gz.

File metadata

  • Download URL: real_estate_lead_agent-1.0.0.tar.gz
  • Upload date:
  • Size: 127.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for real_estate_lead_agent-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7148e50b66830f8b9642a31f3a3da5d740a3d1a1ede99faa278adb7476df4ba1
MD5 137dfeafc07a2bd990070b54714574e6
BLAKE2b-256 22e5c590683542084539d67192124006dfd6cbad704ff9bf28fff69d3f1f74bb

See more details on using hashes here.

File details

Details for the file real_estate_lead_agent-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: real_estate_lead_agent-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 26.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for real_estate_lead_agent-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7ca772184f9095a16e7e69ef521166f73d87ac757594d4c1064fd892b045e7f5
MD5 7d79eadf54d2700087cb26e00bd04578
BLAKE2b-256 d656dd53287a7703f9e74041ab7c84f9cfb1280868fafe392c21256fed517cb1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page