Soacti commited on
Commit
1078d41
·
verified ·
1 Parent(s): c80f57a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +334 -165
app.py CHANGED
@@ -1,168 +1,280 @@
1
- import os
2
  import gradio as gr
3
  import json
4
  import time
5
- from fastapi import FastAPI, HTTPException, Depends, Header
6
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
7
- from pydantic import BaseModel
8
- from typing import Optional
9
-
10
- # Hent API-nøkkel fra miljøvariabler
11
- API_KEY = os.getenv("SOACTI_API_KEY")
12
- if not API_KEY:
13
- raise ValueError("SOACTI_API_KEY miljøvariabel er ikke satt!")
14
-
15
- # FastAPI app
16
- app = FastAPI(title="SoActi AI Quiz API - Secure")
17
- security = HTTPBearer()
18
-
19
- # Hardkodede spørsmål (samme som før)
20
- QUIZ_DATABASE = {
21
- "oslo": [
22
- {
23
- "spørsmål": "Hva heter Oslos hovedflyplass?",
24
- "alternativer": ["Fornebu", "Gardermoen", "Torp", "Rygge"],
25
- "korrekt_svar": 1,
26
- "forklaring": "Oslo lufthavn Gardermoen er Oslos hovedflyplass, åpnet i 1998."
27
- },
28
- {
29
- "spørsmål": "Hvilken fjord ligger Oslo ved?",
30
- "alternativer": ["Trondheimsfjorden", "Oslofjorden", "Hardangerfjorden", "Sognefjorden"],
31
- "korrekt_svar": 1,
32
- "forklaring": "Oslo ligger innerst i Oslofjorden."
33
- },
34
- {
35
- "spørsmål": "Hva heter Oslos berømte operahus?",
36
- "alternativer": ["Operaen", "Den Norske Opera", "Oslo Opera House", "Operahuset"],
37
- "korrekt_svar": 3,
38
- "forklaring": "Operahuset i Oslo åpnet i 2008."
39
- }
40
- ],
41
- "bergen": [
42
- {
43
- "spørsmål": "Hva kalles det fargerike kaiområdet i Bergen?",
44
- "alternativer": ["Bryggen", "Fisketorget", "Torgallmenningen", "Nordnes"],
45
- "korrekt_svar": 0,
46
- "forklaring": "Bryggen er UNESCOs verdensarvsted."
47
- },
48
- {
49
- "spørsmål": "Hvilket fjell kan man ta Fløibanen opp til?",
50
- "alternativer": ["Ulriken", "Fløyen", "Løvstakken", "Sandviksfjellet"],
51
- "korrekt_svar": 1,
52
- "forklaring": "Fløibanen går opp til Fløyen, 320 meter over havet."
53
- }
54
- ],
55
- "norsk historie": [
56
- {
57
- "spørsmål": "Hvilket år ble Norge selvstendig fra Danmark?",
58
- "alternativer": ["1814", "1905", "1821", "1830"],
59
- "korrekt_svar": 0,
60
- "forklaring": "Norge ble selvstendig fra Danmark i 1814."
61
- }
62
- ]
63
- }
64
-
65
- # API-nøkkel validering
66
- async def verify_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
67
- if credentials.credentials != API_KEY:
68
- raise HTTPException(
69
- status_code=401,
70
- detail="Ugyldig API-nøkkel"
71
- )
72
- return credentials.credentials
73
 
74
- # Pydantic modeller
75
- class QuizRequest(BaseModel):
76
- tema: str
77
- språk: str = "no"
78
- antall_spørsmål: int = 5
79
- type: str = "multiple_choice"
80
- vanskelighetsgrad: int = 3
81
 
82
- # API endepunkter
83
- @app.get("/health")
84
- async def health_check():
85
- """Offentlig health check"""
86
- return {
87
- "status": "healthy",
88
- "service": "SoActi AI Quiz API",
89
- "auth_required": True
90
- }
91
 
92
- @app.post("/generate-quiz")
93
- async def generate_quiz_secure(
94
- request: QuizRequest,
95
- api_key: str = Depends(verify_api_key)
96
- ):
97
- """Sikret quiz-generering - krever API-nøkkel"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  try:
99
- tema_lower = request.tema.lower().strip()
100
-
101
- # Finn riktige spørsmål
102
- if tema_lower in QUIZ_DATABASE:
103
- questions = QUIZ_DATABASE[tema_lower]
104
- elif "oslo" in tema_lower:
105
- questions = QUIZ_DATABASE["oslo"]
106
- elif "bergen" in tema_lower:
107
- questions = QUIZ_DATABASE["bergen"]
108
- elif "historie" in tema_lower:
109
- questions = QUIZ_DATABASE["norsk historie"]
110
- else:
111
- questions = QUIZ_DATABASE["oslo"]
112
-
113
- # Begrens antall spørsmål
114
- selected_questions = questions[:request.antall_spørsmål]
115
 
116
  return {
117
  "success": True,
118
- "questions": selected_questions,
119
  "metadata": {
120
- "tema": request.tema,
121
- "språk": request.språk,
122
- "antall_generert": len(selected_questions),
123
- "model_used": "Fallback Database",
124
- "generation_time": 0.1,
125
- "auth_verified": True
126
- }
127
  }
128
-
129
  except Exception as e:
130
- raise HTTPException(
131
- status_code=500,
132
- detail=f"Feil ved quiz-generering: {str(e)}"
133
- )
 
 
134
 
135
- # Gradio interface (kun for testing)
136
- def generate_quiz_ui(tema, antall, api_key_input):
137
- """Gradio wrapper med API-nøkkel input"""
138
- if not api_key_input:
139
- return "❌ API-nøkkel er påkrevd"
140
-
141
- if api_key_input != API_KEY:
142
- return "❌ Ugyldig API-nøkkel"
143
-
144
  try:
145
- tema_lower = tema.lower().strip()
146
-
147
- if tema_lower in QUIZ_DATABASE:
148
- questions = QUIZ_DATABASE[tema_lower]
149
- elif "oslo" in tema_lower:
150
- questions = QUIZ_DATABASE["oslo"]
151
- elif "bergen" in tema_lower:
152
- questions = QUIZ_DATABASE["bergen"]
153
- elif "historie" in tema_lower:
154
- questions = QUIZ_DATABASE["norsk historie"]
155
- else:
156
- questions = QUIZ_DATABASE["oslo"]
157
-
158
- selected_questions = questions[:antall]
159
-
160
- output = f"✅ **Genererte {len(selected_questions)} spørsmål om '{tema}'**\n\n"
161
- output += f"🔐 **Autentisert:** Ja\n"
162
- output += f"🤖 **Modell:** Fallback Database\n"
163
- output += f"⏱️ **Tid:** 0.1s\n\n"
164
-
165
- for i, q in enumerate(selected_questions, 1):
166
  output += f"📝 **Spørsmål {i}:** {q['spørsmål']}\n"
167
  for j, alt in enumerate(q['alternativer']):
168
  marker = "✅" if j == q['korrekt_svar'] else "❌"
@@ -174,17 +286,21 @@ def generate_quiz_ui(tema, antall, api_key_input):
174
  except Exception as e:
175
  return f"❌ **Feil:** {str(e)}"
176
 
177
- # Gradio interface
178
- with gr.Blocks(title="SoActi AI Quiz API - Secure") as demo:
179
- gr.Markdown("# 🔐 SoActi AI Quiz API - Sikker Versjon")
180
- gr.Markdown("**API krever nå autentisering med Bearer token**")
 
 
 
 
181
 
182
  with gr.Row():
183
  with gr.Column():
184
  tema_input = gr.Textbox(
185
- label="Tema",
186
- value="Oslo",
187
- placeholder="Oslo, Bergen, Norsk historie"
188
  )
189
  antall_input = gr.Slider(
190
  minimum=1,
@@ -195,30 +311,83 @@ with gr.Blocks(title="SoActi AI Quiz API - Secure") as demo:
195
  )
196
  api_key_input = gr.Textbox(
197
  label="API-nøkkel (for testing)",
198
- type="password",
199
- placeholder="Skriv inn API-nøkkel..."
200
  )
201
 
202
- generate_btn = gr.Button("🚀 Generer Quiz", variant="primary")
203
 
204
  with gr.Column():
205
  output = gr.Textbox(
206
  label="Generert Quiz",
207
  lines=20,
208
- placeholder="Skriv inn API-nøkkel og klikk 'Generer Quiz'..."
209
  )
210
 
211
  generate_btn.click(
212
- fn=generate_quiz_ui,
213
  inputs=[tema_input, antall_input, api_key_input],
214
  outputs=output
215
  )
216
 
217
- gr.Markdown("## 🔗 API Endepunkt")
218
  gr.Markdown("`POST https://Soacti-soacti-ai-quiz-api.hf.space/generate-quiz`")
219
- gr.Markdown("**Header:** `Authorization: Bearer [din-api-nøkkel]`")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- # Mount Gradio til FastAPI
222
  app = gr.mount_gradio_app(app, demo, path="/")
223
 
224
  if __name__ == "__main__":
 
 
1
  import gradio as gr
2
  import json
3
  import time
4
+ import os
5
+ from typing import List, Dict, Any, Optional
6
+ import random
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ # Import Hugging Face inference API
9
+ from huggingface_hub import InferenceClient
 
 
 
 
 
10
 
11
+ # API key validation
12
+ def validate_api_key(api_key: str) -> bool:
13
+ """Validate the API key against the stored secret"""
14
+ expected_key = os.environ.get("SOACTI_API_KEY")
15
+ if not expected_key:
16
+ print("WARNING: SOACTI_API_KEY not set in environment variables")
17
+ return False
18
+ return api_key == expected_key
 
19
 
20
+ # AI Quiz generation with Hugging Face models
21
+ class AIQuizGenerator:
22
+ def __init__(self):
23
+ self.api_key = os.environ.get("HUGGINGFACE_API_KEY")
24
+ if not self.api_key:
25
+ print("WARNING: HUGGINGFACE_API_KEY not set in environment variables")
26
+
27
+ # Use a more capable model for better quiz generation
28
+ self.default_model = "microsoft/DialoGPT-medium"
29
+ self.fallback_model = "google/flan-t5-base"
30
+
31
+ # Initialize the client
32
+ self.client = InferenceClient(token=self.api_key) if self.api_key else None
33
+
34
+ def generate_quiz(self, tema: str, antall: int = 3, språk: str = "no") -> List[Dict[str, Any]]:
35
+ """Generate quiz questions using AI - NO RESTRICTIONS ON TOPIC"""
36
+ if not self.client:
37
+ print("No Hugging Face API key available, generating basic questions")
38
+ return self._generate_basic_questions(tema, antall)
39
+
40
+ try:
41
+ # Build flexible prompt that works with ANY topic
42
+ prompt = self._build_flexible_prompt(tema, antall, språk)
43
+
44
+ # Try primary model first
45
+ start_time = time.time()
46
+ try:
47
+ response = self.client.text_generation(
48
+ prompt,
49
+ model=self.default_model,
50
+ max_new_tokens=1500,
51
+ temperature=0.8,
52
+ repetition_penalty=1.1,
53
+ do_sample=True
54
+ )
55
+ except:
56
+ # Fallback to more reliable model
57
+ response = self.client.text_generation(
58
+ prompt,
59
+ model=self.fallback_model,
60
+ max_new_tokens=1200,
61
+ temperature=0.7,
62
+ repetition_penalty=1.2,
63
+ )
64
+
65
+ generation_time = time.time() - start_time
66
+
67
+ print(f"AI response received in {generation_time:.2f}s for topic: {tema}")
68
+ print(f"Response preview: {response[:300]}...")
69
+
70
+ # Parse the response into questions
71
+ questions = self._parse_flexible_response(response, tema, antall)
72
+
73
+ # If we couldn't parse enough questions, generate more basic ones
74
+ if len(questions) < antall:
75
+ additional = self._generate_basic_questions(tema, antall - len(questions))
76
+ questions.extend(additional)
77
+
78
+ return questions[:antall]
79
+
80
+ except Exception as e:
81
+ print(f"Error generating quiz with AI: {str(e)}")
82
+ return self._generate_basic_questions(tema, antall)
83
+
84
+ def _build_flexible_prompt(self, tema: str, antall: int, språk: str) -> str:
85
+ """Build a flexible prompt that works with ANY topic"""
86
+ language = "norsk" if språk == "no" else "English"
87
+
88
+ return f"""Create {antall} quiz questions about "{tema}" in {language}.
89
+
90
+ IMPORTANT: Generate questions about ANY topic the user requests - there are NO restrictions.
91
+ Whether it's about science, history, pop culture, technology, sports, entertainment, food, travel, or anything else - create relevant questions.
92
+
93
+ Format each question EXACTLY like this:
94
+
95
+ Q1: [Clear question about {tema}]
96
+ A) [First option]
97
+ B) [Second option]
98
+ C) [Third option]
99
+ D) [Fourth option]
100
+ CORRECT: [A, B, C, or D]
101
+ EXPLANATION: [Brief explanation why this is correct]
102
+
103
+ Q2: [Second question about {tema}]
104
+ A) [First option]
105
+ B) [Second option]
106
+ C) [Third option]
107
+ D) [Fourth option]
108
+ CORRECT: [A, B, C, or D]
109
+ EXPLANATION: [Brief explanation]
110
+
111
+ Continue for all {antall} questions about "{tema}".
112
+
113
+ Make the questions interesting and educational. Use your knowledge to create accurate, relevant questions about this topic.
114
+
115
+ Topic: {tema}
116
+ Generate {antall} questions now:
117
+ """
118
+
119
+ def _parse_flexible_response(self, response: str, tema: str, expected_count: int) -> List[Dict[str, Any]]:
120
+ """Parse AI response with flexible parsing for any topic"""
121
+ questions = []
122
+
123
+ # Split response into potential question blocks
124
+ lines = response.split('\n')
125
+ current_question = {}
126
+ current_options = []
127
+
128
+ for line in lines:
129
+ line = line.strip()
130
+ if not line:
131
+ continue
132
+
133
+ # Look for question patterns
134
+ if line.startswith(('Q1:', 'Q2:', 'Q3:', 'Q4:', 'Q5:')) or 'SPØRSMÅL:' in line.upper():
135
+ # Save previous question if complete
136
+ if self._is_complete_question(current_question, current_options):
137
+ current_question["alternativer"] = current_options
138
+ questions.append(current_question)
139
+
140
+ # Start new question
141
+ question_text = line.split(':', 1)[1].strip() if ':' in line else line
142
+ current_question = {"spørsmål": question_text}
143
+ current_options = []
144
+
145
+ elif line.startswith(('A)', 'B)', 'C)', 'D)')):
146
+ option = line[2:].strip()
147
+ if option:
148
+ current_options.append(option)
149
+
150
+ elif 'CORRECT:' in line.upper() or 'KORREKT:' in line.upper():
151
+ correct_part = line.upper().split('CORRECT:')[-1].split('KORREKT:')[-1].strip()
152
+ if correct_part and correct_part[0] in ['A', 'B', 'C', 'D']:
153
+ current_question["korrekt_svar"] = ['A', 'B', 'C', 'D'].index(correct_part[0])
154
+
155
+ elif 'EXPLANATION:' in line.upper() or 'FORKLARING:' in line.upper():
156
+ explanation = line.split(':')[1].strip() if ':' in line else line
157
+ current_question["forklaring"] = explanation
158
+
159
+ # Add the last question if complete
160
+ if self._is_complete_question(current_question, current_options):
161
+ current_question["alternativer"] = current_options
162
+ questions.append(current_question)
163
+
164
+ return questions
165
+
166
+ def _is_complete_question(self, question: Dict, options: List) -> bool:
167
+ """Check if a question is complete"""
168
+ return (
169
+ "spørsmål" in question and
170
+ len(options) >= 3 and # At least 3 options
171
+ "korrekt_svar" in question and
172
+ question["korrekt_svar"] < len(options)
173
+ )
174
+
175
+ def _generate_basic_questions(self, tema: str, antall: int) -> List[Dict[str, Any]]:
176
+ """Generate basic questions when AI fails - works with ANY topic"""
177
+ questions = []
178
+
179
+ # Generate generic but relevant questions for any topic
180
+ question_templates = [
181
+ f"Hva er det mest kjente ved {tema}?",
182
+ f"Hvilket år er viktig i historien til {tema}?",
183
+ f"Hvor finner man vanligvis {tema}?",
184
+ f"Hva karakteriserer {tema}?",
185
+ f"Hvilken betydning har {tema}?"
186
+ ]
187
+
188
+ for i in range(min(antall, len(question_templates))):
189
+ questions.append({
190
+ "spørsmål": question_templates[i],
191
+ "alternativer": [
192
+ f"Alternativ A om {tema}",
193
+ f"Alternativ B om {tema}",
194
+ f"Alternativ C om {tema}",
195
+ f"Alternativ D om {tema}"
196
+ ],
197
+ "korrekt_svar": 0, # Always A for simplicity
198
+ "forklaring": f"Dette er et generert spørsmål om {tema}. For mer nøyaktige spørsmål, prøv igjen - AI-systemet lærer kontinuerlig."
199
+ })
200
+
201
+ return questions
202
+
203
+ # Initialize the AI generator
204
+ quiz_generator = AIQuizGenerator()
205
+
206
+ # API endpoint for quiz generation - NO TOPIC RESTRICTIONS
207
+ def generate_quiz_api(tema: str, språk: str = "no", antall_spørsmål: int = 3,
208
+ type: str = "sted", vanskelighetsgrad: int = 3,
209
+ api_key: str = None) -> Dict[str, Any]:
210
+ """API endpoint for quiz generation - ACCEPTS ANY TOPIC"""
211
+
212
+ # Validate API key
213
+ if not validate_api_key(api_key):
214
+ return {
215
+ "success": False,
216
+ "message": "Ugyldig API-nøkkel",
217
+ "questions": []
218
+ }
219
+
220
+ # NO TOPIC FILTERING - Accept absolutely anything
221
+ if not tema or len(tema.strip()) < 2:
222
+ return {
223
+ "success": False,
224
+ "message": "Vennligst oppgi et tema (minimum 2 tegn)",
225
+ "questions": []
226
+ }
227
+
228
  try:
229
+ # Generate questions with AI - NO RESTRICTIONS
230
+ start_time = time.time()
231
+ questions = quiz_generator.generate_quiz(tema.strip(), antall_spørsmål, språk)
232
+ generation_time = time.time() - start_time
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
  return {
235
  "success": True,
236
+ "questions": questions,
237
  "metadata": {
238
+ "generation_time": round(generation_time, 2),
239
+ "model_used": quiz_generator.default_model,
240
+ "topic": tema,
241
+ "unrestricted": True # Flag to show no restrictions
242
+ },
243
+ "message": f"Genererte {len(questions)} spørsmål om '{tema}' - ingen begrensninger!"
 
244
  }
 
245
  except Exception as e:
246
+ print(f"Error in generate_quiz_api: {str(e)}")
247
+ return {
248
+ "success": False,
249
+ "message": f"Feil ved generering av quiz: {str(e)}",
250
+ "questions": []
251
+ }
252
 
253
+ # Gradio interface - emphasize NO RESTRICTIONS
254
+ def generate_quiz_gradio(tema, antall, api_key=None):
255
+ """Gradio wrapper - accepts ANY topic"""
256
+ if api_key and not validate_api_key(api_key):
257
+ return "❌ **Ugyldig API-nøkkel**"
258
+
259
+ if not tema or len(tema.strip()) < 2:
260
+ return "❌ **Vennligst skriv inn et tema**"
261
+
262
  try:
263
+ result = generate_quiz_api(tema, "no", antall, "sted", 3, api_key)
264
+
265
+ if not result["success"]:
266
+ return f"❌ **Feil:** {result['message']}"
267
+
268
+ questions = result["questions"]
269
+ model = result["metadata"]["model_used"]
270
+ time_taken = result["metadata"]["generation_time"]
271
+
272
+ output = f" **Genererte {len(questions)} spørsmål om '{tema}'**\n\n"
273
+ output += f"🤖 **Modell:** {model}\n"
274
+ output += f"⏱️ **Tid:** {time_taken}s\n"
275
+ output += f"🔓 **Ingen begrensninger** - alle temaer er tillatt!\n\n"
276
+
277
+ for i, q in enumerate(questions, 1):
 
 
 
 
 
 
278
  output += f"📝 **Spørsmål {i}:** {q['spørsmål']}\n"
279
  for j, alt in enumerate(q['alternativer']):
280
  marker = "✅" if j == q['korrekt_svar'] else "❌"
 
286
  except Exception as e:
287
  return f"❌ **Feil:** {str(e)}"
288
 
289
+ # Health check endpoint
290
+ def health_check():
291
+ return {"status": "healthy", "timestamp": time.time(), "unrestricted": True}
292
+
293
+ # Gradio interface - emphasize freedom
294
+ with gr.Blocks(title="SoActi AI Quiz API - Ubegrenset") as demo:
295
+ gr.Markdown("# 🧠 SoActi AI Quiz API - Ubegrenset")
296
+ gr.Markdown("**🔓 Lag quiz om ABSOLUTT HVASOM HELST - ingen begrensninger!**")
297
 
298
  with gr.Row():
299
  with gr.Column():
300
  tema_input = gr.Textbox(
301
+ label="Tema (skriv hva som helst!)",
302
+ value="",
303
+ placeholder="Fotball, Harry Potter, Kvantfysikk, Baking, TikTok, Dinosaurer, Programmering, K-pop, Filosofi, Gaming..."
304
  )
305
  antall_input = gr.Slider(
306
  minimum=1,
 
311
  )
312
  api_key_input = gr.Textbox(
313
  label="API-nøkkel (for testing)",
314
+ placeholder="Skriv inn API-nøkkel...",
315
+ type="password"
316
  )
317
 
318
+ generate_btn = gr.Button("🚀 Generer Quiz om HVASOM HELST!", variant="primary")
319
 
320
  with gr.Column():
321
  output = gr.Textbox(
322
  label="Generert Quiz",
323
  lines=20,
324
+ placeholder="Skriv inn HVILKET SOM HELST tema og klikk 'Generer Quiz'!\n\nEksempler:\n- Marvel filmer\n- Norsk rap\n- Kryptovaluta\n- Yoga\n- Sushi\n- Elon Musk\n- Klimaendringer\n- Netflix serier\n- Fotografi\n- Skateboard"
325
  )
326
 
327
  generate_btn.click(
328
+ fn=generate_quiz_gradio,
329
  inputs=[tema_input, antall_input, api_key_input],
330
  outputs=output
331
  )
332
 
333
+ gr.Markdown("## 🔗 API for SoActi")
334
  gr.Markdown("`POST https://Soacti-soacti-ai-quiz-api.hf.space/generate-quiz`")
335
+ gr.Markdown("**🔓 Ingen begrensninger - brukere kan spørre om hva som helst!**")
336
+
337
+ # FastAPI setup with CORS for unrestricted access
338
+ from fastapi import FastAPI, HTTPException, Depends, Header
339
+ from fastapi.middleware.cors import CORSMiddleware
340
+ from pydantic import BaseModel
341
+
342
+ app = FastAPI(title="SoActi Quiz API - Ubegrenset")
343
+
344
+ app.add_middleware(
345
+ CORSMiddleware,
346
+ allow_origins=["*"],
347
+ allow_credentials=True,
348
+ allow_methods=["*"],
349
+ allow_headers=["*"],
350
+ )
351
+
352
+ class QuizRequest(BaseModel):
353
+ tema: str # NO restrictions on what this can be
354
+ språk: str = "no"
355
+ antall_spørsmål: int = 3
356
+ type: str = "sted"
357
+ vanskelighetsgrad: int = 3
358
+
359
+ async def get_api_key(authorization: str = Header(None)):
360
+ if not authorization:
361
+ raise HTTPException(status_code=401, detail="API key missing")
362
+
363
+ parts = authorization.split()
364
+ if len(parts) != 2 or parts[0].lower() != "bearer":
365
+ raise HTTPException(status_code=401, detail="Invalid authorization header")
366
+
367
+ return parts[1]
368
+
369
+ @app.post("/generate-quiz")
370
+ async def api_generate_quiz(request: QuizRequest, api_key: str = Depends(get_api_key)):
371
+ """Generate quiz about ANY topic - no restrictions"""
372
+ result = generate_quiz_api(
373
+ request.tema, # Accept ANY topic
374
+ request.språk,
375
+ request.antall_spørsmål,
376
+ request.type,
377
+ request.vanskelighetsgrad,
378
+ api_key
379
+ )
380
+
381
+ if not result["success"]:
382
+ raise HTTPException(status_code=400, detail=result["message"])
383
+
384
+ return result
385
+
386
+ @app.get("/health")
387
+ async def api_health():
388
+ return health_check()
389
 
390
+ # Mount Gradio
391
  app = gr.mount_gradio_app(app, demo, path="/")
392
 
393
  if __name__ == "__main__":