From b63d4cbf63a87f94077957a87bb3d5c07a56b14b Mon Sep 17 00:00:00 2001 From: "info@pi-farm.de" Date: Fri, 6 Mar 2026 16:36:02 +0000 Subject: [PATCH] main.py aktualisiert --- main.py | 123 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 20 deletions(-) diff --git a/main.py b/main.py index c4cea80..c375011 100644 --- a/main.py +++ b/main.py @@ -86,30 +86,77 @@ def get_system_prompt(): return template.replace("{node_info}", node_info) -# --- KI LOGIK (UNVERÄNDERT) --- +# --- KI FUNKTIONEN --- + async def get_ai_response(user_input, system_prompt): global chat_history + + # 1. Die neue User-Nachricht dem Gedächtnis hinzufügen chat_history.append({"role": "user", "content": user_input}) + + # 2. Gedächtnis auf die letzten 30 Nachrichten begrenzen chat_history = chat_history[-30:] + ai_msg = "" + try: - if AI_PROVIDER in ["openai", "ollama"]: - url = OLLAMA_BASE_URL if AI_PROVIDER == "ollama" else None - if url and not url.endswith('/v1'): url = url.rstrip('/') + '/v1' - key = "ollama" if AI_PROVIDER == "ollama" else OPENAI_API_KEY - model_to_use = OLLAMA_MODEL if AI_PROVIDER == "ollama" else OPENAI_MODEL + if AI_PROVIDER == "openai" or AI_PROVIDER == "ollama": + messages = [{"role": "system", "content": system_prompt}] + chat_history + + # Sicherstellen, dass die URL für Ollama korrekt endet + if AI_PROVIDER == "ollama": + url = OLLAMA_BASE_URL + if not url.endswith('/v1') and not url.endswith('/v1/'): + url = url.rstrip('/') + '/v1' + key = "ollama" + model_to_use = OLLAMA_MODEL + else: + url = None # Benutzt Standard OpenAI URL + key = OPENAI_API_KEY + model_to_use = OPENAI_MODEL + client = openai.OpenAI(base_url=url, api_key=key) - response = client.chat.completions.create(model=model_to_use, messages=[{"role": "system", "content": system_prompt}] + chat_history) + response = client.chat.completions.create( + model=model_to_use, + messages=messages + ) ai_msg = response.choices[0].message.content + elif AI_PROVIDER == "google": + # Für Google Gemini + if not GOOGLE_API_KEY: + return "Fehler: GOOGLE_API_KEY fehlt in der .env Datei!" + client = genai.Client(api_key=GOOGLE_API_KEY) - google_history = [types.Content(role="user" if m["role"] == "user" else "model", parts=[types.Part.from_text(text=msg["content"])]) for msg in chat_history[:-1]] - chat = client.chats.create(model=GOOGLE_MODEL, config=types.GenerateContentConfig(system_instruction=system_prompt), history=google_history) + + # Wir müssen unser Array in das spezielle Google-Format umwandeln + google_history = [] + + # Alle Nachrichten AUSSER der allerletzten (die aktuelle User-Frage) in die History packen + for msg in chat_history[:-1]: + role = "user" if msg["role"] == "user" else "model" + google_history.append( + types.Content(role=role, parts=[types.Part.from_text(text=msg["content"])]) + ) + + # Chat MIT dem übersetzten Gedächtnis starten + chat = client.chats.create( + model=GOOGLE_MODEL, + config=types.GenerateContentConfig(system_instruction=system_prompt), + history=google_history + ) + + # Jetzt erst die neue Nachricht an den Chat mit Gedächtnis schicken response = chat.send_message(user_input) ai_msg = response.text + except Exception as e: - ai_msg = f"KI Fehler: {e}" + ai_msg = f"Fehler bei der KI-Anfrage: {e}" + print(f"KI Fehler: {e}") + + # 3. Die Antwort der KI ebenfalls ins Gedächtnis aufnehmen chat_history.append({"role": "assistant", "content": ai_msg}) + return ai_msg # --- WebSocket Manager --- @@ -313,22 +360,43 @@ async def run_remote_task(ip, user, cmd): # --- Settings API --- @app.get("/api/settings") async def get_settings(): - return {"provider": AI_PROVIDER, "google_model": GOOGLE_MODEL, "openai_model": OPENAI_MODEL, "ollama_model": OLLAMA_MODEL, "ollama_base_url": OLLAMA_BASE_URL} + return { + "provider": AI_PROVIDER, + "google_model": GOOGLE_MODEL, + "openai_model": OPENAI_MODEL, + "ollama_model": OLLAMA_MODEL, + "ollama_base_url": OLLAMA_BASE_URL # URL ans Frontend schicken + } @app.post("/api/settings") async def update_settings(request: Request): + # WICHTIG: OLLAMA_BASE_URL als global deklarieren global AI_PROVIDER, GOOGLE_MODEL, OPENAI_MODEL, OLLAMA_MODEL, OLLAMA_BASE_URL + data = await request.json() provider = data.get("provider") - if provider: - AI_PROVIDER = provider; set_key(ENV_FILE, "AI_PROVIDER", provider) - if data.get("model"): - m = data.get("model") - if provider == "google": GOOGLE_MODEL = m; set_key(ENV_FILE, "GOOGLE_MODEL", m) - if provider == "openai": OPENAI_MODEL = m; set_key(ENV_FILE, "OPENAI_MODEL", m) - if provider == "ollama": OLLAMA_MODEL = m; set_key(ENV_FILE, "OLLAMA_MODEL", m) - if data.get("ollama_base_url"): - u = data.get("ollama_base_url"); OLLAMA_BASE_URL = u; set_key(ENV_FILE, "OLLAMA_BASE_URL", u) + model = data.get("model") + ollama_url = data.get("ollama_base_url") # URL vom Frontend empfangen + + if provider: + AI_PROVIDER = provider + set_key(ENV_FILE, "AI_PROVIDER", provider) + + if provider == "google" and model: + GOOGLE_MODEL = model + set_key(ENV_FILE, "GOOGLE_MODEL", model) + elif provider == "openai" and model: + OPENAI_MODEL = model + set_key(ENV_FILE, "OPENAI_MODEL", model) + elif provider == "ollama" and model: + OLLAMA_MODEL = model + set_key(ENV_FILE, "OLLAMA_MODEL", model) + + # Wenn eine Ollama-URL mitgeschickt wurde, speichern wir sie + if ollama_url: + OLLAMA_BASE_URL = ollama_url + set_key(ENV_FILE, "OLLAMA_BASE_URL", ollama_url) + return {"status": "success"} @app.get("/api/models") @@ -372,6 +440,21 @@ async def get_models(provider: str, url: str = None): return {"models": models} + except Exception as e: + print(f"Fehler beim Abrufen der Modelle für {provider}: {str(e)}") + return {"models": []} # Gibt eine leere Liste zurück -> Frontend nutzt Fallback + + # Im neuen SDK (google-genai) heißt das Feld 'supported_actions' + for m in client.models.list(): + if 'generateContent' in m.supported_actions: + # Wir nehmen den Namen und entfernen das 'models/' Präfix + model_name = m.name.replace("models/", "") + models.append(model_name) + + models.sort() + + return {"models": models} + except Exception as e: print(f"Fehler beim Abrufen der Modelle für {provider}: {str(e)}") return {"models": []} # Gibt eine leere Liste zurück -> Frontend nutzt Fallback