You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
3.1 KiB

"""Генерация черновика теста из извлечённого текста (порт части `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) -> 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. '
'Текст и формулировки — на русском, по содержанию входного материала.'
)
user = (
'Составь тест с вопросами с одним или несколькими правильными ответами '
'на основе текста:\n\n' + slice_
)
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],
}