e08c484838
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>
96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
"""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
|