Spaces:
Sleeping
Sleeping
Update Gradio_UI.py
Browse files- Gradio_UI.py +113 -24
Gradio_UI.py
CHANGED
|
@@ -17,8 +17,16 @@ import mimetypes
|
|
| 17 |
import os
|
| 18 |
import re
|
| 19 |
import shutil
|
|
|
|
| 20 |
from typing import Optional
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
from smolagents.agent_types import AgentAudio, AgentImage, AgentText, handle_agent_output_types
|
| 23 |
from smolagents.agents import ActionStep, MultiStepAgent
|
| 24 |
from smolagents.memory import MemoryStep
|
|
@@ -31,6 +39,7 @@ def pull_messages_from_step(
|
|
| 31 |
"""Extract ChatMessage objects from agent steps with proper nesting"""
|
| 32 |
import gradio as gr
|
| 33 |
|
|
|
|
| 34 |
if isinstance(step_log, ActionStep):
|
| 35 |
# Output the step number
|
| 36 |
step_number = f"Step {step_log.step_number}" if step_log.step_number is not None else ""
|
|
@@ -156,22 +165,48 @@ def stream_to_gradio(
|
|
| 156 |
final_answer = step_log # Last log is the run's final_answer
|
| 157 |
final_answer = handle_agent_output_types(final_answer)
|
| 158 |
|
|
|
|
| 159 |
if isinstance(final_answer, AgentText):
|
| 160 |
yield gr.ChatMessage(
|
| 161 |
role="assistant",
|
| 162 |
content=f"**Final answer:**\n{final_answer.to_string()}\n",
|
| 163 |
)
|
| 164 |
elif isinstance(final_answer, AgentImage):
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
elif isinstance(final_answer, AgentAudio):
|
|
|
|
| 170 |
yield gr.ChatMessage(
|
| 171 |
role="assistant",
|
| 172 |
content={"path": final_answer.to_string(), "mime_type": "audio/wav"},
|
| 173 |
)
|
| 174 |
else:
|
|
|
|
| 175 |
yield gr.ChatMessage(role="assistant", content=f"**Final answer:** {str(final_answer)}")
|
| 176 |
|
| 177 |
|
|
@@ -186,19 +221,31 @@ class GradioUI:
|
|
| 186 |
self.agent = agent
|
| 187 |
self.file_upload_folder = file_upload_folder
|
| 188 |
if self.file_upload_folder is not None:
|
| 189 |
-
|
| 190 |
-
|
|
|
|
| 191 |
|
| 192 |
def interact_with_agent(self, prompt, messages):
|
| 193 |
import gradio as gr
|
| 194 |
|
| 195 |
messages.append(gr.ChatMessage(role="user", content=prompt))
|
| 196 |
yield messages
|
| 197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
messages.append(msg)
|
| 199 |
yield messages
|
| 200 |
yield messages
|
| 201 |
|
|
|
|
| 202 |
def upload_file(
|
| 203 |
self,
|
| 204 |
file,
|
|
@@ -241,11 +288,17 @@ class GradioUI:
|
|
| 241 |
sanitized_name.append("" + type_to_ext[mime_type])
|
| 242 |
sanitized_name = "".join(sanitized_name)
|
| 243 |
|
| 244 |
-
#
|
| 245 |
-
|
| 246 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
|
| 248 |
-
return gr.Textbox(f"File uploaded: {file_path}", visible=True), file_uploads_log + [file_path]
|
| 249 |
|
| 250 |
def log_user_message(self, text_input, file_uploads_log):
|
| 251 |
return (
|
|
@@ -266,31 +319,67 @@ class GradioUI:
|
|
| 266 |
file_uploads_log = gr.State([])
|
| 267 |
chatbot = gr.Chatbot(
|
| 268 |
label="Agent",
|
| 269 |
-
type="messages",
|
|
|
|
|
|
|
| 270 |
avatar_images=(
|
| 271 |
-
None,
|
| 272 |
-
|
|
|
|
| 273 |
),
|
| 274 |
-
|
| 275 |
-
|
| 276 |
)
|
| 277 |
# If an upload folder is provided, enable the upload feature
|
| 278 |
if self.file_upload_folder is not None:
|
| 279 |
-
|
| 280 |
-
|
|
|
|
|
|
|
| 281 |
upload_file.change(
|
| 282 |
self.upload_file,
|
| 283 |
[upload_file, file_uploads_log],
|
| 284 |
[upload_status, file_uploads_log],
|
| 285 |
)
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
self.log_user_message,
|
| 289 |
[text_input, file_uploads_log],
|
| 290 |
-
[stored_messages, text_input],
|
| 291 |
-
).then(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
|
| 293 |
-
|
|
|
|
|
|
|
|
|
|
| 294 |
|
| 295 |
|
| 296 |
-
__all__ = ["stream_to_gradio", "GradioUI"]
|
|
|
|
| 17 |
import os
|
| 18 |
import re
|
| 19 |
import shutil
|
| 20 |
+
import tempfile # Import für temporäre Dateien
|
| 21 |
from typing import Optional
|
| 22 |
|
| 23 |
+
# Importiere PIL für Bildverarbeitung (füge 'Pillow' zu requirements.txt hinzu, falls nicht vorhanden)
|
| 24 |
+
try:
|
| 25 |
+
from PIL import Image
|
| 26 |
+
except ImportError:
|
| 27 |
+
print("WARNUNG: Pillow nicht installiert. Bildanzeige funktioniert möglicherweise nicht. Führe 'pip install Pillow' aus oder füge 'Pillow' zu requirements.txt hinzu.")
|
| 28 |
+
Image = None
|
| 29 |
+
|
| 30 |
from smolagents.agent_types import AgentAudio, AgentImage, AgentText, handle_agent_output_types
|
| 31 |
from smolagents.agents import ActionStep, MultiStepAgent
|
| 32 |
from smolagents.memory import MemoryStep
|
|
|
|
| 39 |
"""Extract ChatMessage objects from agent steps with proper nesting"""
|
| 40 |
import gradio as gr
|
| 41 |
|
| 42 |
+
# --- (Rest dieser Funktion bleibt unverändert) ---
|
| 43 |
if isinstance(step_log, ActionStep):
|
| 44 |
# Output the step number
|
| 45 |
step_number = f"Step {step_log.step_number}" if step_log.step_number is not None else ""
|
|
|
|
| 165 |
final_answer = step_log # Last log is the run's final_answer
|
| 166 |
final_answer = handle_agent_output_types(final_answer)
|
| 167 |
|
| 168 |
+
# --- *** HIER IST DIE ÄNDERUNG FÜR DIE BILDANZEIGE *** ---
|
| 169 |
if isinstance(final_answer, AgentText):
|
| 170 |
yield gr.ChatMessage(
|
| 171 |
role="assistant",
|
| 172 |
content=f"**Final answer:**\n{final_answer.to_string()}\n",
|
| 173 |
)
|
| 174 |
elif isinstance(final_answer, AgentImage):
|
| 175 |
+
# Versuche, das Bild anzuzeigen
|
| 176 |
+
try:
|
| 177 |
+
# Annahme: final_answer.image enthält ein PIL Image Objekt
|
| 178 |
+
if Image is not None and hasattr(final_answer, 'image') and isinstance(final_answer.image, Image.Image):
|
| 179 |
+
# Erstelle eine temporäre Datei zum Speichern des Bildes
|
| 180 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
|
| 181 |
+
final_answer.image.save(tmpfile.name, format="PNG")
|
| 182 |
+
temp_file_path = tmpfile.name
|
| 183 |
+
print(f"Bild temporär gespeichert unter: {temp_file_path}") # Debugging-Ausgabe
|
| 184 |
+
|
| 185 |
+
# Gib das ChatMessage mit dem Pfad zur temporären Datei zurück
|
| 186 |
+
yield gr.ChatMessage(
|
| 187 |
+
role="assistant",
|
| 188 |
+
content={"path": temp_file_path, "mime_type": "image/png"},
|
| 189 |
+
# Optional: Füge Text hinzu, falls die Bildanzeige fehlschlägt
|
| 190 |
+
# content=f"Generated Image (saved at {temp_file_path}):",
|
| 191 |
+
)
|
| 192 |
+
else:
|
| 193 |
+
# Fallback, wenn .image nicht das erwartete PIL-Objekt ist oder Pillow fehlt
|
| 194 |
+
print("WARNUNG: Konnte Bild nicht als PIL-Objekt interpretieren. Zeige Text-Repräsentation.")
|
| 195 |
+
yield gr.ChatMessage(role="assistant", content=f"**Final answer (Image Object):** {str(final_answer)}")
|
| 196 |
+
|
| 197 |
+
except Exception as e:
|
| 198 |
+
print(f"FEHLER beim Verarbeiten/Anzeigen des Bildes: {e}")
|
| 199 |
+
# Fallback zur Textanzeige bei Fehlern
|
| 200 |
+
yield gr.ChatMessage(role="assistant", content=f"**Final answer (Error displaying Image):** {str(final_answer)}")
|
| 201 |
+
|
| 202 |
elif isinstance(final_answer, AgentAudio):
|
| 203 |
+
# Annahme: Funktioniert ähnlich wie bei Bildern, falls nötig anpassen
|
| 204 |
yield gr.ChatMessage(
|
| 205 |
role="assistant",
|
| 206 |
content={"path": final_answer.to_string(), "mime_type": "audio/wav"},
|
| 207 |
)
|
| 208 |
else:
|
| 209 |
+
# Fallback für andere Typen
|
| 210 |
yield gr.ChatMessage(role="assistant", content=f"**Final answer:** {str(final_answer)}")
|
| 211 |
|
| 212 |
|
|
|
|
| 221 |
self.agent = agent
|
| 222 |
self.file_upload_folder = file_upload_folder
|
| 223 |
if self.file_upload_folder is not None:
|
| 224 |
+
# Erstelle Ordner, wenn er nicht existiert
|
| 225 |
+
os.makedirs(self.file_upload_folder, exist_ok=True)
|
| 226 |
+
|
| 227 |
|
| 228 |
def interact_with_agent(self, prompt, messages):
|
| 229 |
import gradio as gr
|
| 230 |
|
| 231 |
messages.append(gr.ChatMessage(role="user", content=prompt))
|
| 232 |
yield messages
|
| 233 |
+
# Verwende einen temporären Ordner für generierte Bilder, falls keiner angegeben ist
|
| 234 |
+
# Dies ist wichtig, damit Gradio auf die Dateien zugreifen kann
|
| 235 |
+
temp_image_dir = os.path.join(tempfile.gettempdir(), "gradio_agent_images")
|
| 236 |
+
os.makedirs(temp_image_dir, exist_ok=True)
|
| 237 |
+
|
| 238 |
+
# Füge den temporären Ordner zu additional_args hinzu,
|
| 239 |
+
# damit stream_to_gradio ihn verwenden kann (optional, aber sauberer)
|
| 240 |
+
# current_additional_args = {"image_output_dir": temp_image_dir}
|
| 241 |
+
|
| 242 |
+
# Iteriere durch die Nachrichten vom Agenten
|
| 243 |
+
for msg in stream_to_gradio(self.agent, task=prompt, reset_agent_memory=False): #, additional_args=current_additional_args):
|
| 244 |
messages.append(msg)
|
| 245 |
yield messages
|
| 246 |
yield messages
|
| 247 |
|
| 248 |
+
# --- (Rest der Klasse GradioUI bleibt unverändert) ---
|
| 249 |
def upload_file(
|
| 250 |
self,
|
| 251 |
file,
|
|
|
|
| 288 |
sanitized_name.append("" + type_to_ext[mime_type])
|
| 289 |
sanitized_name = "".join(sanitized_name)
|
| 290 |
|
| 291 |
+
# Ensure the upload folder exists
|
| 292 |
+
if self.file_upload_folder:
|
| 293 |
+
os.makedirs(self.file_upload_folder, exist_ok=True)
|
| 294 |
+
# Save the uploaded file to the specified folder
|
| 295 |
+
file_path = os.path.join(self.file_upload_folder, os.path.basename(sanitized_name))
|
| 296 |
+
shutil.copy(file.name, file_path)
|
| 297 |
+
return gr.Textbox(f"File uploaded: {file_path}", visible=True), file_uploads_log + [file_path]
|
| 298 |
+
else:
|
| 299 |
+
# Handle case where no upload folder is specified (optional)
|
| 300 |
+
return gr.Textbox("File upload folder not configured.", visible=True), file_uploads_log
|
| 301 |
|
|
|
|
| 302 |
|
| 303 |
def log_user_message(self, text_input, file_uploads_log):
|
| 304 |
return (
|
|
|
|
| 319 |
file_uploads_log = gr.State([])
|
| 320 |
chatbot = gr.Chatbot(
|
| 321 |
label="Agent",
|
| 322 |
+
# type="messages", # 'type' ist veraltet, wird automatisch gehandhabt
|
| 323 |
+
elem_id="chatbot", # Gib dem Chatbot eine ID für CSS/JS (optional)
|
| 324 |
+
bubble_full_width=False, # Lässt Nachrichten nicht die volle Breite einnehmen (optional)
|
| 325 |
avatar_images=(
|
| 326 |
+
None, # Kein Avatar für User
|
| 327 |
+
# Standard-Avatar für den Assistenten (URL oder lokaler Pfad)
|
| 328 |
+
"[https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo-round-with-padding.png](https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo-round-with-padding.png)"
|
| 329 |
),
|
| 330 |
+
# height=600, # Setze eine feste Höhe (optional)
|
| 331 |
+
render=False # Wir rendern es manuell unten
|
| 332 |
)
|
| 333 |
# If an upload folder is provided, enable the upload feature
|
| 334 |
if self.file_upload_folder is not None:
|
| 335 |
+
with gr.Row(): # Ordne Upload-Elemente an
|
| 336 |
+
upload_file = gr.File(label="Upload a file", scale=1) # Nimmt weniger Platz
|
| 337 |
+
upload_status = gr.Textbox(label="Upload Status", interactive=False, visible=False, scale=2) # Mehr Platz für Status
|
| 338 |
+
|
| 339 |
upload_file.change(
|
| 340 |
self.upload_file,
|
| 341 |
[upload_file, file_uploads_log],
|
| 342 |
[upload_status, file_uploads_log],
|
| 343 |
)
|
| 344 |
+
|
| 345 |
+
with gr.Row(): # Ordne Textfeld und Senden-Button an (optional)
|
| 346 |
+
text_input = gr.Textbox(
|
| 347 |
+
lines=1,
|
| 348 |
+
label="Chat Message",
|
| 349 |
+
placeholder="Type your message here...",
|
| 350 |
+
scale=4 # Gib dem Textfeld mehr Breite
|
| 351 |
+
)
|
| 352 |
+
# submit_button = gr.Button("Send", scale=1) # Optionaler Senden-Button
|
| 353 |
+
|
| 354 |
+
# Rendere den Chatbot hier, damit er über dem Eingabefeld ist
|
| 355 |
+
chatbot.render()
|
| 356 |
+
|
| 357 |
+
# Definiere die Submit-Aktion
|
| 358 |
+
submit_action = text_input.submit(
|
| 359 |
self.log_user_message,
|
| 360 |
[text_input, file_uploads_log],
|
| 361 |
+
[stored_messages, text_input], # Leere Textbox nach Senden
|
| 362 |
+
).then(
|
| 363 |
+
self.interact_with_agent,
|
| 364 |
+
[stored_messages, chatbot],
|
| 365 |
+
[chatbot] # Update Chatbot
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
# Verknüpfe auch den Button mit der Aktion (falls vorhanden)
|
| 369 |
+
# submit_button.click(
|
| 370 |
+
# self.log_user_message,
|
| 371 |
+
# [text_input, file_uploads_log],
|
| 372 |
+
# [stored_messages, text_input],
|
| 373 |
+
# ).then(
|
| 374 |
+
# self.interact_with_agent,
|
| 375 |
+
# [stored_messages, chatbot],
|
| 376 |
+
# [chatbot]
|
| 377 |
+
# )
|
| 378 |
|
| 379 |
+
# Starte die Demo
|
| 380 |
+
# Entferne share=True, da es auf Spaces nicht unterstützt wird und Warnungen verursacht
|
| 381 |
+
# Füge inline=False hinzu, um sicherzustellen, dass es nicht versucht, inline in Notebooks zu laufen
|
| 382 |
+
demo.launch(debug=True, share=False, inline=False, **kwargs)
|
| 383 |
|
| 384 |
|
| 385 |
+
__all__ = ["stream_to_gradio", "GradioUI"]
|