VL_AI / app_2.py
dtometzki's picture
Update app_2.py
c38f251 verified
import os
import shutil
import tempfile
import threading
import gradio as gr
from google import genai
from google.genai import types
client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
DEFAULT_MODEL = "gemini-3.1-flash-lite-preview"
MODELS = [
"gemini-3.1-flash-lite-preview",
"gemini-3.1-pro-preview",
"gemini-3.1-flash-preview",
]
# Tools (einmalig)
tools = [
types.Tool(url_context=types.UrlContext()),
types.Tool(googleSearch=types.GoogleSearch(
)),
]
SYSTEM_PROMPT = """ Du bist ein intelligenter, effizienter und freundlicher persönlicher Assistent.
Dein Ziel ist es, meine Produktivität zu maximieren und mir bei meinen täglichen Aufgaben zu helfen.
Halte dich an diese Richtlinien: Präzision vor
Füllwörtern: Komm direkt auf den Punkt. Vermeide unnötige Einleitungs- oder Abschlussfloskeln (wie 'Ich hoffe, das hilft Ihnen').
Struktur: Verwende für komplexe Antworten Bullet Points, nummerierte Listen oder Fettdruck, um die Lesbarkeit zu erhöhen.
Rückfragen: Wenn meine Anfrage unklar ist oder wichtige Informationen fehlen, frage mich kurz und gezielt nach dem Kontext, bevor du eine Annahme triffst.
Objektivität: Wenn ich um eine Meinung bitte, präsentiere mir verschiedene Perspektiven oder Vor- und Nachteile, anstatt dich einseitig festzulegen.
Anpassungsfähigkeit: Antworte kurz bei kurzen Fragen und ausführlich bei komplexen Themen. Wenn ich um eine Zusammenfassung bitte, halte sie kompakt. Sprache: Antworte immer in der Sprache, in der ich die Frage stelle (standardmäßig Deutsch, sofern nicht anders gewünscht).
"""
def build_generate_content_config(model_name):
config_kwargs = {"tools": tools,
"system_instruction": SYSTEM_PROMPT}
# Pro-Modelle akzeptieren MINIMAL derzeit nicht.
if "pro" not in model_name:
config_kwargs["thinking_config"] = types.ThinkingConfig(
thinking_level="MINIMAL"
)
return types.GenerateContentConfig(**config_kwargs)
def create_chat_state(model_name):
return {
"model": model_name,
"chat": client.chats.create(
model=model_name,
config=build_generate_content_config(model_name),
),
"lock": threading.Lock(),
}
def respond(message, history, state, model_name):
if state is None:
state = create_chat_state(model_name)
elif state.get("model") != model_name:
state = create_chat_state(model_name)
history = history or []
text = (message or {}).get("text", "")
files = (message or {}).get("files", [])
parts = []
# 1. Dateien verarbeiten (Upload via API & UI-Vorbereitung)
for file_path in files:
# Reinen ASCII-Namen generieren (z.B. 'Lsungen-MP-4 1.pdf')
base_name = os.path.basename(file_path)
safe_name = base_name.encode('ascii', 'ignore').decode('ascii')
# Fallback, falls der Name nach der Filterung komplett leer sein sollte
if not safe_name.strip(". "):
safe_name = "upload_file.pdf"
# Temporären, komplett sicheren Pfad generieren
safe_temp_path = os.path.join(tempfile.gettempdir(), f"safe_{safe_name}")
try:
# Datei an den sicheren Ort kopieren
shutil.copy2(file_path, safe_temp_path)
# Upload mit dem sicheren Pfad durchführen
uploaded_file = client.files.upload(
file=safe_temp_path,
config=types.UploadFileConfig(display_name=safe_name)
)
parts.append(uploaded_file)
finally:
# Temporäre Kopie aufräumen, um Speicherplatz zu sparen
if os.path.exists(safe_temp_path):
os.remove(safe_temp_path)
# Datei in der Gradio UI anzeigen (hier nutzen wir den Originalpfad für die korrekte Anzeige)
history.append({"role": "user", "content": gr.FileData(path=file_path)})
# 2. Text verarbeiten
if text:
parts.append(text)
history.append({"role": "user", "content": text})
if not parts:
yield history, state
return
# 3. UI: Assistant Placeholder hinzufügen
history.append({"role": "assistant", "content": ""})
yield history, state
# 4. Gemini: Senden + Streamen
with state["lock"]:
out = ""
for chunk in state["chat"].send_message_stream(parts):
if getattr(chunk, "text", None):
out += chunk.text
history[-1]["content"] = out
yield history, state
def cleanup_gemini_files():
deleted_count = 0
# Holt alle Dateien, die mit deinem API-Key hochgeladen wurden
for f in client.files.list():
# Löscht die Datei über ihren eindeutigen Google-Ressourcennamen
client.files.delete(name=f.name)
deleted_count += 1
# Zeigt ein kleines Popup in der Gradio UI an
gr.Info(f"{deleted_count} Datei(en) erfolgreich gelöscht.")
def clear_msg():
return {"text": "", "files": []}
def reset_chat_for_model_change(_model_name):
return [], None, {"text": "", "files": []}
with gr.Blocks() as demo:
gr.Markdown("# Gemini AI Chat by Damian")
model_selector = gr.Dropdown(
choices=MODELS,
value=DEFAULT_MODEL,
label="Gemini-Modell",
info="Ein Modellwechsel startet einen neuen Chat.",
)
# Standard-Initialisierung für Gradio >= 6.0
chatbot = gr.Chatbot(height=600)
msg = gr.MultimodalTextbox(
placeholder="Schreib was oder lade Dateien hoch…",
file_count="multiple",
)
state = gr.State(None)
msg.submit(respond, inputs=[msg, chatbot, state, model_selector], outputs=[chatbot, state]) \
.then(clear_msg, outputs=msg)
model_selector.change(
fn=reset_chat_for_model_change,
inputs=model_selector,
outputs=[chatbot, state, msg],
)
with gr.Row():
clear_btn = gr.Button("Clear Chat")
cleanup_btn = gr.Button("🗑️ Server-Dateien bereinigen")
clear_btn.click(
lambda: ([], None, {"text": "", "files": []}),
outputs=[chatbot, state, msg]
)
cleanup_btn.click(fn=cleanup_gemini_files)
if __name__ == "__main__":
print("Das Programm startet jetzt.")
demo.launch(server_name="0.0.0.0", server_port=7860)