Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import json | |
| import re | |
| from dataclasses import dataclass | |
| class ModuleSpec: | |
| title: str | |
| lecturer: str | |
| hours: str | |
| objective: str | |
| language: str | |
| topics: list[str] | |
| _SYSTEM = ( | |
| "Extract the course module from this syllabus. Return ONLY a JSON object with keys: " | |
| "title, lecturer, hours, objective, language, and topics (a list of the 'Main topics' " | |
| "bullets, each a short string). No prose, no code fences." | |
| ) | |
| def _parse_json(raw: str) -> dict: | |
| raw = re.sub(r"```(?:json)?|```", "", raw or "").strip() | |
| m = re.search(r"\{.*\}", raw, flags=re.DOTALL) | |
| if not m: | |
| return {} | |
| try: | |
| return json.loads(m.group(0)) | |
| except Exception: | |
| return {} | |
| def _heuristic_topics(text: str) -> list[str]: | |
| low = text.lower() | |
| i = low.find("main topics") | |
| if i < 0: | |
| return [] | |
| out: list[str] = [] | |
| for line in text[i:i + 1800].splitlines()[1:]: | |
| item = re.sub(r"^[\s•\-\*•●▪]+", "", line).strip() | |
| low_item = item.lower() | |
| if low_item.startswith(("prerequisit", "assessment", "text", "notes", "lecturer", "n. of", "objective")): | |
| break | |
| if 3 <= len(item) <= 180: | |
| out.append(item) | |
| return out[:12] | |
| def extract_module(text: str, llm) -> ModuleSpec: | |
| """LLM-extract the module + topics; fall back to a heuristic 'Main topics' scan.""" | |
| try: | |
| data = _parse_json(llm.complete(_SYSTEM, text[:6000])) | |
| except Exception: | |
| data = {} | |
| topics = data.get("topics") or _heuristic_topics(text) | |
| return ModuleSpec( | |
| title=str(data.get("title") or "").strip(), | |
| lecturer=str(data.get("lecturer") or "").strip(), | |
| hours=str(data.get("hours") or "").strip(), | |
| objective=str(data.get("objective") or "").strip(), | |
| language=str(data.get("language") or "").strip(), | |
| topics=[str(t).strip() for t in topics if str(t).strip()], | |
| ) | |