Add KNIEPUNKT Assistant with multi-LLM editorial workflow

Six-step weekly workflow (research → sources → storyline → draft →
quality → publication) supporting Claude, ChatGPT, Gemini, and Mistral
in parallel for creative steps. Web search via Anthropic tool for news
research. Episode index built from 34 existing KNIEPUNKT episodes for
redundancy checks. Sessions persisted as JSON for mid-workflow resume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 23:54:23 +02:00
commit e08c484838
57 changed files with 3240 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
"""Storyline generation across all configured providers and author selection."""
from rich.console import Console
from rich.panel import Panel
from rich.prompt import IntPrompt, Prompt
console = Console()
_SYSTEM = """Du bist ein erfahrener Redaktionsassistent für die LinkedIn-Kolumne KNIEPUNKT von Dr. André Knie.
KNIEPUNKT ist kolumnenhaft, glossenhaft, amüsant, kulturell gebildet und meinungsstark.
Erlaubt: griechische/römische Mythologie, Kanonliteratur, klassische deutsche Literatur.
Zielgruppe: hochgebildete Entscheider aus Mittelstand, Konzernen und öffentlicher Verwaltung mit Interesse an moralischer KI.
Eine Storyline verbindet ausgewählte Nachrichten zu einem kohärenten redaktionellen Blickwinkel kein neutrales Nachrichtenreferat."""
def _build_prompt(news_digest: str, source_assessment: str, author_input: dict, episodes_context: str) -> str:
initial = (
f"\nVorläufige Autorenstoryline: {author_input['initial_storyline']}"
if author_input.get("initial_storyline")
else ""
)
return f"""Entwickle 3 klar unterschiedliche Storyline-Optionen für die nächste KNIEPUNKT-Episode.
Nachrichten dieser Woche:
{news_digest}
Quellenbewertung (berücksichtigen):
{source_assessment[:800]}
Frühere Episoden Redundanzvermeidung:
{episodes_context[:2000]}
{initial}
Für jede Storyline:
**Option [N]: [Arbeitstitel]**
- **Kernwinkel:** Was ist der redaktionelle Blickwinkel? (2-3 Sätze)
- **Nachrichten-Auswahl:** Welche 2-3 Nachrichten werden verwendet und wie verknüpft?
- **Einstiegsidee:** Konkrete Idee für den ersten Satz oder Absatz
- **Allegorischer Rahmen:** Mythologie, Literatur oder kulturelle Referenz (falls passend)
- **Unterschied** zu den anderen Optionen
- **Stärken / Risiken**
Vermeide: Redundanzen zu früheren Episoden, reines Nachrichtenreferat ohne Meinung, zu technische Tiefe."""
def generate_storylines(
providers: list,
news_digest: str,
source_assessment: str,
author_input: dict,
episodes_context: str,
) -> dict[str, str]:
"""Run storyline generation on all providers. Returns {provider_name: result}."""
prompt = _build_prompt(news_digest, source_assessment, author_input, episodes_context)
messages = [{"role": "user", "content": prompt}]
results = {}
for provider in providers:
console.print(f"\n[yellow]Generiere Storylines mit {provider.name}...[/yellow]")
try:
results[provider.name] = provider.chat(messages, _SYSTEM, max_tokens=4096)
except Exception as e:
console.print(f"[red]{provider.name} übersprungen: {e}[/red]")
return results
def select_storyline(results: dict[str, str]) -> tuple[str, int, str, str]:
"""Show all provider results, return (provider_name, choice, selected_text, adjustments)."""
if not results:
raise RuntimeError("Kein Modell hat Storylines geliefert. API-Keys und Verbindung prüfen.")
provider_names = list(results.keys())
for name, text in results.items():
console.print(Panel(text, title=f"Storylines {name}", border_style="cyan"))
console.print()
if len(provider_names) > 1:
provider_choice = Prompt.ask(
"Von welchem Modell möchten Sie eine Storyline wählen?",
choices=provider_names,
default=provider_names[0],
)
else:
provider_choice = provider_names[0]
option_choice = IntPrompt.ask(
f"Welche Storyline von {provider_choice}? (1/2/3)",
choices=["1", "2", "3"],
default=1,
)
console.print("\n[dim]Anpassungen oder zusätzliche Hinweise zur gewählten Storyline? (Enter zum Überspringen)[/dim]")
adjustments = input().strip()
return provider_choice, option_choice, results[provider_choice], adjustments