Download app_2.py from dtometzki/VL_AI: direct link, hf CLI and curl.
- Browser
- Download file 5.18 kB
-
https://huggingface.co/spaces/dtometzki/VL_AI/resolve/139b7ee86093f877db705ef6fbd89a1ff8d3661a/app_2.py
- Command line
-
hf download hf://spaces/dtometzki/VL_AI@139b7ee86093f877db705ef6fbd89a1ff8d3661a/app_2.py
-
curl -L -o app_2.py https://huggingface.co/spaces/dtometzki/VL_AI/resolve/139b7ee86093f877db705ef6fbd89a1ff8d3661a/app_2.py
5.18 kB
| 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( | |
| )), | |
| ] | |
| def build_generate_content_config(model_name): | |
| config_kwargs = {"tools": tools} | |
| # 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__": | |
| demo.launch() | |