candle-fire / main.py
KevinIsInCoding
feat: Stage 4 — entity extraction + knowledge graph + KG-expanded RAG
42fb3af
Raw
History Blame Contribute Delete
2.68 kB
#!/usr/bin/env python3
"""CLI interface for candle-fire ALS research synthesis."""
from __future__ import annotations
import json
import sys
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
import anthropic
from rich.console import Console
from agents.research_agent import stream_research_agent
from config import CHROMA_COLLECTION, CHROMA_DIR, GRAPH_PICKLE_PATH, TRIALS_PATH
console = Console()
_EXAMPLES = [
"What's the evidence for tofersen targeting SOD1 in ALS?",
"What mechanisms link TDP-43 to ALS pathology?",
"What compounds target glutamate excitotoxicity in ALS?",
"What is the role of C9orf72 repeat expansion in ALS?",
]
def _load_trials() -> list[dict]:
if not TRIALS_PATH.exists():
return []
with open(TRIALS_PATH, encoding="utf-8") as f:
return [json.loads(line) for line in f if line.strip()]
def _load_graph():
try:
from graph.serializer import load_graph
return load_graph(GRAPH_PICKLE_PATH)
except FileNotFoundError:
return None
def main() -> None:
from rag.indexer import load_collection
query = " ".join(sys.argv[1:]).strip()
# Load resources
console.print("[cyan]Loading knowledge base...[/cyan]", end="\r")
try:
collection = load_collection(CHROMA_DIR, CHROMA_COLLECTION)
except Exception:
console.print("[red]ChromaDB collection not found.[/red]")
console.print("[yellow]Run: uv run python scripts/build_index.py[/yellow]")
sys.exit(1)
graph = _load_graph()
trials = _load_trials()
client = anthropic.Anthropic()
n_chunks = collection.count()
kg_status = f"{graph.number_of_nodes()} KG nodes" if graph else "no KG (run build_graph.py)"
console.print(
f"[green]Ready.[/green] {n_chunks} chunks · {len(trials)} trials · {kg_status}.{' ' * 10}"
)
if not query:
console.print("\n[dim]Example questions:[/dim]")
for ex in _EXAMPLES:
console.print(f"[dim] • {ex}[/dim]")
console.print()
try:
query = console.input("[bold]Ask about ALS research:[/bold] ").strip()
except (KeyboardInterrupt, EOFError):
sys.exit(0)
if not query:
sys.exit(0)
console.print()
for event_type, content in stream_research_agent(client, query, collection, trials, graph=graph):
if event_type == "status":
console.print(f"[dim italic]{content}[/dim italic]")
elif event_type == "token":
console.print(content, end="", highlight=False)
elif event_type == "done":
console.print()
if __name__ == "__main__":
main()