From 03212fca51973f66311e5298f0d08855597bff85 Mon Sep 17 00:00:00 2001 From: Logan Date: Sun, 19 Apr 2026 08:18:55 -0400 Subject: [PATCH] Move to GPT for API consistency --- drb-c2-core/.env.example | 5 +---- drb-c2-core/app/internal/intelligence.py | 27 ++++++++++++------------ drb-c2-core/app/internal/summarizer.py | 17 ++++++++------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drb-c2-core/.env.example b/drb-c2-core/.env.example index bcd713d..cdf398f 100644 --- a/drb-c2-core/.env.example +++ b/drb-c2-core/.env.example @@ -18,11 +18,8 @@ GCS_BUCKET=your-bucket-name # How long (seconds) before a node is marked offline if no checkin received NODE_OFFLINE_THRESHOLD=90 -# OpenAI Whisper — for audio transcription +# OpenAI — for transcription (Whisper), intelligence extraction, embeddings, and summaries OPENAI_API_KEY= - -# Gemini — for intelligence extraction, embeddings, and incident summaries -GEMINI_API_KEY= SUMMARY_INTERVAL_MINUTES=15 CORRELATION_WINDOW_HOURS=4 EMBEDDING_SIMILARITY_THRESHOLD=0.82 diff --git a/drb-c2-core/app/internal/intelligence.py b/drb-c2-core/app/internal/intelligence.py index 460e291..bce4a73 100644 --- a/drb-c2-core/app/internal/intelligence.py +++ b/drb-c2-core/app/internal/intelligence.py @@ -113,20 +113,14 @@ def _sync_extract( system_id: Optional[str], segments: Optional[list[dict]], ) -> dict: - """Call Gemini Flash and parse the JSON response.""" + """Call GPT-4o mini and parse the JSON response.""" from app.config import settings - import google.generativeai as genai + from openai import OpenAI - if not settings.gemini_api_key: - logger.warning("GEMINI_API_KEY not set — intelligence extraction disabled.") + if not settings.openai_api_key: + logger.warning("OPENAI_API_KEY not set — intelligence extraction disabled.") return {} - genai.configure(api_key=settings.gemini_api_key) - model = genai.GenerativeModel( - "gemini-2.5-flash-lite", - generation_config={"response_mime_type": "application/json"}, - ) - tg = f"{talkgroup_name} (TGID {talkgroup_id})" if talkgroup_id else (talkgroup_name or "unknown") prompt = _PROMPT_TEMPLATE.format( transcript_block=_build_transcript_block(transcript, segments), @@ -135,13 +129,18 @@ def _sync_extract( ) try: - response = model.generate_content(prompt) - return json.loads(response.text) + client = OpenAI(api_key=settings.openai_api_key) + response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[{"role": "user", "content": prompt}], + response_format={"type": "json_object"}, + ) + return json.loads(response.choices[0].message.content) except json.JSONDecodeError as e: - logger.warning(f"Gemini returned non-JSON: {e}") + logger.warning(f"GPT-4o mini returned non-JSON: {e}") return {} except Exception as e: - logger.warning(f"Gemini extraction failed: {e}") + logger.warning(f"GPT-4o mini extraction failed: {e}") return {} diff --git a/drb-c2-core/app/internal/summarizer.py b/drb-c2-core/app/internal/summarizer.py index f21b469..11054c2 100644 --- a/drb-c2-core/app/internal/summarizer.py +++ b/drb-c2-core/app/internal/summarizer.py @@ -76,14 +76,11 @@ async def _summarize_incident(inc: dict) -> None: def _sync_summarize(inc: dict, transcripts: list[str]) -> Optional[str]: from app.config import settings - import google.generativeai as genai + from openai import OpenAI - if not settings.gemini_api_key: + if not settings.openai_api_key: return None - genai.configure(api_key=settings.gemini_api_key) - model = genai.GenerativeModel("gemini-2.5-flash-lite") - inc_type = inc.get("type", "unknown") location = inc.get("location") or "unknown location" tg_ids = ", ".join(inc.get("talkgroup_ids", [])) or "unknown" @@ -107,8 +104,12 @@ Write a concise factual summary of this incident in 2-4 sentences. Include: Be factual. Do not speculate beyond what the transcripts say. Do not use bullet points.""" try: - response = model.generate_content(prompt) - return response.text.strip() or None + client = OpenAI(api_key=settings.openai_api_key) + response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[{"role": "user", "content": prompt}], + ) + return response.choices[0].message.content.strip() or None except Exception as e: - logger.warning(f"Gemini summary failed: {e}") + logger.warning(f"GPT-4o mini summary failed: {e}") return None