Rag-Catan-Bot / rag_pipeline.py
dewiri's picture
Update rag_pipeline.py
64aba59 verified
import os
import pickle
import requests
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
from dotenv import load_dotenv
from openai import OpenAI
from groq import Groq
# === API Keys laden ===
load_dotenv()
openai_key = os.getenv("OPENAI_API_KEY")
groq_key = os.getenv("GROQ_API_KEY")
openai_client = OpenAI(api_key=openai_key) if openai_key else None
groq_client = Groq(api_key=groq_key) if groq_key else None
# === Modell laden ===
print("🧠 Lade SentenceTransformer...")
model = SentenceTransformer("Sahajtomar/German-semantic")
# === Google Drive Direktlinks
url_index = "https://drive.google.com/uc?export=download&id=1QBg4vjitJ2xHEyp3Ae8TWJHwEHjbwgOO"
url_chunks = "https://drive.google.com/uc?export=download&id=1nsrAm_ozsK4GlmMui9yqZBjmgUfqU2qa"
local_index = "faiss_index.index"
local_chunks = "chunks_mapping.pkl"
# === Datei-Download bei Bedarf
def download_if_missing(url, path):
if not os.path.exists(path):
print(f"⬇️ Lade {path} von Google Drive...")
r = requests.get(url)
if r.status_code == 200:
with open(path, "wb") as f:
f.write(r.content)
print(f"✅ Heruntergeladen: {path}")
else:
raise Exception(f"❌ Fehler beim Herunterladen von {path}")
download_if_missing(url_index, local_index)
download_if_missing(url_chunks, local_chunks)
# === FAISS laden
print("📂 Lade FAISS & Chunks...")
with open(local_chunks, "rb") as f:
token_split_texts = pickle.load(f)
print(f"✅ {len(token_split_texts)} Chunks geladen.")
chunk_embeddings = model.encode(token_split_texts, convert_to_numpy=True)
d = chunk_embeddings.shape[1]
index = faiss.IndexFlatL2(d)
index.add(chunk_embeddings)
print(f"✅ FAISS Index mit {index.ntotal} Einträgen.")
# === Ähnliche Chunks abrufen + Distanzen mitgeben
def retrieve(query, k=5):
query_embedding = model.encode([query], convert_to_numpy=True)
distances, indices = index.search(query_embedding, k)
safe_indices = [i for i in indices[0] if i < len(token_split_texts)]
retrieved_texts = [token_split_texts[i] for i in safe_indices]
return retrieved_texts, distances[0]
# === Prompt zusammenbauen
def build_prompt(query, texts):
context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion mit FAISS-Distanzfilter
def run_qa_pipeline(query, k=5):
try:
retrieved, distances = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
max_dist = max(distances)
print(f"ℹ️ Höchste FAISS-Distanz: {max_dist:.4f}")
# 🔒 Schwelle für Relevanz (anpassbar)
if max_dist > 1.0:
return "🚫 Diese Frage scheint nichts mit Catan zu tun zu haben."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}"def build_prompt(query, texts):
context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion mit FAISS-Distanzfilter
def run_qa_pipeline(query, k=5):
try:
retrieved, distances = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
max_dist = max(distances)
print(f"ℹ️ Höchste FAISS-Distanz: {max_dist:.4f}")
# 🔒 Schwelle für Relevanz
if max_dist > 1.0:
return "🚫 Diese Frage scheint nichts mit Catan zu tun zu haben."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}"def build_prompt(query, texts):
context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion mit FAISS-Distanzfilter
def run_qa_pipeline(query, k=5):
try:
retrieved, distances = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
max_dist = max(distances)
print(f"ℹ️ Höchste FAISS-Distanz: {max_dist:.4f}")
# 🔒 Schwelle für Relevanz (anpassbar)
if max_dist > 1.0:
return "🚫 Diese Frage scheint nichts mit Catan zu tun zu haben."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}"def build_prompt(query, texts):
context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion mit FAISS-Distanzfilter
def run_qa_pipeline(query, k=5):
try:
retrieved, distances = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
max_dist = max(distances)
print(f"ℹ️ Höchste FAISS-Distanz: {max_dist:.4f}")
# 🔒 Schwelle für Relevanz (anpassbar)
if max_dist > 1.0:
return "🚫 Diese Frage scheint nichts mit Catan zu tun zu haben."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}"def build_prompt(query, texts):
context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion mit FAISS-Distanzfilter
def run_qa_pipeline(query, k=5):
try:
retrieved, distances = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
max_dist = max(distances)
print(f"ℹ️ Höchste FAISS-Distanz: {max_dist:.4f}")
# 🔒 Schwelle für Relevanz (je nach Modell ggf. anpassen)
if max_dist > 1.0:
return "🚫 Deine Frage passt wahrscheinlich nicht zu den Catan-Regeln. Bitte stelle eine spezifischere Frage."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}" context = "\n\n".join(texts)
return f"""Beantworte die folgende Frage basierend auf dem Kontext.
Kontext:
{context}
Frage:
{query}
"""
# === Anfrage an OpenAI
def ask_openai(prompt):
if not openai_client:
return "❌ Kein OpenAI API Key gefunden"
res = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Anfrage an Groq
def ask_groq(prompt):
if not groq_client:
return "❌ Kein Groq API Key gefunden"
res = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "Du bist ein hilfsbereiter Catan-Regel-Experte."},
{"role": "user", "content": prompt}
]
)
return res.choices[0].message.content.strip()
# === Hauptfunktion für Gradio
def run_qa_pipeline(query, k=5):
try:
retrieved = retrieve(query, k)
if not retrieved:
return "⚠️ Keine relevanten Textstellen gefunden."
prompt = build_prompt(query, retrieved)
print("📨 Prompt gesendet...")
if openai_client:
answer = ask_openai(prompt)
elif groq_client:
answer = ask_groq(prompt)
else:
return "⚠️ Kein LLM API-Key vorhanden. Bitte OPENAI_API_KEY oder GROQ_API_KEY hinterlegen."
return f"📌 Frage: {query}\n\n📖 Antwort:\n{answer}"
except Exception as e:
return f"❌ Fehler beim Verarbeiten der Anfrage:\n{str(e)}"