EngrMuhammadBilal commited on
Commit
355c578
·
verified ·
1 Parent(s): 186b3fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -118
app.py CHANGED
@@ -8,21 +8,132 @@ import gradio as gr
8
  from groq import Groq
9
  from docx import Document
10
  from docx.shared import Pt
 
11
 
12
  # ---------- Branding ----------
13
- # ---------- Palette ----------
 
 
 
14
  PALETTE = {
15
- "navy": "#083D77", # dark background
16
- "gold": "#F2B400", # accents, primary buttons
17
- "ice": "#FBF8F9", # off-white surfaces
18
- "maroon": "#8B1E1E", # emphasis chips / dividers
19
- "amber": "#F5C26B", # secondary accents
20
- "text_on_dark": "#EAF2FF",
21
- "text_on_light": "#0B1220",
22
  }
23
 
24
- APP_NAME = "ScholarLens"
25
- TAGLINE = "Query your literature, get page-level proof"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  # ---------- Config ----------
28
  EMBED_MODEL_NAME = "intfloat/multilingual-e5-small"
@@ -35,7 +146,7 @@ INDEX_PATH = "rag_index.faiss"
35
  STORE_PATH = "rag_store.pkl"
36
 
37
  MODEL_CHOICES = [
38
- "llama-3.3-70b-versatile",
39
  "llama-3.1-8b-instant",
40
  "mixtral-8x7b-32768",
41
  ]
@@ -131,7 +242,6 @@ def _collect_pdf_paths(upload_paths: List[str]) -> List[str]:
131
  for name in z.namelist():
132
  if name.lower().endswith(".pdf"):
133
  z.extract(name, tmpdir)
134
- # collect extracted PDFs
135
  for root, _, files in os.walk(tmpdir):
136
  for f in files:
137
  if f.lower().endswith(".pdf"):
@@ -195,7 +305,7 @@ def retrieve(query: str, top_k=5, must_contain: str = ""):
195
  return hits
196
 
197
  # ---------- Groq LLM ----------
198
- def groq_answer(query: str, contexts, model_name="llama-3.1-70b-versatile", temperature=0.2, max_tokens=1000):
199
  try:
200
  if not os.environ.get("GROQ_API_KEY"):
201
  return "GROQ_API_KEY is not set. Add it in your Space secrets or the key box."
@@ -233,10 +343,7 @@ def groq_answer(query: str, contexts, model_name="llama-3.1-70b-versatile", temp
233
 
234
  # ---------- Export helpers ----------
235
  def export_answer_to_docx(question: str, answer_md: str, rows: List[List[str]]) -> str:
236
- """
237
- Save Q&A with sources table to a .docx and return path.
238
- rows: [Source, Page, Score, Snippet]
239
- """
240
  doc = Document()
241
  styles = doc.styles
242
  try:
@@ -331,113 +438,15 @@ def do_export_docx(question, answer_md, sources_rows):
331
  except Exception:
332
  return None
333
 
334
- # ---------- Theme (no .set used; styling via CSS) ----------
335
- theme = gr.themes.Soft(
336
- primary_hue="indigo",
337
- secondary_hue="blue",
338
- neutral_hue="slate",
339
- )
340
 
341
  # ---------- Gradio UI ----------
342
  with gr.Blocks(
343
  title=f"{APP_NAME} | RAG over PDFs",
344
  theme=theme,
345
- css=f"""
346
- :root {{
347
- --navy: {PALETTE['navy']};
348
- --gold: {PALETTE['gold']};
349
- --ice: {PALETTE['ice']};
350
- --maroon: {PALETTE['maroon']};
351
- --amber: {PALETTE['amber']};
352
- --text-dark: {PALETTE['text_on_light']};
353
- --text-light: {PALETTE['text_on_dark']};
354
- }}
355
-
356
- body, .gradio-container { color: var(--text-light) !important; }
357
-
358
- }}
359
-
360
- .gradio-container .block,
361
- .gradio-container .tabs,
362
- .gradio-container .tabs > .tabitem {{
363
- background: color-mix(in srgb, var(--navy) 80%, black 20%) !important;
364
- color: var(--text-light) !important;
365
- border-radius: 12px;
366
- border: 1px solid color-mix(in srgb, var(--navy) 70%, white 10%);
367
- }}
368
-
369
- #hero {{
370
- background:
371
- linear-gradient(90deg, var(--navy) 0%, var(--gold) 25%, var(--ice) 45%, var(--maroon) 65%, var(--amber) 85%, transparent 100%);
372
- border: 1px solid color-mix(in srgb, var(--gold) 40%, white 20%);
373
- border-radius: 14px;
374
- padding: 14px 16px;
375
- color: var(--text-light);
376
- }}
377
-
378
- a, .prose a { color: var(--amber) !important; } /* normal */
379
- a:hover { text-decoration: underline; }
380
-
381
- }}
382
- a:hover {{ text-decoration: underline; }}
383
-
384
- .kpi {{
385
- text-align:center;
386
- padding:12px;
387
- border-radius:10px;
388
- border:1px solid color-mix(in srgb, var(--ice) 35%, var(--navy) 65%);
389
- background: color-mix(in srgb, var(--navy) 75%, black 25%);
390
- color: var(--text-light);
391
- }}
392
-
393
- button, .gr-button {{
394
- border-radius: 10px !important;
395
- font-weight: 600 !important;
396
- color: var(--text-light) !important;
397
- }}
398
- button.primary, .gr-button-primary {{
399
- background: var(--gold) !important;
400
- color: var(--text-dark) !important;
401
- border: 1px solid color-mix(in srgb, var(--gold) 70%, black 10%) !important;
402
- }}
403
- button.secondary, .gr-button-secondary {{
404
- background: color-mix(in srgb, var(--amber) 60%, var(--gold) 40%) !important;
405
- color: var(--text-dark) !important;
406
- }}
407
-
408
- input, textarea, .gr-textbox, .gr-text-area, .gr-slider, .gr-dropdown, .gr-file, .wrap.svelte* {{
409
- background: color-mix(in srgb, var(--navy) 65%, black 35%) !important;
410
- color: var(--text-light) !important;
411
- border: 1px solid color-mix(in srgb, var(--ice) 25%, var(--navy) 75%) !important;
412
- border-radius: 10px !important;
413
- }}
414
-
415
- label, .label, .prose h1, .prose h2, .prose h3, .prose p, .markdown-body {{
416
- color: var(--text-light) !important;
417
- }}
418
-
419
- .dataframe, table, .table, .gr-dataframe * {{
420
- color: var(--text-light) !important;
421
- background: transparent !important;
422
- }}
423
- .dataframe th {{
424
- background: color-mix(in srgb, var(--navy) 70%, black 30%) !important;
425
- border-bottom: 1px solid color-mix(in srgb, var(--ice) 20%, var(--navy) 80%) !important;
426
- }}
427
- .dataframe td {{
428
- border-bottom: 1px solid color-mix(in srgb, var(--ice) 15%, var(--navy) 85%) !important;
429
- }}
430
-
431
- .accordion, .gr-accordion {{
432
- background: color-mix(in srgb, var(--navy) 70%, black 30%) !important;
433
- border: 1px solid color-mix(in srgb, var(--ice) 20%, var(--navy) 80%) !important;
434
- border-radius: 10px !important;
435
- }}
436
-
437
- footer, .footer {{ opacity:.75; color: var(--text-light); }}
438
- """
439
  ) as demo:
440
-
441
  # --- Header / Hero ---
442
  with gr.Group(elem_id="hero"):
443
  gr.Markdown(
 
8
  from groq import Groq
9
  from docx import Document
10
  from docx.shared import Pt
11
+ from string import Template
12
 
13
  # ---------- Branding ----------
14
+ APP_NAME = "ScholarLens"
15
+ TAGLINE = "Query your literature, get page-level proof"
16
+
17
+ # ---------- Palette (guarantees light text on dark, dark text on light) ----------
18
  PALETTE = {
19
+ "navy": "#083D77", # dark background
20
+ "gold": "#F2B400", # primary buttons / accents
21
+ "ice": "#FBF8F9", # off-white
22
+ "maroon": "#8B1E1E", # emphasis chips / separators
23
+ "amber": "#F5C26B", # secondary accent
24
+ "text_on_dark": "#EAF2FF", # light text for dark surfaces
25
+ "text_on_light": "#0B1220" # dark text for light (gold/amber/ice)
26
  }
27
 
28
+ def build_custom_css():
29
+ """Safe CSS builder using string.Template so { } braces don't break Python."""
30
+ tmpl = Template(r"""
31
+ :root {
32
+ --navy: $navy;
33
+ --gold: $gold;
34
+ --ice: $ice;
35
+ --maroon: $maroon;
36
+ --amber: $amber;
37
+ --text-dark: $text_dark;
38
+ --text-light: $text_light;
39
+ }
40
+
41
+ /* Global surfaces */
42
+ body, .gradio-container {
43
+ background: var(--navy) !important;
44
+ color: var(--text-light) !important;
45
+ }
46
+
47
+ /* Blocks and tabs */
48
+ .gradio-container .block,
49
+ .gradio-container .tabs,
50
+ .gradio-container .tabs > .tabitem {
51
+ background: color-mix(in srgb, var(--navy) 80%, black 20%) !important;
52
+ color: var(--text-light) !important;
53
+ border-radius: 12px;
54
+ border: 1px solid color-mix(in srgb, var(--navy) 70%, white 10%);
55
+ }
56
+
57
+ /* Hero stripe styled with your palette */
58
+ #hero {
59
+ background:
60
+ linear-gradient(90deg, var(--navy) 0%, var(--gold) 25%, var(--ice) 45%, var(--maroon) 65%, var(--amber) 85%, transparent 100%);
61
+ border: 1px solid color-mix(in srgb, var(--gold) 40%, white 20%);
62
+ border-radius: 14px;
63
+ padding: 14px 16px;
64
+ color: var(--text-light);
65
+ }
66
+
67
+ /* Links */
68
+ a, .prose a { color: var(--amber) !important; text-decoration: none; }
69
+ a:hover { text-decoration: underline; }
70
+
71
+ /* KPI chips */
72
+ .kpi {
73
+ text-align:center; padding:12px; border-radius:10px;
74
+ border:1px solid color-mix(in srgb, var(--ice) 35%, var(--navy) 65%);
75
+ background: color-mix(in srgb, var(--navy) 75%, black 25%);
76
+ color: var(--text-light);
77
+ }
78
+
79
+ /* Buttons */
80
+ button, .gr-button { border-radius: 10px !important; font-weight: 600 !important; }
81
+ .gr-button, button { color: var(--text-light) !important; }
82
+ .gr-button-primary {
83
+ background: var(--gold) !important;
84
+ color: var(--text-dark) !important; /* dark text on light gold */
85
+ border: 1px solid color-mix(in srgb, var(--gold) 70%, black 10%) !important;
86
+ }
87
+ .gr-button-secondary {
88
+ background: color-mix(in srgb, var(--amber) 60%, var(--gold) 40%) !important;
89
+ color: var(--text-dark) !important;
90
+ }
91
+
92
+ /* Inputs */
93
+ input, textarea, .gr-textbox, .gr-text-area, .gr-slider, .gr-dropdown, .gr-file {
94
+ background: color-mix(in srgb, var(--navy) 65%, black 35%) !important;
95
+ color: var(--text-light) !important;
96
+ border: 1px solid color-mix(in srgb, var(--ice) 25%, var(--navy) 75%) !important;
97
+ border-radius: 10px !important;
98
+ }
99
+ input::placeholder, textarea::placeholder {
100
+ color: color-mix(in srgb, var(--text-light) 60%, transparent) !important;
101
+ }
102
+
103
+ /* Text blocks */
104
+ label, .label, .prose h1, .prose h2, .prose h3, .prose p, .markdown-body {
105
+ color: var(--text-light) !important;
106
+ }
107
+
108
+ /* Dataframe / table */
109
+ .dataframe, table, .table, .gr-dataframe * { color: var(--text-light) !important; background: transparent !important; }
110
+ .dataframe th {
111
+ background: color-mix(in srgb, var(--navy) 70%, black 30%) !important;
112
+ border-bottom: 1px solid color-mix(in srgb, var(--ice) 20%, var(--navy) 80%) !important;
113
+ }
114
+ .dataframe td {
115
+ border-bottom: 1px solid color-mix(in srgb, var(--ice) 15%, var(--navy) 85%) !important;
116
+ }
117
+
118
+ /* Accordions */
119
+ .accordion, .gr-accordion {
120
+ background: color-mix(in srgb, var(--navy) 70%, black 30%) !important;
121
+ border: 1px solid color-mix(in srgb, var(--ice) 20%, var(--navy) 80%) !important;
122
+ border-radius: 10px !important;
123
+ }
124
+
125
+ /* Footer */
126
+ footer, .footer { opacity:.75; color: var(--text-light); }
127
+ """)
128
+ return tmpl.substitute(
129
+ navy=PALETTE["navy"],
130
+ gold=PALETTE["gold"],
131
+ ice=PALETTE["ice"],
132
+ maroon=PALETTE["maroon"],
133
+ amber=PALETTE["amber"],
134
+ text_dark=PALETTE["text_on_light"],
135
+ text_light=PALETTE["text_on_dark"],
136
+ )
137
 
138
  # ---------- Config ----------
139
  EMBED_MODEL_NAME = "intfloat/multilingual-e5-small"
 
146
  STORE_PATH = "rag_store.pkl"
147
 
148
  MODEL_CHOICES = [
149
+ "llama-3.1-70b-versatile",
150
  "llama-3.1-8b-instant",
151
  "mixtral-8x7b-32768",
152
  ]
 
242
  for name in z.namelist():
243
  if name.lower().endswith(".pdf"):
244
  z.extract(name, tmpdir)
 
245
  for root, _, files in os.walk(tmpdir):
246
  for f in files:
247
  if f.lower().endswith(".pdf"):
 
305
  return hits
306
 
307
  # ---------- Groq LLM ----------
308
+ def groq_answer(query: str, contexts, model_name="llama-3.3-70b-versatile", temperature=0.2, max_tokens=1000):
309
  try:
310
  if not os.environ.get("GROQ_API_KEY"):
311
  return "GROQ_API_KEY is not set. Add it in your Space secrets or the key box."
 
343
 
344
  # ---------- Export helpers ----------
345
  def export_answer_to_docx(question: str, answer_md: str, rows: List[List[str]]) -> str:
346
+ """Save Q&A with sources table to a .docx and return path (rows = [Source, Page, Score, Snippet])."""
 
 
 
347
  doc = Document()
348
  styles = doc.styles
349
  try:
 
438
  except Exception:
439
  return None
440
 
441
+ # ---------- Theme (simple; main styling via CSS for compatibility) ----------
442
+ theme = gr.themes.Soft(primary_hue="indigo", secondary_hue="blue", neutral_hue="slate")
 
 
 
 
443
 
444
  # ---------- Gradio UI ----------
445
  with gr.Blocks(
446
  title=f"{APP_NAME} | RAG over PDFs",
447
  theme=theme,
448
+ css=build_custom_css()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  ) as demo:
 
450
  # --- Header / Hero ---
451
  with gr.Group(elem_id="hero"):
452
  gr.Markdown(