File size: 1,971 Bytes
8db761b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from __future__ import annotations

import json
import re
from dataclasses import dataclass


@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()],
    )