aidn commited on
Commit
9e2fab4
·
verified ·
1 Parent(s): 2e0b9a9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -188
app.py CHANGED
@@ -2,207 +2,198 @@ import gradio as gr
2
  from huggingface_hub import InferenceClient
3
  import os
4
 
5
- # NEUE PROMPTS: Neutral, kollegial, sachlich und lösungsorientiert
 
 
 
 
 
 
6
  COUNCIL_MEMBERS = {
7
- "🧠 Fachexperte für Struktur (GPT-OSS-120b)": (
8
- "openai/gpt-oss-120b:novita",
9
- """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf der Strukturierung des Themas und dem großen Ganzen.
10
  REGELN:
11
  - Beginne mit: "[STRUKTUR] "
12
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
13
  - Wenn Vorredner gute Punkte gemacht haben, stimme zu und ergänze sinnvolle Aspekte.
14
  - Wenn du etwas anders siehst, korrigiere höflich und fachlich fundiert. Keine künstliche Dramatik."""
15
- ),
16
- "🧐 Fachexperte für Details (DeepSeek-V3)": (
17
- "deepseek-ai/DeepSeek-V3.2:novita",
18
- """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf wichtigen Details, Nuancen und potenziellen Fallstricken.
19
  REGELN:
20
  - Beginne mit: "[DETAILS] "
21
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
22
  - Ergänze die Diskussion um wichtige Aspekte, die vielleicht vergessen wurden (z.B. Alternativen, häufige Anfängerfehler, Kontext).
23
  - Du darfst deinen Vorrednern zustimmen und darauf aufbauen. Widersprich nur, wenn es inhaltlich wirklich nötig ist."""
24
- ),
25
- "🛠️ Fachexperte für Praxis (Llama-4-Maverick)": (
26
- "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8:novita",
27
- """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf der praktischen Umsetzung und Anwendbarkeit.
28
  REGELN:
29
  - Beginne mit: "[PRAXIS] "
30
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
31
  - Übersetze die bisherige Diskussion in greifbare, einfache Ratschläge oder Schritte.
32
  - Baue konstruktiv auf den Ideen der anderen auf. Ergänze praktische Tipps aus der Realität."""
33
- )
34
  }
35
 
36
-
37
- MODERATOR_MODEL = "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8:novita"
38
-
39
-
40
- client = InferenceClient(token=os.getenv("HF_TOKEN"))
41
-
42
- def ask_model(model_id, system_prompt, user_input):
43
- messages = [
44
- {"role": "system", "content": system_prompt},
45
- {"role": "user", "content": user_input}
46
- ]
47
- response = ""
48
- try:
49
- for chunk in client.chat_completion(
50
- model=model_id,
51
- messages=messages,
52
- max_tokens=4000,
53
- temperature=0.4,
54
- stream=True
55
- ):
56
- if hasattr(chunk, "choices") and chunk.choices and len(chunk.choices) > 0:
57
- response += chunk.choices[0].delta.content or ""
58
-
59
- return response
60
- except Exception as e:
61
- return f"🚨 System Error ({model_id}): {str(e)}"
62
-
63
- def run_council(user_prompt, rounds):
64
- if not user_prompt:
65
- yield [{"role": "assistant", "content": "Bitte gib ein Thema oder eine Frage ein, um die Sitzung zu starten."}]
66
- return
67
-
68
- history = [{"role": "user", "content": user_prompt}]
69
- yield history
70
-
71
- discussion_history = ""
72
 
73
- # --- PHASE 1: DAS PLENUM DISKUTIERT ---
74
- for r in range(int(rounds)):
75
- round_header = f"<h2 style='color: #FF5A4D; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>🔄 ZYKLUS {r+1} - EXPERTENDEBATTE</h2>"
76
- history.append({"role": "assistant", "content": round_header})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  yield history
78
 
79
- def run_council(user_prompt, rounds):
80
- if not user_prompt:
81
- yield [{"role": "assistant", "content": "Bitte gib ein Thema oder eine Frage ein, um die Sitzung zu starten."}]
82
- return
83
-
84
- history = [{"role": "user", "content": user_prompt}]
85
- yield history
86
-
87
- discussion_history = ""
88
-
89
- # ==========================================
90
- # NEU: MODERATOR KICK-OFF
91
- # ==========================================
92
- history.append({"role": "assistant", "content": "<h2 style='color: #FF5A4D; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>🎤 MODERATOR: SITZUNGSERÖFFNUNG</h2>"})
93
- yield history
94
-
95
- kickoff_sys = (
96
- "Du bist der Lead-Moderator eines 3-köpfigen Expertenrates (Struktur, Details, Praxis). "
97
- "Deine Aufgabe: Übersetze die eher generische User-Anfrage in ein messerscharfes Briefing für dein Team. "
98
- "Gib in 3-4 Sätzen das klare Ziel vor und weise den Experten ihren initialen Fokus zu. Keine langen Floskeln, sei ein pragmatischer Leader."
99
- )
100
- kickoff_prompt = f"User-Anfrage lautet: '{user_prompt}'\nBitte eröffne die Sitzung und briefe das Team."
101
- kickoff_res = ask_model(MODERATOR_MODEL, kickoff_sys, kickoff_prompt)
102
-
103
- discussion_history += f"Moderator (Sitzungseröffnung): {kickoff_res}\n\n"
104
- display_kickoff = f"**<span style='color: #FF5A4D; font-size: 1.1em;'>🎤 Moderator</span>**\n\n> {kickoff_res}"
105
- history.append({"role": "assistant", "content": display_kickoff})
106
- yield history
107
-
108
- # --- PHASE 1: DAS PLENUM DISKUTIERT ---
109
- for r in range(int(rounds)):
110
- round_header = f"<h2 style='color: #4241A6; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>🔄 ZYKLUS {r+1} - EXPERTENDEBATTE</h2>"
111
- history.append({"role": "assistant", "content": round_header})
112
  yield history
113
 
114
- # ==========================================
115
- # NEU: MODERATOR STEUERT ZWISCHEN DEN RUNDEN (Ab Zyklus 2)
116
- # ==========================================
117
- if r > 0:
118
-
119
- mid_sys = (
120
- "Du bist der Lead-Moderator. Analysiere den Stand der Experten intern, ABER gib als Output NUR EINEN EINZIGEN, harten Arbeitsauftrag (max. 2 Sätze) für die nächste Runde aus. "
121
- "Beispiel: 'Gute Struktur, aber die Flüssigkeitsmengen stimmen rechnerisch nicht. Details-Experte, korrigiere das jetzt!' "
122
- "Kein langes Intro, kein 'Was bisher gut ist' – nur der nackte Befehl."
123
- )
124
-
125
- mid_prompt = f"Bisheriges Protokoll:\n{discussion_history}\n\nGib dem Team die Anweisung für die nächste Runde."
126
- mid_res = ask_model(MODERATOR_MODEL, mid_sys, mid_prompt)
127
-
128
- discussion_history += f"Moderator (Kurskorrektur): {mid_res}\n\n"
129
- display_mid = f"**<span style='color: #FF5A4D; font-size: 1.1em;'>🎤 Moderator (Steuerung)</span>**\n\n> {mid_res}"
130
- history.append({"role": "assistant", "content": display_mid})
131
- yield history
132
 
133
- # --- DIE EXPERTEN ANTWORTEN ---
134
- for name, (model_id, role_focus) in COUNCIL_MEMBERS.items():
135
-
136
- system_msg = (
137
- f"{role_focus}\n\n"
138
- "WICHTIG: Diskutiere konstruktiv. Euer Ziel ist EXAKT das vom User geforderte Endprodukt. "
139
- "Arbeitet ITERATIV am Entwurf und hört zwingend auf die Anweisungen des Moderators."
140
- )
141
 
142
- if discussion_history == "": # Fallback, wird durch Kickoff meist umgangen
143
- current_prompt = f"Auftrag: '{user_prompt}'"
144
- else:
145
- current_prompt = (
146
- f"Der ursprüngliche Auftrag lautet: '{user_prompt}'.\n\n"
147
- f"Bisheriges Protokoll:\n{discussion_history}\n\n"
148
- f"ANWEISUNG FÜR DICH ({name}):\n"
149
- f"1. Richte dich nach der letzten Anweisung des Moderators!\n"
150
- f"2. Fasse Vorredner NICHT zusammen. Wiederhole nichts.\n"
151
- f"3. Bringe den Entwurf konkret voran (z.B. durch Textvorschläge, das Schließen von Lücken oder Formatierungen).\n"
152
- f"4. Komm direkt zum Punkt."
153
- )
154
 
155
- answer = ask_model(model_id, system_msg, current_prompt)
156
-
157
- discussion_history += f"{name}: {answer}\n\n"
158
- display_answer = f"**<span style='color: #4241A6; font-size: 1.1em;'>👤 {name}</span>**\n\n> {answer}"
159
- history.append({"role": "assistant", "content": display_answer})
160
- yield history
161
 
162
- # ==========================================
163
- # PHASE 2 & 3: MODERATOR ZIEHT KONSENS UND BAUT ENDPRODUKT
164
- # (Bleibt identisch wie in deinem Code)
165
- # ==========================================
166
- history.append({"role": "assistant", "content": "<h2 style='color: #FF5A4D; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>🧠 MODERATOR: ANALYSE DER DISKUSSION</h2>"})
167
- yield history
168
-
169
- prep_prompt = (
170
- f"Hier ist das Protokoll einer Experten-Diskussion:\n{discussion_history}\n\n"
171
- "Fasse die wichtigsten Argumente und den finalen pragmatischen Konsens zusammen. "
172
- "WICHTIG: Erhalte ZWINGEND alle konkreten Zahlen, Metriken, Mengenangaben (z.B. ml, bpm), "
173
- "Zutaten und spezifischen Handlungsschritte aus dem Protokoll. "
174
- "Vermeide abstrakte Verallgemeinerungen!"
175
- )
176
- consensus_res = ask_model(MODERATOR_MODEL, "Du bist der Chef-Analyst des Rates.", prep_prompt)
177
-
178
- history.append({"role": "assistant", "content": f"> {consensus_res}"})
179
- yield history
180
 
181
- history.append({"role": "assistant", "content": "<h2 style='color: #FF5A4D; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>🏆 FINALE AUSGABE</h2>"})
182
- yield history
183
-
184
- final_prompt = (
185
- f"Der Benutzer hat folgende Aufgabe gestellt:\n'{user_prompt}'\n\n"
186
- f"Hier ist das vollständige Roh-Protokoll der Experten:\n{discussion_history}\n\n"
187
- f"Hier ist der destillierte Konsens:\n{consensus_res}\n\n"
188
- """ANWEISUNG:
189
- - Erfülle die Aufgabe des Users präzise basierend auf dem Konsens UND greife auf die konkreten Details aus dem Roh-Protokoll zurück.
190
- - Übernimm ZWINGEND alle spezifischen Vorgaben (wie exakte Mengen, Zahlen).
191
- - Wenn der User ein Format wünscht (z.B. Post, Code, Tabelle), halte dich strikt daran.
192
- - Strukturiere Pläne zwingend chronologisch.
193
- - Liefere direkt das fertige, anwendbare Endprodukt ohne Intro!"""
194
- )
195
-
196
- moderator_system_prompt = (
197
- "Du bist ein brillanter Redakteur und Executive Consultant. "
198
- "Liefere AUSSCHLIESSLICH das finale, direkt nutzbare Endprodukt ohne KI-Geschwafel."
199
- )
200
-
201
- final_res = ask_model(MODERATOR_MODEL, moderator_system_prompt, final_prompt)
202
- history.append({"role": "assistant", "content": final_res})
203
- yield history
204
 
205
- # --- THEME ---
 
 
206
  v_theme = gr.themes.Soft(
207
  primary_hue="indigo",
208
  font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
@@ -216,9 +207,7 @@ v_theme = gr.themes.Soft(
216
  color_accent_soft="#FFEBE8",
217
  )
218
 
219
- # --- UI LAYOUT ---
220
- with gr.Blocks() as demo:
221
-
222
  gr.HTML("""
223
  <div style="text-align: center; margin-bottom: 2rem; margin-top: 1rem;">
224
  <h1 style="color: #FF5A4D; font-weight: 900; font-size: 2.8rem; margin-bottom: 0.2rem; font-family: 'Inter', sans-serif; letter-spacing: -0.02em;">PromptPlenum42</h1>
@@ -234,25 +223,18 @@ with gr.Blocks() as demo:
234
  lines=2
235
  )
236
  with gr.Column(scale=1):
237
- rounds_slider = gr.Slider(
238
- minimum=1, maximum=5, value=1, step=1,
239
- label="Diskussionszyklen"
240
- )
241
 
242
  with gr.Row():
243
  start_btn = gr.Button("Sitzung starten", variant="primary", size="lg")
244
  clear_btn = gr.ClearButton(components=[input_text], value="Protokoll leeren", size="lg")
245
 
246
- chatbot = gr.Chatbot(
247
- label="Sitzungsprotokoll",
248
- height=650
249
- )
250
-
251
  clear_btn.add(chatbot)
252
 
253
- input_text.submit(run_council, inputs=[input_text, rounds_slider], outputs=[chatbot])
254
- start_btn.click(run_council, inputs=[input_text, rounds_slider], outputs=[chatbot])
 
255
 
256
  if __name__ == "__main__":
257
- demo.launch(theme=v_theme)
258
-
 
2
  from huggingface_hub import InferenceClient
3
  import os
4
 
5
+ # ==========================================
6
+ # 1. KONFIGURATION & PROMPTS
7
+ # ==========================================
8
+ # Hier lagern wir alle Texte aus, damit die Logik sauber bleibt.
9
+
10
+ MODERATOR_MODEL = "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8:novita"
11
+
12
  COUNCIL_MEMBERS = {
13
+ "🧠 Fachexperte für Struktur (GPT-OSS-120b)": {
14
+ "model": "openai/gpt-oss-120b:novita",
15
+ "role": """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf der Strukturierung des Themas und dem großen Ganzen.
16
  REGELN:
17
  - Beginne mit: "[STRUKTUR] "
18
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
19
  - Wenn Vorredner gute Punkte gemacht haben, stimme zu und ergänze sinnvolle Aspekte.
20
  - Wenn du etwas anders siehst, korrigiere höflich und fachlich fundiert. Keine künstliche Dramatik."""
21
+ },
22
+ "🧐 Fachexperte für Details (DeepSeek-V3)": {
23
+ "model": "deepseek-ai/DeepSeek-V3.2:novita",
24
+ "role": """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf wichtigen Details, Nuancen und potenziellen Fallstricken.
25
  REGELN:
26
  - Beginne mit: "[DETAILS] "
27
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
28
  - Ergänze die Diskussion um wichtige Aspekte, die vielleicht vergessen wurden (z.B. Alternativen, häufige Anfängerfehler, Kontext).
29
  - Du darfst deinen Vorrednern zustimmen und darauf aufbauen. Widersprich nur, wenn es inhaltlich wirklich nötig ist."""
30
+ },
31
+ "🛠️ Fachexperte für Praxis (Llama-4-Maverick)": {
32
+ "model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8:novita",
33
+ "role": """Du bist ein neutraler, sachlicher Fachexperte. Dein Fokus liegt auf der praktischen Umsetzung und Anwendbarkeit.
34
  REGELN:
35
  - Beginne mit: "[PRAXIS] "
36
  - Antworte in 2-4 Sätzen, professionell und bodenständig.
37
  - Übersetze die bisherige Diskussion in greifbare, einfache Ratschläge oder Schritte.
38
  - Baue konstruktiv auf den Ideen der anderen auf. Ergänze praktische Tipps aus der Realität."""
39
+ }
40
  }
41
 
42
+ class PromptManager:
43
+ """Verwaltet alle dynamischen Prompts für Moderator und Experten."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ @staticmethod
46
+ def get_moderator_kickoff_sys():
47
+ return (
48
+ "Du bist der Lead-Moderator eines 3-köpfigen Expertenrates (Struktur, Details, Praxis). "
49
+ "Deine Aufgabe: Übersetze die eher generische User-Anfrage in ein messerscharfes Briefing für dein Team. "
50
+ "Gib in 3-4 Sätzen das klare Ziel vor und weise den Experten ihren initialen Fokus zu. Keine langen Floskeln, sei ein pragmatischer Leader."
51
+ )
52
+
53
+ @staticmethod
54
+ def get_moderator_mid_sys():
55
+ return (
56
+ "Du bist der Lead-Moderator. Analysiere den Stand der Experten intern, ABER gib als Output nur direkte harte Arbeitsäuftrage für die nächste Runde aus. "
57
+ "Beispiel: 'Gute Struktur, aber die Flüssigkeitsmengen stimmen rechnerisch nicht. Details-Experte, korrigiere das jetzt!' usw "
58
+ "Kein langes Intro, kein 'Was bisher gut ist' – nur der nackte Befehl."
59
+ )
60
+
61
+ @staticmethod
62
+ def get_expert_sys(role_focus):
63
+ return (
64
+ f"{role_focus}\n\n"
65
+ "WICHTIG: Diskutiere konstruktiv. Euer Ziel ist EXAKT das vom User geforderte Endprodukt. "
66
+ "Arbeitet ITERATIV am Entwurf und hört zwingend auf die Anweisungen des Moderators."
67
+ )
68
+
69
+ @staticmethod
70
+ def get_expert_user_prompt(user_prompt, discussion_history, name):
71
+ if not discussion_history:
72
+ return f"Auftrag: '{user_prompt}'"
73
+ return (
74
+ f"Der ursprüngliche Auftrag lautet: '{user_prompt}'.\n\n"
75
+ f"Bisheriges Protokoll:\n{discussion_history}\n\n"
76
+ f"ANWEISUNG FÜR DICH ({name}):\n"
77
+ f"1. Richte dich nach der letzten Anweisung des Moderators!\n"
78
+ f"2. Fasse Vorredner NICHT zusammen. Wiederhole nichts.\n"
79
+ f"3. Bringe den Entwurf konkret voran (z.B. durch Textvorschläge, das Schließen von Lücken oder Formatierungen).\n"
80
+ f"4. Komm direkt zum Punkt."
81
+ )
82
+
83
+ # ==========================================
84
+ # 2. CORE SERVICES (API & UI Helpers)
85
+ # ==========================================
86
+ class LLMService:
87
+ """Kapselt die gesamte API-Kommunikation mit Hugging Face."""
88
+ def __init__(self):
89
+ self.client = InferenceClient(token=os.getenv("HF_TOKEN"))
90
+
91
+ def ask(self, model_id, system_prompt, user_input):
92
+ messages = [
93
+ {"role": "system", "content": system_prompt},
94
+ {"role": "user", "content": user_input}
95
+ ]
96
+ response = ""
97
+ try:
98
+ for chunk in self.client.chat_completion(
99
+ model=model_id, messages=messages, max_tokens=4000, temperature=0.4, stream=True
100
+ ):
101
+ if hasattr(chunk, "choices") and chunk.choices and len(chunk.choices) > 0:
102
+ response += chunk.choices[0].delta.content or ""
103
+ return response
104
+ except Exception as e:
105
+ return f"🚨 System Error ({model_id}): {str(e)}"
106
+
107
+ class UIHelper:
108
+ """Formatiert Ausgaben für die Gradio Chatbot-UI."""
109
+ @staticmethod
110
+ def header(title, color="#FF5A4D"):
111
+ return f"<h2 style='color: {color}; border-bottom: 2px solid #FFEBE8; padding-bottom: 5px; margin-top: 20px;'>{title}</h2>"
112
+
113
+ @staticmethod
114
+ def message(name, content, color="#4241A6"):
115
+ return f"**<span style='color: {color}; font-size: 1.1em;'>👤 {name}</span>**\n\n> {content}"
116
+
117
+ # ==========================================
118
+ # 3. DER ORCHESTRATOR (Die Business Logik)
119
+ # ==========================================
120
+ class PlenumOrchestrator:
121
+ """Steuert den gesamten Diskussions- und Generierungsprozess."""
122
+ def __init__(self):
123
+ self.llm = LLMService()
124
+ self.prompts = PromptManager()
125
+ self.ui = UIHelper()
126
+
127
+ def run(self, user_prompt, rounds):
128
+ if not user_prompt:
129
+ yield [{"role": "assistant", "content": "Bitte gib ein Thema oder eine Frage ein."}]
130
+ return
131
+
132
+ history = [{"role": "user", "content": user_prompt}]
133
  yield history
134
 
135
+ discussion_history = ""
136
+
137
+ # --- KICK-OFF ---
138
+ history.append({"role": "assistant", "content": self.ui.header("🎤 MODERATOR: SITZUNGSERÖFFNUNG")})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  yield history
140
 
141
+ kickoff_res = self.llm.ask(MODERATOR_MODEL, self.prompts.get_moderator_kickoff_sys(), f"User-Anfrage: '{user_prompt}'\nBriefe das Team.")
142
+ discussion_history += f"Moderator (Kick-off): {kickoff_res}\n\n"
143
+ history.append({"role": "assistant", "content": self.ui.message("🎤 Moderator", kickoff_res, "#FF5A4D")})
144
+ yield history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ # --- ZYKLEN ---
147
+ for r in range(int(rounds)):
148
+ history.append({"role": "assistant", "content": self.ui.header(f"🔄 ZYKLUS {r+1} - EXPERTENDEBATTE", "#4241A6")})
149
+ yield history
 
 
 
 
150
 
151
+ # Moderator Steuerung (ab Runde 2)
152
+ if r > 0:
153
+ mid_res = self.llm.ask(MODERATOR_MODEL, self.prompts.get_moderator_mid_sys(), f"Protokoll:\n{discussion_history}\n\nGib die Anweisung.")
154
+ discussion_history += f"Moderator (Steuerung): {mid_res}\n\n"
155
+ history.append({"role": "assistant", "content": self.ui.message("🎤 Moderator (Steuerung)", mid_res, "#FF5A4D")})
156
+ yield history
157
+
158
+ # Experten antworten
159
+ for name, config in COUNCIL_MEMBERS.items():
160
+ sys_msg = self.prompts.get_expert_sys(config["role"])
161
+ user_msg = self.prompts.get_expert_user_prompt(user_prompt, discussion_history, name)
 
162
 
163
+ answer = self.llm.ask(config["model"], sys_msg, user_msg)
164
+ discussion_history += f"{name}: {answer}\n\n"
165
+
166
+ history.append({"role": "assistant", "content": self.ui.message(name, answer)})
167
+ yield history
 
168
 
169
+ # --- ANALYSE ---
170
+ history.append({"role": "assistant", "content": self.ui.header("🧠 MODERATOR: ANALYSE DER DISKUSSION")})
171
+ yield history
172
+
173
+ prep_sys = "Du bist der Chef-Analyst des Rates."
174
+ prep_user = f"Protokoll:\n{discussion_history}\n\nFasse zusammen. Erhalte ZWINGEND alle konkreten Zahlen, Zutaten und Schritte. Vermeide Verallgemeinerungen!"
175
+ consensus_res = self.llm.ask(MODERATOR_MODEL, prep_sys, prep_user)
176
+
177
+ history.append({"role": "assistant", "content": f"> {consensus_res}"})
178
+ yield history
 
 
 
 
 
 
 
 
179
 
180
+ # --- FINALE AUSGABE ---
181
+ history.append({"role": "assistant", "content": self.ui.header("🏆 FINALE AUSGABE")})
182
+ yield history
183
+
184
+ final_sys = "Du bist ein brillanter Redakteur. Liefere AUSSCHLIESSLICH das finale, direkt nutzbare Endprodukt ohne KI-Geschwafel."
185
+ final_user = f"Auftrag:\n'{user_prompt}'\n\nKonsens:\n{consensus_res}\n\nErfülle den Auftrag präzise, übernimm alle Zahlen/Fakten, strukturiere Pläne chronologisch und liefere das fertige Endprodukt."
186
+
187
+ final_res = self.llm.ask(MODERATOR_MODEL, final_sys, final_user)
188
+ history.append({"role": "assistant", "content": final_res})
189
+ yield history
190
+
191
+ # Instanziiere den Orchestrator
192
+ orchestrator = PlenumOrchestrator()
 
 
 
 
 
 
 
 
 
 
193
 
194
+ # ==========================================
195
+ # 4. GRADIO UI
196
+ # ==========================================
197
  v_theme = gr.themes.Soft(
198
  primary_hue="indigo",
199
  font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
 
207
  color_accent_soft="#FFEBE8",
208
  )
209
 
210
+ with gr.Blocks(theme=v_theme) as demo:
 
 
211
  gr.HTML("""
212
  <div style="text-align: center; margin-bottom: 2rem; margin-top: 1rem;">
213
  <h1 style="color: #FF5A4D; font-weight: 900; font-size: 2.8rem; margin-bottom: 0.2rem; font-family: 'Inter', sans-serif; letter-spacing: -0.02em;">PromptPlenum42</h1>
 
223
  lines=2
224
  )
225
  with gr.Column(scale=1):
226
+ rounds_slider = gr.Slider(minimum=1, maximum=5, value=1, step=1, label="Diskussionszyklen")
 
 
 
227
 
228
  with gr.Row():
229
  start_btn = gr.Button("Sitzung starten", variant="primary", size="lg")
230
  clear_btn = gr.ClearButton(components=[input_text], value="Protokoll leeren", size="lg")
231
 
232
+ chatbot = gr.Chatbot(label="Sitzungsprotokoll", height=650)
 
 
 
 
233
  clear_btn.add(chatbot)
234
 
235
+ # UI Events an den Orchestrator binden
236
+ input_text.submit(orchestrator.run, inputs=[input_text, rounds_slider], outputs=[chatbot])
237
+ start_btn.click(orchestrator.run, inputs=[input_text, rounds_slider], outputs=[chatbot])
238
 
239
  if __name__ == "__main__":
240
+ demo.launch()