| """GARÍBEL brain API (FastAPI) — wraps the grounded Orchestrator for C's Next UI. |
| POST /garibel {message, intent?, level?, session_id?} -> {answer, sources, audio?}. |
| Reuses the EXACT orchestrator/brain/RAG/TTS bundle the Gradio Space proved (foundry + LILA NISAMINA + |
| full corpus + anti-fabrication + greetings/numbers + mms-tts-cab).""" |
| import os, sys, base64 |
| from fastapi import FastAPI, Request |
| from fastapi.responses import JSONResponse |
| _BR = os.path.join(os.path.dirname(__file__), "brain") |
| |
| |
| for _p in (_BR, os.path.join(_BR,"30_lexicon"), os.path.join(_BR,"99_publish"), os.path.join(_BR,"nisamina_mcp")): |
| if os.path.isdir(_p) and _p not in sys.path: sys.path.insert(0, _p) |
| app = FastAPI(title="GARIBEL brain") |
| _ORCH = None; _SESS = {} |
| def _orch(): |
| global _ORCH |
| if _ORCH is None: |
| from orchestrator import Orchestrator |
| from brain import load_brain |
| rm = os.getenv("NISAMINA_REAL_BRAIN", "1") == "1" |
| b = load_brain(real_mode=rm) |
| tts = None |
| if rm: |
| try: |
| from tts_garifuna import GarifunaTTS; tts = GarifunaTTS() |
| except Exception as e: |
| print("[tts] mock:", e) |
| _ORCH = Orchestrator(brain=b, tts=tts, audio_enabled=True) |
| return _ORCH |
| def _sess(sid): |
| from orchestrator import SessionState |
| if sid not in _SESS: _SESS[sid] = SessionState() |
| return _SESS[sid] |
| @app.get("/health") |
| def health(): return {"ok": True} |
| @app.post("/garibel") |
| async def garibel(req: Request): |
| b = await req.json() |
| msg = (b.get("message") or b.get("text") or "").strip() |
| if not msg: return JSONResponse({"error": "empty"}, status_code=400) |
| sid = str(b.get("session_id") or "default") |
| intent = b.get("intent"); level = b.get("level") |
| pre = "" |
| if intent == "translate": pre = "[Just translate, concisely.] " |
| elif intent == "simpler": pre = "[Explain more simply.] " |
| elif intent == "sentence": pre = "[Use it in a sentence.] " |
| if level == "beginner": pre += "[Beginner level.] " |
| try: |
| ss = _sess(sid) |
| resp = _orch().orchestrate(pre + msg, ss) |
| _SESS[sid] = resp.session_state |
| srcs = [] |
| if resp.citations: |
| try: |
| from nisamina_mcp.source_attribution import cite_record |
| for rec in resp.citations[:6]: |
| for c in cite_record(rec, limit=2): |
| if c not in srcs: srcs.append(c) |
| except Exception: pass |
| out = {"answer": resp.text, "sources": srcs[:6], "blocked": resp.blocked_reason} |
| if resp.audio_garifuna_wav: |
| out["audio_b64"] = base64.b64encode(resp.audio_garifuna_wav).decode() |
| out["audio_attribution"] = resp.audio_attribution |
| out["audio_text"] = resp.audio_synthesized_text |
| return out |
| except Exception as e: |
| import traceback; traceback.print_exc() |
| return JSONResponse({"error": "brain_error", "detail": str(e)}, status_code=500) |
|
|