Upload 5 files
Browse files- utils/api_handler.py +183 -0
- utils/constants.py +21 -0
- utils/helpers.py +15 -0
- utils/logger.py +143 -0
- utils/security.py +97 -0
utils/api_handler.py
ADDED
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
utils/api_handler.py - API-Kommunikationsmodul für den Dr. Franz Psychochatbot
|
3 |
+
|
4 |
+
Dieses Modul verwaltet die Kommunikation mit der HuggingFace Inference API:
|
5 |
+
- Senden von Anfragen
|
6 |
+
- Verarbeiten von Antworten
|
7 |
+
- Fehlerbehandlung und Wiederholungslogik
|
8 |
+
"""
|
9 |
+
|
10 |
+
import requests
|
11 |
+
import time
|
12 |
+
import random
|
13 |
+
import json
|
14 |
+
from typing import Dict, Any, Optional, List, Union
|
15 |
+
|
16 |
+
# Importieren der Konfiguration
|
17 |
+
import config
|
18 |
+
|
19 |
+
class ApiHandler:
|
20 |
+
"""Klasse zur Verwaltung der API-Kommunikation"""
|
21 |
+
|
22 |
+
def __init__(self, api_token: str = config.API_TOKEN, model_id: str = config.MODEL_ID):
|
23 |
+
"""
|
24 |
+
Initialisiert den API-Handler
|
25 |
+
|
26 |
+
Args:
|
27 |
+
api_token: Der API-Token für HuggingFace
|
28 |
+
model_id: Die ID des zu verwendenden Modells
|
29 |
+
"""
|
30 |
+
self.api_token = api_token
|
31 |
+
self.model_id = model_id
|
32 |
+
self.api_url = f"{config.API_BASE_URL}{model_id}"
|
33 |
+
self.headers = {"Authorization": f"Bearer {api_token}"}
|
34 |
+
self.max_retries = 3
|
35 |
+
self.retry_delay = 2 # Sekunden
|
36 |
+
|
37 |
+
def generate_text(self, prompt: str, params: Optional[Dict[str, Any]] = None) -> str:
|
38 |
+
"""
|
39 |
+
Generiert Text über die HuggingFace Inference API
|
40 |
+
|
41 |
+
Args:
|
42 |
+
prompt: Der Prompt für die Textgenerierung
|
43 |
+
params: Optional, Parameter für die Textgenerierung
|
44 |
+
|
45 |
+
Returns:
|
46 |
+
Der generierte Text
|
47 |
+
"""
|
48 |
+
# Standardparameter verwenden, wenn keine angegeben sind
|
49 |
+
if params is None:
|
50 |
+
params = {
|
51 |
+
"max_new_tokens": config.MAX_NEW_TOKENS,
|
52 |
+
"do_sample": True,
|
53 |
+
"temperature": config.TEMPERATURE,
|
54 |
+
"top_p": config.TOP_P,
|
55 |
+
"top_k": config.TOP_K,
|
56 |
+
"repetition_penalty": config.REPETITION_PENALTY
|
57 |
+
}
|
58 |
+
|
59 |
+
payload = {
|
60 |
+
"inputs": prompt,
|
61 |
+
"parameters": params
|
62 |
+
}
|
63 |
+
|
64 |
+
return self._send_api_request(payload)
|
65 |
+
|
66 |
+
def _send_api_request(self, payload: Dict[str, Any]) -> str:
|
67 |
+
"""
|
68 |
+
Sendet eine Anfrage an die API mit Wiederholungslogik
|
69 |
+
|
70 |
+
Args:
|
71 |
+
payload: Die Anfragedaten
|
72 |
+
|
73 |
+
Returns:
|
74 |
+
Die generierte Antwort
|
75 |
+
"""
|
76 |
+
for attempt in range(self.max_retries):
|
77 |
+
try:
|
78 |
+
response = requests.post(
|
79 |
+
self.api_url,
|
80 |
+
headers=self.headers,
|
81 |
+
json=payload,
|
82 |
+
timeout=config.API_TIMEOUT
|
83 |
+
)
|
84 |
+
|
85 |
+
# Prüfen auf erfolgreiche Antwort
|
86 |
+
if response.status_code == 200:
|
87 |
+
return self._process_successful_response(response.json())
|
88 |
+
|
89 |
+
# Behandlung von Fehlercodes
|
90 |
+
if response.status_code == 401:
|
91 |
+
if config.DEBUG_MODE:
|
92 |
+
print("API-Fehler: Ungültiger API-Token")
|
93 |
+
return self._get_fallback_response("authentication_error")
|
94 |
+
|
95 |
+
if response.status_code == 503 or response.status_code == 429:
|
96 |
+
# Server überlastet oder Rate-Limit erreicht, erneuter Versuch
|
97 |
+
if config.DEBUG_MODE:
|
98 |
+
print(f"API-Fehler: Server überlastet (Versuch {attempt+1}/{self.max_retries})")
|
99 |
+
time.sleep(self.retry_delay * (attempt + 1)) # Exponentielles Backoff
|
100 |
+
continue
|
101 |
+
|
102 |
+
# Andere Fehler
|
103 |
+
if config.DEBUG_MODE:
|
104 |
+
print(f"API-Fehler: Statuscode {response.status_code}")
|
105 |
+
return self._get_fallback_response("general_error")
|
106 |
+
|
107 |
+
except requests.exceptions.Timeout:
|
108 |
+
if config.DEBUG_MODE:
|
109 |
+
print(f"API-Timeout (Versuch {attempt+1}/{self.max_retries})")
|
110 |
+
if attempt < self.max_retries - 1:
|
111 |
+
time.sleep(self.retry_delay * (attempt + 1))
|
112 |
+
else:
|
113 |
+
return self._get_fallback_response("timeout")
|
114 |
+
|
115 |
+
except Exception as e:
|
116 |
+
if config.DEBUG_MODE:
|
117 |
+
print(f"API-Anfragefehler: {e}")
|
118 |
+
return self._get_fallback_response("general_error")
|
119 |
+
|
120 |
+
# Alle Versuche fehlgeschlagen
|
121 |
+
return self._get_fallback_response("max_retries")
|
122 |
+
|
123 |
+
def _process_successful_response(self, response_data: Union[List[Dict[str, Any]], Dict[str, Any]]) -> str:
|
124 |
+
"""
|
125 |
+
Verarbeitet eine erfolgreiche API-Antwort
|
126 |
+
|
127 |
+
Args:
|
128 |
+
response_data: Die Antwortdaten von der API
|
129 |
+
|
130 |
+
Returns:
|
131 |
+
Der extrahierte generierte Text
|
132 |
+
"""
|
133 |
+
try:
|
134 |
+
if isinstance(response_data, list) and len(response_data) > 0 and "generated_text" in response_data[0]:
|
135 |
+
full_response = response_data[0]["generated_text"]
|
136 |
+
# Extrahieren der Antwort nach "Dr. Franz:"
|
137 |
+
if "Dr. Franz:" in full_response:
|
138 |
+
reply = full_response.split("Dr. Franz:")[-1].strip()
|
139 |
+
return reply
|
140 |
+
else:
|
141 |
+
return full_response
|
142 |
+
elif isinstance(response_data, dict) and "generated_text" in response_data:
|
143 |
+
return response_data["generated_text"]
|
144 |
+
else:
|
145 |
+
if config.DEBUG_MODE:
|
146 |
+
print(f"Unerwartetes API-Antwortformat: {response_data}")
|
147 |
+
return self._get_fallback_response("unexpected_format")
|
148 |
+
except Exception as e:
|
149 |
+
if config.DEBUG_MODE:
|
150 |
+
print(f"Fehler bei der Verarbeitung der API-Antwort: {e}")
|
151 |
+
return self._get_fallback_response("processing_error")
|
152 |
+
|
153 |
+
def _get_fallback_response(self, error_type: str) -> str:
|
154 |
+
"""
|
155 |
+
Gibt eine Fallback-Antwort basierend auf dem Fehlertyp zurück
|
156 |
+
|
157 |
+
Args:
|
158 |
+
error_type: Der Typ des aufgetretenen Fehlers
|
159 |
+
|
160 |
+
Returns:
|
161 |
+
Eine passende Fallback-Antwort
|
162 |
+
"""
|
163 |
+
# Spezifische Antworten je nach Fehlertyp
|
164 |
+
error_responses = {
|
165 |
+
"authentication_error": [
|
166 |
+
"Es scheint ein Problem mit meiner Verbindung zu geben. Erzählen Sie mir mehr über Ihre Gedanken.",
|
167 |
+
"Ich muss kurz nachdenken. Was meinen Sie genau mit Ihrer letzten Aussage?"
|
168 |
+
],
|
169 |
+
"timeout": [
|
170 |
+
"Ihre Aussage ist komplex und bedarf tieferer Analyse. Könnten Sie Ihren Gedanken weiter ausführen?",
|
171 |
+
"Interessant, dass Sie das so formulieren. Ich brauche einen Moment, um das zu verarbeiten."
|
172 |
+
],
|
173 |
+
"max_retries": [
|
174 |
+
"Ihre Gedankengänge sind bemerkenswert verschlungen. Lassen Sie uns einen Schritt zurückgehen.",
|
175 |
+
"Ich spüre Widerstand in unserer Kommunikation. Vielleicht sollten wir einen anderen Ansatz versuchen."
|
176 |
+
]
|
177 |
+
}
|
178 |
+
|
179 |
+
# Spezifische Antwort für den Fehlertyp oder allgemeine Fallback-Antwort
|
180 |
+
if error_type in error_responses:
|
181 |
+
return random.choice(error_responses[error_type])
|
182 |
+
else:
|
183 |
+
return random.choice(config.FALLBACK_RESPONSES)
|
utils/constants.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Configuration constants
|
2 |
+
MAX_RESPONSE_LENGTH = 2000
|
3 |
+
DEFAULT_PROMPT = "Dr. Franz Psychochatbot:"
|
4 |
+
|
5 |
+
# Response types
|
6 |
+
RESPONSE_TYPES = {
|
7 |
+
"NORMAL": "normal",
|
8 |
+
"ANALYSIS": "analysis",
|
9 |
+
"ADVICE": "advice",
|
10 |
+
"EMOTIONAL": "emotional"
|
11 |
+
}
|
12 |
+
|
13 |
+
# Emotion categories
|
14 |
+
EMOTION_CATEGORIES = [
|
15 |
+
"angry",
|
16 |
+
"sad",
|
17 |
+
"happy",
|
18 |
+
"neutral",
|
19 |
+
"confused",
|
20 |
+
"excited"
|
21 |
+
]
|
utils/helpers.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from typing import Dict, Any
|
3 |
+
|
4 |
+
def load_config() -> Dict[str, Any]:
|
5 |
+
"""Load configuration from config.py"""
|
6 |
+
from config import CONFIG
|
7 |
+
return CONFIG
|
8 |
+
|
9 |
+
def get_asset_path(asset_name: str) -> str:
|
10 |
+
"""Get the full path to an asset"""
|
11 |
+
return os.path.join(os.path.dirname(__file__), "../assets", asset_name)
|
12 |
+
|
13 |
+
def format_response(text: str) -> str:
|
14 |
+
"""Format the bot's response text"""
|
15 |
+
return text.strip().capitalize()
|
utils/logger.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
utils/logger.py - Logging-Modul für den Dr. Franz Psychochatbot
|
3 |
+
|
4 |
+
Dieses Modul stellt Logging-Funktionalitäten bereit:
|
5 |
+
- Protokollierung von Aktivitäten
|
6 |
+
- Unterstützung beim Debugging
|
7 |
+
- Überwachung der Performance
|
8 |
+
"""
|
9 |
+
|
10 |
+
import logging
|
11 |
+
import os
|
12 |
+
import time
|
13 |
+
from datetime import datetime
|
14 |
+
from typing import Optional, Dict, Any
|
15 |
+
|
16 |
+
# Importieren der Konfiguration
|
17 |
+
import config
|
18 |
+
|
19 |
+
class Logger:
|
20 |
+
"""Klasse zur Verwaltung des Loggings"""
|
21 |
+
|
22 |
+
def __init__(self, log_level: str = config.LOG_LEVEL):
|
23 |
+
"""
|
24 |
+
Initialisiert den Logger
|
25 |
+
|
26 |
+
Args:
|
27 |
+
log_level: Das Log-Level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
28 |
+
"""
|
29 |
+
self.log_level = log_level
|
30 |
+
self.logger = self._setup_logger()
|
31 |
+
self.start_time = time.time()
|
32 |
+
self.interaction_count = 0
|
33 |
+
|
34 |
+
def _setup_logger(self) -> logging.Logger:
|
35 |
+
"""
|
36 |
+
Richtet den Logger ein
|
37 |
+
|
38 |
+
Returns:
|
39 |
+
Konfigurierter Logger
|
40 |
+
"""
|
41 |
+
# Log-Level aus String in Logging-Konstante umwandeln
|
42 |
+
numeric_level = getattr(logging, self.log_level.upper(), logging.INFO)
|
43 |
+
|
44 |
+
# Logger konfigurieren
|
45 |
+
logger = logging.getLogger("psychobot")
|
46 |
+
logger.setLevel(numeric_level)
|
47 |
+
|
48 |
+
# Handler für Konsolenausgabe
|
49 |
+
console_handler = logging.StreamHandler()
|
50 |
+
console_handler.setLevel(numeric_level)
|
51 |
+
|
52 |
+
# Formatter für lesbares Format
|
53 |
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
54 |
+
console_handler.setFormatter(formatter)
|
55 |
+
|
56 |
+
# Handler hinzufügen, falls noch nicht vorhanden
|
57 |
+
if not logger.handlers:
|
58 |
+
logger.addHandler(console_handler)
|
59 |
+
|
60 |
+
return logger
|
61 |
+
|
62 |
+
def log_startup(self) -> None:
|
63 |
+
"""Protokolliert den Start der Anwendung"""
|
64 |
+
self.logger.info(f"=== {config.CHATBOT_TITLE} gestartet ===")
|
65 |
+
self.logger.info(f"Verwende Modell: {config.MODEL_ID}")
|
66 |
+
self.logger.info(f"Debug-Modus: {config.DEBUG_MODE}")
|
67 |
+
self.logger.info(f"API-Token vorhanden: {bool(config.API_TOKEN)}")
|
68 |
+
|
69 |
+
def log_user_input(self, user_input: str) -> None:
|
70 |
+
"""
|
71 |
+
Protokolliert eine Nutzereingabe
|
72 |
+
|
73 |
+
Args:
|
74 |
+
user_input: Die Eingabe des Nutzers
|
75 |
+
"""
|
76 |
+
self.interaction_count += 1
|
77 |
+
self.logger.info(f"Nutzeranfrage #{self.interaction_count}: {user_input[:50]}...")
|
78 |
+
|
79 |
+
def log_bot_response(self, response: str, generation_time: float) -> None:
|
80 |
+
"""
|
81 |
+
Protokolliert eine Bot-Antwort
|
82 |
+
|
83 |
+
Args:
|
84 |
+
response: Die Antwort des Bots
|
85 |
+
generation_time: Die Zeit zur Generierung der Antwort in Sekunden
|
86 |
+
"""
|
87 |
+
self.logger.info(f"Bot-Antwort #{self.interaction_count}: {response[:50]}... (Generiert in {generation_time:.2f}s)")
|
88 |
+
|
89 |
+
def log_api_request(self, model_id: str, prompt_length: int) -> None:
|
90 |
+
"""
|
91 |
+
Protokolliert eine API-Anfrage
|
92 |
+
|
93 |
+
Args:
|
94 |
+
model_id: Die ID des verwendeten Modells
|
95 |
+
prompt_length: Die Länge des Prompts in Zeichen
|
96 |
+
"""
|
97 |
+
self.logger.debug(f"API-Anfrage an {model_id} mit Prompt-Länge: {prompt_length} Zeichen")
|
98 |
+
|
99 |
+
def log_api_response(self, status_code: int, response_time: float) -> None:
|
100 |
+
"""
|
101 |
+
Protokolliert eine API-Antwort
|
102 |
+
|
103 |
+
Args:
|
104 |
+
status_code: Der HTTP-Statuscode
|
105 |
+
response_time: Die Antwortzeit in Sekunden
|
106 |
+
"""
|
107 |
+
self.logger.debug(f"API-Antwort erhalten: Status {status_code}, Zeit: {response_time:.2f}s")
|
108 |
+
|
109 |
+
def log_error(self, error_type: str, error_message: str, details: Optional[Dict[str, Any]] = None) -> None:
|
110 |
+
"""
|
111 |
+
Protokolliert einen Fehler
|
112 |
+
|
113 |
+
Args:
|
114 |
+
error_type: Der Typ des Fehlers
|
115 |
+
error_message: Die Fehlermeldung
|
116 |
+
details: Optional, zusätzliche Details zum Fehler
|
117 |
+
"""
|
118 |
+
self.logger.error(f"FEHLER - {error_type}: {error_message}")
|
119 |
+
if details and config.DEBUG_MODE:
|
120 |
+
self.logger.error(f"Details: {details}")
|
121 |
+
|
122 |
+
def log_performance_stats(self) -> Dict[str, Any]:
|
123 |
+
"""
|
124 |
+
Protokolliert Performance-Statistiken
|
125 |
+
|
126 |
+
Returns:
|
127 |
+
Dictionary mit Performance-Statistiken
|
128 |
+
"""
|
129 |
+
uptime = time.time() - self.start_time
|
130 |
+
hours, remainder = divmod(uptime, 3600)
|
131 |
+
minutes, seconds = divmod(remainder, 60)
|
132 |
+
|
133 |
+
stats = {
|
134 |
+
"uptime": f"{int(hours)}h {int(minutes)}m {int(seconds)}s",
|
135 |
+
"interactions": self.interaction_count,
|
136 |
+
"interactions_per_hour": round(self.interaction_count / (uptime / 3600), 2) if uptime > 0 else 0
|
137 |
+
}
|
138 |
+
|
139 |
+
self.logger.info(f"Performance-Statistiken: Laufzeit {stats['uptime']}, "
|
140 |
+
f"{stats['interactions']} Interaktionen, "
|
141 |
+
f"{stats['interactions_per_hour']} Interaktionen/Stunde")
|
142 |
+
|
143 |
+
return stats
|
utils/security.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
utils/security.py - Sicherheitsmodul für den Dr. Franz Psychochatbot
|
3 |
+
|
4 |
+
Dieses Modul verwaltet die Sicherheitsaspekte des Chatbots:
|
5 |
+
- Sichere Verwaltung von API-Tokens
|
6 |
+
- Laden von Umgebungsvariablen
|
7 |
+
- Schutz sensibler Daten
|
8 |
+
"""
|
9 |
+
|
10 |
+
import os
|
11 |
+
import re
|
12 |
+
from typing import Optional, Dict, Any
|
13 |
+
|
14 |
+
class Security:
|
15 |
+
"""Klasse zur Verwaltung der Sicherheitsaspekte"""
|
16 |
+
|
17 |
+
def __init__(self):
|
18 |
+
"""Initialisiert die Sicherheitskomponente"""
|
19 |
+
self.sensitive_patterns = [
|
20 |
+
r'\b(?:\d[ -]*?){13,16}\b', # Kreditkartennummern
|
21 |
+
r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', # E-Mail-Adressen
|
22 |
+
r'\b(?:\+\d{1,3}[ -]?)?(?:\(?\d{2,4}\)?[ -]?)?[\d -]{7,10}\b', # Telefonnummern
|
23 |
+
r'\bhf_\w+\b', # HuggingFace API-Tokens
|
24 |
+
r'\bsk-\w+\b' # OpenAI API-Tokens
|
25 |
+
]
|
26 |
+
|
27 |
+
def get_api_token(self, env_var_name: str = "HF_API_TOKEN", default: str = "") -> str:
|
28 |
+
"""
|
29 |
+
Holt den API-Token aus den Umgebungsvariablen
|
30 |
+
|
31 |
+
Args:
|
32 |
+
env_var_name: Name der Umgebungsvariable
|
33 |
+
default: Standardwert, falls die Variable nicht existiert
|
34 |
+
|
35 |
+
Returns:
|
36 |
+
Der API-Token oder der Standardwert
|
37 |
+
"""
|
38 |
+
return os.environ.get(env_var_name, default)
|
39 |
+
|
40 |
+
def sanitize_user_input(self, text: str) -> str:
|
41 |
+
"""
|
42 |
+
Entfernt potenziell sensible Informationen aus der Nutzereingabe
|
43 |
+
|
44 |
+
Args:
|
45 |
+
text: Die zu bereinigende Nutzereingabe
|
46 |
+
|
47 |
+
Returns:
|
48 |
+
Die bereinigte Nutzereingabe
|
49 |
+
"""
|
50 |
+
sanitized_text = text
|
51 |
+
|
52 |
+
# Ersetzen sensibler Muster
|
53 |
+
for pattern in self.sensitive_patterns:
|
54 |
+
sanitized_text = re.sub(pattern, "[ENTFERNT]", sanitized_text)
|
55 |
+
|
56 |
+
return sanitized_text
|
57 |
+
|
58 |
+
def validate_api_response(self, response: Any) -> bool:
|
59 |
+
"""
|
60 |
+
Überprüft, ob eine API-Antwort sicher ist
|
61 |
+
|
62 |
+
Args:
|
63 |
+
response: Die zu überprüfende API-Antwort
|
64 |
+
|
65 |
+
Returns:
|
66 |
+
True, wenn die Antwort sicher ist, sonst False
|
67 |
+
"""
|
68 |
+
# Konvertieren der Antwort in einen String für die Überprüfung
|
69 |
+
if not isinstance(response, str):
|
70 |
+
try:
|
71 |
+
response_str = str(response)
|
72 |
+
except:
|
73 |
+
return False
|
74 |
+
else:
|
75 |
+
response_str = response
|
76 |
+
|
77 |
+
# Überprüfen auf sensible Informationen
|
78 |
+
for pattern in self.sensitive_patterns:
|
79 |
+
if re.search(pattern, response_str):
|
80 |
+
return False
|
81 |
+
|
82 |
+
return True
|
83 |
+
|
84 |
+
def is_valid_api_token(self, token: str) -> bool:
|
85 |
+
"""
|
86 |
+
Überprüft, ob ein API-Token gültig erscheint
|
87 |
+
|
88 |
+
Args:
|
89 |
+
token: Der zu überprüfende API-Token
|
90 |
+
|
91 |
+
Returns:
|
92 |
+
True, wenn der Token gültig erscheint, sonst False
|
93 |
+
"""
|
94 |
+
# HuggingFace-Tokens beginnen mit "hf_"
|
95 |
+
if token.startswith("hf_") and len(token) > 10:
|
96 |
+
return True
|
97 |
+
return False
|