7ad0ee7624
New backend/matrix_intake/ runs as its own process (matrix-nio isolated from the stdlib CRM): local-Qwen parse via Spark Control → in-thread human approval (yes/edit/no) → write through the CRM's own log-communication endpoint, tagged source=matrix_intake. Adds read-only GET /api/intake/match (returns grid row id, no-duplicate contract); threads provenance through handle_log_fundraising_communication. Reviewer-passed: pop-before-commit closes a double-approve race; edit-grammar fix. Text-only v1; business-card photo (M3) deferred (no Spark vision model). 26/26 tests green; live Matrix smoke pending deploy.
22 lines
1008 B
Python
22 lines
1008 B
Python
"""Thin reuse of the in-repo local-Qwen client (backend/ingest/llm.py) via Spark Control.
|
|
|
|
We import the ingest client rather than re-implementing the HTTP call so the intake bot
|
|
speaks the exact same Spark contract (model, /v1/chat/completions, TLS verify, .env load).
|
|
The intake message is real LP substance, but it goes ONLY to the local Qwen on Ten31 infra
|
|
— never Claude — so no scrub boundary applies (same basis as the daily digest). Never call a
|
|
Spark directly; everything goes through SPARK_CONTROL_URL.
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
_INGEST = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "ingest")
|
|
if _INGEST not in sys.path:
|
|
sys.path.insert(0, _INGEST)
|
|
|
|
import llm # noqa: E402 (backend/ingest/llm.py — chat / chat_json over Spark Control)
|
|
|
|
|
|
def parse_json(prompt, system=None, max_tokens=400):
|
|
"""Send to local Qwen (temp 0, thinking off) and parse the first JSON object, or None."""
|
|
return llm.chat_json(prompt, system=system, max_tokens=max_tokens)
|