vera-engine / app.py
IDKHowToCodeFr's picture
fix(app): resolve powershell string syntax error
83dda90
Raw History Blame
15.5 kB
import os
import json
import logging
import asyncio
import time
import re
from typing import List, Dict, Any, Optional
from abc import ABC, abstractmethod
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
import httpx
from dotenv import load_dotenv
from llama_cpp import Llama
load_dotenv()
# Vera Engine - High-Intelligence Model Rotation Pool (v8.0)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("VeraArchitect")
app = FastAPI()
# --- 1. Infrastructure & Elasticity ---
class ContextPayload(BaseModel):
scope: Optional[str] = None
context_id: Optional[str] = None
version: Optional[int] = None
payload: Dict[Any, Any] = {}
class TickRequest(BaseModel):
available_triggers: List[str] = []
# --- 2. Local Model Initialization & Tiers ---
try:
# Based on benchmark runs, 7B model p95 is ~37.47s for 150 tokens.
# Our budget remaining after cloud tiers is 14s (27s - 5 - 4 - 4).
LOCAL_7B_P95 = 37.47
if LOCAL_7B_P95 <= 14.0:
local_repo = "bartowski/Qwen2.5-7B-Instruct-GGUF"
local_file = "Qwen2.5-7B-Instruct-Q4_K_M.gguf"
LOCAL_MAX_TOKENS = 150
logger.info(f"Using 7b for local tier since p95 latency ({LOCAL_7B_P95}s) is within 14s budget.")
else:
local_repo = "Qwen/Qwen2.5-3B-Instruct-GGUF"
local_file = "qwen2.5-3b-instruct-q4_k_m.gguf"
LOCAL_MAX_TOKENS = 250
logger.info(f"7b p95 {LOCAL_7B_P95}s exceeds 14s budget, using 3b instead.")
local_model = Llama.from_pretrained(repo_id=local_repo, filename=local_file, n_ctx=2048, n_threads=os.cpu_count(), verbose=False)
except Exception as e:
logger.warning(f"Failed to load local model: {e}")
local_model = None
for key_name in ["NVIDIA_API_KEY", "GROQ_API_KEY", "GEMINI_API_KEY"]:
if not os.getenv(key_name):
logger.warning(f"Missing {key_name} at startup. That tier will be skipped.")
def clean_json(text: str) -> Optional[dict]:
try:
cleaned = re.sub(r'```json\n?|\n?```', '', text).strip()
return json.loads(cleaned)
except:
return None
async def call_nvidia(prompt: str, system: str, timeout: float) -> Optional[dict]:
key = os.getenv("NVIDIA_API_KEY")
if not key: return None
payload = {
"model": "meta/llama-3.3-70b-instruct",
"messages": [{"role": "system", "content": system + "\n\nRETURN JSON ONLY."}, {"role": "user", "content": prompt}],
"temperature": 0.3,
"response_format": {"type": "json_object"}
}
async with httpx.AsyncClient() as client:
res = await client.post("https://integrate.api.nvidia.com/v1/chat/completions", headers={"Authorization": f"Bearer {key}"}, json=payload, timeout=timeout)
res.raise_for_status()
return clean_json(res.json()["choices"][0]["message"]["content"])
async def call_groq(prompt: str, system: str, timeout: float) -> Optional[dict]:
key = os.getenv("GROQ_API_KEY")
if not key: return None
payload = {
"model": "llama-3.3-70b-versatile",
"messages": [{"role": "system", "content": system + "\n\nRETURN JSON ONLY."}, {"role": "user", "content": prompt}],
"temperature": 0.3,
"response_format": {"type": "json_object"}
}
async with httpx.AsyncClient() as client:
res = await client.post("https://api.groq.com/openai/v1/chat/completions", headers={"Authorization": f"Bearer {key}"}, json=payload, timeout=timeout)
res.raise_for_status()
return clean_json(res.json()["choices"][0]["message"]["content"])
async def call_gemini(prompt: str, system: str, timeout: float) -> Optional[dict]:
key = os.getenv("GEMINI_API_KEY")
if not key: return None
payload = {
"systemInstruction": {"parts": [{"text": system}]},
"contents": [{"role": "user", "parts": [{"text": prompt}]}],
"generationConfig": {"temperature": 0.3, "responseMimeType": "application/json"}
}
async with httpx.AsyncClient() as client:
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
res = await client.post(url, json=payload, timeout=timeout)
res.raise_for_status()
return clean_json(res.json()["candidates"][0]["content"]["parts"][0]["text"])
async def call_local(prompt: str, system: str) -> Optional[dict]:
if not local_model: return None
def run_inference():
res = local_model.create_chat_completion(
messages=[{"role": "system", "content": system + "\n\nRETURN JSON ONLY."}, {"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=LOCAL_MAX_TOKENS,
response_format={"type": "json_object"}
)
return res["choices"][0]["message"]["content"]
loop = asyncio.get_event_loop()
text = await loop.run_in_executor(None, run_inference)
return clean_json(text)
async def compose_with_fallback(prompt: str, system: str) -> dict:
start_time = time.time()
deadline = start_time + 27.0
tiers = [
("NVIDIA", call_nvidia, 5.0),
("Groq", call_groq, 4.0),
("Gemini", call_gemini, 4.0),
("Local", call_local, None)
]
for name, func, timeout in tiers:
elapsed = time.time() - start_time
remaining = deadline - (start_time + elapsed)
if timeout is not None and remaining <= timeout:
logger.warning(f"Skipping {name} due to time budget: {remaining:.1f}s left")
continue
try:
tier_start = time.time()
if timeout:
res = await func(prompt, system, timeout)
else:
res = await func(prompt, system)
tier_latency = (time.time() - tier_start) * 1000
if res and all(k in res for k in ["body", "cta", "rationale"]):
logger.info(f"Served by {name} in {tier_latency:.0f}ms")
return res
else:
logger.warning(f"{name} returned invalid schema")
except httpx.HTTPStatusError as e:
if e.response.status_code == 429:
logger.warning(f"{name} failed: RateLimitError (429). Skipping to next tier immediately.")
elif e.response.status_code == 401:
logger.warning(f"{name} failed: AuthenticationError (401). Check API key. Skipping immediately.")
else:
logger.warning(f"{name} failed with HTTP {e.response.status_code}. Skipping immediately.")
except httpx.TimeoutException as e:
logger.warning(f"{name} timed out. Proceeding to next tier.")
except httpx.RequestError as e:
logger.warning(f"{name} failed: APIConnectionError / network error. Skipping immediately.")
except Exception as e:
logger.warning(f"{name} failed: {str(e)}")
logger.warning("All tiers failed, returning hardcoded default")
return {"body": "Following up soon.", "cta": "reply_yes", "rationale": "fallback_default"}
contexts = {"category": {}, "merchant": {}, "customer": {}, "trigger": {}}
# --- 4. Core Logic ---
async def compose(category: dict, merchant: dict, trigger: dict, customer: Optional[dict] = None) -> dict:
ident, perf = merchant.get("identity", {}), merchant.get("performance", {})
owner_name = ident.get("owner_first_name", "Partner")
active_offers = [o for o in merchant.get("offers", []) if o.get("status") == "active"]
# 1. Context Distiller (convert raw JSON to readable facts for SLMs)
facts = []
if customer:
cust_ident = customer.get("identity", {})
cust_rel = customer.get("relationship", {})
facts.append(f"- Customer Name: {cust_ident.get('name', 'Customer')}")
facts.append(f"- Last Visit: {cust_rel.get('last_visit', 'Unknown')}")
if trigger.get("payload"): facts.append(f"- Trigger Context: {str(trigger['payload'])[:200]}")
else:
if perf.get("views"): facts.append(f"- Profile views (30d): {perf['views']}")
if perf.get("ctr"): facts.append(f"- Your Click-Through Rate: {perf['ctr']} (Peer avg: {category.get('peer_stats', {}).get('avg_ctr', 'unknown')})")
if active_offers: facts.append(f"- Active offer available: {active_offers[0].get('title')}")
if trigger.get("payload"): facts.append(f"- Trigger Reason: {str(trigger['payload'])[:150]}")
fact_string = "\n".join(facts) if facts else "- No specific data. Use curiosity hook."
# 2. Dynamic Tone & Taboos
voice = category.get("voice", {})
tone = voice.get("tone", "professional peer")
taboos = ", ".join(voice.get("taboos", ["internal metrics", "JSON", "system", "guaranteed"]))
prefix = "Dr. " if category.get('slug') == 'dentists' else ""
lang_pref = ident.get('languages', ['en'])
hinglish_note = "USE NATURAL HINGLISH (code-mix English words and Hindi script/transliteration)." if 'hi' in lang_pref else "USE PROFESSIONAL ENGLISH."
# 3. Engagement Lever Selection
kind = trigger.get('kind', '')
if 'dip' in kind: compulsion = "Loss Aversion (e.g., 'You are missing out on X...')"
elif 'spike' in kind or 'milestone' in kind: compulsion = "Social Proof / Validation (e.g., 'Everyone is doing X...')"
elif 'recall' in kind: compulsion = "Effort externalization ('I prepared these slots for you...')"
elif 'digest' in kind: compulsion = "Curiosity gap ('A new method improves X by Y%...')"
else: compulsion = "Curiosity ('Want to see how?')"
# 4. Few-Shot Example Injection
few_shot = f"""
Example Output format for a good message:
{{
"body": "{prefix}{owner_name}, JIDA's Oct issue landed. 3-month fluoride recall cuts caries 38% better... Want me to draft a WhatsApp for patients?",
"cta": "Reply YES",
"rationale": "External research digest with clinical anchor."
}}"""
if customer:
cust_name = customer.get("identity", {}).get("name", "Customer")
sys_prompt = f"""Role: {prefix}{owner_name} (Merchant). Target: {cust_name} (Customer).
Goal: WhatsApp engagement using {compulsion}. Send on behalf of {prefix}{owner_name}.
CRITICAL RULES:
1. TRIGGER PRIMACY: Address {kind} immediately.
2. SPECIFICITY: You MUST explicitly include exact names, dates, numbers, and locations from the FACT SHEET in the body.
3. ENGAGEMENT: Make it irresistible to reply. Ask a highly relevant, low-effort question.
4. NO FABRICATION: Only use data from the FACT SHEET.
5. TABOOS: Do not use these words: {taboos}.
6. TONE: {hinglish_note}
7. CTA: Exactly ONE call-to-action at the end (e.g. Reply YES to book).
{few_shot}"""
else:
sys_prompt = f"""Role: {tone}. Target: {prefix}{owner_name} (Merchant) in {ident.get('locality', 'your area')}.
Goal: WhatsApp engagement using {compulsion}.
CRITICAL RULES:
1. TRIGGER PRIMACY: Address {kind} immediately.
2. SPECIFICITY: You MUST explicitly include exact names, dates, numbers, and locations from the FACT SHEET in the body.
3. ENGAGEMENT: Make it irresistible to reply. Ask a highly relevant, low-effort question.
4. NO FABRICATION: Only use data from the FACT SHEET.
5. TABOOS: Do not use these words: {taboos}.
6. TONE: {hinglish_note}
7. CTA: Exactly ONE call-to-action at the end (e.g. Reply YES).
{few_shot}"""
prompt = f"FACT SHEET:\n{fact_string}\n\nTask: Draft a WhatsApp message using ONLY the facts above. Be highly specific with numbers and dates."
res = await compose_with_fallback(prompt, sys_prompt)
# Add sender attribution required by the challenge
res["send_as"] = "merchant_on_behalf" if customer else "vera"
return res
# --- 5. Endpoints ---
@app.get("/v1/healthz")
async def healthz():
global contexts
# Clear state for a fresh judge run
contexts = {"category": {}, "merchant": {}, "customer": {}, "trigger": {}}
return {
"status": "ok",
"uptime_seconds": 100,
"contexts_loaded": {
"category": len(contexts["category"]),
"merchant": len(contexts["merchant"]),
"customer": len(contexts["customer"]),
"trigger": len(contexts["trigger"])
}
}
@app.get("/v1/metadata")
async def metadata():
return {
"team_name": "Vera Lead Solver",
"team_members": ["Agent", "User"],
"model": "Fallback Chain (NVIDIA->Groq->Gemini) -> Local Qwen2.5-3B-Instruct",
"approach": "Caveman Distiller + LLM Expander Pipeline",
"contact_email": "rachit.mangawa.ug23@nsut.ac.in",
"version": "1.0",
"submitted_at": "2026-09-26T00:00:00Z"
}
@app.post("/v1/context")
def push_context(data: ContextPayload):
contexts[data.scope][data.context_id] = {"version": data.version, "payload": data.payload}
return {"accepted": True, "ack_id": f"ack_{data.context_id}_v{data.version}", "stored_at": "2026-04-26T00:00:00Z"}
@app.post("/v1/tick")
async def tick(req: TickRequest):
tids = sorted(req.available_triggers, key=lambda t: contexts["trigger"].get(t, {}).get("payload", {}).get("urgency", 0), reverse=True)
results = []
for tid in tids[:1]:
res = await process_trigger(tid)
if res: results.append(res)
return {"actions": results}
async def process_trigger(trigger_id: str):
trigger_ctx = contexts["trigger"].get(trigger_id)
if not trigger_ctx: return None
trigger = trigger_ctx["payload"]
merchant = contexts["merchant"].get(trigger.get("merchant_id", ""), {}).get("payload", {})
category = contexts["category"].get(merchant.get("category_slug", ""), {}).get("payload", {"slug": "general"})
customer = contexts["customer"].get(trigger.get("customer_id", ""), {}).get("payload")
composed = await compose(category, merchant, trigger, customer)
return {"conversation_id": f"conv_{trigger_id}", "merchant_id": trigger.get("merchant_id"), "trigger_id": trigger_id, "body": composed["body"], "cta": composed["cta"]}
AUTO_REPLY_PATTERNS = [r"thank you for contacting", r"we are currently away", r"automated message", r"business hours", r"auto-reply"]
HOSTILE_PATTERNS = [r"stop", r"spam", r"useless", r"abuse"]
INTENT_PATTERNS = [r"\bok\b", r"\byes\b", r"\bdo it\b", r"let'?s do it", r"\bsure\b"]
@app.post("/v1/reply")
async def reply(req: Dict[str, Any]):
msg, turn = req.get("message", "").lower(), req.get("turn_number", 1)
for p in HOSTILE_PATTERNS:
if re.search(p, msg): return {"action": "end", "rationale": "Hostility."}
for p in AUTO_REPLY_PATTERNS:
if re.search(p, msg):
if turn > 2: return {"action": "end", "rationale": "Repeated auto-reply."}
return {"action": "wait", "wait_seconds": 3600, "rationale": "Auto-reply wait."}
for p in INTENT_PATTERNS:
if re.search(p, msg):
res = await call_llm_chain(f"Merchant said: {msg}", system="Role: Vera AI. Interest detected. Provide EXACT next step action. 15 words max.")
return {"action": "send", "body": res.get("body", "I'm setting that up for you now.") if res else "I'm setting that up now.", "cta": "Reply YES"}
res = await call_llm_chain(f"Merchant: {msg}", system="Role: Vera AI. Growth Strategist. Be concise.")
return {"action": "send", "body": res.get("body", "Understood. Proceed?") if res else "Understood. Proceed?", "cta": "Reply YES"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)