"""Генерация черновика теста из извлечённого текста (порт части `documentGenService.js`).""" from __future__ import annotations from .draft_validator import ( parse_json_from_llm_text, validate_and_normalize_draft, ) from .llm_client import LlmError, chat_completion_text_content, get_llm_config MAX_EXTRACT_CHARS = 14000 def generation_for_import_document(extracted_text: str, user_hint: str = '') -> dict: text = (extracted_text or '').strip() if not text: return { 'available': False, 'message': 'Нет извлечённого текста — нечего передавать в модель.', } cfg = get_llm_config() if cfg is None: return { 'available': False, 'message': ( 'Автогенерация выключена: задайте DEEPSEEK_API_KEY или OPENAI_API_KEY ' 'в .env. Превью текста ниже — можно вставить вручную.' ), 'textPreview': text[:4000], } if len(text) > MAX_EXTRACT_CHARS: slice_ = text[:MAX_EXTRACT_CHARS] + '\n\n[…фрагмент обрезан для API]' else: slice_ = text try: system = ( 'Ты помощник для составления тестов. Отвечай ТОЛЬКО одним JSON-объектом ' 'без пояснений. Схема: {"title": string, "description"?: string, ' '"questions": array}. Каждый вопрос: {"text", "hasMultipleAnswers": boolean, ' '"options": [{"text", "isCorrect": boolean}, ...]}. Минимум 2 варианта. ' 'Для одиночного выбора ровно один isCorrect: true. ' 'Текст и формулировки — на русском, по содержанию входного материала.' ) hint_block = f'\n\nДополнительные инструкции от автора теста:\n{user_hint.strip()}' if user_hint and user_hint.strip() else '' user = ( 'Составь тест с вопросами с одним или несколькими правильными ответами ' 'на основе текста:\n\n' + slice_ + hint_block ) raw = chat_completion_text_content(cfg, system, user, 0.25) parsed = parse_json_from_llm_text(raw) draft = validate_and_normalize_draft(parsed) return { 'available': True, 'message': ( f'Сгенерировано: «{draft["title"]}», вопросов: ' f'{len(draft["questions"])}. Нажмите «Применить сгенерированный черновик».' ), 'draft': draft, } except LlmError as e: return { 'available': False, 'message': f'Генерация не удалась: {e}', 'errorCode': e.code, 'textPreview': text[:4000], } except Exception as e: return { 'available': False, 'message': f'Генерация не удалась: {e}', 'errorCode': 'unknown', 'textPreview': text[:4000], }