File size: 6,559 Bytes
346f022
b3aa8c6
 
346f022
 
b3aa8c6
e8634b4
 
346f022
 
 
 
 
b3aa8c6
346f022
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b3aa8c6
346f022
 
b3aa8c6
7bd3326
346f022
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7bd3326
 
 
346f022
 
7bd3326
 
 
 
 
 
346f022
 
 
 
b3aa8c6
 
 
 
 
 
 
 
 
 
 
 
 
 
346f022
 
 
 
b3aa8c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346f022
 
 
 
b3aa8c6
 
 
 
 
 
 
346f022
 
 
 
b3aa8c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# api/config.py
import os
from typing import List, Dict

import httpx
from openai import OpenAI
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# ============================
# Environment & Core Settings
# ============================

OPENAI_API_KEY = (os.getenv("OPENAI_API_KEY") or "").strip()
if not OPENAI_API_KEY:
    raise RuntimeError("OPENAI_API_KEY is not set. Please go to Settings → Secrets and add it.")

# Optional: allow overriding base URL (useful for gateways / proxies)
OPENAI_BASE_URL = (os.getenv("OPENAI_BASE_URL") or "").strip() or None

# Models
DEFAULT_MODEL = (os.getenv("CLARE_DEFAULT_MODEL") or "gpt-4.1-mini").strip()
EMBEDDING_MODEL = (os.getenv("CLARE_EMBEDDING_MODEL") or "text-embedding-3-small").strip()

# Timeout (seconds) - single source of truth
OPENAI_TIMEOUT_SECONDS = float(os.getenv("CLARE_OPENAI_TIMEOUT_SECONDS", "20").strip())

# Connection pooling / keep-alive
HTTP_MAX_CONNECTIONS = int(os.getenv("CLARE_HTTP_MAX_CONNECTIONS", "20").strip())
HTTP_MAX_KEEPALIVE = int(os.getenv("CLARE_HTTP_MAX_KEEPALIVE", "10").strip())
HTTP_KEEPALIVE_EXPIRY = float(os.getenv("CLARE_HTTP_KEEPALIVE_EXPIRY", "30").strip())

# Network retries (transport-level)
HTTP_RETRIES = int(os.getenv("CLARE_HTTP_RETRIES", "2").strip())


# ============================
# Shared HTTP client (singleton)
# ============================

# httpx Timeout object (connect/read/write/pool)
_httpx_timeout = httpx.Timeout(
    timeout=OPENAI_TIMEOUT_SECONDS,
    connect=min(10.0, OPENAI_TIMEOUT_SECONDS),
    read=OPENAI_TIMEOUT_SECONDS,
    write=OPENAI_TIMEOUT_SECONDS,
    pool=min(10.0, OPENAI_TIMEOUT_SECONDS),
)

_limits = httpx.Limits(
    max_connections=HTTP_MAX_CONNECTIONS,
    max_keepalive_connections=HTTP_MAX_KEEPALIVE,
    keepalive_expiry=HTTP_KEEPALIVE_EXPIRY,
)

# A single httpx client reused across the process
_http_client = httpx.Client(
    timeout=_httpx_timeout,
    limits=_limits,
    headers={
        # Helps some proxies; safe default
        "Connection": "keep-alive",
    },
    follow_redirects=True,
)

# ============================
# OpenAI SDK client (singleton)
# ============================

# Keep naming as `client` to avoid touching call sites
client = OpenAI(
    api_key=OPENAI_API_KEY,
    base_url=OPENAI_BASE_URL,
    http_client=_http_client,
    max_retries=HTTP_RETRIES,
)

# ============================
# LangChain wrappers (optional)
# ============================

# If you use LangChain later, reuse the same timeout policy
llm_default = ChatOpenAI(
    model=DEFAULT_MODEL,
    temperature=0.5,
    timeout=OPENAI_TIMEOUT_SECONDS,
    # Note: LangChain uses its own http stack; keep it simple.
)

embedding_client = OpenAIEmbeddings(
    model=EMBEDDING_MODEL,
)

# ============================
# Default course outline
# ============================

DEFAULT_COURSE_TOPICS: List[str] = [
    "Week 0 – Welcome & What is Generative AI; course outcomes LO1–LO5.",
    "Week 1 – Foundations of GenAI: LLMs, Transformer & self-attention, perplexity.",
    "Week 2 – Foundation Models & multimodal models; data scale, bias & risks.",
    "Week 3 – Choosing Pre-trained Models; open-source vs proprietary; cost vs quality.",
    "Week 4 – Prompt Engineering: core principles; zero/few-shot; CoT; ReAct.",
    "Week 5 – Building a Simple Chatbot; memory (short vs long term); LangChain & UI.",
    "Week 6 – Review Week; cross-module consolidation & self-check prompts.",
    "Week 7 – Retrieval-Augmented Generation (RAG); embeddings; hybrid retrieval.",
    "Week 8 – Agents & Agentic RAG; planning, tools, knowledge augmentation.",
    "Week 9 – Evaluating GenAI Apps; hallucination, bias/fairness, metrics.",
    "Week 10 – Responsible AI; risks, governance, EU AI Act-style ideas.",
]

# ============================
# Learning modes
# ============================

LEARNING_MODES: List[str] = [
    "Concept Explainer",
    "Socratic Tutor",
    "Exam Prep / Quiz",
    "Assignment Helper",
    "Quick Summary",
]

LEARNING_MODE_INSTRUCTIONS: Dict[str, str] = {
    "Concept Explainer": (
        "Explain concepts step by step. Use clear definitions, key formulas or structures, "
        "and one or two simple examples. Focus on clarity over depth. Regularly check if "
        "the student is following."
    ),
    "Socratic Tutor": (
        "Use a Socratic style. Ask the student ONE short question at a time, guide them to "
        "reason step by step, and only give full explanations after they try. Prioritize "
        "questions and hints over long lectures."
    ),
    "Exam Prep / Quiz": (
        "Behave like an exam prep coach. Often propose short quiz-style questions "
        "(multiple choice or short answer), then explain the solutions clearly. Emphasize "
        "common traps and how to avoid them."
    ),
    "Assignment Helper": (
        "Help with assignments WITHOUT giving full final solutions. Clarify requirements, "
        "break tasks into smaller steps, and provide hints, partial examples, or pseudo-code "
        "instead of complete code or final answers. Encourage the student to attempt each "
        "step before revealing more."
    ),
    "Quick Summary": (
        "Provide concise, bullet-point style summaries and cheat-sheet style notes. "
        "Focus on key ideas and avoid long paragraphs."
    ),
}

# ============================
# Upload doc types
# ============================

DOC_TYPES: List[str] = [
    "Syllabus",
    "Lecture Slides / PPT",
    "Literature Review / Paper",
    "Other Course Document",
]

# ============================
# Clare system prompt
# ============================

CLARE_SYSTEM_PROMPT = """
You are Clare, an AI teaching assistant for Hanbridge University.

Core identity:
- You are patient, encouraging, and structured like a very good TA.
- Your UI and responses should be in ENGLISH by default.
- However, you can understand BOTH English and Chinese, and you may reply in Chinese
  if the student clearly prefers Chinese or asks you to.

General responsibilities:
1. Help students understand course concepts step by step.
2. Ask short check-up questions to confirm understanding instead of giving huge long lectures.
3. When the student seems confused, break content into smaller chunks and use simple language first.
4. When the student is advanced, you can switch to more technical explanations.

Safety and honesty:
- If you don’t know, say you are not sure and suggest how to verify.
- Do not fabricate references, exam answers, or grades.
"""