β™₯ HeartMatch AI β€” Compatibility, Safety & Honest Dating Coach

HeartMatch AI is a self-hosted dating copilot for adults. It scores genuine compatibility between you and the people you actually know, reviews your profile for honesty and clarity, drafts messages you would not be embarrassed to send, blocks manipulative drafts before they leave your hands, and detects romance-scam patterns in theirs.

Built by Sushan Ghimire (@sushan98) β€” third in the agent family after ⚑ Opportunity Hunter and 🎯 Client Hunter.


What it is, and what it refuses to be

Most things called a "dating AI" are spam engines: mass-DM bots, opener farms, manipulation scripts. Those get accounts banned, make the internet worse, and do not work anyway.

HeartMatch AI is built the other way round.

It does

Compatibility scoring 0–100 across seven weighted dimensions, fully deterministic
Honest profile review finds clichΓ©s, vague lines, and claims a stranger would read as inflated
Message coaching 3 draft options (warm / playful / direct), every one linted before you see it
Respect Guard blocks pressure, guilt, negging, love-bombing, deception, money talk
Scam detection flags the classic fraud script: fast intimacy β†’ isolation β†’ crisis β†’ money
First-meeting safety plan concrete, boring, effective steps, generated per person
Cookie-cutter rejection hard filters from your dealbreakers, applied literally

It will not

  • message anyone. There is no send code path. You copy, paste, and send yourself. One person at a time.
  • invent a profile, income, height, job, or photo β€” the rewrite path only uses facts already in your file.
  • help with pressure, guilt, jealousy baiting, negging, or "make her come back" tactics. These are blocked, not merely discouraged.
  • build a database of people who did not consent. Every profile needs a consent_basis string or it is skipped and counted.
  • run for under-18s. validate_profile() returns an error before anything else happens.
  • scrape dating apps. Sources are your own files, forms, and feeds.

Compatibility model

score = values_alignment(25) + life_goals(20) + communication_match(15)
      + lifestyle_fit(15) + interests_overlap(10) + logistics(10) + intent_match(5)

Hard blocks β†’ score 0, no appeal:

Block Source
age outside your range hard_filters.min_age / max_age
distance beyond limit hard_filters.max_distance_km
different country hard_filters.same_country_only
intent mismatch hard_filters.require_intent
any stated dealbreaker dealbreakers matched against their record

Verdicts: strong β‰₯ 80 Β· promising 65–79 Β· maybe 50–64 Β· skip < 50 Β· blocked.

Sample run on the bundled pool

Person Score Result
Anisha, 26, Kathmandu 93 strong β€” values 24/25, life goals 20/20, same city, 4 shared interests
Bipana, 29, Kathmandu 85 strong score + high scam risk β€” compatibility and safety are judged separately
Prakriti, 28, Lalitpur 70 promising β€” ambitious traveller, but conflict style and timeline diverge
Sneha, 24, Pokhara 0 blocked β€” 205 km > your 80 km limit
Rita, 31, Kathmandu 0 blocked β€” your dealbreaker: smoking
Kritika, 27, Kathmandu 0 blocked β€” looking for casual, you are not
Maya, 25, Kathmandu 0 blocked β€” honesty concern flagged in her record

Notice Bipana: a naive matcher would put her at the top and get you defrauded. Here the score and the risk live side by side, and the risk is loud.

Every person, message and profile in this repository is fictional. The bundled data/demo_candidates.json and agent/config/self_profile.json are synthetic examples so the agent runs out of the box. No real person's data ships with this model. Run python main.py profile to see what your own profile still needs, then replace the demo file with your real answers β€” locally, never in a public fork.


Respect Guard β€” the part that matters

Every outgoing draft is scanned before it is shown as sendable. Score starts at 100; below RESPECT_FLOOR (default 70) the draft is blocked.

$ python main.py guard "why aren't you replying? don't ignore me"
Respect Guard 66/100 β€” β›” do not send
  β€’ pressure: "why aren't you replying"
    This demands compliance instead of inviting a reply.
    β†’ Ask once, then leave space. Silence is an answer.

$ python main.py guard "That trek story is great β€” which route did you do?"
Respect Guard 100/100 β€” βœ… fine to send

Detected families: pressure, guilt_trip, negging, love_bombing, manufactured_urgency, jealousy_bait, deception, money_pressure, sexual_escalation_early, no_respect_for_no, interrogation, shouting, excess_emoji.

Direct, blunt or flirty is fine. Only attempts to override someone's agency fail. That distinction is the whole design.


Scam detection on the other side

Romance fraud follows a stable script, and it targets men and women alike β€” including, heavily, Nepali and South Asian users through WhatsApp/Telegram "investment" and "customs fee" stories.

$ python main.py safety HM-f21bac
Safety: Bipana β€” high (100/100)
  🚩 money_request: "western union"
  🚩 emergency_crisis: "hospital bill"
  🚩 isolation: "Don't tell your family"
  🚩 fast_intimacy: "my love"

  Do next:
   β€’ Do not send money, ever β€” not as a loan, not as a test.
   β€’ Ask for a live video call; refusal confirms the pattern.
   β€’ Report and block. Screenshot everything first.

Hard signals are weighted separately from soft ones, so one clumsy message never triggers a scam verdict β€” but a money request always does.


Quickstart

git clone https://huggingface.co/sushan98/heartmatch-ai-model
cd heartmatch-ai-model
pip install -r requirements.txt

python main.py doctor          # env + safety + profile check
python main.py run             # score the pool, scan incoming messages
python main.py list            # ranked candidates
python main.py show HM-66c3db  # full breakdown + meeting plan
python main.py profile         # completeness + honesty review
python main.py guard "text"    # lint a draft before sending
python main.py serve           # dashboard + REST API β†’ http://localhost:7861
python main.py daemon          # re-score every 12h

Runs offline with no API key β€” deterministic scoring, template coaching, rule-based copilot. Add GEMINI_API_KEY (or Groq / OpenAI / Ollama) to .env for prose generation. Same providers as the rest of the family:

LLM_PROVIDER=auto          # auto | gemini | openai | groq | ollama
GEMINI_API_KEY=
MATCH_THRESHOLD=75
RESPECT_FLOOR=70
PORT=7861

Configure it in one file

agent/config/self_profile.json decides everything. Rate your own values on 0–5 scales, and the ranker moves with you:

{
  "age": 27, "city": "Kathmandu", "intent": "serious", "seeking": "woman",
  "values": { "family_closeness": 5, "honesty": 5, "career_ambition": 4 },
  "life_goals": { "kids": "yes", "marriage_timeline": "1-2_years" },
  "dealbreakers": ["smoking", "honesty_issues", "wants_nothing_serious"],
  "hard_filters": { "min_age": 23, "max_age": 33, "max_distance_km": 80 },
  "honesty_rules": ["only state facts I have provided", "no fake accounts"]
}

Optional onboarding question bank: data/compatibility_questions.json.


Adding a pool (consent-first)

class MyPool(Pool):
    name = "community_form"

    def fetch(self) -> list[dict]:
        return [normalize(row, self.name) for row in load_my_form_responses()]

Every candidate needs consent_basis. Enable it in profile.json β†’ pool.sources. The agent counts and reports anything it skipped for missing consent.


REST API

Standard-library HTTP server, no FastAPI, no install friction.

Method Endpoint Purpose
GET / dashboard
GET /api/stats pool counters
GET /api/candidates?min_score=&status=&q= ranked list
GET /api/candidates/{id} breakdown + drafts + first-meeting plan
GET /api/profile completeness + honesty review
GET /api/openapi.json schema
POST /api/run full cycle
POST /api/guard {"text": "..."} β†’ Respect Guard verdict
POST /api/safety {"candidate_id": "..."} or {"messages": [...]}
POST /api/coach {"candidate_id": "...", "conversation": "...", "mode": "openers"}
POST /api/score score an arbitrary candidate object
POST /api/chat ask the copilot
POST /api/export csv / json / markdown
curl -s -X POST localhost:7861/api/guard \
  -H 'Content-Type: application/json' \
  -d '{"text":"you would be pretty if you smiled more"}'

Project layout

heartmatch-ai/
β”œβ”€β”€ main.py                      CLI entry
β”œβ”€β”€ app.py                       web entry (PORT/HOST aware)
β”œβ”€β”€ config.json                  agent manifest (incl. safety flags)
β”œβ”€β”€ agent/
β”‚   β”œβ”€β”€ config/                  settings.py Β· self_profile.json  ← edit this
β”‚   β”œβ”€β”€ core/                    brain Β· match_loop Β· chat_engine Β· rest_api
β”‚   β”‚                            dashboard Β· exporter Β· scheduler
β”‚   β”œβ”€β”€ safety/                  respect_guard.py Β· red_flag_detector.py
β”‚   β”œβ”€β”€ scoring/                 compatibility.py
β”‚   β”œβ”€β”€ research/                pool_source.py
β”‚   β”œβ”€β”€ tools/                   message_coach.py Β· profile_builder.py
β”‚   β”œβ”€β”€ memory/                  memory_manager.py (SQLite)
β”‚   └── prompts/                 system_prompts.py
β”œβ”€β”€ data/                        demo_candidates.json Β· heartmatch.db Β· reports/
└── tests/                       test_smoke.py β€” 37 tests, no keys, no network
$ python tests/test_smoke.py
Ran 37 tests β€” OK

Half those tests assert that the agent refuses things: under-18 profiles, missing consent, manipulative drafts, blocked autosave. Safety is a test suite here, not a paragraph in a policy document.


Deploy

docker build -t heartmatch .
docker run -p 7861:7861 --env-file .env heartmatch

Cron instead of the daemon:

0 */12 * * * cd /srv/heartmatch && .venv/bin/python main.py run

Limitations β€” read this part

  • The score is not a verdict on a person. It measures fit against your stated profile. Change your values and the ranking moves. It cannot detect chemistry, timing, or the fact that someone had a bad week.
  • Data thinness is real. If a candidate has no life_goals, that dimension quietly defaults to neutral. Pools built from short intros score with low confidence; the report says so.
  • Scam detection is pattern-based. It catches the known script and misses a patient, bespoke con. Nothing replaces a video call and a public first meeting.
  • Keyword-level scoring cannot read between the lines. That is what the LLM layer and your own judgement are for.
  • Not therapy. If a relationship is controlling or violent, this tool is not the right help β€” local support services are.
  • Single-user by design. It is your private sheet, not a public directory.

Privacy

  • agent/config/self_profile.json is the only file that contains personal data. It ships with a fictional demo profile.
  • Keep your real profile out of git: it is already in .gitignore for the DB, and you can add agent/config/self_profile.json there too.
  • Candidate records stay in local SQLite (data/heartmatch.db), which is not committed.
  • No telemetry, no analytics, no phone-home. The only outbound calls are to the LLM provider you configure (and Telegram, if you set it up).

License

MIT β€” see LICENSE.

Author: Sushan Ghimire Β· @sushan98 Β· Nepali NLP and speech datasets, AI agents and automation with Python.

Downloads last month
23
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support