adrian4444 commited on
Commit
3a21631
ยท
0 Parent(s):

Initial deployment

Browse files
Files changed (8) hide show
  1. .gitattributes +1 -0
  2. .gitignore +7 -0
  3. Dockerfile +32 -0
  4. HF_DEPLOYMENT_GUIDE.md +275 -0
  5. README.md +46 -0
  6. app.py +202 -0
  7. harrypotter.txt +3 -0
  8. requirements.txt +3 -0
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.txt filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .env
5
+ .DS_Store
6
+ student_manual_faiss/
7
+ *.log
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dockerfile for KUMPAS RAG โ€” Hugging Face Spaces
2
+ FROM python:3.11-slim
3
+
4
+ # System dependencies for faiss-cpu and sentence-transformers
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ curl \
8
+ git \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Working directory
12
+ WORKDIR /app
13
+
14
+ # Copy requirements first (Docker layer caching โ€” faster rebuilds)
15
+ COPY requirements.txt .
16
+ RUN pip install --no-cache-dir -r requirements.txt
17
+
18
+ # Copy application files
19
+ COPY app.py .
20
+
21
+ # Copy your Harry Potter text file
22
+ COPY harrypotter.txt .
23
+
24
+ # HF Spaces runs on port 7860
25
+ EXPOSE 7860
26
+
27
+ # Predownload the embedding model at build time
28
+ # (so the first request isn't slow)
29
+ RUN python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"
30
+
31
+ # Start the server
32
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
HF_DEPLOYMENT_GUIDE.md ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deploying KUMPAS RAG to Hugging Face Spaces
2
+ ## Complete Step-by-Step Guide
3
+
4
+ ---
5
+
6
+ ## What You Need Before Starting
7
+ - [ ] A Hugging Face account (free) โ€” huggingface.co
8
+ - [ ] Your Groq API key โ€” console.groq.com
9
+ - [ ] Git installed on your computer
10
+ - [ ] Your `harrypotter.txt` file (from Google Drive)
11
+
12
+ ---
13
+
14
+ ## PHASE 1 โ€” Hugging Face Account & Token
15
+
16
+ ### 1.1 Create Account
17
+ 1. Go to **https://huggingface.co**
18
+ 2. Click **Sign Up** โ†’ fill in username, email, password
19
+ 3. Verify your email
20
+
21
+ ### 1.2 Get Your Access Token
22
+ 1. Click your profile picture (top right) โ†’ **Settings**
23
+ 2. Left sidebar โ†’ **Access Tokens**
24
+ 3. Click **New token**
25
+ - Name: `kumpas-deploy`
26
+ - Role: **Write**
27
+ 4. Click **Generate token** โ†’ **Copy it** (you'll need it in a moment)
28
+
29
+ ---
30
+
31
+ ## PHASE 2 โ€” Create the Space
32
+
33
+ ### 2.1 New Space
34
+ 1. Click your profile picture โ†’ **New Space**
35
+ 2. Fill in:
36
+ - **Owner**: your username
37
+ - **Space name**: `kumpas-rag` (URL will be `yourname-kumpas-rag.hf.space`)
38
+ - **License**: MIT
39
+ - **SDK**: **Docker** โ† IMPORTANT: choose Docker, not Gradio/Streamlit
40
+ - **Visibility**: Public (free) or Private (requires Pro)
41
+ 3. Click **Create Space**
42
+
43
+ You'll land on an empty space page โ€” that's normal.
44
+
45
+ ---
46
+
47
+ ## PHASE 3 โ€” Set Up the Secret (Groq API Key)
48
+
49
+ Do this BEFORE pushing code, so it's available when the app builds.
50
+
51
+ 1. In your Space page โ†’ **Settings** tab (top right of the space)
52
+ 2. Scroll down to **Repository secrets**
53
+ 3. Click **New secret**
54
+ - **Name**: `GROQ_API_KEY` โ† must be exactly this name
55
+ - **Value**: paste your Groq API key (`gsk_...`)
56
+ 4. Click **Add secret**
57
+
58
+ ---
59
+
60
+ ## PHASE 4 โ€” Prepare Files on Your Computer
61
+
62
+ ### 4.1 Your folder should look like this:
63
+ ```
64
+ kumpas-hf-space/
65
+ โ”œโ”€โ”€ app.py โ† from the zip
66
+ โ”œโ”€โ”€ Dockerfile โ† from the zip
67
+ โ”œโ”€โ”€ requirements.txt โ† from the zip
68
+ โ”œโ”€โ”€ README.md โ† from the zip
69
+ โ”œโ”€โ”€ .gitignore โ† from the zip
70
+ โ””โ”€โ”€ harrypotter.txt โ† YOU add this (download from Google Drive)
71
+ ```
72
+
73
+ ### 4.2 Download harrypotter.txt from Google Drive
74
+ 1. Open Google Drive โ†’ find `harrypotter.txt`
75
+ 2. Right-click โ†’ **Download**
76
+ 3. Move the downloaded file into your `kumpas-hf-space/` folder
77
+
78
+ ---
79
+
80
+ ## PHASE 5 โ€” Push to Hugging Face via Git
81
+
82
+ Open your terminal (Command Prompt on Windows, Terminal on Mac/Linux).
83
+
84
+ ### 5.1 Navigate to your folder
85
+ ```bash
86
+ cd path/to/kumpas-hf-space
87
+ ```
88
+
89
+ ### 5.2 Install Git LFS (for large files like harrypotter.txt)
90
+ ```bash
91
+ # Windows (if not installed):
92
+ # Download from https://git-lfs.com
93
+
94
+ # Mac:
95
+ brew install git-lfs
96
+
97
+ # Ubuntu/Linux:
98
+ sudo apt-get install git-lfs
99
+
100
+ # Then enable it:
101
+ git lfs install
102
+ ```
103
+
104
+ ### 5.3 Initialize and push
105
+ ```bash
106
+ # Initialize git
107
+ git init
108
+
109
+ # Track large text files with LFS
110
+ git lfs track "*.txt"
111
+ git add .gitattributes
112
+
113
+ # Add all your files
114
+ git add .
115
+ git commit -m "Initial KUMPAS RAG deployment"
116
+
117
+ # Connect to your HF Space
118
+ # Replace YOUR_USERNAME with your actual HF username
119
+ git remote add origin https://YOUR_USERNAME:YOUR_HF_TOKEN@huggingface.co/spaces/YOUR_USERNAME/kumpas-rag
120
+
121
+ # Push!
122
+ git push -u origin main
123
+ ```
124
+
125
+ > **Example:** If your username is `jdelacruz` and your token starts with `hf_abc`:
126
+ > ```
127
+ > git remote add origin https://jdelacruz:hf_abc123@huggingface.co/spaces/jdelacruz/kumpas-rag
128
+ > ```
129
+
130
+ ---
131
+
132
+ ## PHASE 6 โ€” Watch It Build
133
+
134
+ 1. Go back to your Space page on huggingface.co
135
+ 2. Click the **Logs** tab โ€” you'll see the Docker build in real time:
136
+
137
+ ```
138
+ Step 1/10 : FROM python:3.11-slim
139
+ Step 2/10 : RUN apt-get update...
140
+ Step 3/10 : COPY requirements.txt .
141
+ Step 4/10 : RUN pip install... โ† takes 3-5 minutes
142
+ Step 5/10 : COPY app.py .
143
+ Step 6/10 : COPY harrypotter.txt .
144
+ Step 7/10 : RUN python -c "...SentenceTransformer..." โ† downloads model
145
+ ...
146
+ ```
147
+
148
+ 3. After the build succeeds (~5-8 minutes), the app starts:
149
+ ```
150
+ INFO: Loading embeddings model...
151
+ INFO: Building FAISS index from harrypotter.txt... โ† first run only, ~2 min
152
+ INFO: Created 14222 chunks
153
+ INFO: QA chain ready โœ…
154
+ INFO: ๐Ÿ”ฎ Server ready!
155
+ INFO: Uvicorn running on http://0.0.0.0:7860
156
+ ```
157
+
158
+ 4. The status indicator turns **green** โ€” your Space is live! ๐ŸŽ‰
159
+
160
+ ---
161
+
162
+ ## PHASE 7 โ€” Get Your Permanent URL & Test It
163
+
164
+ ### 7.1 Your URL
165
+ ```
166
+ https://YOUR_USERNAME-kumpas-rag.hf.space
167
+ ```
168
+ Example: `https://jdelacruz-kumpas-rag.hf.space`
169
+
170
+ **This URL never changes.** Unlike ngrok, it's permanent.
171
+
172
+ ### 7.2 Test in browser
173
+ ```
174
+ https://jdelacruz-kumpas-rag.hf.space/health
175
+ ```
176
+ Should return:
177
+ ```json
178
+ {"status": "ok", "oracle": "ready", "model": "llama-3.3-70b-versatile"}
179
+ ```
180
+
181
+ ### 7.3 Test the /ask endpoint
182
+ Open: `https://jdelacruz-kumpas-rag.hf.space/docs`
183
+
184
+ This opens Swagger UI. Click **POST /ask** โ†’ **Try it out** โ†’ paste:
185
+ ```json
186
+ {
187
+ "question": "Who is Voldemort?",
188
+ "history": []
189
+ }
190
+ ```
191
+ Click **Execute** โ†’ you should get a proper answer!
192
+
193
+ ---
194
+
195
+ ## PHASE 8 โ€” Update Your ASP.NET App
196
+
197
+ Open `appsettings.json` and update permanently:
198
+
199
+ ```json
200
+ {
201
+ "Rag": {
202
+ "BaseUrl": "https://YOUR_USERNAME-kumpas-rag.hf.space",
203
+ "ApiKey": ""
204
+ }
205
+ }
206
+ ```
207
+
208
+ Restart your ASP.NET app โ†’ open the chatbot โ†’ it now uses the always-on server! โœ…
209
+
210
+ ---
211
+
212
+ ## Important Notes About Free HF Spaces
213
+
214
+ | Thing | Detail |
215
+ |---|---|
216
+ | **Sleep after inactivity** | Free spaces sleep after ~15 min of no traffic. First request after sleep takes ~30 sec to wake up. |
217
+ | **CPU only** | Free tier is CPU โ€” FAISS and inference still work, just no GPU speedup. |
218
+ | **Storage** | 50GB limit โ€” your files are well under this. |
219
+ | **Build time** | ~5-8 min on first build. Rebuilds on every `git push`. |
220
+ | **Always-on** | Upgrade to HF Pro ($9/month) to disable sleep. |
221
+
222
+ ### Handling the "sleep" wake-up delay
223
+ The first chatbot message after inactivity will take ~30 seconds. You can handle this gracefully in the chatbot widget โ€” in `chatbot.js`, the timeout is already set to 30 seconds in `RagService.cs`. The user will see the typing dots while it wakes up.
224
+
225
+ ---
226
+
227
+ ## Updating Your Code Later
228
+
229
+ Whenever you want to update the RAG server (e.g. change the prompt):
230
+
231
+ ```bash
232
+ # Edit app.py locally, then:
233
+ git add app.py
234
+ git commit -m "update prompt"
235
+ git push
236
+ ```
237
+
238
+ HF Spaces auto-rebuilds on every push โ€” takes ~3-5 minutes.
239
+
240
+ ---
241
+
242
+ ## Troubleshooting
243
+
244
+ ### โŒ Build fails: "GROQ_API_KEY not set"
245
+ - You forgot Phase 3. Go to Space Settings โ†’ Repository secrets โ†’ add `GROQ_API_KEY`.
246
+ - Then go to **Factory reboot** in Space settings to trigger a fresh build.
247
+
248
+ ### โŒ "harrypotter.txt not found"
249
+ - The file wasn't pushed. Check it's in your folder: `ls -la` should show it.
250
+ - Re-run `git add . && git commit -m "add text" && git push`
251
+
252
+ ### โŒ Space shows "Runtime error"
253
+ - Click **Logs** tab โ†’ read the error message.
254
+ - Most common cause: missing file or wrong env var name.
255
+
256
+ ### โŒ Push rejected: file too large
257
+ - `harrypotter.txt` might be >10MB. HF needs Git LFS for that.
258
+ - Make sure you ran `git lfs track "*.txt"` before `git add`.
259
+
260
+ ### โŒ Answers are slow (10-20 seconds)
261
+ - Normal for free CPU tier with the LLaMA 70B model via Groq API.
262
+ - Groq's own latency is ~2-3 seconds. The rest is FAISS retrieval + network.
263
+ - Perfectly acceptable for a chatbot.
264
+
265
+ ---
266
+
267
+ ## Summary: The 3 Files You Must Have
268
+
269
+ | File | Purpose |
270
+ |---|---|
271
+ | `app.py` | The FastAPI server (already written for you) |
272
+ | `Dockerfile` | Tells HF how to build the container |
273
+ | `requirements.txt` | Python dependencies |
274
+ | `harrypotter.txt` | Your HP corpus โ€” YOU must add this |
275
+ | `README.md` | Space description + metadata |
README.md ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: KUMPAS Harry Potter RAG Oracle
3
+ emoji: ๐Ÿ”ฎ
4
+ colorFrom: purple
5
+ colorTo: yellow
6
+ sdk: docker
7
+ pinned: false
8
+ app_port: 7860
9
+ ---
10
+
11
+ # ๐Ÿ”ฎ KUMPAS โ€” Wizarding Oracle RAG API
12
+
13
+ A Harry Potter RAG (Retrieval-Augmented Generation) API built for the KUMPAS web app.
14
+
15
+ ## Stack
16
+ - **Vector Store**: FAISS with `all-MiniLM-L6-v2` embeddings
17
+ - **LLM**: Groq `llama-3.3-70b-versatile`
18
+ - **Framework**: FastAPI
19
+
20
+ ## Endpoints
21
+
22
+ | Method | Path | Description |
23
+ |--------|------|-------------|
24
+ | GET | `/health` | Server status |
25
+ | POST | `/ask` | Ask the Oracle |
26
+
27
+ ## Request Format
28
+
29
+ ```json
30
+ POST /ask
31
+ {
32
+ "question": "Who is Harry Potter's best friend?",
33
+ "history": [
34
+ { "role": "user", "content": "previous question" },
35
+ { "role": "assistant", "content": "previous answer" }
36
+ ]
37
+ }
38
+ ```
39
+
40
+ ## Response Format
41
+
42
+ ```json
43
+ {
44
+ "answer": "Harry Potter's best friend is Ron Weasley..."
45
+ }
46
+ ```
app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py โ€” KUMPAS RAG Server for Hugging Face Spaces
2
+ # Stack: FAISS + HuggingFace all-MiniLM-L6-v2 + Groq llama-3.3-70b
3
+
4
+ import os
5
+ import logging
6
+ from contextlib import asynccontextmanager
7
+ from typing import List, Optional
8
+
9
+ from fastapi import FastAPI, HTTPException
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+ from pydantic import BaseModel
12
+
13
+ from langchain_community.embeddings import HuggingFaceEmbeddings
14
+ from langchain_community.vectorstores import FAISS
15
+ from langchain_groq import ChatGroq
16
+ from langchain_core.prompts import ChatPromptTemplate
17
+ from langchain_core.runnables import RunnablePassthrough
18
+ from langchain_core.output_parsers import StrOutputParser
19
+
20
+ logging.basicConfig(level=logging.INFO)
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # โ”€โ”€ Global chain (loaded once at startup) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
24
+ qa_chain = None
25
+
26
+ def build_chain():
27
+ """
28
+ Loads the FAISS index from disk and builds the QA chain.
29
+ Called once when the server starts.
30
+ """
31
+ global qa_chain
32
+
33
+ groq_api_key = os.environ.get("GROQ_API_KEY", "")
34
+ if not groq_api_key:
35
+ raise RuntimeError("GROQ_API_KEY environment variable is not set!")
36
+
37
+ faiss_path = os.environ.get("FAISS_PATH", "student_manual_faiss")
38
+ text_path = os.environ.get("TEXT_PATH", "harrypotter.txt")
39
+
40
+ logger.info("Loading embeddings model...")
41
+ embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
42
+
43
+ # โ”€โ”€ Try loading saved FAISS index first (fast) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
44
+ if os.path.exists(faiss_path):
45
+ logger.info(f"Loading FAISS index from {faiss_path}...")
46
+ vectorstore = FAISS.load_local(
47
+ faiss_path,
48
+ embeddings,
49
+ allow_dangerous_deserialization=True
50
+ )
51
+ logger.info("FAISS index loaded from disk โœ…")
52
+
53
+ # โ”€โ”€ Otherwise build from text file (slow, first run only) โ”€โ”€โ”€
54
+ elif os.path.exists(text_path):
55
+ logger.info(f"Building FAISS index from {text_path} (this takes a few minutes)...")
56
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
57
+
58
+ try:
59
+ with open(text_path, "r", encoding="latin-1") as f:
60
+ text = f.read()
61
+ except UnicodeDecodeError:
62
+ with open(text_path, "r", encoding="cp1252") as f:
63
+ text = f.read()
64
+
65
+ splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
66
+ chunks = splitter.split_text(text)
67
+ logger.info(f"Created {len(chunks)} chunks")
68
+
69
+ vectorstore = FAISS.from_texts(chunks, embedding=embeddings)
70
+ vectorstore.save_local(faiss_path)
71
+ logger.info("FAISS index built and saved โœ…")
72
+
73
+ else:
74
+ raise RuntimeError(
75
+ f"Neither FAISS index ({faiss_path}) nor text file ({text_path}) found! "
76
+ "Make sure harrypotter.txt is in your Space files."
77
+ )
78
+
79
+ # โ”€โ”€ Build retriever โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
80
+ retriever = vectorstore.as_retriever(
81
+ search_type="similarity",
82
+ search_kwargs={"k": 3}
83
+ )
84
+
85
+ # โ”€โ”€ Groq LLM โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
86
+ llm = ChatGroq(
87
+ model="llama-3.3-70b-versatile",
88
+ temperature=0.5,
89
+ groq_api_key=groq_api_key
90
+ )
91
+
92
+ # โ”€โ”€ Prompt (same as your Colab notebook) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
93
+ prompt = ChatPromptTemplate.from_template("""
94
+ Answer the question based only on the following context from the Harry Potter series:
95
+ {context}
96
+
97
+ Question: {question}
98
+
99
+ Answer clearly and concisely. If the answer is not in the context, say so honestly.
100
+ """)
101
+
102
+ # โ”€โ”€ LCEL chain (identical to your Colab) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
103
+ qa_chain = (
104
+ {"context": retriever, "question": RunnablePassthrough()}
105
+ | prompt
106
+ | llm
107
+ | StrOutputParser()
108
+ )
109
+
110
+ logger.info("QA chain ready โœ…")
111
+ return qa_chain
112
+
113
+
114
+ # โ”€โ”€ Lifespan: build chain on startup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
115
+ @asynccontextmanager
116
+ async def lifespan(app: FastAPI):
117
+ logger.info("๐Ÿ”ฎ Starting KUMPAS RAG server...")
118
+ build_chain()
119
+ logger.info("๐Ÿ”ฎ Server ready!")
120
+ yield
121
+ logger.info("Server shutting down.")
122
+
123
+
124
+ # โ”€โ”€ FastAPI app โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
125
+ app = FastAPI(
126
+ title="KUMPAS Harry Potter RAG API",
127
+ description="Wizarding Oracle โ€” FAISS + Groq LLaMA",
128
+ version="1.0.0",
129
+ lifespan=lifespan
130
+ )
131
+
132
+ app.add_middleware(
133
+ CORSMiddleware,
134
+ allow_origins=["*"],
135
+ allow_methods=["GET", "POST"],
136
+ allow_headers=["*"],
137
+ )
138
+
139
+
140
+ # โ”€โ”€ Request / Response models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
141
+ class HistoryItem(BaseModel):
142
+ role: str
143
+ content: str
144
+
145
+ class AskRequest(BaseModel):
146
+ question: str
147
+ history: Optional[List[HistoryItem]] = []
148
+
149
+ class AskResponse(BaseModel):
150
+ answer: str
151
+
152
+
153
+ # โ”€โ”€ Endpoints โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
154
+ @app.get("/")
155
+ def root():
156
+ return {"message": "๐Ÿ”ฎ KUMPAS Wizarding Oracle is alive!", "status": "ok"}
157
+
158
+ @app.get("/health")
159
+ def health():
160
+ return {
161
+ "status": "ok",
162
+ "oracle": "ready" if qa_chain else "loading",
163
+ "model": "llama-3.3-70b-versatile"
164
+ }
165
+
166
+ @app.post("/ask", response_model=AskResponse)
167
+ def ask(req: AskRequest):
168
+ if qa_chain is None:
169
+ raise HTTPException(status_code=503, detail="Oracle is still initializing. Try again in a moment.")
170
+
171
+ question = req.question.strip()
172
+ if not question:
173
+ raise HTTPException(status_code=400, detail="Question cannot be empty.")
174
+
175
+ # โ”€โ”€ Prepend recent history to give the LLM context โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
176
+ if req.history:
177
+ recent = req.history[-4:] # last 2 turns
178
+ history_text = "\n".join(
179
+ f"{'User' if h.role == 'user' else 'Oracle'}: {h.content}"
180
+ for h in recent
181
+ )
182
+ full_question = f"Previous conversation:\n{history_text}\n\nCurrent question: {question}"
183
+ else:
184
+ full_question = question
185
+
186
+ try:
187
+ logger.info(f"Question: {question[:80]}...")
188
+ answer = qa_chain.invoke(full_question)
189
+ answer = str(answer).strip()
190
+
191
+ if not answer:
192
+ answer = "The wizarding archives hold no record of this. Try rephrasing your question."
193
+
194
+ logger.info(f"Answer: {answer[:80]}...")
195
+ return AskResponse(answer=answer)
196
+
197
+ except Exception as e:
198
+ logger.error(f"Chain error: {e}")
199
+ raise HTTPException(
200
+ status_code=500,
201
+ detail="The magic is disrupted. The Oracle cannot answer right now."
202
+ )
harrypotter.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:565fb203ee98c0002c14de4df4dd1b648254f4d5d64d439574ddd62ca235b3b0
3
+ size 6617234
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:696c6e9ed85fa80cdb8240845987008f6a18ca05a7d65c534de9a70f73526b04
3
+ size 285