Remove Anthropic API call from transcribe.py - agent generates Whisper prompt itself

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Safi
2026-04-10 15:55:22 +01:00
parent db07e9f93a
commit 2a7d2f4fdc
11 changed files with 146 additions and 191 deletions
+15 -15
View File
@@ -115,30 +115,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -15
View File
@@ -115,30 +115,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -14
View File
@@ -114,29 +114,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model — write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder``"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm``"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -15
View File
@@ -117,30 +117,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -15
View File
@@ -115,30 +115,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -15
View File
@@ -115,30 +115,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -15
View File
@@ -114,30 +114,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transcription command.
**Step 2 - Transcribe:**
```bash
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+15 -14
View File
@@ -107,29 +107,30 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from the detect output or analysis file. You are already a language model - write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command (PowerShell):**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder` -> `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm` -> `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `$env:GRAPHIFY_WHISPER_PROMPT` before running the transcription command.
**Step 2 - Transcribe (PowerShell):**
```powershell
& (Get-Content graphify-out\.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+16 -15
View File
@@ -119,30 +119,31 @@ Skip this step entirely if `detect` returned zero `video` files.
Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
**Strategy:** Run non-video semantic extraction first (Step 3B) to get god nodes, use those to build a domain hint for Whisper, then transcribe. This keeps the prompt relevant without guessing the corpus topic from filenames.
**Strategy:** Read the god nodes from `graphify-out/.graphify_detect.json` (or the analysis file if it exists from a previous run). You are already a language model — write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
**However**, if the corpus has *only* video files and no other docs/code, skip the god-node step and transcribe with the generic fallback prompt immediately.
**However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
**Transcription command:**
**Step 1 - Write the Whisper prompt yourself.**
Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
- Labels: `transformer, attention, encoder, decoder``"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
- Labels: `kubernetes, deployment, pod, helm``"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
Set it as `WHISPER_PROMPT` to use in the next command.
**Step 2 - Transcribe:**
```bash
GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed
$(cat graphify-out/.graphify_python) -c "
import json
import json, os
from pathlib import Path
from graphify.transcribe import build_whisper_prompt, transcribe_all
from graphify.transcribe import transcribe_all
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text())
video_files = detect.get('files', {}).get('video', [])
# Try to load god nodes from a previous partial run or pass [] if not yet available
try:
analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())
god_nodes = analysis.get('god_nodes', [])
except Exception:
god_nodes = []
prompt = build_whisper_prompt(god_nodes)
print(f'Whisper prompt: {prompt}')
prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
print(json.dumps(transcript_paths))
+6 -26
View File
@@ -91,14 +91,14 @@ def download_audio(url: str, output_dir: Path) -> Path:
def build_whisper_prompt(god_nodes: list[dict]) -> str:
"""Build a domain hint for Whisper from god nodes extracted from the corpus.
Takes the top god nodes (most connected concepts) already extracted from
non-video files and asks the LLM to summarise them into a one-sentence
speech-to-text hint. Falls back to a generic prompt if no nodes available.
Formats the top god node labels into a topic string for Whisper.
The coding agent (Claude Code, Codex, etc.) generates the actual one-sentence
domain hint from these labels and passes it via GRAPHIFY_WHISPER_PROMPT or
as initial_prompt no separate API call needed here.
"""
if not god_nodes:
return _FALLBACK_PROMPT
# Use env override if set
override = os.environ.get("GRAPHIFY_WHISPER_PROMPT")
if override:
return override
@@ -107,28 +107,8 @@ def build_whisper_prompt(god_nodes: list[dict]) -> str:
if not labels:
return _FALLBACK_PROMPT
try:
import anthropic
client = anthropic.Anthropic()
msg = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=60,
messages=[{
"role": "user",
"content": (
f"These are the key concepts from a document corpus: {', '.join(labels)}. "
"Write a single short sentence (under 20 words) that describes the domain "
"for a speech-to-text model. Start with 'Technical' or the domain name. "
"No explanation, just the sentence."
),
}],
)
prompt = msg.content[0].text.strip().strip('"')
return prompt + " Use proper punctuation and paragraph breaks."
except Exception:
# If LLM call fails for any reason, fall back gracefully
topics = ", ".join(labels[:5])
return f"Technical discussion about {topics}. Use proper punctuation and paragraph breaks."
topics = ", ".join(labels[:5])
return f"Technical discussion about {topics}. Use proper punctuation and paragraph breaks."
def transcribe(
+4 -32
View File
@@ -1,13 +1,10 @@
"""Tests for graphify.transcribe — video/audio transcription support."""
from __future__ import annotations
import json
import os
from pathlib import Path
from unittest.mock import MagicMock, patch
import sys
import pytest
from graphify.transcribe import (
@@ -47,38 +44,13 @@ def test_build_whisper_prompt_env_override(monkeypatch):
assert prompt == "Custom domain hint."
def test_build_whisper_prompt_llm_success():
"""Successful LLM call returns generated prompt with punctuation suffix."""
def test_build_whisper_prompt_returns_topic_string():
"""Returns a topic-based prompt from god node labels — no LLM call."""
god_nodes = [{"label": "neural networks"}, {"label": "transformers"}, {"label": "attention"}]
fake_response = MagicMock()
fake_response.content = [MagicMock(text="Machine learning and deep learning research")]
mock_anthropic = MagicMock()
mock_anthropic.Anthropic.return_value.messages.create.return_value = fake_response
with patch.dict(os.environ, {}, clear=False):
os.environ.pop("GRAPHIFY_WHISPER_PROMPT", None)
with patch.dict(sys.modules, {"anthropic": mock_anthropic}):
prompt = build_whisper_prompt(god_nodes)
assert "Machine learning" in prompt
assert "punctuation" in prompt.lower()
def test_build_whisper_prompt_llm_failure_fallback():
"""If LLM call raises, falls back to topic-based prompt."""
god_nodes = [{"label": "kubernetes"}, {"label": "docker"}, {"label": "helm"}]
mock_anthropic = MagicMock()
mock_anthropic.Anthropic.return_value.messages.create.side_effect = Exception("API error")
with patch.dict(os.environ, {}, clear=False):
os.environ.pop("GRAPHIFY_WHISPER_PROMPT", None)
with patch.dict(sys.modules, {"anthropic": mock_anthropic}):
prompt = build_whisper_prompt(god_nodes)
assert "kubernetes" in prompt.lower() or "docker" in prompt.lower()
prompt = build_whisper_prompt(god_nodes)
assert "neural networks" in prompt.lower() or "transformers" in prompt.lower()
assert "punctuation" in prompt.lower()