SPB Git forge

spb/uqo-chat

Public
14commits 1branches 0releases
1.4 MBsize
maindefault branch
17 days agolast push
Python 64.6% TypeScript 33.7% CSS 0.8%
5.6 KB · 121 lines python
Raw Blame History
1"""Course records (seeded), professor settings, announcements."""23from __future__ import annotations45from typing import Any67from sqlalchemy import select89from app.core.config import get_settings10from app.db import SessionLocal11from app.models import Course1213SEED = {14    "IMM1003": {15        "title": "Éléments d'évaluation immobilière",16        "site": "https://www.uqo-imm1003.app",17        "modules": [18            "Introduction à l'évaluation immobilière", "Le cadre professionnel au Québec",19            "Les principes fondamentaux de l'évaluation", "Le marché immobilier québécois",20            "Collecte et analyse des données", "La valeur : concepts et types",21            "Examen mi-session : révision des blocs 1 et 2",22            "La méthode de comparaison — Partie 1", "La méthode de comparaison — Partie 2",23            "La méthode du coût", "La méthode du revenu — Partie 1",24            "La méthode du revenu — Partie 2", "Le rapport d'évaluation",25            "Révision générale et cas intégrateur",26        ],27        "suggestions": [28            "Explique-moi les 8 étapes du processus d'évaluation",29            "Différence entre valeur marchande et valeur d'usage ?",30            "Quiz sur les principes de la valeur",31            "Comment ajuster des comparables vers le sujet ?",32            "Crée un Excel de grille de comparables ajustés",33        ],34    },35    "IMM1033": {36        "title": "Méthodes du coût en évaluation immobilière",37        "site": "https://www.uqo-imm1033.app",38        "modules": [39            "Introduction à la méthode du coût", "Cadre conceptuel et terminologie",40            "Méthodes d'évaluation du terrain", "Analyse du terrain et ajustements",41            "Coût de reproduction et coût de remplacement", "Méthodes d'estimation des coûts",42            "Coûts directs de construction", "Coûts indirects et profit entrepreneurial",43            "Concepts de dépréciation", "Dépréciation physique", "Dépréciation fonctionnelle",44            "Dépréciation économique (externe)", "Applications spécialisées",45            "Synthèse et révision",46        ],47        "suggestions": [48            "Calcule la dépréciation par la méthode âge-vie",49            "Crée un Excel de la méthode du coût pour un plex",50            "Coût de reproduction vs remplacement ?",51            "Quiz sur les types de dépréciation",52            "Comment estimer la valeur d'un terrain par extraction ?",53        ],54    },55}565758async def seed_courses() -> None:59    s = get_settings()60    async with SessionLocal() as session:61        for code in s.courses:62            existing = await session.scalar(select(Course).where(Course.code == code))63            meta = SEED.get(code, {"title": code, "modules": [], "suggestions": []})64            if existing is None:65                session.add(Course(code=code, title=meta["title"], term=s.TERM_LABEL,66                                   syllabus={"modules": meta["modules"],67                                             "suggestions": meta["suggestions"],68                                             "site": meta.get("site", ""), "deadlines": []},69                                   settings={"tools_enabled": None, "model_primary": None}))70        await session.commit()717273async def list_courses(include_private: bool = False) -> list[dict[str, Any]]:74    async with SessionLocal() as session:75        rows = (await session.execute(select(Course).where(Course.active.is_(True))76                                      .order_by(Course.code))).scalars()77        out = []78        for c in rows:79            d: dict[str, Any] = {"code": c.code, "title": c.title, "term": c.term,80                                 "modules": c.syllabus.get("modules", []),81                                 "suggestions": c.syllabus.get("suggestions", []),82                                 "site": c.syllabus.get("site", ""),83                                 "deadlines": c.syllabus.get("deadlines", []),84                                 "announcement": c.announcement}85            if include_private:86                d["extra_system_prompt"] = c.extra_system_prompt87                d["settings"] = c.settings88            out.append(d)89        return out909192async def get_course(code: str) -> Course | None:93    async with SessionLocal() as session:94        return await session.scalar(select(Course).where(Course.code == code.upper()))959697async def update_course(code: str, data: dict[str, Any]) -> dict[str, Any] | None:98    async with SessionLocal() as session:99        c = await session.scalar(select(Course).where(Course.code == code.upper()))100        if c is None:101            return None102        if "extra_system_prompt" in data:103            c.extra_system_prompt = str(data["extra_system_prompt"] or "")[:6000]104        if "announcement" in data:105            c.announcement = str(data["announcement"] or "")[:1000]106        if "deadlines" in data or "suggestions" in data:107            syl = dict(c.syllabus)108            if "deadlines" in data:109                syl["deadlines"] = list(data["deadlines"] or [])[:20]110            if "suggestions" in data:111                syl["suggestions"] = [str(x)[:120] for x in (data["suggestions"] or [])][:8]112            c.syllabus = syl113        if "settings" in data:114            st = dict(c.settings or {})115            st.update({k: v for k, v in (data["settings"] or {}).items() if k in116                       {"tools_enabled", "model_primary", "budget_usd", "tone"}})117            c.settings = st118        await session.commit()119        return {"code": c.code, "extra_system_prompt": c.extra_system_prompt,120                "announcement": c.announcement, "syllabus": c.syllabus, "settings": c.settings}121