Commit 563f3250 authored by Kantz's avatar Kantz
Browse files

retrival einbinden

parent eaecc684
......@@ -3,11 +3,14 @@ from __future__ import annotations
from typing import List, Optional
import os
import httpx
from fastapi import APIRouter, HTTPException
from dotenv import load_dotenv
import httpx
from pydantic import BaseModel, Field
from app.services.embeddings import OpenAILikeEmbeddings
from app.services import vector_store
router = APIRouter()
load_dotenv()
......@@ -17,16 +20,19 @@ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
SYSTEM_PROMPT = """Du bist ein Mathe-Tutor. Antworte auf Deutsch, klar und korrekt.
Nutze ausschließlich den bereitgestellten Kontext.
Gib wenn möglich eine kurze Struktur:
(1) Idee,
(2) Definition,
(3) kurzer Begründungs-/Rechenweg,
(4) Mini-Beispiel.
Nutze ausschließlich den bereitgestellten Kontext. Wenn nichts zur Frage im Kontext steht, antworte mit "Dazu steht nichts im Material" und nichts weiter.
Gib wenn möglich eine kurze Struktur: (1) Idee, (2) Definition, (3) kurzer Begründungs-/Rechenweg, (4) Mini-Beispiel.
Zitiere Quellen inline mit den eckigen Klammern, die im Kontext vorangestellt sind, z.B. [s2/ss1/c3 | definition | ...].
Wenn nichts zur Frage im Kontext steht, antworte mit "Dazu steht nichts im Material" und gib nichts weiter aus.
"""
CONTEXT_LIMITS = {
"direct": 4,
"indirect": 6,
"subsection": 2,
"section": 1,
}
class ChatMessage(BaseModel):
role: str = Field(..., pattern="^(user|assistant)$")
text: str = Field(..., min_length=1)
......@@ -42,6 +48,59 @@ class ChatResponse(BaseModel):
sources: List[str] = []
def _get_embedder() -> OpenAILikeEmbeddings:
base_url = os.getenv("OPENAI_BASE_URL")
api_key = os.getenv("OPENAI_API_KEY")
model = os.getenv("OPENAI_EMBED_MODEL", "text-embedding-3-large")
if not base_url or not api_key:
raise HTTPException(status_code=500, detail="Missing OPENAI_BASE_URL or OPENAI_API_KEY")
return OpenAILikeEmbeddings(base_url=base_url, api_key=api_key, model=model, target_dim=1024)
def _format_ref(doc: vector_store.Retrieved) -> str:
meta = doc.metadata
sec = meta.get("section_index")
sub = meta.get("subsection_index")
child = meta.get("child_index")
ref = []
if sec is not None:
ref.append(f"s{sec}")
if sub is not None:
ref.append(f"ss{sub}")
if child is not None:
ref.append(f"c{child}")
ref_id = "/".join(ref) if ref else "unknown"
doc_type = meta.get("type") or doc.doc_type
title = (
meta.get("title")
or meta.get("subsection_title")
or meta.get("section_title")
or meta.get("path")
or "Untitled"
)
return f"[{ref_id} | {doc_type} | {title}]"
def _build_context(result: dict) -> str:
blocks: List[str] = []
def add_group(label: str, items: List[vector_store.Retrieved], limit: int) -> None:
if not items:
return
for doc in items[:limit]:
blocks.append(f"{label} {_format_ref(doc)}\n{doc.markdown}")
add_group("DIRECT", result.get("children_direct", []), CONTEXT_LIMITS["direct"])
add_group("INDIRECT", result.get("children_expanded", []), CONTEXT_LIMITS["indirect"])
add_group("SUBSECTION", result.get("subsections", []), CONTEXT_LIMITS["subsection"])
add_group("SECTION", result.get("sections", []), CONTEXT_LIMITS["section"])
if not blocks:
return "KONTEXT: (leer)"
return "KONTEXT:\n" + "\n\n".join(blocks)
@router.post("/api/chat", response_model=ChatResponse)
def chat(request: ChatRequest) -> ChatResponse:
if not request.messages:
......@@ -52,10 +111,25 @@ def chat(request: ChatRequest) -> ChatResponse:
reply = f"Mock reply to: {last.text}"
return ChatResponse(reply=reply, sources=["doc:example"])
messages_payload = [{"role": "system", "content": SYSTEM_PROMPT}] + [
{"role": message.role, "content": message.text}
for message in request.messages
]
pg_url = os.getenv("POSTGRES_URL")
if not pg_url:
raise HTTPException(status_code=500, detail="Missing POSTGRES_URL")
query_text = request.messages[-1].text
embedder = _get_embedder()
retrieval = vector_store.retrieve(
pg_url=pg_url,
embedder=embedder,
query=query_text,
k=8,
expand_links=True,
)
context_block = _build_context(retrieval)
messages_payload = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "system", "content": context_block},
] + [{"role": message.role, "content": message.text} for message in request.messages]
payload = {
"model": OPENAI_MODEL,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment