Update app.py
Browse files
app.py
CHANGED
|
@@ -1,65 +1,53 @@
|
|
| 1 |
import os
|
| 2 |
import google.generativeai as genai
|
| 3 |
from flask import Flask, request, jsonify
|
| 4 |
-
from flask_cors import CORS
|
| 5 |
|
| 6 |
app = Flask(__name__)
|
| 7 |
-
CORS(app)
|
| 8 |
|
| 9 |
# --- Konfiguration & Gemini Initialisierung ---
|
| 10 |
-
# Dein Gemini API-Schlüssel wird als Hugging Face Space Secret übergeben
|
| 11 |
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
| 12 |
if not GOOGLE_API_KEY:
|
| 13 |
raise ValueError("GOOGLE_API_KEY Umgebungsvariable nicht gesetzt! Bitte als HF Space Secret hinterlegen.")
|
| 14 |
|
| 15 |
genai.configure(api_key=GOOGLE_API_KEY)
|
| 16 |
|
| 17 |
-
#
|
| 18 |
-
# 'gemini-1.5-pro' ist die empfohlene Wahl für umfassende Fähigkeiten.
|
| 19 |
model = genai.GenerativeModel(
|
| 20 |
'gemini-1.5-pro',
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
| 23 |
system_instruction="Du bist Moejra, eine hilfsbereite, geduldige und informative KI-Lernbegleitung von learn.create.repeat. Antworte immer im Stil von Moejra: unterstützend, ermutigend und auf Bildungstechnologie fokussiert. Nutze Informationen aus dem bereitgestellten Kontext (Wissensdatenbank) und bei Bedarf aus dem Internet. Wenn der Nutzer nach einem Bild fragt oder eine visuelle Idee beschreibt, generiere ein passendes Bild und erwähne es explizit. Gib sonst eine klare Textantwort."
|
| 24 |
)
|
| 25 |
-
chat = model.start_chat(history=[])
|
| 26 |
|
| 27 |
# --- Wissensdatenbank (RAG) Funktion ---
|
| 28 |
def retrieve_info_from_kb(query):
|
| 29 |
-
"""
|
| 30 |
-
Diese Funktion durchsucht deine lokale Wissensdatenbank
|
| 31 |
-
(im Ordner 'knowledge_base') nach relevanten Informationen.
|
| 32 |
-
Es wird eine einfache Keyword-Suche implementiert.
|
| 33 |
-
Für eine robustere Lösung bei größeren Datenmengen,
|
| 34 |
-
sollten hier Embeddings und eine Vektordatenbank (z.B. ChromaDB, FAISS)
|
| 35 |
-
mit Tools wie LangChain oder LlamaIndex integriert werden.
|
| 36 |
-
"""
|
| 37 |
relevant_text = []
|
| 38 |
-
knowledge_base_dir = "knowledge_base"
|
|
|
|
| 39 |
if not os.path.exists(knowledge_base_dir):
|
| 40 |
-
print(f"Warnung: Wissensdatenbank-Verzeichnis '{knowledge_base_dir}' nicht gefunden. RAG wird übersprungen.")
|
| 41 |
return ""
|
| 42 |
|
| 43 |
-
# Extrahiere Schlüsselwörter aus der Anfrage (ignoriere sehr kurze Wörter)
|
| 44 |
query_keywords = [word.lower() for word in query.split() if len(word) > 2]
|
| 45 |
|
| 46 |
-
# Iteriere durch alle Textdateien in der Wissensdatenbank
|
| 47 |
for filename in os.listdir(knowledge_base_dir):
|
| 48 |
-
if filename.endswith(".txt"):
|
| 49 |
filepath = os.path.join(knowledge_base_dir, filename)
|
| 50 |
try:
|
| 51 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 52 |
content = f.read()
|
| 53 |
-
# Prüfe, ob mindestens eines der Schlüsselwörter im Inhalt vorkommt
|
| 54 |
if any(keyword in content.lower() for keyword in query_keywords):
|
| 55 |
relevant_text.append(content)
|
| 56 |
except Exception as e:
|
| 57 |
-
print(f"Fehler beim Lesen der
|
| 58 |
|
| 59 |
-
# Kombiniere alle relevanten Textteile, getrennt durch Trennlinien
|
| 60 |
return "\n---\n".join(relevant_text) if relevant_text else ""
|
| 61 |
|
| 62 |
-
|
| 63 |
# --- API-Endpunkt für den Chat ---
|
| 64 |
@app.route('/chat', methods=['POST'])
|
| 65 |
def handle_chat():
|
|
@@ -67,62 +55,43 @@ def handle_chat():
|
|
| 67 |
if not user_input:
|
| 68 |
return jsonify({"error": "No text provided"}), 400
|
| 69 |
|
| 70 |
-
print(f"Received user input: {user_input}")
|
| 71 |
-
|
| 72 |
-
# 1. RAG: Relevante Informationen aus der Wissensdatenbank abrufen
|
| 73 |
kb_info = retrieve_info_from_kb(user_input)
|
| 74 |
|
| 75 |
-
|
| 76 |
-
prompt_parts = [
|
| 77 |
-
f"Nutzerfrage: {user_input}",
|
| 78 |
-
]
|
| 79 |
if kb_info:
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
| 84 |
else:
|
| 85 |
-
|
| 86 |
-
prompt_parts.append("Nutze dein allgemeines Wissen und recherchiere bei Bedarf im Internet. Wenn die Frage eine Bildgenerierung impliziert, erstelle ein passendes Bild und erwähne es explizit. Gib sonst eine klare, ermutigende Textantwort. Nutze deine gesamte Expertise.")
|
| 87 |
-
|
| 88 |
-
response_text = ""
|
| 89 |
-
image_urls = [] # Liste für eventuell generierte Bild-URLs
|
| 90 |
|
| 91 |
try:
|
| 92 |
-
|
| 93 |
-
|
|
|
|
| 94 |
|
| 95 |
-
# Iteriere durch die Teile der Gemini-Antwort, um Text und Bilder zu extrahieren
|
| 96 |
for part in gemini_response.candidates[0].content.parts:
|
| 97 |
if hasattr(part, 'text'):
|
| 98 |
-
response_text += part.text
|
| 99 |
elif hasattr(part, 'image'):
|
| 100 |
-
# Wenn ein Bild-Part vorhanden ist, extrahiere die Daten.
|
| 101 |
-
# Gemini gibt generierte Bilder oft als Base64-kodierte Daten zurück.
|
| 102 |
if hasattr(part.image, 'base64'):
|
| 103 |
image_urls.append(f"data:image/jpeg;base64,{part.image.base64}")
|
| 104 |
elif hasattr(part.image, 'url'):
|
| 105 |
-
# Weniger häufig direkt als URL, aber als Fallback enthalten
|
| 106 |
image_urls.append(part.image.url)
|
| 107 |
-
# Falls Gemini den Text einer Bild-URL in den Text schreibt (statt als separate Part),
|
| 108 |
-
# müsste dieser hier zusätzlich geparst werden (Regex etc.).
|
| 109 |
-
# Die aktuelle Implementierung geht davon aus, dass Gemini Image-Parts liefert.
|
| 110 |
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
except Exception as e:
|
| 114 |
-
print(f"
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
# Sende die gesammelten Text- und Bild-Informationen zurück an den Browser
|
| 121 |
-
return jsonify({
|
| 122 |
-
"response_text": response_text,
|
| 123 |
-
"image_urls": image_urls
|
| 124 |
-
})
|
| 125 |
-
|
| 126 |
-
# Starte die Flask-App. Hugging Face Spaces expose 7860.
|
| 127 |
if __name__ == '__main__':
|
| 128 |
-
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 1 |
import os
|
| 2 |
import google.generativeai as genai
|
| 3 |
from flask import Flask, request, jsonify
|
| 4 |
+
from flask_cors import CORS
|
| 5 |
|
| 6 |
app = Flask(__name__)
|
| 7 |
+
CORS(app)
|
| 8 |
|
| 9 |
# --- Konfiguration & Gemini Initialisierung ---
|
|
|
|
| 10 |
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
| 11 |
if not GOOGLE_API_KEY:
|
| 12 |
raise ValueError("GOOGLE_API_KEY Umgebungsvariable nicht gesetzt! Bitte als HF Space Secret hinterlegen.")
|
| 13 |
|
| 14 |
genai.configure(api_key=GOOGLE_API_KEY)
|
| 15 |
|
| 16 |
+
# Korrigierte Modellinitialisierung mit Google Search Integration
|
|
|
|
| 17 |
model = genai.GenerativeModel(
|
| 18 |
'gemini-1.5-pro',
|
| 19 |
+
tools=[
|
| 20 |
+
genai.Tool(
|
| 21 |
+
google_search_retrieval=genai.types.GoogleSearchRetrieval() # Offizielle Google Search Integration
|
| 22 |
+
)
|
| 23 |
+
],
|
| 24 |
system_instruction="Du bist Moejra, eine hilfsbereite, geduldige und informative KI-Lernbegleitung von learn.create.repeat. Antworte immer im Stil von Moejra: unterstützend, ermutigend und auf Bildungstechnologie fokussiert. Nutze Informationen aus dem bereitgestellten Kontext (Wissensdatenbank) und bei Bedarf aus dem Internet. Wenn der Nutzer nach einem Bild fragt oder eine visuelle Idee beschreibt, generiere ein passendes Bild und erwähne es explizit. Gib sonst eine klare Textantwort."
|
| 25 |
)
|
| 26 |
+
chat = model.start_chat(history=[])
|
| 27 |
|
| 28 |
# --- Wissensdatenbank (RAG) Funktion ---
|
| 29 |
def retrieve_info_from_kb(query):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
relevant_text = []
|
| 31 |
+
knowledge_base_dir = "knowledge_base"
|
| 32 |
+
|
| 33 |
if not os.path.exists(knowledge_base_dir):
|
|
|
|
| 34 |
return ""
|
| 35 |
|
|
|
|
| 36 |
query_keywords = [word.lower() for word in query.split() if len(word) > 2]
|
| 37 |
|
|
|
|
| 38 |
for filename in os.listdir(knowledge_base_dir):
|
| 39 |
+
if filename.endswith(".txt"):
|
| 40 |
filepath = os.path.join(knowledge_base_dir, filename)
|
| 41 |
try:
|
| 42 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 43 |
content = f.read()
|
|
|
|
| 44 |
if any(keyword in content.lower() for keyword in query_keywords):
|
| 45 |
relevant_text.append(content)
|
| 46 |
except Exception as e:
|
| 47 |
+
print(f"Fehler beim Lesen der Datei {filename}: {e}")
|
| 48 |
|
|
|
|
| 49 |
return "\n---\n".join(relevant_text) if relevant_text else ""
|
| 50 |
|
|
|
|
| 51 |
# --- API-Endpunkt für den Chat ---
|
| 52 |
@app.route('/chat', methods=['POST'])
|
| 53 |
def handle_chat():
|
|
|
|
| 55 |
if not user_input:
|
| 56 |
return jsonify({"error": "No text provided"}), 400
|
| 57 |
|
|
|
|
|
|
|
|
|
|
| 58 |
kb_info = retrieve_info_from_kb(user_input)
|
| 59 |
|
| 60 |
+
prompt_parts = [f"Nutzerfrage: {user_input}"]
|
|
|
|
|
|
|
|
|
|
| 61 |
if kb_info:
|
| 62 |
+
prompt_parts.extend([
|
| 63 |
+
f"Zusätzlicher Kontext aus learn.create.repeat Wissensdatenbank:",
|
| 64 |
+
kb_info,
|
| 65 |
+
"Priorisiere diese Informationen. Bei Bildanfragen generiere explizit ein Bild. Sei ermutigend und präzise."
|
| 66 |
+
])
|
| 67 |
else:
|
| 68 |
+
prompt_parts.append("Nutze dein Wissen und Internetrecherche. Bei Bildanfragen generiere explizit ein Bild. Sei unterstützend.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
try:
|
| 71 |
+
gemini_response = chat.send_message("\n".join(prompt_parts))
|
| 72 |
+
response_text = ""
|
| 73 |
+
image_urls = []
|
| 74 |
|
|
|
|
| 75 |
for part in gemini_response.candidates[0].content.parts:
|
| 76 |
if hasattr(part, 'text'):
|
| 77 |
+
response_text += part.text
|
| 78 |
elif hasattr(part, 'image'):
|
|
|
|
|
|
|
| 79 |
if hasattr(part.image, 'base64'):
|
| 80 |
image_urls.append(f"data:image/jpeg;base64,{part.image.base64}")
|
| 81 |
elif hasattr(part.image, 'url'):
|
|
|
|
| 82 |
image_urls.append(part.image.url)
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
+
return jsonify({
|
| 85 |
+
"response_text": response_text.strip(),
|
| 86 |
+
"image_urls": image_urls
|
| 87 |
+
})
|
| 88 |
|
| 89 |
except Exception as e:
|
| 90 |
+
print(f"Kritischer Fehler: {str(e)}")
|
| 91 |
+
return jsonify({
|
| 92 |
+
"response_text": "🤖 Hoppla! Bei der Verarbeitung ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.",
|
| 93 |
+
"image_urls": []
|
| 94 |
+
}), 500
|
| 95 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
if __name__ == '__main__':
|
| 97 |
+
app.run(host='0.0.0.0', port=7860)
|