bash98 commited on
Commit
518cbbb
·
verified ·
1 Parent(s): 7021839

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -377
app.py CHANGED
@@ -1,36 +1,33 @@
 
1
 
2
- """Document Q&A with Manual RAG — CPU inference on ZeroGPU hardware."""
 
 
3
 
4
- # Import spaces before any ML libraries
5
- import spaces
6
 
7
  import os
8
  import traceback
9
 
 
10
  os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
11
 
12
  import gradio as gr
13
 
14
- from rag_core import (
15
- answer_question,
16
- display_evidence,
17
- load_retriever,
18
- )
19
-
20
 
21
- # -----------------------------------------
22
- # ZeroGPU startup compatibility
23
- # -----------------------------------------
24
 
25
  @spaces.GPU(duration=10)
26
  def zerogpu_registration():
27
- """Registered but intentionally unused GPU function."""
 
 
 
 
 
28
  return "ZeroGPU registration handler (unused)."
29
 
30
 
31
- # -----------------------------------------
32
- # Custom styling
33
- # -----------------------------------------
34
 
35
  CUSTOM_CSS = """
36
  .gradio-container {
@@ -45,16 +42,11 @@ CUSTOM_CSS = """
45
  border-radius: 20px;
46
  background: linear-gradient(
47
  125deg,
48
- color-mix(
49
- in srgb,
50
- var(--primary-500) 13%,
51
- var(--block-background-fill)
52
- ) 0%,
53
  var(--block-background-fill) 75%
54
  );
55
  margin-bottom: 18px;
56
  }
57
-
58
  #rag-hero .eyebrow {
59
  font-size: 0.76rem;
60
  text-transform: uppercase;
@@ -63,7 +55,6 @@ CUSTOM_CSS = """
63
  color: var(--primary-500);
64
  margin-bottom: 9px;
65
  }
66
-
67
  #rag-hero h1 {
68
  font-size: clamp(1.65rem, 3vw, 2.35rem);
69
  font-weight: 760;
@@ -71,7 +62,6 @@ CUSTOM_CSS = """
71
  letter-spacing: -0.035em;
72
  margin: 0 0 10px;
73
  }
74
-
75
  #rag-hero p {
76
  color: var(--body-text-color-subdued);
77
  font-size: 0.99rem;
@@ -79,369 +69,28 @@ CUSTOM_CSS = """
79
  line-height: 1.6;
80
  margin: 0;
81
  }
82
-
83
  #rag-hero .meta {
84
  font-size: 0.82rem;
85
  color: var(--body-text-color-subdued);
86
  margin-top: 15px;
87
  }
88
-
89
- #rag-input textarea {
90
- font-size: 1.03rem !important;
91
- }
92
-
93
- #rag-actions button {
94
- min-height: 48px !important;
95
- font-weight: 650;
96
- }
97
-
98
- #rag-status {
99
- margin: 4px 0 8px;
100
- }
101
-
102
- #rag-answer textarea {
103
- font-size: 1.04rem !important;
104
- line-height: 1.6 !important;
105
- }
106
-
107
- #rag-evidence textarea {
108
- font-size: 0.94rem !important;
109
- line-height: 1.55 !important;
110
- }
111
-
112
  @media (max-width: 680px) {
113
- #rag-hero {
114
- padding: 20px 18px;
115
- border-radius: 16px;
116
- }
117
-
118
- .gradio-container {
119
- padding: 12px 10px 22px !important;
120
- }
121
  }
122
  """
123
 
124
 
125
- # -----------------------------------------
126
- # Format results
127
- # -----------------------------------------
128
-
129
  def format_result(result):
130
-
131
  answer = result.get("answer", "")
132
  evidence = display_evidence(result)
133
-
134
- hits = result.get("retrieved") or []
135
- count = len(hits)
136
-
137
- top_score = hits[0]["score"] if hits else None
138
-
139
- score_note = (
140
- f" | Top cosine similarity: {top_score:.3f}"
141
- if top_score is not None
142
- else ""
143
- )
144
-
145
- status = result.get("status", "")
146
-
147
- if status == "retrieval_only":
148
- answer = (
149
- "Evidence retrieved. Select Generate Answer "
150
- "to create a response."
151
- )
152
- message = (
153
- f"**Evidence retrieved** | "
154
- f"{count} source passages{score_note}"
155
- )
156
-
157
- elif status == "generated":
158
- message = (
159
- f"**Answer generated on CPU** | "
160
- f"{count} source passages{score_note}"
161
- )
162
-
163
- elif status == "low_similarity_refusal":
164
- message = (
165
- "**No answer generated** | "
166
- "Evidence is below the similarity threshold."
167
- f"{score_note}"
168
- )
169
-
170
- else:
171
- message = (
172
- f"**Completed on CPU** | "
173
- f"{count} source passages{score_note}"
174
- )
175
-
176
- return answer, evidence, message
177
-
178
-
179
- # -----------------------------------------
180
- # CPU evidence retrieval
181
- # -----------------------------------------
182
-
183
- def retrieve_evidence(question):
184
-
185
- try:
186
- result = answer_question(
187
- question,
188
- retrieval_only=True
189
- )
190
-
191
- return format_result(result)
192
-
193
- except ValueError as error:
194
- return (
195
- "Please check your question.",
196
- "",
197
- f"**Input error:** {error}"
198
- )
199
-
200
- except Exception:
201
- traceback.print_exc()
202
-
203
- return (
204
- "Unable to retrieve evidence.",
205
- "",
206
- "**Retrieval error.** Check the logs."
207
- )
208
-
209
-
210
- # -----------------------------------------
211
- # CPU answer generation
212
- # -----------------------------------------
213
-
214
- def generate_answer(question):
215
-
216
- try:
217
- result = answer_question(
218
- question,
219
- retrieval_only=False
220
- )
221
-
222
- return format_result(result)
223
-
224
- except ValueError as error:
225
- return (
226
- "Please check your question.",
227
- "",
228
- f"**Input error:** {error}"
229
- )
230
-
231
- except Exception:
232
- traceback.print_exc()
233
-
234
- return (
235
- "Unable to generate an answer.",
236
- "",
237
- "**Generation error.** Check the logs."
238
- )
239
-
240
-
241
- # -----------------------------------------
242
- # Build interface
243
- # -----------------------------------------
244
-
245
- def make_demo():
246
-
247
- with gr.Blocks(
248
- title="Document Q&A with Manual RAG"
249
- ) as demo:
250
-
251
- gr.HTML(
252
- """
253
- <section id="rag-hero">
254
- <div class="eyebrow">
255
- Manual RAG | CPU Inference
256
- </div>
257
-
258
- <h1>
259
- Document Q&amp;A with Manual RAG
260
- </h1>
261
-
262
- <p>
263
- Ask a question, retrieve supporting
264
- passages, and generate an answer
265
- using only the available documents.
266
- </p>
267
-
268
- <div class="meta">
269
- 30 SQuAD/Wikipedia passages
270
- &nbsp; | &nbsp;
271
- MiniLM Retrieval
272
- &nbsp; | &nbsp;
273
- FLAN-T5 Small Generation
274
- </div>
275
- </section>
276
- """
277
- )
278
-
279
- question = gr.Textbox(
280
- label="Ask a Question",
281
- placeholder="Which company produces the iPod?",
282
- lines=2,
283
- max_lines=3,
284
- max_length=300,
285
- elem_id="rag-input"
286
- )
287
-
288
- with gr.Row(elem_id="rag-actions"):
289
-
290
- answer_button = gr.Button(
291
- "Generate Answer",
292
- variant="primary",
293
- size="lg"
294
- )
295
-
296
- retrieve_button = gr.Button(
297
- "Retrieve Evidence",
298
- variant="secondary",
299
- size="lg"
300
- )
301
-
302
- status = gr.Markdown(
303
- "**Ready** | CPU inference enabled.",
304
- elem_id="rag-status"
305
- )
306
-
307
- gr.Markdown("### Generated Answer")
308
-
309
- answer = gr.Textbox(
310
- label="Answer",
311
- placeholder="Your answer will appear here.",
312
- lines=4,
313
- max_lines=8,
314
- interactive=False,
315
- buttons=["copy"],
316
- elem_id="rag-answer"
317
- )
318
-
319
- with gr.Accordion(
320
- "Source Passages and Similarity Scores",
321
- open=True
322
- ):
323
-
324
- evidence = gr.Textbox(
325
- show_label=False,
326
- placeholder=(
327
- "Retrieved passages will appear here."
328
- ),
329
- lines=11,
330
- max_lines=14,
331
- interactive=False,
332
- buttons=["copy"],
333
- elem_id="rag-evidence"
334
- )
335
-
336
- gr.Examples(
337
- examples=[
338
- ["Which company produces the iPod?"],
339
- ["At what age did Frédéric move to Paris?"],
340
- [
341
- "What is the live price of Bitcoin "
342
- "in Nigerian naira right now?"
343
- ]
344
- ],
345
- inputs=[question],
346
- cache_examples=False,
347
- label="Try an Example Question"
348
- )
349
-
350
- gr.Markdown(
351
- """
352
- **Note:** Answers come from the 30
353
- available passages, not the live internet.
354
- Cosine similarity is not a confidence score.
355
- Always verify answers against the sources.
356
- """
357
- )
358
-
359
- # Visible CPU actions
360
- outputs = [
361
- answer,
362
- evidence,
363
- status
364
- ]
365
-
366
- answer_button.click(
367
- fn=generate_answer,
368
- inputs=question,
369
- outputs=outputs
370
- )
371
-
372
- retrieve_button.click(
373
- fn=retrieve_evidence,
374
- inputs=question,
375
- outputs=outputs
376
- )
377
-
378
- # Hidden compatibility event.
379
- # ZeroGPU requires a GPU-decorated function
380
- # registered directly with a Gradio event.
381
-
382
- hidden_button = gr.Button(
383
- "ZeroGPU registration",
384
- visible=False,
385
- interactive=False
386
- )
387
-
388
- hidden_output = gr.Textbox(
389
- visible=False
390
- )
391
-
392
- hidden_button.click(
393
- fn=zerogpu_registration,
394
- inputs=[],
395
- outputs=hidden_output,
396
- api_visibility="private"
397
- )
398
-
399
- return demo
400
-
401
-
402
- # -----------------------------------------
403
- # Initialize at module level
404
- # -----------------------------------------
405
-
406
- print(
407
- "Starting Manual RAG: CPU inference "
408
- "on ZeroGPU hardware",
409
- flush=True
410
- )
411
-
412
- shape = load_retriever()
413
-
414
- print(
415
- f"Retriever initialized: {shape}",
416
- flush=True
417
- )
418
-
419
- # Register all Gradio events before launch
420
- demo = make_demo()
421
-
422
- demo.queue(
423
- default_concurrency_limit=1,
424
- max_size=20
425
- )
426
-
427
-
428
- # -----------------------------------------
429
- # Launch application
430
- # -----------------------------------------
431
-
432
- if __name__ == "__main__":
433
-
434
- demo.launch(
435
- server_name="0.0.0.0",
436
- server_port=int(
437
- os.getenv("PORT", "7860")
438
- ),
439
- share=False,
440
- show_error=True,
441
- ssr_mode=False,
442
- theme=gr.themes.Soft(
443
- primary_hue="indigo",
444
- neutral_hue="slate"
445
- ),
446
- css=CUSTOM_CSS
447
- )
 
1
+ """Document Q&A with Manual RAG - CPU inference on a ZeroGPU Space.
2
 
3
+ The two visible actions stay on CPU. A hidden, registered GPU handler
4
+ is present solely to satisfy ZeroGPU startup validation.
5
+ """
6
 
7
+ import spaces # Import before Gradio, torch, or Hugging Face model libraries.
 
8
 
9
  import os
10
  import traceback
11
 
12
+ # Do NOT set CUDA_VISIBLE_DEVICES on ZeroGPU hardware.
13
  os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
14
 
15
  import gradio as gr
16
 
17
+ from rag_core import answer_question, display_evidence, load_retriever
 
 
 
 
 
18
 
 
 
 
19
 
20
  @spaces.GPU(duration=10)
21
  def zerogpu_registration():
22
+ """Registered but intentionally unused ZeroGPU handler.
23
+
24
+ The host requires at least one @spaces.GPU decorated Gradio event
25
+ on a ZeroGPU Space. Users do not click this handler, and the two
26
+ visible buttons do all work on CPU.
27
+ """
28
  return "ZeroGPU registration handler (unused)."
29
 
30
 
 
 
 
31
 
32
  CUSTOM_CSS = """
33
  .gradio-container {
 
42
  border-radius: 20px;
43
  background: linear-gradient(
44
  125deg,
45
+ color-mix(in srgb, var(--primary-500) 13%, var(--block-background-fill)) 0%,
 
 
 
 
46
  var(--block-background-fill) 75%
47
  );
48
  margin-bottom: 18px;
49
  }
 
50
  #rag-hero .eyebrow {
51
  font-size: 0.76rem;
52
  text-transform: uppercase;
 
55
  color: var(--primary-500);
56
  margin-bottom: 9px;
57
  }
 
58
  #rag-hero h1 {
59
  font-size: clamp(1.65rem, 3vw, 2.35rem);
60
  font-weight: 760;
 
62
  letter-spacing: -0.035em;
63
  margin: 0 0 10px;
64
  }
 
65
  #rag-hero p {
66
  color: var(--body-text-color-subdued);
67
  font-size: 0.99rem;
 
69
  line-height: 1.6;
70
  margin: 0;
71
  }
 
72
  #rag-hero .meta {
73
  font-size: 0.82rem;
74
  color: var(--body-text-color-subdued);
75
  margin-top: 15px;
76
  }
77
+ #rag-input textarea { font-size: 1.03rem !important; }
78
+ #rag-actions button { min-height: 48px !important; font-weight: 650; }
79
+ #rag-status { margin: 4px 0 8px; }
80
+ #rag-status p { font-size: 0.9rem; color: var(--body-text-color-subdued); }
81
+ #rag-result-heading h3 { font-size: 1.13rem; margin: 12px 0 0; }
82
+ #rag-answer textarea { font-size: 1.04rem !important; line-height: 1.6 !important; }
83
+ #rag-evidence textarea { font-size: 0.94rem !important; line-height: 1.55 !important; }
84
+ #rag-footnote p { font-size: 0.82rem; color: var(--body-text-color-subdued); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  @media (max-width: 680px) {
86
+ #rag-hero { padding: 20px 18px; border-radius: 16px; }
87
+ .gradio-container { padding: 12px 10px 22px !important; }
 
 
 
 
 
 
88
  }
89
  """
90
 
91
 
 
 
 
 
92
  def format_result(result):
93
+ """Return answer, complete source evidence, and a simple status line."""
94
  answer = result.get("answer", "")
95
  evidence = display_evidence(result)
96
+ hits = result.get("retrieved") or []