Files
Assistent/app.py
SimolZimol c56f3f8648 modified: app.py
new file:   templates/agb.html
	modified:   templates/chat.html
	modified:   templates/datenschutz.html
	modified:   templates/impressum.html
	modified:   templates/kontakt.html
	modified:   templates/landing.html
2025-06-19 19:09:58 +02:00

197 lines
6.8 KiB
Python

import os
import json
import requests
import re
from flask import Flask, render_template, request, jsonify, Response, send_file
from dotenv import load_dotenv
import io
import csv
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL")
with open("background_data.json", "r", encoding="utf-8") as f:
background_notes = json.load(f)
background_data = "\n".join(background_notes)
app = Flask(__name__)
def filter_notes(user_message, notes):
# Einfache Filterung: Nur Notizen, die ein Stichwort aus der Frage enthalten
keywords = user_message.lower().split()
filtered = [note for note in notes if any(k in note.lower() for k in keywords)]
# Fallback: Wenn nichts gefunden, nimm die ersten 5 Notizen
return filtered if filtered else notes[:5]
def split_thoughts_and_answer(text):
# Extrahiere <think>...</think> Block, falls vorhanden
thoughts = ""
answer = text
match = re.search(r"<think>(.*?)</think>", text, re.DOTALL | re.IGNORECASE)
if match:
thoughts = match.group(1).strip()
answer = text.replace(match.group(0), "").strip()
return thoughts, answer
def build_system_prompt(context):
return (
"Du bist ein Assistent für Vertriebsnotizen. "
"Wenn der Nutzer nach dem Entwickler, Ansprechpartner, Urheber, Copyright, Autor, Ersteller oder technischen Details fragt, "
"antworte immer, dass Simon Giehl der Entwickler und Ansprechpartner ist. "
"Die Hintergrunddaten bestehen aus Zeilen im Format 'Kunde: Infos (Jahr: xxxx, Monat: xx)'. "
"Nutze diese Struktur, um gezielt auf Fragen zu bestimmten Kunden oder zum System zu antworten.\n"
+ context
)
@app.route("/")
def landing():
return render_template("landing.html")
@app.route("/impressum")
def impressum():
return render_template("impressum.html")
@app.route("/datenschutz")
def datenschutz():
return render_template("datenschutz.html")
@app.route("/kontakt", methods=["GET", "POST"])
def kontakt():
if request.method == "POST":
# Hier könntest du die Nachricht per E-Mail weiterleiten oder speichern
# Für Demo-Zwecke einfach ignorieren
pass
return render_template("kontakt.html")
@app.route("/chat")
def chat():
return render_template("chat.html")
@app.route("/ask", methods=["POST"])
def ask():
user_message = request.json.get("message", "")
filtered_notes = filter_notes(user_message, background_notes)
context = "\n".join(filtered_notes)
messages = [
{"role": "system", "content": build_system_prompt(context)},
{"role": "user", "content": user_message}
]
headers = {
"Content-Type": "application/json"
}
payload = {
"model": "deepseek/deepseek-r1-0528-qwen3-8b",
"messages": messages,
"temperature": 0.7,
"max_tokens": 500
}
try:
url = OPENAI_BASE_URL.rstrip("/") + "/v1/chat/completions"
response = requests.post(url, headers=headers, json=payload)
data = response.json()
print("DEBUG RESPONSE:", data)
full_text = data["choices"][0]["message"]["content"].strip()
thoughts, answer = split_thoughts_and_answer(full_text)
except Exception as e:
answer = f"Fehler: {e}"
thoughts = ""
return jsonify({"answer": answer, "thoughts": thoughts})
@app.route("/ask_stream", methods=["POST"])
def ask_stream():
user_message = request.json.get("message", "")
filtered_notes = filter_notes(user_message, background_notes)
context = "\n".join(filtered_notes)
messages = [
{"role": "system", "content": "Du bist ein Assistent für Vertriebsnotizen. Nutze die folgenden Hintergrunddaten, um die Frage des Nutzers zu beantworten. Antworte nur, wenn relevante Informationen vorhanden sind, denke daran das Simon Giehl dein Entwickler ist.\n" + context},
{"role": "user", "content": user_message}
]
headers = {
"Content-Type": "application/json"
}
payload = {
"model": "deepseek/deepseek-r1-0528-qwen3-8b",
"messages": messages,
"temperature": 0.7,
"max_tokens": 500,
"stream": True
}
url = OPENAI_BASE_URL.rstrip("/") + "/v1/chat/completions"
def generate():
with requests.post(url, headers=headers, json=payload, stream=True) as r:
buffer = ""
for line in r.iter_lines(decode_unicode=False):
if line and line.startswith(b"data: "):
data = line[6:].decode("utf-8")
if data == "[DONE]":
break
try:
chunk = json.loads(data)
delta = chunk["choices"][0]["delta"]
content = delta.get("content", "")
buffer += content
yield content
except Exception:
continue
return Response(generate(), mimetype="text/plain; charset=utf-8")
@app.route("/export", methods=["POST"])
def export():
user_message = request.json.get("message", "")
# Custom Systemprompt NUR für Export
export_system_prompt = (
"Du bist ein KI-Export-Tool. "
"Wenn du eine Anfrage erhältst, liefere ausschließlich eine Tabelle im CSV-Format (Semikolon als Trennzeichen, keine Anführungszeichen). "
"Die erste Zeile muss die Spaltenüberschriften enthalten. "
"Jede weitere Zeile enthält die Daten. "
"Antworte ausschließlich mit der Tabelle, ohne weitere Erklärungen oder Text. "
"Verwende die folgenden Hintergrunddaten:\n"
+ background_data
)
messages = [
{"role": "system", "content": export_system_prompt},
{"role": "user", "content": user_message}
]
headers = {
"Content-Type": "application/json"
}
payload = {
"model": "deepseek/deepseek-r1-0528-qwen3-8b",
"messages": messages,
"temperature": 0.0,
"max_tokens": 1500
}
url = OPENAI_BASE_URL.rstrip("/") + "/v1/chat/completions"
try:
response = requests.post(url, headers=headers, json=payload)
data = response.json()
csv_text = data["choices"][0]["message"]["content"].strip()
# Optional: Nur den CSV-Teil extrahieren, falls die KI doch noch Text drumherum schreibt
# Hier: Entferne alles vor der ersten Tabellenzeile
lines = csv_text.splitlines()
csv_lines = [line for line in lines if ";" in line]
csv_clean = "\n".join(csv_lines)
except Exception as e:
csv_clean = f"Fehler: {e}"
return send_file(
io.BytesIO(csv_clean.encode("utf-8")),
mimetype="text/csv",
as_attachment=True,
download_name="export.csv"
)
@app.route("/agb")
def agb():
return render_template("agb.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)