Dr_Frank / utils /api_handler.py
Frajosgro's picture
Upload 5 files
9eb915e verified
raw
history blame
7.3 kB
"""
utils/api_handler.py - API-Kommunikationsmodul für den Dr. Franz Psychochatbot
Dieses Modul verwaltet die Kommunikation mit der HuggingFace Inference API:
- Senden von Anfragen
- Verarbeiten von Antworten
- Fehlerbehandlung und Wiederholungslogik
"""
import requests
import time
import random
import json
from typing import Dict, Any, Optional, List, Union
# Importieren der Konfiguration
import config
class ApiHandler:
"""Klasse zur Verwaltung der API-Kommunikation"""
def __init__(self, api_token: str = config.API_TOKEN, model_id: str = config.MODEL_ID):
"""
Initialisiert den API-Handler
Args:
api_token: Der API-Token für HuggingFace
model_id: Die ID des zu verwendenden Modells
"""
self.api_token = api_token
self.model_id = model_id
self.api_url = f"{config.API_BASE_URL}{model_id}"
self.headers = {"Authorization": f"Bearer {api_token}"}
self.max_retries = 3
self.retry_delay = 2 # Sekunden
def generate_text(self, prompt: str, params: Optional[Dict[str, Any]] = None) -> str:
"""
Generiert Text über die HuggingFace Inference API
Args:
prompt: Der Prompt für die Textgenerierung
params: Optional, Parameter für die Textgenerierung
Returns:
Der generierte Text
"""
# Standardparameter verwenden, wenn keine angegeben sind
if params is None:
params = {
"max_new_tokens": config.MAX_NEW_TOKENS,
"do_sample": True,
"temperature": config.TEMPERATURE,
"top_p": config.TOP_P,
"top_k": config.TOP_K,
"repetition_penalty": config.REPETITION_PENALTY
}
payload = {
"inputs": prompt,
"parameters": params
}
return self._send_api_request(payload)
def _send_api_request(self, payload: Dict[str, Any]) -> str:
"""
Sendet eine Anfrage an die API mit Wiederholungslogik
Args:
payload: Die Anfragedaten
Returns:
Die generierte Antwort
"""
for attempt in range(self.max_retries):
try:
response = requests.post(
self.api_url,
headers=self.headers,
json=payload,
timeout=config.API_TIMEOUT
)
# Prüfen auf erfolgreiche Antwort
if response.status_code == 200:
return self._process_successful_response(response.json())
# Behandlung von Fehlercodes
if response.status_code == 401:
if config.DEBUG_MODE:
print("API-Fehler: Ungültiger API-Token")
return self._get_fallback_response("authentication_error")
if response.status_code == 503 or response.status_code == 429:
# Server überlastet oder Rate-Limit erreicht, erneuter Versuch
if config.DEBUG_MODE:
print(f"API-Fehler: Server überlastet (Versuch {attempt+1}/{self.max_retries})")
time.sleep(self.retry_delay * (attempt + 1)) # Exponentielles Backoff
continue
# Andere Fehler
if config.DEBUG_MODE:
print(f"API-Fehler: Statuscode {response.status_code}")
return self._get_fallback_response("general_error")
except requests.exceptions.Timeout:
if config.DEBUG_MODE:
print(f"API-Timeout (Versuch {attempt+1}/{self.max_retries})")
if attempt < self.max_retries - 1:
time.sleep(self.retry_delay * (attempt + 1))
else:
return self._get_fallback_response("timeout")
except Exception as e:
if config.DEBUG_MODE:
print(f"API-Anfragefehler: {e}")
return self._get_fallback_response("general_error")
# Alle Versuche fehlgeschlagen
return self._get_fallback_response("max_retries")
def _process_successful_response(self, response_data: Union[List[Dict[str, Any]], Dict[str, Any]]) -> str:
"""
Verarbeitet eine erfolgreiche API-Antwort
Args:
response_data: Die Antwortdaten von der API
Returns:
Der extrahierte generierte Text
"""
try:
if isinstance(response_data, list) and len(response_data) > 0 and "generated_text" in response_data[0]:
full_response = response_data[0]["generated_text"]
# Extrahieren der Antwort nach "Dr. Franz:"
if "Dr. Franz:" in full_response:
reply = full_response.split("Dr. Franz:")[-1].strip()
return reply
else:
return full_response
elif isinstance(response_data, dict) and "generated_text" in response_data:
return response_data["generated_text"]
else:
if config.DEBUG_MODE:
print(f"Unerwartetes API-Antwortformat: {response_data}")
return self._get_fallback_response("unexpected_format")
except Exception as e:
if config.DEBUG_MODE:
print(f"Fehler bei der Verarbeitung der API-Antwort: {e}")
return self._get_fallback_response("processing_error")
def _get_fallback_response(self, error_type: str) -> str:
"""
Gibt eine Fallback-Antwort basierend auf dem Fehlertyp zurück
Args:
error_type: Der Typ des aufgetretenen Fehlers
Returns:
Eine passende Fallback-Antwort
"""
# Spezifische Antworten je nach Fehlertyp
error_responses = {
"authentication_error": [
"Es scheint ein Problem mit meiner Verbindung zu geben. Erzählen Sie mir mehr über Ihre Gedanken.",
"Ich muss kurz nachdenken. Was meinen Sie genau mit Ihrer letzten Aussage?"
],
"timeout": [
"Ihre Aussage ist komplex und bedarf tieferer Analyse. Könnten Sie Ihren Gedanken weiter ausführen?",
"Interessant, dass Sie das so formulieren. Ich brauche einen Moment, um das zu verarbeiten."
],
"max_retries": [
"Ihre Gedankengänge sind bemerkenswert verschlungen. Lassen Sie uns einen Schritt zurückgehen.",
"Ich spüre Widerstand in unserer Kommunikation. Vielleicht sollten wir einen anderen Ansatz versuchen."
]
}
# Spezifische Antwort für den Fehlertyp oder allgemeine Fallback-Antwort
if error_type in error_responses:
return random.choice(error_responses[error_type])
else:
return random.choice(config.FALLBACK_RESPONSES)