Soacti commited on
Commit
765f19b
·
verified ·
1 Parent(s): 4491987

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -213
app.py CHANGED
@@ -1,226 +1,145 @@
1
  import gradio as gr
2
- from fastapi import FastAPI, HTTPException
3
- from pydantic import BaseModel
4
  import json
5
- import os
6
- import asyncio
7
- import aiohttp
8
- from typing import List, Optional, Literal
9
  import time
10
- import logging
11
- import re
12
 
13
- # Setup logging
14
- logging.basicConfig(level=logging.INFO)
15
- logger = logging.getLogger(__name__)
16
-
17
- app = FastAPI(
18
- title="SoActi AI Quiz API",
19
- description="Separat AI-tjeneste for quiz-generering som SoActi kan bruke",
20
- version="1.0.0"
21
- )
22
-
23
- # Request/Response models
24
- class QuizRequest(BaseModel):
25
- tema: str
26
- språk: Literal["no", "en"] = "no"
27
- antall_spørsmål: int = 5
28
- type: Literal["sted", "rute"] = "sted"
29
- vanskelighetsgrad: int = 3
30
-
31
- class QuizQuestion(BaseModel):
32
- spørsmål: str
33
- alternativer: List[str]
34
- korrekt_svar: int
35
- forklaring: str
36
-
37
- class QuizResponse(BaseModel):
38
- success: bool
39
- questions: List[QuizQuestion]
40
- metadata: dict
41
- message: str
42
-
43
- class HealthResponse(BaseModel):
44
- status: str
45
- models_loaded: bool
46
- api_key_configured: bool
47
- uptime_seconds: float
48
-
49
- # Global state
50
- start_time = time.time()
51
- api_key = os.getenv("HUGGINGFACE_API_KEY")
52
-
53
- @app.get("/", response_model=dict)
54
- async def root():
55
- """Root endpoint med API-informasjon"""
56
- return {
57
- "service": "SoActi AI Quiz API",
58
- "version": "1.0.0",
59
- "status": "running",
60
- "endpoints": {
61
- "generate": "/generate-quiz",
62
- "health": "/health",
63
- "models": "/models",
64
- "docs": "/docs"
65
  },
66
- "description": "Separat AI-tjeneste for quiz-generering"
67
- }
68
-
69
- @app.get("/health", response_model=HealthResponse)
70
- async def health_check():
71
- """Helsesjekk for tjenesten"""
72
- uptime = time.time() - start_time
73
-
74
- return HealthResponse(
75
- status="healthy",
76
- models_loaded=True,
77
- api_key_configured=bool(api_key),
78
- uptime_seconds=uptime
79
- )
80
-
81
- @app.get("/models")
82
- async def get_available_models():
83
- """Liste over tilgjengelige AI-modeller"""
84
- return {
85
- "norwegian_models": [
86
- {
87
- "name": "NbAiLab/nb-gpt-j-6B",
88
- "description": "Beste for norsk - Nasjonalbiblioteket",
89
- "cost": "Gratis",
90
- "quality": "Høy (norsk)"
91
- }
92
- ],
93
- "english_models": [
94
- {
95
- "name": "meta-llama/Llama-2-70b-chat-hf",
96
- "description": "Beste kvalitet - Premium",
97
- "cost": "Premium ($$$)",
98
- "quality": "Exceptional"
99
- },
100
- {
101
- "name": "mistralai/Mistral-7B-Instruct-v0.1",
102
- "description": "Balansert kvalitet/kostnad",
103
- "cost": "Premium ($$)",
104
- "quality": "Meget høy"
105
- }
106
- ],
107
- "fallback_models": [
108
- {
109
- "name": "google/flan-t5-small",
110
- "description": "Gratis fallback",
111
- "cost": "Gratis",
112
- "quality": "Middels"
113
- }
114
- ]
115
- }
116
-
117
- @app.post("/generate-quiz", response_model=QuizResponse)
118
- async def generate_quiz(request: QuizRequest):
119
- """Hovedendepunkt for quiz-generering"""
120
- try:
121
- logger.info(f"Genererer quiz for tema: {request.tema} ({request.språk})")
122
-
123
- # Valider request
124
- if not request.tema.strip():
125
- raise HTTPException(status_code=400, detail="Tema kan ikke være tomt")
126
-
127
- if request.antall_spørsmål < 1 or request.antall_spørsmål > 20:
128
- raise HTTPException(status_code=400, detail="Antall spørsmål må være mellom 1 og 20")
129
-
130
- # Generer quiz
131
- from quiz_generator import QuizGenerator
132
- generator = QuizGenerator(api_key)
133
-
134
- start_time = time.time()
135
- questions = await generator.generate_quiz(request)
136
- generation_time = time.time() - start_time
137
-
138
- if not questions:
139
- raise HTTPException(status_code=500, detail="Kunne ikke generere spørsmål")
140
-
141
- logger.info(f"Genererte {len(questions)} spørsmål på {generation_time:.2f}s")
142
-
143
- return QuizResponse(
144
- success=True,
145
- questions=questions,
146
- metadata={
147
- "generation_time": round(generation_time, 2),
148
- "model_used": generator.get_model_used(),
149
- "method": generator.get_generation_method(),
150
- "tema": request.tema,
151
- "språk": request.språk
152
- },
153
- message=f"Genererte {len(questions)} spørsmål om '{request.tema}'"
154
- )
155
-
156
- except HTTPException:
157
- raise
158
- except Exception as e:
159
- logger.error(f"Feil ved quiz-generering: {str(e)}")
160
- raise HTTPException(status_code=500, detail=f"Intern feil: {str(e)}")
161
-
162
- @app.post("/validate-quiz")
163
- async def validate_quiz(questions: List[QuizQuestion]):
164
- """Valider genererte quiz-spørsmål"""
165
- try:
166
- from quiz_validator import QuizValidator
167
- validator = QuizValidator()
168
-
169
- results = []
170
- for i, question in enumerate(questions):
171
- validation = validator.validate_question(question.dict())
172
- results.append({
173
- "question_index": i,
174
- "valid": validation["valid"],
175
- "score": validation["score"],
176
- "issues": validation["issues"]
177
- })
178
-
179
- overall_score = sum(r["score"] for r in results) / len(results)
180
-
181
- return {
182
- "overall_valid": all(r["valid"] for r in results),
183
- "overall_score": round(overall_score, 2),
184
- "question_results": results
185
  }
186
-
187
- except Exception as e:
188
- raise HTTPException(status_code=500, detail=f"Valideringsfeil: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
- # Gradio interface for testing
191
- def gradio_generate_quiz(tema, språk, antall, type_val, vanskelighet):
192
- """Gradio wrapper for quiz generation"""
193
  try:
194
- import asyncio
195
-
196
- request = QuizRequest(
197
- tema=tema,
198
- språk=språk,
199
- antall_spørsmål=antall,
200
- type=type_val,
201
- vanskelighetsgrad=vanskelighet
202
- )
203
-
204
- # Run async function in sync context
205
- loop = asyncio.new_event_loop()
206
- asyncio.set_event_loop(loop)
207
- response = loop.run_until_complete(generate_quiz(request))
208
- loop.close()
209
-
210
- # Format for display
211
- output = f"✅ {response.message}\n\n"
212
- output += f"🤖 Modell: {response.metadata.get('model_used', 'Ukjent')}\n"
213
- output += f"⏱️ Tid: {response.metadata.get('generation_time', 0)}s\n"
214
- output += f"🔧 Metode: {response.metadata.get('method', 'Ukjent')}\n\n"
215
-
216
- for i, q in enumerate(response.questions, 1):
217
- output += f"📝 **Spørsmål {i}:** {q.spørsmål}\n"
218
- for j, alt in enumerate(q.alternativer):
219
- marker = "✅" if j == q.korrekt_svar else "❌"
 
 
220
  output += f" {chr(65+j)}) {alt} {marker}\n"
221
- output += f"💡 **Forklaring:** {q.forklaring}\n\n"
222
 
223
  return output
224
 
225
  except Exception as e:
226
- retur
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
 
 
2
  import json
 
 
 
 
3
  import time
 
 
4
 
5
+ # Hardkodede spørsmål direkte i app.py
6
+ QUIZ_DATABASE = {
7
+ "oslo": [
8
+ {
9
+ "spørsmål": "Hva heter Oslos hovedflyplass?",
10
+ "alternativer": ["Fornebu", "Gardermoen", "Torp", "Rygge"],
11
+ "korrekt_svar": 1,
12
+ "forklaring": "Oslo lufthavn Gardermoen er Oslos hovedflyplass, åpnet i 1998."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  },
14
+ {
15
+ "spørsmål": "Hvilken fjord ligger Oslo ved?",
16
+ "alternativer": ["Trondheimsfjorden", "Oslofjorden", "Hardangerfjorden", "Sognefjorden"],
17
+ "korrekt_svar": 1,
18
+ "forklaring": "Oslo ligger innerst i Oslofjorden."
19
+ },
20
+ {
21
+ "spørsmål": "Hva heter Oslos berømte operahus?",
22
+ "alternativer": ["Operaen", "Den Norske Opera", "Oslo Opera House", "Operahuset"],
23
+ "korrekt_svar": 3,
24
+ "forklaring": "Operahuset i Oslo åpnet i 2008."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
+ ],
27
+ "bergen": [
28
+ {
29
+ "spørsmål": "Hva kalles det fargerike kaiområdet i Bergen?",
30
+ "alternativer": ["Bryggen", "Fisketorget", "Torgallmenningen", "Nordnes"],
31
+ "korrekt_svar": 0,
32
+ "forklaring": "Bryggen er UNESCOs verdensarvsted."
33
+ },
34
+ {
35
+ "spørsmål": "Hvilket fjell kan man ta Fløibanen opp til?",
36
+ "alternativer": ["Ulriken", "Fløyen", "Løvstakken", "Sandviksfjellet"],
37
+ "korrekt_svar": 1,
38
+ "forklaring": "Fløibanen går opp til Fløyen, 320 meter over havet."
39
+ }
40
+ ],
41
+ "norsk historie": [
42
+ {
43
+ "spørsmål": "Hvilket år ble Norge selvstendig fra Danmark?",
44
+ "alternativer": ["1814", "1905", "1821", "1830"],
45
+ "korrekt_svar": 0,
46
+ "forklaring": "Norge ble selvstendig fra Danmark i 1814."
47
+ }
48
+ ]
49
+ }
50
 
51
+ def generate_quiz_for_soacti(tema, språk, antall, type_val, vanskelighet):
52
+ """Quiz-generering som SoActi kan bruke"""
 
53
  try:
54
+ # Normaliser tema
55
+ tema_lower = tema.lower().strip()
56
+
57
+ # Finn spørsmål
58
+ if tema_lower in QUIZ_DATABASE:
59
+ questions = QUIZ_DATABASE[tema_lower]
60
+ elif "oslo" in tema_lower:
61
+ questions = QUIZ_DATABASE["oslo"]
62
+ elif "bergen" in tema_lower:
63
+ questions = QUIZ_DATABASE["bergen"]
64
+ elif "historie" in tema_lower:
65
+ questions = QUIZ_DATABASE["norsk historie"]
66
+ else:
67
+ questions = QUIZ_DATABASE["oslo"] # Default
68
+
69
+ # Begrens antall
70
+ selected = questions[:antall]
71
+
72
+ # Format output for visning
73
+ output = f" **Genererte {len(selected)} spørsmål om '{tema}'**\n\n"
74
+ output += f"🤖 **Modell:** Fallback (forhåndsdefinerte spørsmål)\n"
75
+ output += f"🌐 **Språk:** {språk}\n"
76
+ output += f"⏱️ **Tid:** 0.1s\n\n"
77
+
78
+ for i, q in enumerate(selected, 1):
79
+ output += f"📝 **Spørsmål {i}:** {q['spørsmål']}\n"
80
+ for j, alt in enumerate(q['alternativer']):
81
+ marker = "✅" if j == q['korrekt_svar'] else "❌"
82
  output += f" {chr(65+j)}) {alt} {marker}\n"
83
+ output += f"💡 **Forklaring:** {q['forklaring']}\n\n"
84
 
85
  return output
86
 
87
  except Exception as e:
88
+ return f"❌ **Feil:** {str(e)}"
89
+
90
+ # Gradio interface
91
+ with gr.Blocks(title="SoActi AI Quiz API") as demo:
92
+ gr.Markdown("# 🧠 SoActi AI Quiz API")
93
+ gr.Markdown("**Fungerende quiz-generering for SoActi**")
94
+
95
+ with gr.Row():
96
+ with gr.Column():
97
+ tema_input = gr.Textbox(
98
+ label="Tema",
99
+ value="Oslo",
100
+ placeholder="Oslo, Bergen, Norsk historie"
101
+ )
102
+ språk_input = gr.Dropdown(
103
+ choices=["no", "en"],
104
+ label="Språk",
105
+ value="no"
106
+ )
107
+ antall_input = gr.Slider(
108
+ minimum=1,
109
+ maximum=5,
110
+ step=1,
111
+ label="Antall spørsmål",
112
+ value=3
113
+ )
114
+ type_input = gr.Dropdown(
115
+ choices=["sted", "rute"],
116
+ label="Type",
117
+ value="sted"
118
+ )
119
+ vanskelighet_input = gr.Slider(
120
+ minimum=1,
121
+ maximum=5,
122
+ step=1,
123
+ label="Vanskelighetsgrad",
124
+ value=3
125
+ )
126
+
127
+ generate_btn = gr.Button("🚀 Generer Quiz", variant="primary")
128
+
129
+ with gr.Column():
130
+ output = gr.Textbox(
131
+ label="Generert Quiz",
132
+ lines=20,
133
+ placeholder="Klikk 'Generer Quiz' for å starte..."
134
+ )
135
+
136
+ generate_btn.click(
137
+ fn=generate_quiz_for_soacti,
138
+ inputs=[tema_input, språk_input, antall_input, type_input, vanskelighet_input],
139
+ outputs=output
140
+ )
141
+
142
+ gr.Markdown("## 🔗 API URL for SoActi")
143
+ gr.Markdown("`https://Soacti-soacti-ai-quiz-api.hf.space`")
144
+
145
+ demo.launch()