import json import re import os from huggingface_hub import InferenceClient HF_TOKEN = os.getenv("HF_TOKEN", "") MODEL_NAME = os.getenv("HF_MODEL", "Qwen/Qwen2.5-72B-Instruct") _client = None def _get_client() -> InferenceClient: global _client if _client is None: _client = InferenceClient(token=HF_TOKEN or None) return _client def _call_hf(system: str, user: str, max_tokens: int = 1500, temperature: float = 0.3) -> str: client = _get_client() response = client.chat_completion( model=MODEL_NAME, messages=[ {"role": "system", "content": system}, {"role": "user", "content": user}, ], max_tokens=max_tokens, temperature=temperature, ) return response.choices[0].message.content.strip() def _extract_json_array(raw: str) -> list: cleaned = re.sub(r'```(?:json)?\s*|```', '', raw).strip() try: result = json.loads(cleaned) if isinstance(result, list): return result except Exception: pass start = cleaned.find('[') if start != -1: depth = 0 for i, ch in enumerate(cleaned[start:], start): if ch == '[': depth += 1 elif ch == ']': depth -= 1 if depth == 0: candidate = re.sub(r',\s*([}\]])', r'\1', cleaned[start:i+1]) try: return json.loads(candidate) except Exception: pass break return [] def generate_quiz(topic: str, num_questions: int = 5, difficulty: str = "medium") -> list[dict]: difficulty_map = { "easy": "simples et directes, pour débutants", "medium": "de difficulté intermédiaire", "hard": "difficiles et approfondies, pour experts", } level_desc = difficulty_map.get(difficulty, "de difficulté intermédiaire") system = ( "Tu es un générateur de quiz pédagogique. " "Tu réponds UNIQUEMENT avec un tableau JSON valide, sans texte avant ni après." ) user = ( f"Génère {num_questions} questions QCM ({level_desc}) sur : \"{topic}\".\n" "Chaque objet : question, options (4 chaînes A/B/C/D), correct_answer (A/B/C/D), explanation.\n" "Réponds UNIQUEMENT avec le tableau JSON." ) raw = _call_hf(system, user) questions = _extract_json_array(raw) if questions: clean = [ { "question": str(q.get("question", "")), "options": list(q.get("options", [])), "correct_answer": str(q.get("correct_answer", "A")), "explanation": str(q.get("explanation", "")), } for q in questions if isinstance(q, dict) and q.get("question") and q.get("options") ] if clean: return clean return [{"question": f"Question sur {topic}", "options": ["A) -", "B) -", "C) -", "D) -"], "correct_answer": "A", "explanation": "Erreur de génération."}]