Spaces:
Sleeping
Sleeping
import gradio as gr | |
import json | |
import time | |
import os | |
from typing import List, Dict, Any, Optional | |
import random | |
# Import Hugging Face inference API | |
from huggingface_hub import InferenceClient | |
# API key validation | |
def validate_api_key(api_key: str) -> bool: | |
"""Validate the API key against the stored secret""" | |
expected_key = os.environ.get("SOACTI_API_KEY") | |
if not expected_key: | |
print("WARNING: SOACTI_API_KEY not set in environment variables") | |
return False | |
return api_key == expected_key | |
# AI Quiz generation with Hugging Face models | |
class AIQuizGenerator: | |
def __init__(self): | |
self.api_key = os.environ.get("HUGGINGFACE_API_KEY") | |
if not self.api_key: | |
print("WARNING: HUGGINGFACE_API_KEY not set in environment variables") | |
# Use a more capable model for better quiz generation | |
self.default_model = "microsoft/DialoGPT-medium" | |
self.fallback_model = "google/flan-t5-base" | |
# Initialize the client | |
self.client = InferenceClient(token=self.api_key) if self.api_key else None | |
def generate_quiz(self, tema: str, antall: int = 3, språk: str = "no") -> List[Dict[str, Any]]: | |
"""Generate quiz questions using AI - NO RESTRICTIONS ON TOPIC""" | |
if not self.client: | |
print("No Hugging Face API key available, generating basic questions") | |
return self._generate_basic_questions(tema, antall) | |
try: | |
# Build flexible prompt that works with ANY topic | |
prompt = self._build_flexible_prompt(tema, antall, språk) | |
# Try primary model first | |
start_time = time.time() | |
try: | |
response = self.client.text_generation( | |
prompt, | |
model=self.default_model, | |
max_new_tokens=1500, | |
temperature=0.8, | |
repetition_penalty=1.1, | |
do_sample=True | |
) | |
except: | |
# Fallback to more reliable model | |
response = self.client.text_generation( | |
prompt, | |
model=self.fallback_model, | |
max_new_tokens=1200, | |
temperature=0.7, | |
repetition_penalty=1.2, | |
) | |
generation_time = time.time() - start_time | |
print(f"AI response received in {generation_time:.2f}s for topic: {tema}") | |
print(f"Response preview: {response[:300]}...") | |
# Parse the response into questions | |
questions = self._parse_flexible_response(response, tema, antall) | |
# If we couldn't parse enough questions, generate more basic ones | |
if len(questions) < antall: | |
additional = self._generate_basic_questions(tema, antall - len(questions)) | |
questions.extend(additional) | |
return questions[:antall] | |
except Exception as e: | |
print(f"Error generating quiz with AI: {str(e)}") | |
return self._generate_basic_questions(tema, antall) | |
def _build_flexible_prompt(self, tema: str, antall: int, språk: str) -> str: | |
"""Build a flexible prompt that works with ANY topic""" | |
language = "norsk" if språk == "no" else "English" | |
return f"""Create {antall} quiz questions about "{tema}" in {language}. | |
IMPORTANT: Generate questions about ANY topic the user requests - there are NO restrictions. | |
Whether it's about science, history, pop culture, technology, sports, entertainment, food, travel, or anything else - create relevant questions. | |
Format each question EXACTLY like this: | |
Q1: [Clear question about {tema}] | |
A) [First option] | |
B) [Second option] | |
C) [Third option] | |
D) [Fourth option] | |
CORRECT: [A, B, C, or D] | |
EXPLANATION: [Brief explanation why this is correct] | |
Q2: [Second question about {tema}] | |
A) [First option] | |
B) [Second option] | |
C) [Third option] | |
D) [Fourth option] | |
CORRECT: [A, B, C, or D] | |
EXPLANATION: [Brief explanation] | |
Continue for all {antall} questions about "{tema}". | |
Make the questions interesting and educational. Use your knowledge to create accurate, relevant questions about this topic. | |
Topic: {tema} | |
Generate {antall} questions now: | |
""" | |
def _parse_flexible_response(self, response: str, tema: str, expected_count: int) -> List[Dict[str, Any]]: | |
"""Parse AI response with flexible parsing for any topic""" | |
questions = [] | |
# Split response into potential question blocks | |
lines = response.split('\n') | |
current_question = {} | |
current_options = [] | |
for line in lines: | |
line = line.strip() | |
if not line: | |
continue | |
# Look for question patterns | |
if line.startswith(('Q1:', 'Q2:', 'Q3:', 'Q4:', 'Q5:')) or 'SPØRSMÅL:' in line.upper(): | |
# Save previous question if complete | |
if self._is_complete_question(current_question, current_options): | |
current_question["alternativer"] = current_options | |
questions.append(current_question) | |
# Start new question | |
question_text = line.split(':', 1)[1].strip() if ':' in line else line | |
current_question = {"spørsmål": question_text} | |
current_options = [] | |
elif line.startswith(('A)', 'B)', 'C)', 'D)')): | |
option = line[2:].strip() | |
if option: | |
current_options.append(option) | |
elif 'CORRECT:' in line.upper() or 'KORREKT:' in line.upper(): | |
correct_part = line.upper().split('CORRECT:')[-1].split('KORREKT:')[-1].strip() | |
if correct_part and correct_part[0] in ['A', 'B', 'C', 'D']: | |
current_question["korrekt_svar"] = ['A', 'B', 'C', 'D'].index(correct_part[0]) | |
elif 'EXPLANATION:' in line.upper() or 'FORKLARING:' in line.upper(): | |
explanation = line.split(':')[1].strip() if ':' in line else line | |
current_question["forklaring"] = explanation | |
# Add the last question if complete | |
if self._is_complete_question(current_question, current_options): | |
current_question["alternativer"] = current_options | |
questions.append(current_question) | |
return questions | |
def _is_complete_question(self, question: Dict, options: List) -> bool: | |
"""Check if a question is complete""" | |
return ( | |
"spørsmål" in question and | |
len(options) >= 3 and # At least 3 options | |
"korrekt_svar" in question and | |
question["korrekt_svar"] < len(options) | |
) | |
def _generate_basic_questions(self, tema: str, antall: int) -> List[Dict[str, Any]]: | |
"""Generate basic questions when AI fails - works with ANY topic""" | |
questions = [] | |
# Generate generic but relevant questions for any topic | |
question_templates = [ | |
f"Hva er det mest kjente ved {tema}?", | |
f"Hvilket år er viktig i historien til {tema}?", | |
f"Hvor finner man vanligvis {tema}?", | |
f"Hva karakteriserer {tema}?", | |
f"Hvilken betydning har {tema}?" | |
] | |
for i in range(min(antall, len(question_templates))): | |
questions.append({ | |
"spørsmål": question_templates[i], | |
"alternativer": [ | |
f"Alternativ A om {tema}", | |
f"Alternativ B om {tema}", | |
f"Alternativ C om {tema}", | |
f"Alternativ D om {tema}" | |
], | |
"korrekt_svar": 0, # Always A for simplicity | |
"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." | |
}) | |
return questions | |
# Initialize the AI generator | |
quiz_generator = AIQuizGenerator() | |
# API endpoint for quiz generation - NO TOPIC RESTRICTIONS | |
def generate_quiz_api(tema: str, språk: str = "no", antall_spørsmål: int = 3, | |
type: str = "sted", vanskelighetsgrad: int = 3, | |
api_key: str = None) -> Dict[str, Any]: | |
"""API endpoint for quiz generation - ACCEPTS ANY TOPIC""" | |
# Validate API key | |
if not validate_api_key(api_key): | |
return { | |
"success": False, | |
"message": "Ugyldig API-nøkkel", | |
"questions": [] | |
} | |
# NO TOPIC FILTERING - Accept absolutely anything | |
if not tema or len(tema.strip()) < 2: | |
return { | |
"success": False, | |
"message": "Vennligst oppgi et tema (minimum 2 tegn)", | |
"questions": [] | |
} | |
try: | |
# Generate questions with AI - NO RESTRICTIONS | |
start_time = time.time() | |
questions = quiz_generator.generate_quiz(tema.strip(), antall_spørsmål, språk) | |
generation_time = time.time() - start_time | |
return { | |
"success": True, | |
"questions": questions, | |
"metadata": { | |
"generation_time": round(generation_time, 2), | |
"model_used": quiz_generator.default_model, | |
"topic": tema, | |
"unrestricted": True # Flag to show no restrictions | |
}, | |
"message": f"Genererte {len(questions)} spørsmål om '{tema}' - ingen begrensninger!" | |
} | |
except Exception as e: | |
print(f"Error in generate_quiz_api: {str(e)}") | |
return { | |
"success": False, | |
"message": f"Feil ved generering av quiz: {str(e)}", | |
"questions": [] | |
} | |
# Gradio interface - emphasize NO RESTRICTIONS | |
def generate_quiz_gradio(tema, antall, api_key=None): | |
"""Gradio wrapper - accepts ANY topic""" | |
if api_key and not validate_api_key(api_key): | |
return "❌ **Ugyldig API-nøkkel**" | |
if not tema or len(tema.strip()) < 2: | |
return "❌ **Vennligst skriv inn et tema**" | |
try: | |
result = generate_quiz_api(tema, "no", antall, "sted", 3, api_key) | |
if not result["success"]: | |
return f"❌ **Feil:** {result['message']}" | |
questions = result["questions"] | |
model = result["metadata"]["model_used"] | |
time_taken = result["metadata"]["generation_time"] | |
output = f"✅ **Genererte {len(questions)} spørsmål om '{tema}'**\n\n" | |
output += f"🤖 **Modell:** {model}\n" | |
output += f"⏱️ **Tid:** {time_taken}s\n" | |
output += f"🔓 **Ingen begrensninger** - alle temaer er tillatt!\n\n" | |
for i, q in enumerate(questions, 1): | |
output += f"📝 **Spørsmål {i}:** {q['spørsmål']}\n" | |
for j, alt in enumerate(q['alternativer']): | |
marker = "✅" if j == q['korrekt_svar'] else "❌" | |
output += f" {chr(65+j)}) {alt} {marker}\n" | |
output += f"💡 **Forklaring:** {q['forklaring']}\n\n" | |
return output | |
except Exception as e: | |
return f"❌ **Feil:** {str(e)}" | |
# Health check endpoint | |
def health_check(): | |
return {"status": "healthy", "timestamp": time.time(), "unrestricted": True} | |
# Gradio interface - emphasize freedom | |
with gr.Blocks(title="SoActi AI Quiz API - Ubegrenset") as demo: | |
gr.Markdown("# 🧠 SoActi AI Quiz API - Ubegrenset") | |
gr.Markdown("**🔓 Lag quiz om ABSOLUTT HVASOM HELST - ingen begrensninger!**") | |
with gr.Row(): | |
with gr.Column(): | |
tema_input = gr.Textbox( | |
label="Tema (skriv hva som helst!)", | |
value="", | |
placeholder="Fotball, Harry Potter, Kvantfysikk, Baking, TikTok, Dinosaurer, Programmering, K-pop, Filosofi, Gaming..." | |
) | |
antall_input = gr.Slider( | |
minimum=1, | |
maximum=5, | |
step=1, | |
label="Antall spørsmål", | |
value=3 | |
) | |
api_key_input = gr.Textbox( | |
label="API-nøkkel (for testing)", | |
placeholder="Skriv inn API-nøkkel...", | |
type="password" | |
) | |
generate_btn = gr.Button("🚀 Generer Quiz om HVASOM HELST!", variant="primary") | |
with gr.Column(): | |
output = gr.Textbox( | |
label="Generert Quiz", | |
lines=20, | |
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" | |
) | |
generate_btn.click( | |
fn=generate_quiz_gradio, | |
inputs=[tema_input, antall_input, api_key_input], | |
outputs=output | |
) | |
gr.Markdown("## 🔗 API for SoActi") | |
gr.Markdown("`POST https://Soacti-soacti-ai-quiz-api.hf.space/generate-quiz`") | |
gr.Markdown("**🔓 Ingen begrensninger - brukere kan spørre om hva som helst!**") | |
# FastAPI setup with CORS for unrestricted access | |
from fastapi import FastAPI, HTTPException, Depends, Header | |
from fastapi.middleware.cors import CORSMiddleware | |
from pydantic import BaseModel | |
app = FastAPI(title="SoActi Quiz API - Ubegrenset") | |
app.add_middleware( | |
CORSMiddleware, | |
allow_origins=["*"], | |
allow_credentials=True, | |
allow_methods=["*"], | |
allow_headers=["*"], | |
) | |
class QuizRequest(BaseModel): | |
tema: str # NO restrictions on what this can be | |
språk: str = "no" | |
antall_spørsmål: int = 3 | |
type: str = "sted" | |
vanskelighetsgrad: int = 3 | |
async def get_api_key(authorization: str = Header(None)): | |
if not authorization: | |
raise HTTPException(status_code=401, detail="API key missing") | |
parts = authorization.split() | |
if len(parts) != 2 or parts[0].lower() != "bearer": | |
raise HTTPException(status_code=401, detail="Invalid authorization header") | |
return parts[1] | |
async def api_generate_quiz(request: QuizRequest, api_key: str = Depends(get_api_key)): | |
"""Generate quiz about ANY topic - no restrictions""" | |
result = generate_quiz_api( | |
request.tema, # Accept ANY topic | |
request.språk, | |
request.antall_spørsmål, | |
request.type, | |
request.vanskelighetsgrad, | |
api_key | |
) | |
if not result["success"]: | |
raise HTTPException(status_code=400, detail=result["message"]) | |
return result | |
async def api_health(): | |
return health_check() | |
# Mount Gradio | |
app = gr.mount_gradio_app(app, demo, path="/") | |
if __name__ == "__main__": | |
import uvicorn | |
uvicorn.run(app, host="0.0.0.0", port=7860) | |