Soacti commited on
Commit
2300b9a
·
verified ·
1 Parent(s): 17e49b6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -0
app.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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