AI_Toolkit / src /core /QuizEngine.py
NavyDevilDoc's picture
Update src/core/QuizEngine.py
74a6e3b verified
raw
history blame
4.86 kB
import random
import os
import logging
from core.AcronymManager import AcronymManager
class QuizEngine:
def __init__(self, source_dir="source_documents"):
self.acronym_mgr = AcronymManager()
self.source_dir = source_dir
self.logger = logging.getLogger(__name__)
# --- MODE 1: ACRONYMS ---
def get_random_acronym(self):
if not self.acronym_mgr.acronyms:
return None
acronym = random.choice(list(self.acronym_mgr.acronyms.keys()))
definition = self.acronym_mgr.acronyms[acronym]
return {
"type": "acronym",
"term": acronym,
"correct_definition": definition,
"question": f"What does **{acronym}** stand for?"
}
# --- MODE 2: DOCUMENTS (NEW) ---
# ... inside QuizEngine class ...
def get_document_context(self, username):
user_dir = os.path.join(self.source_dir, username)
if not os.path.exists(user_dir): return None
# 1. Get files
files = [f for f in os.listdir(user_dir) if f.lower().endswith(('.txt', '.md'))]
if not files: return None
# Retry Loop: Try up to 5 times to find a "worthy" chunk
for attempt in range(5):
selected_file = random.choice(files)
try:
with open(os.path.join(user_dir, selected_file), 'r', encoding='utf-8', errors='ignore') as f:
text = f.read()
# DEFENSE 1: Aggressive Heuristic Filtering
# Split by double newline (paragraphs)
paragraphs = text.split('\n\n')
candidates = []
for p in paragraphs:
p = p.strip()
# A. Too short?
if len(p) < 250: continue
# B. Looks like a list item or table row? (starts with number/bullet)
if p[0].isdigit() or p.startswith(('-', '*', '•')): continue
# C. Looks like administrative noise?
if "intentionally left blank" in p.lower(): continue
candidates.append(p)
if not candidates: continue
# Pick a random survivor
selected_context = random.choice(candidates)
return {
"type": "document",
"source_file": selected_file,
"context_text": selected_context
}
except Exception as e:
self.logger.error(f"Error fetching context: {e}")
continue
return None # Failed to find good text after 5 tries
def construct_question_generation_prompt(self, context_text):
"""
DEFENSE 2: Explicit Instructions to Ignore Trivia
"""
return (
f"Act as a US Navy Engineering Duty Officer Board Examiner.\n"
f"Review the following source text for suitability:\n"
f"'''{context_text}'''\n\n"
f"DECISION LOGIC:\n"
f"1. Does this text contain a specific Engineering Concept, Responsibility, or Procedural Rule?\n"
f"2. Is it free of pure administrative trivia (dates, page numbers, formatting rules)?\n\n"
f"IF NO: Output the word 'SKIP'.\n"
f"IF YES: Generate a difficult, scenario-based question that tests the candidate's understanding of the concept. "
f"Do not ask 'What does the text say?'. Ask 'How would you apply...?' or 'What are the requirements for...?'\n\n"
f"OUTPUT: Just the question text."
)
def construct_grading_prompt(self, question, answer, context_text):
"""Grades the deep dive answer."""
return (
f"You are a Board Examiner.\n"
f"Reference Material: '{context_text}'\n\n"
f"Question: {question}\n"
f"Candidate Answer: {answer}\n\n"
f"TASK: Grade the answer based strictly on the Reference Material.\n"
f"1. If the answer is factually correct according to the text, grade PASS.\n"
f"2. If it misses key details mentioned in the text, grade FAIL or PASS with Comments.\n"
f"OUTPUT FORMAT:\n"
f"**GRADE:** [PASS/FAIL]\n"
f"**FEEDBACK:** [Brief correction or confirmation]"
)
def construct_acronym_grading_prompt(self, term, correct_definition, user_answer):
"""Grades the acronym answer."""
return (
f"Term: {term}\n"
f"Official Definition: {correct_definition}\n"
f"User Answer: {user_answer}\n\n"
f"Grade as PASS (correct expansion) or FAIL. If close, PASS with comment.\n"
f"Output: **GRADE:** [Status]\n**FEEDBACK:** [Details]"
)