Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions grading.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import requests
import re
from io import StringIO


def extract_latex_content(text):
"""Парсер LaTeX-контента с обработкой таблиц и спецформатирования"""
# Удаление комментариев
text = re.sub(r'%.*', '', text)

# Извлечение содержимого между \begin{titlepage} и \end{document}
doc_match = re.search(r'\\begin{titlepage}(.*?)\\end{document}', text, re.DOTALL)
if not doc_match:
return ""
content = doc_match.group(1)

# Обработка таблиц - извлечение текста из ячеек
content = re.sub(r'\\begin{tabular}.*?\\end{tabular}',
lambda m: ' '.join(re.findall(r'\{([^{}]*)\}', m.group())),
content, flags=re.DOTALL)

# Нормализация пробелов
content = ' '.join(content.split())
return content

def extract_titlepage_content(text):
"""Извлекает содержимое титульного листа"""
# Удаление комментариев
text = re.sub(r'%.*', '', text)

# Извлечение содержимого между \begin{titlepage} и \end{titlepage}
titlepage_match = re.search(r'\\begin{titlepage}(.*?)\\end{titlepage}', text, re.DOTALL)
if not titlepage_match:
return ""
content = titlepage_match.group(1)

# Обработка содержимого
content = re.sub(r'\\[a-zA-Z]+\*?\s*\{([^{}]*)\}', r'\1', content)
content = re.sub(r'\\[a-zA-Z]+\*?\s*', ' ', content)
content = re.sub(r'[{}]', '', content)
content = re.sub(r'\\[^\s]*', '', content)
content = ' '.join(content.split())

return content

def convert_fullname_to_initials(fullname):
"""Преобразует 'Фамилия Имя Отчество' в 'И.О.Фамилия'"""
parts = fullname.split()
if len(parts) == 3:
surname, name, patronymic = parts
return f"{name[0]}.{patronymic[0]}.{surname}"
return fullname

def grade_report_latex(repo, filename, subject, lab_name, group, student_name, required_sections, branch=None, commit=None, github_token=None):
"""Улучшенная функция проверки LaTeX-отчета"""
# Скачивание файла
ref = commit if commit else branch if branch else 'main'
api_url = f"https://api.github.com/repos/{repo}/contents/{filename}?ref={ref}"

try:
# Заголовки для GitHub API
headers = {
'Accept': 'application/vnd.github.v3+json',
}
if github_token:
headers['Authorization'] = f'token {github_token}'

response = requests.get(api_url, headers=headers)
response.raise_for_status()

# Декодируем содержимое файла из base64
import base64
content = base64.b64decode(response.json()['content']).decode('utf-8')

except Exception as e:
raise Exception(f"Ошибка при загрузке файла через GitHub API: {str(e)}")

# Извлечение содержимого титульного листа
titlepage_text = extract_titlepage_content(content)

# Извлечение основного содержимого
full_text = extract_latex_content(content)

# Преобразование 'Фамилия Имя Отчество' в 'И.О.Фамилия'
student_name = convert_fullname_to_initials(student_name)

# Проверка титульной информации (только в titlepage)
title_checks = {
"subject": subject.lower() in titlepage_text.lower(),
"lab_name": lab_name.lower() in titlepage_text.lower(),
"group": str(group).lower() in titlepage_text.lower(),
"student_name": student_name.lower() in titlepage_text.lower().replace(" ", "")
}

# Проверка разделов (ищем как \section{Name}, так и \section*{Name})
sections = re.findall(r'\\section\*?\{([^{}]*)\}', full_text)
section_checks = {sec: any(sec.lower() in s.lower() for s in sections)
for sec in required_sections}

return {
"title_page": title_checks,
"sections": section_checks
}

40 changes: 40 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from fastapi import UploadFile, File
from dotenv import load_dotenv
from itsdangerous import TimestampSigner, BadSignature
from grading import grade_report_latex
import re

load_dotenv()
Expand Down Expand Up @@ -456,6 +457,45 @@ def grade_lab(course_id: str, group_id: str, lab_id: str, request: GradeRequest)
lab_number = parse_lab_id(lab_id)
row_idx = github_values.index(username) + 3
lab_col = student_col + lab_number + lab_offset

report_checks = {}
if lab_config.get("report"):
report_file = "report.tex" # или можно брать из конфига
report_url = f"https://api.github.com/repos/{org}/{repo_name}/contents/{report_file}"
report_resp = requests.get(report_url, headers=headers)

if report_resp.status_code == 200:
try:
# Получаем информацию о студенте из таблицы
student_name = sheet.cell(row_idx, student_col).value
report_checks = grade_report_latex(
repo=f"{org}/{repo_name}",
filename=report_file,
subject=course_info.get("name", ""),
# Учитывать, что все названия предметов на английском в конфигах
lab_name=lab_config.get("short-name", ""),
# Полного названия лабы в конфиге нет, поэтому пока берем short-name
group=group_id,
student_name=student_name,
required_sections=lab_config.get("report", []),
branch="main",
github_token=GITHUB_TOKEN
)

# Проверяем результаты
title_ok = all(report_checks["title_page"].values())
sections_ok = all(report_checks["sections"].values())

if not title_ok or not sections_ok:
final_result = "✗"
summary.append("❌ Отчет не соответствует требованиям")
else:
summary.append("✅ Отчет соответствует требованиям")

except Exception as e:
final_result = "✗"
summary.append(f"❌ Ошибка при проверке отчета: {str(e)}")

sheet.update_cell(row_idx, lab_col, final_result)

return {
Expand Down