nyxionlabs commited on
Commit
d32e99b
·
verified ·
1 Parent(s): 8769b06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -195
app.py CHANGED
@@ -1,210 +1,100 @@
1
- import os, gradio as gr
2
- import numpy as np
3
- import faiss
4
- from datasets import load_dataset
5
- from sentence_transformers import SentenceTransformer
6
 
7
- # Optional LLM step (still works without it)
8
- OPENAI_API_KEY = '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'
9
- USE_OPENAI = bool(OPENAI_API_KEY)
 
10
 
11
- print(f"[RAG] OPENAI_API_KEY found: {bool(OPENAI_API_KEY)}")
12
 
13
- if USE_OPENAI:
14
- try:
15
- from openai import OpenAI
16
- oai = OpenAI(api_key=OPENAI_API_KEY)
17
- OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
18
- print(f"[RAG] OpenAI initialized with model: {OPENAI_MODEL}")
19
- except Exception as e:
20
- print("[RAG] OpenAI import failed:", e)
21
- USE_OPENAI = False
22
- else:
23
- print("[RAG] No OpenAI API key detected. Set OPENAI_API_KEY in Space Settings.")
24
-
25
- # Tunables (can override in Space → Settings → Variables)
26
- MODEL_NAME = os.getenv("EMBED_MODEL", "all-MiniLM-L6-v2")
27
- SQUAD_SLICE = os.getenv("SQUAD_SLICE", "2000") # e.g. "1000" or "2%" also works
28
- MAX_CTX_CHAR = int(os.getenv("MAX_CTX_CHAR", "1200"))
29
-
30
- STATE = {"index": None, "contexts": None, "encoder": None}
31
-
32
- def _fallback_corpus():
33
- # Tiny backup if SQuAD fails to download (offline)
34
- return [
35
- "Paris is the capital and most populous city of France.",
36
- "The Pacific Ocean is the largest and deepest of Earth's oceanic divisions.",
37
- "The human heart has four chambers: two atria and two ventricles.",
38
- "Mount Everest is Earth's highest mountain above sea level.",
39
- "Photosynthesis converts light energy into chemical energy in plants.",
40
- "The Nile is a major north-flowing river in northeastern Africa.",
41
- "Berlin is the capital and largest city of Germany.",
42
- "Tokyo is the capital of Japan and one of the world's most populous cities.",
43
- "The Great Wall of China is one of the most famous landmarks in the world.",
44
- "DNA contains the genetic instructions for all living organisms.",
45
- ]
46
-
47
- def build_index():
48
- """
49
- Build a small FAISS index directly from SQuAD v2 (no uploaded files).
50
- """
51
- if STATE["index"] is not None:
52
- return "Index already loaded."
53
 
54
- try:
55
- print(f"[RAG] Loading SQuAD v2 sample: train[:{SQUAD_SLICE}] …")
56
- ds = load_dataset("rajpurkar/squad_v2", split=f"train[:{SQUAD_SLICE}]")
57
- seen, contexts = set(), []
58
- for row in ds:
59
- c = row["context"]
60
- if c not in seen:
61
- seen.add(c); contexts.append(c)
62
- if len(contexts) == 0:
63
- raise RuntimeError("Empty SQuAD slice.")
64
- except Exception as e:
65
- print("[RAG] Could not load SQuAD, using fallback corpus:", e)
66
- contexts = _fallback_corpus()
67
-
68
- print(f"[RAG] Encoding {len(contexts)} contexts with {MODEL_NAME} …")
69
- encoder = SentenceTransformer(MODEL_NAME)
70
- # batch encode → float32 for faiss
71
- emb = encoder.encode(contexts, show_progress_bar=True, batch_size=128).astype("float32")
72
-
73
- # Simple exact search index (robust & dependency-free)
74
- index = faiss.IndexFlatL2(emb.shape[1])
75
- index.add(emb)
76
-
77
- STATE.update(index=index, contexts=contexts, encoder=encoder)
78
- print(f"[RAG] Ready: ntotal={STATE['index'].ntotal}")
79
- return f"Built FAISS index with {len(contexts)} contexts."
80
-
81
- def retrieve(question: str, k: int):
82
- q = STATE["encoder"].encode([question]).astype("float32")
83
- D, I = STATE["index"].search(q, int(k))
84
- pairs = []
85
- for rank, (i, dist) in enumerate(zip(I[0], D[0]), start=1):
86
- if 0 <= i < len(STATE["contexts"]):
87
- ctx = STATE["contexts"][i]
88
- pairs.append({
89
- "rank": rank,
90
- "faiss_dist": float(dist),
91
- "snippet": ctx[:240] + ("…" if len(ctx) > 240 else ""),
92
- "full": ctx
93
- })
94
- return pairs
95
-
96
- def build_prompt(question: str, pairs):
97
- blocks = []
98
- for j, p in enumerate(pairs, start=1):
99
- ctx = p["full"].strip()
100
- if len(ctx) > MAX_CTX_CHAR:
101
- ctx = ctx[:MAX_CTX_CHAR] + "…"
102
- blocks.append(f"[Source {j}] {ctx}")
103
- context_block = "\n\n".join(blocks) if blocks else "(no context)"
104
- return f"""Answer strictly from the context below. If not answerable, say so.
105
- Include [Source X] citations in your answer.
106
-
107
- Context:
108
- {context_block}
109
-
110
- Question: {question}
111
- Answer:"""
112
-
113
- def answer(question: str, k: int):
114
- if STATE["index"] is None:
115
- build_index()
116
 
 
 
117
  if not question.strip():
118
- return "Please enter a question.", [], {"status": "idle", "openai_enabled": USE_OPENAI}
119
-
120
- pairs = retrieve(question, k)
121
- if not pairs:
122
- return "No results in index.", [], {"status": "empty", "openai_enabled": USE_OPENAI}
123
-
124
- cites = [{"rank": p["rank"], "faiss_dist": round(p["faiss_dist"], 4), "snippet": p["snippet"]} for p in pairs]
125
-
126
- if USE_OPENAI:
127
- prompt = build_prompt(question, pairs)
128
- try:
129
- print(f"[RAG] Calling OpenAI with model: {OPENAI_MODEL}")
130
- resp = oai.chat.completions.create(
131
- model=OPENAI_MODEL,
132
- messages=[{"role": "user", "content": prompt}],
133
- temperature=0.2,
134
- max_tokens=500
135
  )
136
- ans = resp.choices[0].message.content
137
- print(f"[RAG] OpenAI response received successfully")
138
- except Exception as e:
139
- print(f"[RAG] LLM call failed: {e}")
140
- ans = f"❌ LLM call failed: {e}\n\n**Top result shown below:**\n\n{pairs[0]['full'][:MAX_CTX_CHAR]}"
141
- else:
142
- ans = ("⚠️ **No OPENAI_API_KEY set** — Add it in Space Settings → Repository secrets\n\n"
143
- "**Showing most relevant context instead:**\n\n"
144
- + pairs[0]["full"][:MAX_CTX_CHAR])
145
-
146
- return ans, cites, {
147
- "status": "ok",
148
- "ntotal": STATE['index'].ntotal,
149
- "model": MODEL_NAME,
150
- "openai_enabled": USE_OPENAI,
151
- "openai_model": OPENAI_MODEL if USE_OPENAI else None
152
- }
153
-
154
- # ------------------- UI -------------------
155
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
156
  gr.Markdown("""
157
- ## Nyxion Labs · Grounded Q&A (RAG Demo)
158
-
159
- Ask questions and get answers grounded in context with citations.
 
160
  """)
161
-
162
- if not USE_OPENAI:
163
- gr.Markdown("""
164
- ⚠️ **OpenAI API Key Not Detected**
165
-
166
- To enable AI-generated answers:
167
- 1. Go to Space Settings
168
- 2. Add `OPENAI_API_KEY` as a repository secret
169
- 3. Restart the Space
170
-
171
- Currently showing raw context retrieval only.
172
- """)
173
 
174
  with gr.Row():
175
- q = gr.Textbox(
176
- label="Ask a question",
177
- placeholder="e.g., What is the capital of Germany?",
178
- lines=2
179
- )
180
- k = gr.Slider(1, 10, value=3, step=1, label="Number of Citations (top-k)")
181
-
182
- btn = gr.Button("🔍 Ask", variant="primary")
183
- ans = gr.Markdown(label="Answer")
184
- cites = gr.Dataframe(
185
- headers=["rank", "faiss_dist", "snippet"],
186
- datatype=["number","number","str"],
187
- row_count=(0, "dynamic"),
188
- label="Retrieved Contexts"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  )
190
- meta = gr.JSON(label="System Status")
191
-
192
- def _startup():
193
- try:
194
- msg = build_index()
195
- return {
196
- "status": msg,
197
- "openai_enabled": USE_OPENAI,
198
- "openai_model": OPENAI_MODEL if USE_OPENAI else None,
199
- "embed_model": MODEL_NAME
200
- }
201
- except Exception as e:
202
- return {"status": f"Startup build failed: {e}", "openai_enabled": False}
203
-
204
- demo.load(_startup, inputs=None, outputs=meta)
205
- btn.click(answer, [q, k], [ans, cites, meta])
206
- q.submit(answer, [q, k], [ans, cites, meta]) # Allow Enter key to submit
207
 
208
  if __name__ == "__main__":
209
- build_index()
210
  demo.launch()
 
1
+ import os
2
+ import gradio as gr
3
+ import google.generativeai as genai
 
 
4
 
5
+ # Gemini setup
6
+ GOOGLE_API_KEY = 'AIzaSyD17tAA1QiJlGrzQXgjKc4OShU_sF2_UAI'
7
+ if not GOOGLE_API_KEY:
8
+ raise ValueError("GOOGLE_API_KEY must be set in Space Settings!")
9
 
10
+ genai.configure(api_key=GOOGLE_API_KEY)
11
 
12
+ # Try different model names that actually work
13
+ GEMINI_MODEL = os.getenv("GEMINI_MODEL", "gemini-2.0-flash")
14
+ print(f"[Q&A] Using Gemini model: {GEMINI_MODEL}")
15
+
16
+ # List available models for debugging
17
+ try:
18
+ print("[Q&A] Available models:")
19
+ for m in genai.list_models():
20
+ if 'generateContent' in m.supported_generation_methods:
21
+ print(f" - {m.name}")
22
+ except Exception as e:
23
+ print(f"[Q&A] Could not list models: {e}")
24
+
25
+ model = genai.GenerativeModel(GEMINI_MODEL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ def answer_question(question: str, temperature: float = 0.7):
29
+ """Generate an answer using Gemini"""
30
  if not question.strip():
31
+ return "Please enter a question.", {"status": "idle"}
32
+
33
+ try:
34
+ print(f"[Q&A] Processing question with temperature={temperature}")
35
+
36
+ response = model.generate_content(
37
+ question,
38
+ generation_config=genai.GenerationConfig(
39
+ temperature=temperature,
40
+ max_output_tokens=2048,
 
 
 
 
 
 
 
41
  )
42
+ )
43
+
44
+ answer = response.text
45
+ print("[Q&A] Response received successfully")
46
+
47
+ return answer, {
48
+ "status": "success",
49
+ "model": GEMINI_MODEL,
50
+ "temperature": temperature
51
+ }
52
+
53
+ except Exception as e:
54
+ error_msg = f"Error: {str(e)}\n\nTry one of these models in Space Settings:\n- gemini-1.5-flash-latest\n- gemini-1.5-pro-latest\n- models/gemini-1.5-flash\n- models/gemini-1.5-pro"
55
+ print(f"[Q&A] Error: {e}")
56
+ return error_msg, {"status": "error", "error": str(e)}
57
+
58
+
59
+ # UI
60
+ with gr.Blocks(theme=gr.themes.Soft(), title="Nyxion Labs Q&A") as demo:
 
61
  gr.Markdown("""
62
+ # Nyxion Labs · AI Q&A
63
+
64
+ Ask any question and get AI-generated answers.
65
+ Powered by Google Gemini.
66
  """)
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  with gr.Row():
69
+ with gr.Column(scale=4):
70
+ question = gr.Textbox(
71
+ label="Ask a question",
72
+ placeholder="e.g., What is the capital of Pakistan?",
73
+ lines=3
74
+ )
75
+ with gr.Column(scale=1):
76
+ temperature = gr.Slider(
77
+ 0, 1,
78
+ value=0.7,
79
+ step=0.1,
80
+ label="Temperature",
81
+ info="Higher = more creative"
82
+ )
83
+
84
+ btn = gr.Button("Ask", variant="primary", size="lg")
85
+
86
+ answer = gr.Markdown(label="Answer")
87
+ meta = gr.JSON(label="System Status")
88
+
89
+ btn.click(answer_question, [question, temperature], [answer, meta])
90
+ question.submit(answer_question, [question, temperature], [answer, meta])
91
+
92
+ # Show startup status
93
+ demo.load(
94
+ lambda: {"status": "ready", "model": GEMINI_MODEL},
95
+ inputs=None,
96
+ outputs=meta
97
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
  if __name__ == "__main__":
 
100
  demo.launch()