πŸ”΄ RalfBot Code-Flow: Von der User-Eingabe zur Bot-Antwort

1
Frontend: User sendet Nachricht
πŸ“ index.html - send() Funktion

const obj_response = await fetch(`${STR_SERVER_URL}/chat`, {
    method: 'POST',
    body: JSON.stringify({ 
        str_prompt: str_text,          // User-Frage
        str_session_id: str_session_id  // Session-Tracking
    })
});
            
↓ HTTP POST zu localhost:8000/chat
2
Backend: FastAPI empfΓ€ngt Request
πŸ“ server_fastAPI.py - chat_endpoint()
@app_endpoint.post("/chat")
async def chat_endpoint(request: ChatRequest):
    str_session_id = request.str_session_id or str(uuid.uuid4())
    bot = CONFIG.get_session(str_session_id)  ← Session-Management
    
    return StreamingResponse(
        bot.generiere_stream(request.str_prompt),  ← Generator
        media_type="text/plain"
    )
↓ Holt Bot-Instanz vom Singleton
3
Singleton: Session-Management
πŸ“ singleton_llm.py - get_session()
def get_session(self, str_session_id: str):
    if (str_session_id not in self.__sessions):
        from ralf_bot import RalfBot
        self.__sessions[str_session_id] = {
            'bot': RalfBot(),  ← Neue Bot-Instanz
            'last_seen': time.time()
        }
    
    return self.__sessions[str_session_id]['bot']
↓ Pro Session eigener Bot mit eigenem Conversation-History
4
RalfBot: Hauptlogik startet
πŸ“ ralf_bot.py - generiere_stream()
def generiere_stream(self, str_prompt: str) -> Iterator[str]:
    bln_needs_web = self.__pruefe_web_bedarf(str_prompt)  ← Keyword-Check
    
    if (bln_needs_web):
        yield from self.__generiere_antwort_mit_web(str_prompt)
    else:
        yield from self.__generiere_antwort_ohne_web(str_prompt)
↓ Entscheidung: Web-Suche oder direktes LLM?
5
Keyword-Erkennung
πŸ“ ralf_bot.py - __pruefe_web_bedarf()
lst_web_keywords = ['neuigkeiten', 'wetter', 'datum', 'heute', ...]

return ((any((str_keyword in str_prompt.lower()) 
                 for str_keyword in lst_web_keywords)) or 
        (obj_regex.search(r'https?://|www\.', str_prompt) is not None))
↓ "Wetter in Wachtendonk" triggert Web-Pfad
6
Web-Tools: Externe Daten holen
πŸ“ ralf_bot.py - __generiere_antwort_mit_web()
if ('wetter' in str_prompt_lower):
    yield "🌀️ Hole Wetterdaten...\n\n"
    str_web_results = get_weather(str_location)  ← wttr.in API

elif ('datum' in str_prompt_lower):
    yield "πŸ“… Hole aktuelles Datum...\n\n"
    str_web_results = get_current_datetime()  ← datetime.now()

else:
    yield "πŸ” Suche im Web...\n\n"
    str_web_results = web_search_and_read(str_prompt)  ← DuckDuckGo
↓ Externe APIs werden synchron aufgerufen
7
Prompt-Konstruktion mit Web-Daten
πŸ“ ralf_bot.py
str_full_prompt = (
    "<|system|>\n"
    "Du bist Ralf. Antworte AUSSCHLIEẞLICH auf DEUTSCH.\n"
    "Web-Ergebnisse:\n\n"
    f"{str_web_results}\n\n"  ← Kontext injiziert
    "<|user|>\n"
    f"{str_prompt}\n"
    "<|assistant|>\n"
)
↓ LLaMA3-Prompt mit Kontext
8
Thread-Safe Model-Zugriff
πŸ“ ralf_bot.py - __generiere_model_response()
def __generiere_model_response(self, str_full_prompt: str) -> Iterator[str]:
    with obj_LLM_SINGLETON.model_lock:  ← Toilet-Lock Metapher!
        stream_response = obj_LLM_SINGLETON.model(
            str_full_prompt,
            max_tokens=512,
            temperature=0.0,  ← Deterministisch
            top_p=0.9,
            repeat_penalty=1.1
        )
↓ Lock verhindert parallele Model-Zugriffe (Race Conditions)
9
LLM generiert Token-Stream
πŸ“ singleton_llm.py - model Property
# llama_cpp.Llama generiert Tokens StΓΌck fΓΌr StΓΌck
for str_chunk in stream_response:
    str_token = str_chunk["choices"][0]["text"]
    
    if ((len(str_token) > 0) and (not ("<|" in str_token))):  # Filter
        yield str_token  ← Token fließt zurΓΌck zum Client
↓ Jedes Token wird sofort ausgegeben (Streaming)
10
FastAPI: StreamingResponse sendet Chunks
πŸ“ server_fastAPI.py
return StreamingResponse(
    bot.generiere_stream(request.str_prompt),  # Generator
    media_type="text/plain",
    headers={"X-Session-ID": str_session_id}
)
↓ HTTP Chunked Transfer Encoding
11
Frontend: ReadableStream empfΓ€ngt Daten
πŸ“ index.html
const obj_reader = obj_response.body.getReader();
const obj_decoder = new TextDecoder();

while (true) {
    const obj_chunk = await obj_reader.read();
    if (obj_chunk.done) break;
    
    const str_decoded = obj_decoder.decode(obj_chunk.value);
    obj_reply_div.textContent += str_decoded;  ← Live-Update!
    obj_chat.scrollTop = obj_chat.scrollHeight;
}
βœ… Token erscheinen in Echtzeit im Chat

🎯 Zusammenfassung des Code-Flows

Datenfluss:
User Input (JS)
↓
FastAPI Endpoint
↓
Singleton Session-Manager
↓
RalfBot Keyword-Check
↓
Web-Tools (API-Calls)
↓
Prompt-Building
↓
Thread-Lock + LLM-Inference
↓
Token-Filtering
↓
HTTP Streaming
↓
DOM-Update (JS)

Key-Features: