GitHub Actions commited on
Commit
1788936
·
1 Parent(s): eb803dd

🚀 Auto-deploy from GitHub

Browse files
app/api/v1/endpoints/generate.py CHANGED
@@ -2,6 +2,7 @@ from fastapi import APIRouter, HTTPException, Depends, Request
2
  from dotenv import load_dotenv
3
  from supabase import Client
4
  import uuid
 
5
  from typing import Optional, Dict, Any
6
  from ..schemas.card_schemas import CardGenerateRequest, CardGenerateResponse
7
  from ....core.generator import build_prompt # get_constellation wird hier nicht direkt verwendet
@@ -16,6 +17,21 @@ from ....services.request_logger import RequestEventLogger
16
  from ....services.auth_logger import get_client_info
17
  from fastapi.concurrency import run_in_threadpool # Importieren
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  load_dotenv()
20
  router = APIRouter()
21
 
@@ -35,16 +51,28 @@ async def generate_endpoint(
35
  authenticated: bool = Depends(authenticate_request),
36
  current_user: Optional[Dict[str, Any]] = Depends(get_current_user)
37
  ):
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  try:
39
- # Generate unique request ID for tracking
40
- request_id = str(uuid.uuid4())
41
-
42
  # Extract client information
43
  client_ip, user_agent = get_client_info(fastapi_request)
44
 
45
  lang = request.lang or "de"
46
  input_date_str = request.card_date.isoformat()
47
 
 
 
48
  # Log user context if available
49
  user_id = current_user["id"] if current_user else None
50
  username = current_user["username"] if current_user else "anonymous"
@@ -63,13 +91,16 @@ async def generate_endpoint(
63
  request_id=request_id
64
  )
65
 
 
66
  card_prompt = build_prompt(
67
  lang=lang,
68
  card_date=input_date_str,
69
  terms=request.terms,
70
  request_id=request_id
71
  )
 
72
 
 
73
  llm_pipeline = get_generator()
74
 
75
  generation_params = {
@@ -81,6 +112,7 @@ async def generate_endpoint(
81
  "return_full_text": False
82
  }
83
 
 
84
  card_text = await generate_with_retry(
85
  prompt=card_prompt,
86
  generator=llm_pipeline,
@@ -89,9 +121,11 @@ async def generate_endpoint(
89
  generation_params=generation_params,
90
  request_id=request_id
91
  )
 
92
 
93
  if card_text == "Leider konnte kein gültiger Text erzeugt werden." or not check_constraints(card_text, request.terms):
94
  error_msg = "Kartentext konnte nicht generiert werden oder erfüllt nicht die Bedingungen."
 
95
 
96
  # Log failed card generation
97
  RequestEventLogger.log_card_generation_result(
@@ -105,8 +139,10 @@ async def generate_endpoint(
105
  detail=error_msg
106
  )
107
 
 
108
  card_id_for_url = str(uuid.uuid4())
109
  qr_content_url = f"{settings.FRONTEND_BASE_URL}/card/{card_id_for_url}"
 
110
 
111
  qr_code_file_id = await generate_qr_code_async(
112
  data=qr_content_url,
@@ -114,7 +150,9 @@ async def generate_endpoint(
114
  size=settings.QR_CODE_SIZE
115
  )
116
  qr_code_url = f"{settings.API_PREFIX}/static/images/qr/{qr_code_file_id}.png"
 
117
 
 
118
  card_design_id_to_render = request.card_design_id_override or 1
119
  symbol_ids_to_render = request.symbol_ids_override or [1, 2]
120
 
@@ -128,6 +166,9 @@ async def generate_endpoint(
128
  output_path=settings.resolved_generated_path,
129
  request_id=request_id
130
  )
 
 
 
131
 
132
  card_data_for_db = {
133
  "terms": request.terms,
@@ -160,6 +201,11 @@ async def generate_endpoint(
160
  qr_content_url=qr_content_url
161
  )
162
 
 
 
 
 
 
163
  return CardGenerateResponse(
164
  message="Karte erfolgreich generiert.",
165
  card_id=db_id if db_id else card_id_for_url,
@@ -167,7 +213,7 @@ async def generate_endpoint(
167
  )
168
  except FileNotFoundError as e:
169
  error_msg = f"Ein benötigtes Template oder eine Datei wurde nicht gefunden: {e.filename}"
170
- print(f"FileNotFoundError in generate_endpoint: {e}")
171
 
172
  # Log failed card generation
173
  RequestEventLogger.log_card_generation_result(
@@ -188,8 +234,8 @@ async def generate_endpoint(
188
  except Exception as e:
189
  error_msg = f"Ein interner Fehler ist aufgetreten: {str(e)}"
190
  import traceback
191
- print(f"Unerwarteter Fehler in generate_endpoint: {type(e).__name__} - {str(e)}")
192
- traceback.print_exc()
193
 
194
  # Log failed card generation
195
  RequestEventLogger.log_card_generation_result(
 
2
  from dotenv import load_dotenv
3
  from supabase import Client
4
  import uuid
5
+ import logging
6
  from typing import Optional, Dict, Any
7
  from ..schemas.card_schemas import CardGenerateRequest, CardGenerateResponse
8
  from ....core.generator import build_prompt # get_constellation wird hier nicht direkt verwendet
 
17
  from ....services.auth_logger import get_client_info
18
  from fastapi.concurrency import run_in_threadpool # Importieren
19
 
20
+ # Configure logger for this module
21
+ logger = logging.getLogger(__name__)
22
+ logger.setLevel(logging.INFO)
23
+
24
+ # Create console handler if not already configured
25
+ if not logger.handlers:
26
+ console_handler = logging.StreamHandler()
27
+ console_handler.setLevel(logging.INFO)
28
+ formatter = logging.Formatter(
29
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
30
+ datefmt='%Y-%m-%d %H:%M:%S'
31
+ )
32
+ console_handler.setFormatter(formatter)
33
+ logger.addHandler(console_handler)
34
+
35
  load_dotenv()
36
  router = APIRouter()
37
 
 
51
  authenticated: bool = Depends(authenticate_request),
52
  current_user: Optional[Dict[str, Any]] = Depends(get_current_user)
53
  ):
54
+ # IMMEDIATE DEBUG LOG - Should appear as soon as endpoint is hit
55
+ logger.info(f"🎯 GENERATE ENDPOINT HIT! Terms: {request.terms}")
56
+
57
+ # Generate unique request ID for tracking
58
+ request_id = str(uuid.uuid4())
59
+
60
+ # Log to console for HuggingFace visibility
61
+ logger.info(f"🚀 [REQUEST START] ID: {request_id}")
62
+ logger.info(f"📝 Terms: {request.terms}")
63
+ logger.info(f"📅 Date: {request.card_date}")
64
+ logger.info(f"🌐 Language: {request.lang}")
65
+ logger.info(f"👤 User: {current_user.get('username', 'anonymous') if current_user else 'anonymous'}")
66
+
67
  try:
 
 
 
68
  # Extract client information
69
  client_ip, user_agent = get_client_info(fastapi_request)
70
 
71
  lang = request.lang or "de"
72
  input_date_str = request.card_date.isoformat()
73
 
74
+ logger.info(f"🔄 [PROCESSING] Generating card for date: {input_date_str}, lang: {lang}")
75
+
76
  # Log user context if available
77
  user_id = current_user["id"] if current_user else None
78
  username = current_user["username"] if current_user else "anonymous"
 
91
  request_id=request_id
92
  )
93
 
94
+ logger.info(f"📝 [PROMPT] Building prompt for LLM...")
95
  card_prompt = build_prompt(
96
  lang=lang,
97
  card_date=input_date_str,
98
  terms=request.terms,
99
  request_id=request_id
100
  )
101
+ logger.info(f"✅ [PROMPT] Built prompt with {len(card_prompt)} characters")
102
 
103
+ logger.info(f"🤖 [LLM] Loading model and preparing generation...")
104
  llm_pipeline = get_generator()
105
 
106
  generation_params = {
 
112
  "return_full_text": False
113
  }
114
 
115
+ logger.info(f"🎯 [LLM] Starting text generation with {settings.GENERATION_MAX_RETRIES} max retries...")
116
  card_text = await generate_with_retry(
117
  prompt=card_prompt,
118
  generator=llm_pipeline,
 
121
  generation_params=generation_params,
122
  request_id=request_id
123
  )
124
+ logger.info(f"📝 [LLM] Generated text: {card_text[:100]}{'...' if len(card_text) > 100 else ''}")
125
 
126
  if card_text == "Leider konnte kein gültiger Text erzeugt werden." or not check_constraints(card_text, request.terms):
127
  error_msg = "Kartentext konnte nicht generiert werden oder erfüllt nicht die Bedingungen."
128
+ logger.error(f"❌ [ERROR] {error_msg}")
129
 
130
  # Log failed card generation
131
  RequestEventLogger.log_card_generation_result(
 
139
  detail=error_msg
140
  )
141
 
142
+ logger.info(f"🎨 [QR] Generating QR code...")
143
  card_id_for_url = str(uuid.uuid4())
144
  qr_content_url = f"{settings.FRONTEND_BASE_URL}/card/{card_id_for_url}"
145
+ logger.info(f"🔗 [QR] QR Code URL: {qr_content_url}")
146
 
147
  qr_code_file_id = await generate_qr_code_async(
148
  data=qr_content_url,
 
150
  size=settings.QR_CODE_SIZE
151
  )
152
  qr_code_url = f"{settings.API_PREFIX}/static/images/qr/{qr_code_file_id}.png"
153
+ logger.info(f"✅ [QR] QR code generated: {qr_code_file_id}")
154
 
155
+ logger.info(f"🖼️ [CARD] Rendering card image...")
156
  card_design_id_to_render = request.card_design_id_override or 1
157
  symbol_ids_to_render = request.symbol_ids_override or [1, 2]
158
 
 
166
  output_path=settings.resolved_generated_path,
167
  request_id=request_id
168
  )
169
+ logger.info(f"✅ [CARD] Card image generated: {card_file_id}")
170
+
171
+ logger.info(f"💾 [DB] Saving card to database...")
172
 
173
  card_data_for_db = {
174
  "terms": request.terms,
 
201
  qr_content_url=qr_content_url
202
  )
203
 
204
+ logger.info(f"🎉 [SUCCESS] Card generation completed!")
205
+ logger.info(f"📋 Card ID: {db_id if db_id else card_id_for_url}")
206
+ logger.info(f"🖼️ Image: {card_file_id}.png")
207
+ logger.info(f"📱 QR Code: {qr_code_file_id}.png")
208
+
209
  return CardGenerateResponse(
210
  message="Karte erfolgreich generiert.",
211
  card_id=db_id if db_id else card_id_for_url,
 
213
  )
214
  except FileNotFoundError as e:
215
  error_msg = f"Ein benötigtes Template oder eine Datei wurde nicht gefunden: {e.filename}"
216
+ logger.error(f"FileNotFoundError in generate_endpoint: {e}")
217
 
218
  # Log failed card generation
219
  RequestEventLogger.log_card_generation_result(
 
234
  except Exception as e:
235
  error_msg = f"Ein interner Fehler ist aufgetreten: {str(e)}"
236
  import traceback
237
+ logger.error(f"Unerwarteter Fehler in generate_endpoint: {type(e).__name__} - {str(e)}")
238
+ logger.error(traceback.format_exc())
239
 
240
  # Log failed card generation
241
  RequestEventLogger.log_card_generation_result(
app/core/card_renderer.py CHANGED
@@ -1,7 +1,11 @@
1
  from PIL import Image, ImageDraw, ImageFont
2
  import uuid
 
3
  from pathlib import Path
4
 
 
 
 
5
  # Handle import for both package and direct execution
6
  try:
7
  from ..services.request_logger import RequestEventLogger
@@ -62,7 +66,7 @@ def generate_card(
62
  for i, sid in enumerate(symbol_ids):
63
  symbol_file = symbols_images_path / f"symbol{sid}.png"
64
  if not symbol_file.exists():
65
- print(f"Warnung: Symbolbild nicht gefunden: symbol{symbol_file}, wird übersprungen.")
66
  continue
67
  symbol_img = Image.open(symbol_file).convert("RGBA")
68
 
@@ -81,7 +85,7 @@ def generate_card(
81
  font_size = 20 # Beispiel
82
  font = ImageFont.truetype(str(font_path), font_size)
83
  except IOError:
84
- print(f"Warnung: Konnte Schriftart {font_path} nicht laden. Fallback auf Standard-Schriftart (falls verfügbar).")
85
  font = ImageFont.load_default() # Fallback
86
 
87
  # Textpositionierung und -umbruch (vereinfacht)
 
1
  from PIL import Image, ImageDraw, ImageFont
2
  import uuid
3
+ import logging
4
  from pathlib import Path
5
 
6
+ # Configure logger for this module
7
+ logger = logging.getLogger(__name__)
8
+
9
  # Handle import for both package and direct execution
10
  try:
11
  from ..services.request_logger import RequestEventLogger
 
66
  for i, sid in enumerate(symbol_ids):
67
  symbol_file = symbols_images_path / f"symbol{sid}.png"
68
  if not symbol_file.exists():
69
+ logger.warning(f"Symbolbild nicht gefunden: symbol{symbol_file}, wird übersprungen.")
70
  continue
71
  symbol_img = Image.open(symbol_file).convert("RGBA")
72
 
 
85
  font_size = 20 # Beispiel
86
  font = ImageFont.truetype(str(font_path), font_size)
87
  except IOError:
88
+ logger.warning(f"Konnte Schriftart {font_path} nicht laden. Fallback auf Standard-Schriftart (falls verfügbar).")
89
  font = ImageFont.load_default() # Fallback
90
 
91
  # Textpositionierung und -umbruch (vereinfacht)
app/core/constraints.py CHANGED
@@ -1,8 +1,12 @@
1
  # constraints.py
2
  # Constraints: Begriffe prüfen, Filter
3
  import asyncio
 
4
  from fastapi.concurrency import run_in_threadpool
5
 
 
 
 
6
  # Handle import for both package and direct execution
7
  try:
8
  from ..services.request_logger import RequestEventLogger
@@ -66,7 +70,7 @@ async def generate_with_retry(prompt: str, generator, terms: list[str], max_retr
66
  if constraints_met:
67
  return generated_text
68
  else:
69
- print(f"Unerwartete Antwortstruktur vom Generator bei Versuch {attempt + 1}: {responses}")
70
  generated_text = ""
71
 
72
  # Log failed response
@@ -79,7 +83,7 @@ async def generate_with_retry(prompt: str, generator, terms: list[str], max_retr
79
  )
80
 
81
  except Exception as e:
82
- print(f"Fehler bei der Textgenerierung (Versuch {attempt + 1}/{max_retries}): {e}")
83
 
84
  # Log error response
85
  RequestEventLogger.log_llm_response(
 
1
  # constraints.py
2
  # Constraints: Begriffe prüfen, Filter
3
  import asyncio
4
+ import logging
5
  from fastapi.concurrency import run_in_threadpool
6
 
7
+ # Configure logger for this module
8
+ logger = logging.getLogger(__name__)
9
+
10
  # Handle import for both package and direct execution
11
  try:
12
  from ..services.request_logger import RequestEventLogger
 
70
  if constraints_met:
71
  return generated_text
72
  else:
73
+ logger.warning(f"Unerwartete Antwortstruktur vom Generator bei Versuch {attempt + 1}: {responses}")
74
  generated_text = ""
75
 
76
  # Log failed response
 
83
  )
84
 
85
  except Exception as e:
86
+ logger.error(f"Fehler bei der Textgenerierung (Versuch {attempt + 1}/{max_retries}): {e}")
87
 
88
  # Log error response
89
  RequestEventLogger.log_llm_response(
app/main.py CHANGED
@@ -83,7 +83,10 @@ except Exception as e:
83
  origins = [
84
  "http://localhost",
85
  "http://localhost:3000",
86
- # TODO: Optional Füge hier deine Frontend-URL(s) hinzu
 
 
 
87
  ]
88
 
89
  app.add_middleware(
 
83
  origins = [
84
  "http://localhost",
85
  "http://localhost:3000",
86
+ "https://huggingface.co",
87
+ "https://ch404-cardserver.hf.space",
88
+ "https://huggingface.co/spaces/ch404/cardserver",
89
+ "*", # Allow all origins for debugging
90
  ]
91
 
92
  app.add_middleware(
test_card_renderer.py DELETED
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import sys
4
- import traceback
5
- from pathlib import Path
6
-
7
- # Add the app directory to Python path
8
- sys.path.insert(0, str(Path(__file__).parent / "app"))
9
-
10
- try:
11
- from core.card_renderer import generate_card
12
- from core.config import settings
13
-
14
- print('Testing card renderer...')
15
-
16
- # Test parameters
17
- card_design_id = 1
18
- symbol_ids = [1, 2]
19
- text = 'Test card text for debugging'
20
-
21
- file_id = generate_card(
22
- card_design_id=card_design_id,
23
- symbol_ids=symbol_ids,
24
- text=text,
25
- base_images_path=settings.resolved_base_path,
26
- symbols_images_path=settings.resolved_symbols_path,
27
- font_path=settings.resolved_default_font_path,
28
- output_path=settings.resolved_generated_path,
29
- request_id='test-12345'
30
- )
31
-
32
- print(f'Success! Generated card with ID: {file_id}')
33
-
34
- # Check if file was created
35
- output_file = settings.resolved_generated_path / f'{file_id}.png'
36
- print(f'File exists: {output_file.exists()}')
37
- if output_file.exists():
38
- print(f'File size: {output_file.stat().st_size} bytes')
39
-
40
- except Exception as e:
41
- print(f'Error: {type(e).__name__}: {str(e)}')
42
- traceback.print_exc()