Lab6 / exam_functions.py
Denysyk's picture
Upload 5 files
5d2b004 verified
"""
Exam backend functions for AI Examiner Agent.
"""
import json
import random
import os
from datetime import datetime
from typing import TypedDict, Literal
TOPICS = [
"Tokenization and text preprocessing",
"Word embeddings (Word2Vec, GloVe, FastText)",
"Recurrent neural networks (RNN, LSTM, GRU)",
"Attention mechanism and Transformers",
"BERT and pre-trained language models",
"Named Entity Recognition (NER)",
"Sentiment analysis",
"Machine translation",
"Text classification",
"Language model evaluation metrics (BLEU, ROUGE, Perplexity)",
]
STUDENTS = [
{"name": "Stanislav Androshchuk", "email": "Stanislav.Androshchuk.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksandr Babilia", "email": "Oleksandr.Babilia.mKNSSh.2025@lpnu.ua"},
{"name": "Vitalii Bahrynets", "email": "Vitalii.Bahrynets.mKNSSh.2025@lpnu.ua"},
{"name": "Dmytro Betsa", "email": "Dmytro.Betsa.mKNSSh.2025@lpnu.ua"},
{"name": "Kateryna Bilyk", "email": "Kateryna.Bilyk.mKNSSh.2025@lpnu.ua"},
{"name": "Iryna Boiko", "email": "Iryna.Boiko.mKNSSh.2025@lpnu.ua"},
{"name": "Ihor Boklach", "email": "Ihor.Boklach.mKNSSh.2025@lpnu.ua"},
{"name": "Bohdan Boretskyi", "email": "Bohdan.Boretskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Yaroslav Borys", "email": "Yaroslav.Borys.mKNSSh.2025@lpnu.ua"},
{"name": "Denys Brativnyk", "email": "Denys.Brativnyk.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksandr Vlasiuk", "email": "Oleksandr.Vlasiuk.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksandr Voznyi", "email": "Oleksandr.Voznyi.mKNSSh.2025@lpnu.ua"},
{"name": "Khrystyna Dolynska", "email": "Khrystyna.Dolynska.mKNSSh.2025@lpnu.ua"},
{"name": "Viktor Zharkivskyi", "email": "Viktor.Zharkivskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Olena Kalenchuk", "email": "Olena.Kalenchuk.mKNSSh.2025@lpnu.ua"},
{"name": "Dmytro Kostinskyi", "email": "Dmytro.Kostinskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Anastasiia Kudybovska", "email": "Anastasiia.Kudybovska.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Kuchynskyi", "email": "Vladyslav.Kuchynskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Olena Litovska", "email": "Olena.Litovska.mKNSSh.2025@lpnu.ua"},
{"name": "Oleh Lozovyi", "email": "Oleh.Lozovyi.mKNSSh.2025@lpnu.ua"},
{"name": "Roman Maior", "email": "Roman.Maior.mKNSSh.2025@lpnu.ua"},
{"name": "Yevhen Makarenko", "email": "Yevhen.Makarenko.mKNSSh.2025@lpnu.ua"},
{"name": "Serhii Matsyshyn", "email": "Serhii.Matsyshyn.mKNSSh.2025@lpnu.ua"},
{"name": "Maksym Myna", "email": "Maksym.Myna.mKNSSh.2025@lpnu.ua"},
{"name": "Artem Mikanov", "email": "Artem.Mikanov.mKNSSh.2025@lpnu.ua"},
{"name": "Vitalii Mil", "email": "Vitalii.Mil.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Miniailo", "email": "Vladyslav.Miniailo.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Moiseienko", "email": "Vladyslav.Moiseienko.mKNSSh.2025@lpnu.ua"},
{"name": "Tymofii Nasobko", "email": "Tymofii.Nasobko.mKNSSh.2025@lpnu.ua"},
{"name": "Arsenii Ohar", "email": "Arsenii.Ohar.mKNSSh.2025@lpnu.ua"},
{"name": "Marta Oliinyk", "email": "Marta.Oliinyk.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksii Oliinyk", "email": "Oleksii.Oliinyk.mKNSSh.2025@lpnu.ua"},
{"name": "Roman Omelchuk", "email": "Roman.Omelchuk.mKNSSh.2025@lpnu.ua"},
{"name": "Maksym Orlianskyi", "email": "Maksym.Orlianskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Alina Pavliv", "email": "Alina.Pavliv.mKNSSh.2025@lpnu.ua"},
{"name": "Andrii Pytel", "email": "Andrii.Pytel.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksii Postovyi", "email": "Oleksii.Postovyi.mKNSSh.2025@lpnu.ua"},
{"name": "Myroslav Pronyshyn", "email": "Myroslav.Pronyshyn.mKNSSh.2025@lpnu.ua"},
{"name": "Yurii Pukhta", "email": "Yurii.Pukhta.mKNSSh.2025@lpnu.ua"},
{"name": "Denys Ratushniak", "email": "Denys.Ratushniak.mKNSSh.2025@lpnu.ua"},
{"name": "Nazar Savitskyi", "email": "Nazar.Savitskyi.mKNSSh.2025@lpnu.ua"},
{"name": "Oleksandr Siryk", "email": "Oleksandr.Siryk.mKNSSh.2025@lpnu.ua"},
{"name": "Petro Slobodian", "email": "Petro.Slobodian.mKNSSh.2025@lpnu.ua"},
{"name": "Artem Somar", "email": "Artem.Somar.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Spivakov", "email": "Vladyslav.Spivakov.mKNSSh.2025@lpnu.ua"},
{"name": "Pavlo Stetsiuk", "email": "Pavlo.Stetsiuk.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Taraban", "email": "Vladyslav.Taraban.mKNSSh.2025@lpnu.ua"},
{"name": "Andrii Tarasov", "email": "Andrii.Tarasov.mKNSSh.2025@lpnu.ua"},
{"name": "Illia Feloniuk", "email": "Illia.Feloniuk.mKNSSh.2025@lpnu.ua"},
{"name": "Sviatoslav Shainoha", "email": "Sviatoslav.Shainoha.mKNSSh.2025@lpnu.ua"},
{"name": "Sviatoslav Shylkov", "email": "Sviatoslav.Shylkov.mKNSSh.2025@lpnu.ua"},
{"name": "Vitalii Yuzvyn", "email": "Vitalii.Yuzvyn.mKNSSh.2025@lpnu.ua"},
{"name": "Vladyslav Yakymchuk", "email": "Vladyslav.Yakymchuk.mKNSSh.2025@lpnu.ua"},
# demo
{"name": "Test", "email": "test@test.com"},
]
DB_FILE = "exam_db.json"
def _load_db() -> dict:
if os.path.exists(DB_FILE):
with open(DB_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {"exams": []}
def _save_db(db: dict) -> None:
with open(DB_FILE, "w", encoding="utf-8") as f:
json.dump(db, f, ensure_ascii=False, indent=2)
def start_exam(email: str, name: str) -> list[str]:
student = next(
(s for s in STUDENTS if s["email"].lower() == email.strip().lower()),
None,
)
if student is None:
raise ValueError(
f"Student with email '{email}' not found. Please check your email address."
)
topics = random.sample(TOPICS, k=random.randint(2, 3))
db = _load_db()
db["exams"].append({
"email": email,
"name": name,
"started_at": datetime.now().isoformat(),
"topics": topics,
"score": None,
"finished_at": None,
})
_save_db(db)
print(f"[DB] Exam started for {name} <{email}>. Topics: {topics}")
return topics
_topic_queue: list[str] = []
def set_topic_queue(topics: list[str]) -> None:
global _topic_queue
_topic_queue = list(topics)
def get_next_topic() -> str:
if _topic_queue:
return _topic_queue.pop(0)
return ""
class Message(TypedDict):
role: Literal["system", "user", "tool_call"]
content: str
datetime: str
def end_exam(email: str, score: float, history: list[Message]) -> None:
db = _load_db()
for exam in reversed(db["exams"]):
if exam["email"].lower() == email.lower() and exam["score"] is None:
exam["score"] = score
exam["finished_at"] = datetime.now().isoformat()
exam["history"] = history
break
_save_db(db)
print(f"[DB] Exam finished for {email}. Score: {score}/10")