#!/usr/bin/env python3 """KNIEPUNKT Assistant — weekly editorial workflow for Dr. André Knie.""" from rich.console import Console from rich.panel import Panel from rich.prompt import Confirm from kniepunkt.llm import get_client from kniepunkt.providers import get_configured from kniepunkt import episodes as ep_module from kniepunkt import session as sess_module from kniepunkt import research, storyline, drafting, quality, publication console = Console() def _header(): console.print(Panel( "[bold cyan]KNIEPUNKT Assistant[/bold cyan]\n" "[dim]Redaktioneller Workflow · Dr. André Knie[/dim]", border_style="cyan", )) def _build_or_load_index(client) -> list[dict]: import json from pathlib import Path cache = Path("episodes_cache.json") if cache.exists(): rebuild = Confirm.ask("\n[dim]Episode-Index vorhanden. Neu aufbauen?[/dim]", default=False) if not rebuild: with open(cache) as f: index = json.load(f) console.print(f"[green]Episode-Index: {len(index)} Episoden geladen[/green]") return index console.print("\n[yellow]Baue Episode-Index auf (einmalig, danach gecacht)...[/yellow]") index = ep_module.build_index(client, force=True) console.print(f"[green]Episode-Index erstellt: {len(index)} Episoden[/green]") return index def _run(client, providers: list, session: dict, index: list): episodes_context = ep_module.format_for_context(index) # ── 1. Research ────────────────────────────────────────────────────────── if session["step"] == "research": author_input = research.get_author_input() news_digest = research.research_news(client, author_input, episodes_context) console.print(Panel(news_digest, title="Nachrichten-Kandidaten", border_style="green")) session["research"] = {"author_input": author_input, "news_digest": news_digest} session["step"] = "sources" sess_module.save(session) # ── 2. Source assessment ───────────────────────────────────────────────── if session["step"] == "sources": source_assessment = research.assess_sources(client, session["research"]["news_digest"]) console.print(Panel(source_assessment, title="Quellenbewertung", border_style="yellow")) if not Confirm.ask("\nWeiter zur Storyline-Entwicklung?", default=True): console.print("[dim]Session gespeichert. Neustart setzt hier fort.[/dim]") return session["sources"] = source_assessment session["step"] = "storyline" sess_module.save(session) # ── 3. Storyline ───────────────────────────────────────────────────────── if session["step"] == "storyline": results = storyline.generate_storylines( providers, session["research"]["news_digest"], session["sources"], session["research"]["author_input"], episodes_context, ) provider_name, choice, selected_text, adjustments = storyline.select_storyline(results) session["storyline"] = { "results": results, "selected_provider": provider_name, "choice": choice, "selected_text": selected_text, "adjustments": adjustments, } session["step"] = "draft" sess_module.save(session) # ── 4. Draft ───────────────────────────────────────────────────────────── if session["step"] == "draft": sl = session["storyline"] draft_results = drafting.generate_drafts( providers, sl["selected_text"], sl["choice"], sl["adjustments"], session["research"]["news_digest"], session["sources"], session["research"]["author_input"], ) provider_name, draft = drafting.select_draft(draft_results) console.print("\n[dim]Überarbeitungshinweise? (Enter = Entwurf übernehmen)[/dim]") feedback = input().strip() if feedback: draft = drafting.enrich_draft(client, draft, feedback) console.print(Panel(draft, title="Überarbeiteter Entwurf", border_style="green")) session["draft_results"] = draft_results session["draft"] = draft session["step"] = "quality" sess_module.save(session) # ── 5. Quality review ──────────────────────────────────────────────────── if session["step"] == "quality": quality_report = quality.review( client, session["draft"], session["sources"], episodes_context, ) console.print(Panel(quality_report, title="Qualitätsprüfung", border_style="yellow")) console.print("\n[dim]Weitere Überarbeitungen? (Enter = weiter zur Publikation)[/dim]") feedback = input().strip() if feedback: draft = drafting.enrich_draft(client, session["draft"], feedback) session["draft"] = draft console.print(Panel(draft, title="Finalisierter Entwurf", border_style="green")) session["quality"] = quality_report session["step"] = "publication" sess_module.save(session) # ── 6. Publication prep ────────────────────────────────────────────────── if session["step"] == "publication": teasers = publication.generate_teasers(client, session["draft"]) console.print(Panel(teasers, title="Teaser-Varianten", border_style="cyan")) visual_ideas = publication.generate_visual_ideas(client, session["draft"]) console.print(Panel(visual_ideas, title="Cover-Ideen", border_style="cyan")) out_path = publication.save_package( session["date"], session["draft"], teasers, session["sources"], visual_ideas, ) console.print(Panel( f"[green]Publikationspaket gespeichert:[/green] {out_path}\n\n" "Enthält: Artikel · Teaser-Varianten · Cover-Ideen · Quellenbewertung", title="✓ Fertig", border_style="green", )) session["publication"] = {"teasers": teasers, "visual_ideas": visual_ideas} session["step"] = "done" sess_module.save(session) def main(): _header() try: client = get_client() except RuntimeError as e: console.print(f"[red]{e}[/red]\nBitte ANTHROPIC_API_KEY in der .env-Datei eintragen.") return providers = get_configured() if not providers: console.print("[red]Keine LLM-API-Keys konfiguriert. Bitte .env-Datei prüfen.[/red]") return provider_names = ", ".join(p.name for p in providers) console.print(f"[green]Aktive Modelle: {provider_names}[/green]") index = _build_or_load_index(client) latest = sess_module.load_latest() session = None if latest and latest.get("step") not in ("done",): if Confirm.ask( f"\nGefundene Session vom [bold]{latest['date']}[/bold] " f"(Schritt: [bold]{latest['step']}[/bold]). Fortfahren?", default=True, ): session = latest if session is None: session = sess_module.new_session() console.print(f"\n[green]Neue Session: {session['date']}[/green]") _run(client, providers, session, index) if __name__ == "__main__": main()