""" ai.py — Groq-powered reasoning for the B24 Browser AI backend. Uses llama-3.3-70b-versatile, same model as Joy on B24 Messenger. """ import os from groq import Groq GROQ_KEY = os.environ.get("groq_key") _client = Groq(api_key=GROQ_KEY) if GROQ_KEY else None MODEL = "llama-3.3-70b-versatile" def _chat(system: str, user: str, max_tokens: int = 700) -> str: if not _client: return "AI is not configured (missing groq_key secret)." completion = _client.chat.completions.create( model=MODEL, messages=[ {"role": "system", "content": system}, {"role": "user", "content": user}, ], max_tokens=max_tokens, temperature=0.4, ) return completion.choices[0].message.content.strip() def summarize_page(url: str, text: str) -> str: text = (text or "")[:12000] system = ( "You summarize web pages clearly and concisely for someone browsing " "on a phone. Use short paragraphs or bullet points. No fluff." ) user = f"URL: {url}\n\nPage content:\n{text}\n\nSummarize this page." return _chat(system, user, max_tokens=500) def synthesize_search(query: str, results: list) -> str: listing = "\n".join( f"- {r['title']}: {r['snippet']} ({r['url']})" for r in results[:8] ) system = ( "You are a smart search assistant. Given raw search results, write " "a short, direct answer to the user's query, citing which result(s) " "back it up by title. Keep it tight — a few sentences." ) user = f"Query: {query}\n\nSearch results:\n{listing}\n\nAnswer the query." return _chat(system, user, max_tokens=400) def suggest_related(url: str, text: str) -> list: text = (text or "")[:6000] system = ( "Given a web page's content, suggest 5 short, specific search " "queries a curious reader might want to explore next. " "Return ONLY a JSON array of strings, nothing else." ) user = f"URL: {url}\n\nPage content:\n{text}" raw = _chat(system, user, max_tokens=200) import json try: cleaned = raw.strip().strip("`").replace("json", "", 1) if raw.strip().startswith("```") else raw parsed = json.loads(cleaned) if isinstance(parsed, list): return [str(x) for x in parsed[:5]] except (json.JSONDecodeError, ValueError): pass lines = [l.strip("-• ").strip() for l in raw.splitlines() if l.strip()] return lines[:5]