decodingdatascience commited on
Commit
77c2f68
·
verified ·
1 Parent(s): 598f52b

Update app3.py

Browse files
Files changed (1) hide show
  1. app3.py +297 -89
app3.py CHANGED
@@ -1,108 +1,316 @@
1
- # Section 2: FAQ (FOR CHALLENGE PARTICIPANTS)
2
- with gr.Column(scale=4):
3
- gr.HTML(
4
- """
5
- <div class="dds-card">
6
- <h3 class="dds-section-title">Section 2 — Challenge FAQ</h3>
7
- <p class="dds-muted">
8
- Quick answers for participants. If something isn’t answered here, ask the Copilot in the chat.
9
- </p>
10
- </div>
11
- """
12
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- with gr.Accordion("FAQ 1 — What should I build for this challenge?", open=False):
15
- gr.Markdown(
16
- """
17
- - Build a simple AI application that matches one of the challenge paths (e.g., LLM/API integration, no-code/low-code, etc.).
18
- - Your goal is a **working demo** + **proof-of-work** you can share.
19
- - Ask in chat: *“What are good project ideas that fit the rules in this challenge?”*
20
- """.strip()
21
- )
22
 
23
- with gr.Accordion("FAQ 2 — What are the paths/tracks and which one should I choose?", open=False):
24
- gr.Markdown(
25
- """
26
- - Choose based on your comfort level:
27
- - **LLM/API Integration Path:** Python + API calls + basic RAG patterns
28
- - **No-code/Low-code Path:** build fast using tooling
29
- - **Sponsor/Tool-specific path (if applicable):** follow the workshop/demo tool
30
- - Ask in chat: *“Given my background (X), which path fits best and why?”*
31
- """.strip()
 
32
  )
33
 
34
- with gr.Accordion("FAQ 3 What is the minimum deliverable to be eligible?", open=False):
35
- gr.Markdown(
36
- """
37
- Typical minimum for eligibility:
38
- - A working app link (Gradio / Hugging Face / Streamlit / etc.)
39
- - A short description + how to use it
40
- - A repo or shared proof-of-work (optional but recommended)
41
- Ask in chat: *“What is the minimum submission requirement mentioned in the challenge doc?”*
42
- """.strip()
43
  )
44
 
45
- with gr.Accordion("FAQ 4 — How do I submit my project?", open=False):
46
- gr.Markdown(
47
- """
48
- - Usually you submit:
49
- - App URL (where judges can open it)
50
- - Repo URL (optional but strong)
51
- - Short write-up + screenshots/video (if required)
52
- Ask in chat: *“What is the official submission format and where do I submit?”*
53
- """.strip()
 
 
 
 
 
 
 
 
 
 
54
  )
55
 
56
- with gr.Accordion("FAQ 5 — Where should I deploy so judges can access easily?", open=False):
57
- gr.Markdown(
58
- """
59
- Low-friction options (no install needed):
60
- - **Hugging Face Spaces (Gradio)** ✅ easiest for demos
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  - **Streamlit Community Cloud**
62
- - **Vercel (for web apps)**
63
- Ask in chat: *“Which deployment options are recommended in the challenge rules?”*
64
- """.strip()
65
- )
66
 
67
- with gr.Accordion("FAQ 6 — What do judges usually look for?", open=False):
68
- gr.Markdown(
69
- """
70
- Common judging signals:
71
- - **Working demo** (no errors, easy to use)
72
- - Clear problem statement + target user
73
- - Good AI behavior (grounded answers, guardrails, no hallucination)
74
  - Product thinking (UX, clarity, flow)
75
- Ask in chat: *“What are the judging criteria stated in the challenge document?”*
76
- """.strip()
77
- )
78
 
79
- with gr.Accordion("FAQ 7 — What should I post on LinkedIn (proof-of-work)?", open=False):
80
- gr.Markdown(
81
- """
82
- Strong proof-of-work post includes:
83
  - 1-line problem + who it helps
84
  - Demo link + screenshot/GIF
85
  - What you learned + next improvement
86
- Ask in chat: *“Give me a LinkedIn post draft based on my project and this challenge.”*
87
- """.strip()
88
- )
89
 
90
- with gr.Accordion("FAQ 8 — How do I make my app ‘RAG grounded’ (not hallucinating)?", open=False):
91
- gr.Markdown(
92
- """
93
  Best practices:
94
- - Keep answers restricted to retrieved context
95
  - Show sources/snippets (optional but strong)
96
- - If missing info → respond “Not in document” and ask to add content
97
- Ask in chat: *“What does the document say about [X]? If not present, tell me what to add.”*
98
- """.strip()
99
- )
100
 
101
- with gr.Accordion("FAQ 9 — I can’t find a detail (dates/rules/prizes). What now?", open=False):
102
- gr.Markdown(
103
- f"""
104
- - The Copilot can only answer what is inside **{DOC_PATH.name}**.
105
- - If the official rule/prize/date isn’t in the TXT, add it and restart the Space.
106
- Ask in chat: *“What exact section should I add to the TXT to cover [missing detail]?”*
107
- """.strip()
108
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+ import gradio as gr
4
+
5
+ from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
6
+ from llama_index.llms.openai import OpenAI
7
+ from llama_index.embeddings.openai import OpenAIEmbedding
8
+
9
+
10
+ # ======================
11
+ # Config (safe defaults)
12
+ # ======================
13
+ MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
14
+ EMBED_MODEL = os.getenv("OPENAI_EMBED_MODEL", "text-embedding-3-small")
15
+ TOP_K = int(os.getenv("TOP_K", "3"))
16
+
17
+ # Knowledge base file in the Space repo root (recommended)
18
+ DOC_PATH = Path(os.getenv("DOC_PATH", "challenge_context.txt"))
19
+
20
+ # DDS logo (raw GitHub URL)
21
+ LOGO_URL = os.getenv(
22
+ "LOGO_URL",
23
+ "https://github.com/Decoding-Data-Science/airesidency/blob/main/dds_logo.jpg?raw=true",
24
+ )
25
+
26
+ # Behavior / guardrails
27
+ SYSTEM_GUARDRAILS = (
28
+ "You are Challenge Copilot. Answer ONLY using the provided context from challenge_context.txt. "
29
+ "If the answer is not in the context, say: 'I don’t know based on the current document.' "
30
+ "Then ask the user to add the missing official details to challenge_context.txt."
31
+ )
32
+
33
+ APP_TITLE = "Challenge Copilot — RAG Q&A Bot"
34
+ APP_SUBTITLE = (
35
+ "Ask questions about the Building AI Application Challenge using the official content you put into "
36
+ "challenge_context.txt (LlamaIndex + OpenAI)."
37
+ )
38
+
39
+
40
+ # ======================
41
+ # Index build (cached)
42
+ # ======================
43
+ _INDEX = None
44
+ _QUERY_ENGINE = None
45
 
 
 
 
 
 
 
 
 
46
 
47
+ def build_index():
48
+ """Build and cache the LlamaIndex query engine."""
49
+ global _INDEX, _QUERY_ENGINE
50
+ if _QUERY_ENGINE is not None:
51
+ return _QUERY_ENGINE
52
+
53
+ # OpenAI key must exist in Space secrets
54
+ if not os.getenv("OPENAI_API_KEY"):
55
+ raise RuntimeError(
56
+ "OPENAI_API_KEY is missing. Add it in the Space → Settings → Variables and secrets."
57
  )
58
 
59
+ # Create placeholder TXT if missing so Space can boot
60
+ if not DOC_PATH.exists():
61
+ DOC_PATH.write_text(
62
+ "Add the official Building AI Application Challenge content here.\n",
63
+ encoding="utf-8",
 
 
 
 
64
  )
65
 
66
+ # LlamaIndex global settings
67
+ Settings.llm = OpenAI(model=MODEL, temperature=0.2)
68
+ Settings.embed_model = OpenAIEmbedding(model=EMBED_MODEL)
69
+ Settings.chunk_size = 800
70
+ Settings.chunk_overlap = 120
71
+
72
+ # Reader expects a directory
73
+ data_dir = str(DOC_PATH.parent)
74
+ docs = SimpleDirectoryReader(
75
+ input_dir=data_dir,
76
+ required_exts=[".txt"],
77
+ recursive=False,
78
+ ).load_data()
79
+
80
+ # Only index the target file
81
+ docs = [d for d in docs if d.metadata.get("file_name") == DOC_PATH.name]
82
+ if not docs:
83
+ raise FileNotFoundError(
84
+ f"Could not load {DOC_PATH.name}. Make sure it exists in the repo root (or set DOC_PATH env var)."
85
  )
86
 
87
+ _INDEX = VectorStoreIndex.from_documents(docs)
88
+ _QUERY_ENGINE = _INDEX.as_query_engine(similarity_top_k=TOP_K)
89
+ return _QUERY_ENGINE
90
+
91
+
92
+ def format_sources(resp, max_sources=3, max_chars=240):
93
+ """Format top retrieved chunks for transparency."""
94
+ lines = []
95
+ for i, sn in enumerate(getattr(resp, "source_nodes", [])[:max_sources], start=1):
96
+ fn = sn.node.metadata.get("file_name", "unknown")
97
+ snippet = sn.node.get_content().replace("\n", " ").strip()[:max_chars]
98
+ score = getattr(sn, "score", None)
99
+ score_txt = f" (score={score:.3f})" if isinstance(score, (float, int)) else ""
100
+ lines.append(f"{i}. {fn}{score_txt}: {snippet}...")
101
+ return "\n".join(lines) if lines else "No sources returned."
102
+
103
+
104
+ def chat(message, history):
105
+ """Chat handler used by Gradio ChatInterface."""
106
+ qe = build_index()
107
+
108
+ prompt = (
109
+ f"{SYSTEM_GUARDRAILS}\n\n"
110
+ f"User question: {message}\n"
111
+ f"Answer using ONLY the context."
112
+ )
113
+
114
+ resp = qe.query(prompt)
115
+ answer = str(resp).strip()
116
+
117
+ show_sources = os.getenv("SHOW_SOURCES", "true").lower() == "true"
118
+ if show_sources:
119
+ answer += "\n\n---\n**Sources:**\n" + format_sources(resp, max_sources=TOP_K)
120
+
121
+ return answer
122
+
123
+
124
+ # ======================
125
+ # UI (professional layout)
126
+ # ======================
127
+ CSS = """
128
+ /* Global polish */
129
+ .dds-header { display:flex; align-items:center; gap:16px; }
130
+ .dds-logo img { height:60px; width:auto; border-radius:10px; box-shadow: 0 2px 10px rgba(0,0,0,0.10); }
131
+ .dds-title { margin:0; line-height:1.1; }
132
+ .dds-subtitle { margin:6px 0 0 0; color: #555; }
133
+ .dds-muted { color: #666; font-size: 0.95rem; }
134
+ .dds-card { border: 1px solid rgba(0,0,0,0.08); border-radius: 14px; padding: 14px; background: rgba(255,255,255,0.7); }
135
+ .dds-section-title { margin: 0 0 6px 0; }
136
+ """
137
+
138
+ # Theme fallback (don’t pass theme to ChatInterface to avoid older-gradio errors)
139
+ try:
140
+ theme_obj = gr.themes.Soft()
141
+ except Exception:
142
+ theme_obj = None
143
+
144
+ with gr.Blocks(theme=theme_obj, css=CSS, title=APP_TITLE) as demo:
145
+ # Header row (Logo left + Title right)
146
+ with gr.Row():
147
+ with gr.Column(scale=1, min_width=140):
148
+ gr.HTML(
149
+ f"""
150
+ <div class="dds-logo">
151
+ <img src="{LOGO_URL}" alt="DDS Logo"/>
152
+ </div>
153
+ """
154
+ )
155
+ with gr.Column(scale=6):
156
+ gr.HTML(
157
+ f"""
158
+ <div class="dds-header">
159
+ <div>
160
+ <h2 class="dds-title">{APP_TITLE}</h2>
161
+ <p class="dds-subtitle">{APP_SUBTITLE}</p>
162
+ <p class="dds-muted">
163
+ If something is missing, add official details to <b>{DOC_PATH.name}</b> and restart the Space.
164
+ </p>
165
+ </div>
166
+ </div>
167
+ """
168
+ )
169
+
170
+ gr.Markdown("---")
171
+
172
+ # Two sections: Chat + Challenge FAQ
173
+ with gr.Row():
174
+ # Section 1: Chat
175
+ with gr.Column(scale=6):
176
+ gr.HTML(
177
+ """
178
+ <div class="dds-card">
179
+ <h3 class="dds-section-title">Section 1 — Ask the Copilot</h3>
180
+ <p class="dds-muted">RAG flow: retrieve relevant chunks → generate a grounded answer using your LLM API.</p>
181
+ </div>
182
+ """
183
+ )
184
+
185
+ # IMPORTANT: No theme= here (avoids your earlier error)
186
+ gr.ChatInterface(
187
+ fn=chat,
188
+ examples=[
189
+ "What will I build in this live session?",
190
+ "Who is this best for?",
191
+ "What are the prerequisites?",
192
+ "What is the RAG flow in this project?",
193
+ "What should I submit (link + repo + write-up)?",
194
+ ],
195
+ )
196
+
197
+ # Section 2: Challenge FAQ (participant-focused)
198
+ with gr.Column(scale=4):
199
+ gr.HTML(
200
+ """
201
+ <div class="dds-card">
202
+ <h3 class="dds-section-title">Section 2 — Challenge FAQ</h3>
203
+ <p class="dds-muted">
204
+ Quick guidance for participants. If something is not answered here, ask in the Copilot chat.
205
+ </p>
206
+ </div>
207
+ """
208
+ )
209
+
210
+ with gr.Accordion("FAQ 1 — What should I build for this challenge?", open=False):
211
+ gr.Markdown(
212
+ """
213
+ - Build a simple AI application aligned to the challenge tracks (LLM/API, no-code/low-code, sponsor tool track, etc.).
214
+ - Aim for a **working demo** + **proof-of-work** you can share.
215
+ - Ask in chat: *“Suggest 5 project ideas that fit the official rules in the document.”*
216
+ """.strip()
217
+ )
218
+
219
+ with gr.Accordion("FAQ 2 — Which track/path should I choose?", open=False):
220
+ gr.Markdown(
221
+ """
222
+ - Pick based on your level:
223
+ - **LLM/API Integration:** Python + API + simple RAG patterns
224
+ - **No-code/Low-code:** fastest to ship, less code
225
+ - **Sponsor/tool track:** follow the workshop tool (if applicable)
226
+ - Ask in chat: *“Given my background (X), which track is best and why?”*
227
+ """.strip()
228
+ )
229
+
230
+ with gr.Accordion("FAQ 3 — What is the minimum deliverable to be eligible?", open=False):
231
+ gr.Markdown(
232
+ """
233
+ Typical minimum:
234
+ - A working **app link** that judges can open
235
+ - A short description (problem + user + how to use)
236
+ - Repo is optional but strongly recommended
237
+ Ask in chat: *“What does the official document say about minimum submission requirements?”*
238
+ """.strip()
239
+ )
240
+
241
+ with gr.Accordion("FAQ 4 — How do I submit my project?", open=False):
242
+ gr.Markdown(
243
+ """
244
+ Common submission package:
245
+ - App URL (Hugging Face Spaces / Streamlit / etc.)
246
+ - Repo URL (optional but strong)
247
+ - Short write-up + screenshots/video (if required)
248
+ Ask in chat: *“What is the official submission format and where is the submission link?”*
249
+ """.strip()
250
+ )
251
+
252
+ with gr.Accordion("FAQ 5 — Where should I deploy so judges can access easily?", open=False):
253
+ gr.Markdown(
254
+ """
255
+ Low-friction options:
256
+ - **Hugging Face Spaces (Gradio)** — easiest for demos
257
  - **Streamlit Community Cloud**
258
+ - **Vercel** (for web apps)
259
+ Ask in chat: *“What deployment options are recommended in the official challenge doc?”*
260
+ """.strip()
261
+ )
262
 
263
+ with gr.Accordion("FAQ 6 — What do judges usually look for?", open=False):
264
+ gr.Markdown(
265
+ """
266
+ Strong signals:
267
+ - Working demo (no errors, easy to use)
268
+ - Clear problem + target audience
269
+ - Good AI behavior (grounded, safe, consistent)
270
  - Product thinking (UX, clarity, flow)
271
+ Ask in chat: *“What are the judging criteria in the official document?”*
272
+ """.strip()
273
+ )
274
 
275
+ with gr.Accordion("FAQ 7 — What should I post as proof-of-work?", open=False):
276
+ gr.Markdown(
277
+ """
278
+ Suggested proof post structure:
279
  - 1-line problem + who it helps
280
  - Demo link + screenshot/GIF
281
  - What you learned + next improvement
282
+ Ask in chat: *“Draft a proof-of-work post based on my project idea.”*
283
+ """.strip()
284
+ )
285
 
286
+ with gr.Accordion("FAQ 8 — How do I make my app ‘RAG grounded’ (not hallucinating)?", open=False):
287
+ gr.Markdown(
288
+ """
289
  Best practices:
290
+ - Restrict answers to retrieved context
291
  - Show sources/snippets (optional but strong)
292
+ - If missing info → say “Not in document” and request adding content
293
+ Ask in chat: *“Answer using only the document; if missing, tell me what section to add.”*
294
+ """.strip()
295
+ )
296
 
297
+ with gr.Accordion("FAQ 9 — I can’t find a detail (dates/rules/prizes). What now?", open=False):
298
+ gr.Markdown(
299
+ f"""
300
+ - The Copilot can only answer what exists inside **{DOC_PATH.name}**.
301
+ - If the official detail isn’t in the TXT, add it, commit, and restart the Space.
302
+ Ask in chat: *“What exact section should I add to cover [missing detail]?”*
303
+ """.strip()
304
+ )
305
+
306
+ gr.Markdown("---")
307
+ gr.Markdown(
308
+ f"""
309
+ **Admin notes**
310
+ - Context file: `{DOC_PATH.name}`
311
+ - Optional env vars: `OPENAI_MODEL`, `OPENAI_EMBED_MODEL`, `TOP_K`, `SHOW_SOURCES`, `DOC_PATH`, `LOGO_URL`
312
+ """.strip()
313
+ )
314
+
315
+ if __name__ == "__main__":
316
+ demo.launch()