André Oliveira commited on
Commit
c2fcdce
·
1 Parent(s): 07b4f45

refactored app

Browse files
Files changed (2) hide show
  1. README.md +5 -1
  2. app.py +442 -87
README.md CHANGED
@@ -31,7 +31,11 @@ Ragmint MCP Server exposes the full power of **Ragmint**, a modular Python libra
31
  ![Python](https://img.shields.io/badge/python-3.9%2B-blue)
32
  ![License](https://img.shields.io/badge/license-Apache%202.0-green)
33
  [![PyPI](https://img.shields.io/pypi/v/ragmint?color=blue)](https://pypi.org/project/ragmint/)
34
-
 
 
 
 
35
 
36
 
37
  ### Features exposed via MCP:
 
31
  ![Python](https://img.shields.io/badge/python-3.9%2B-blue)
32
  ![License](https://img.shields.io/badge/license-Apache%202.0-green)
33
  [![PyPI](https://img.shields.io/pypi/v/ragmint?color=blue)](https://pypi.org/project/ragmint/)
34
+ [![HF Space](https://img.shields.io/badge/HF-Space-blue)](https://huggingface.co/spaces/andyolivers/ragmint-mcp-server)
35
+ ![MCP](https://img.shields.io/badge/MCP-Enabled-green)
36
+ ![Status](https://img.shields.io/badge/Status-Beta-orange)
37
+ ![Optuna](https://img.shields.io/badge/Optuna-Bayesian%20Optimization-6f42c1?logo=optuna&logoColor=white)
38
+ ![Google Gemini 2.5](https://img.shields.io/badge/Google%20Gemini-LLM-lightblue?logo=google&logoColor=white)
39
 
40
 
41
  ### Features exposed via MCP:
app.py CHANGED
@@ -107,25 +107,25 @@ def upload_docs_tool(files, docs_path="data/docs"):
107
  pass
108
 
109
 
110
- def optimize_rag_tool(payload: str) -> str:
111
  """🔧 Explicit optimization request: user provides all pipeline configs manually."""
112
  return call_api("/optimize_rag", json.loads(payload))
113
 
114
 
115
- def autotune_tool(payload: str) -> str:
116
  """🔧 Autotune RAG: recommends chunk sizes and embedding models automatically."""
117
  return call_api("/autotune_rag", json.loads(payload))
118
 
119
 
120
- def generate_qa_tool(payload: str) -> str:
121
  """🧩 Generates a validation QA dataset for RAG evaluation."""
122
  return call_api("/generate_validation_qa", json.loads(payload))
123
 
124
 
125
  # Assign Pydantic docstrings
126
- optimize_rag_tool.__doc__ = OptimizeRequest.__doc__
127
- autotune_tool.__doc__ = AutotuneRequest.__doc__
128
- generate_qa_tool.__doc__ = QARequest.__doc__
129
 
130
 
131
  def model_to_json(model_cls) -> str:
@@ -140,92 +140,447 @@ DEFAULT_QA_JSON = model_to_json(QARequest)
140
 
141
 
142
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
143
- gr.Markdown("# Ragmint MCP Server")
144
-
145
- # Upload Documents
146
- with gr.Column():
147
- gr.Markdown("## Upload Documents")
148
- gr.Markdown("📂 Upload files (local paths or URLs) to your `data/docs` folder")
149
- upload_files = gr.File(file_count="multiple", type="filepath")
150
- upload_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path")
151
- upload_btn = gr.Button("Upload", variant="primary")
152
- upload_out = gr.JSON(label="Response")
153
- upload_btn.click(upload_docs_tool, inputs=[upload_files, upload_path], outputs=upload_out)
154
- gr.Markdown("---")
155
-
156
- # Upload MCP Documents (no file uploader)
157
- with gr.Column():
158
- gr.Markdown("## Upload Documents (URLs) via MCP")
159
- gr.Markdown("📂 Upload files (URLs) to your `data/docs` folder on MCP.")
160
- upload_mcp_input = gr.Textbox(
161
- lines=5,
162
- placeholder='Enter list of URLs (e.g., ["https://example.com/example.txt",...])',
163
- label="Files (JSON list)"
164
- )
165
- upload_mcp_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path")
166
- upload_mcp_out = gr.JSON(label="Response")
167
- upload_mcp_btn = gr.Button("Upload via MCP", variant="primary")
168
-
169
- # MCP callable function
170
- def upload_urls_tool(files_json, docs_path):
171
- """
172
- Upload documents to the server's docs folder via MCP.
173
- Accepts:
174
- - URLs (str)
175
- """
176
- import ast
177
- try:
178
- files = ast.literal_eval(files_json)
179
- except Exception:
180
- return {"error": "Invalid JSON list of files"}
181
- return upload_docs_tool(files, docs_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
- upload_mcp_btn.click(
184
- upload_urls_tool,
185
- inputs=[upload_mcp_input, upload_mcp_path],
186
- outputs=upload_mcp_out
187
- )
188
- gr.Markdown("---")
189
-
190
- # Optimize RAG
191
- with gr.Column():
192
- gr.Markdown("## Optimize RAG")
193
- gr.Markdown(OptimizeRequest.__doc__ or "No description available.")
194
- optimize_input = gr.Textbox(lines=12, value=DEFAULT_OPTIMIZE_JSON, label="OptimizeRequest JSON")
195
- optimize_btn = gr.Button("Submit", variant="primary")
196
- optimize_out = gr.Textbox(lines=15, label="Response")
197
- optimize_btn.click(optimize_rag_tool, inputs=optimize_input, outputs=optimize_out)
198
  gr.Markdown("---")
199
 
200
- # Autotune RAG
201
- with gr.Column():
202
- gr.Markdown("## Autotune RAG")
203
- gr.Markdown(AutotuneRequest.__doc__ or "No description available.")
204
- autotune_input = gr.Textbox(lines=12, value=DEFAULT_AUTOTUNE_JSON, label="AutotuneRequest JSON")
205
- autotune_btn = gr.Button("Submit", variant="primary")
206
- autotune_out = gr.Textbox(lines=15, label="Response")
207
- autotune_btn.click(autotune_tool, inputs=autotune_input, outputs=autotune_out)
208
- gr.Markdown("---")
209
 
210
- # Generate QA
211
- with gr.Column():
212
- gr.Markdown("## Generate QA")
213
- gr.Markdown(QARequest.__doc__ or "No description available.")
214
- qa_input = gr.Textbox(lines=12, value=DEFAULT_QA_JSON, label="QARequest JSON")
215
- qa_btn = gr.Button("Submit", variant="primary")
216
- qa_out = gr.Textbox(lines=15, label="Response")
217
- qa_btn.click(generate_qa_tool, inputs=qa_input, outputs=qa_out)
218
- gr.Markdown("---")
219
 
220
- # Clear Cache
221
- with gr.Column():
222
- gr.Markdown("## Clear Cache")
223
- gr.Markdown("🧹 Deletes all files and directories inside docs_path on the server.")
224
- clear_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path to Clear")
225
- clear_btn = gr.Button("Clear Cache", variant="primary")
226
- clear_out = gr.JSON(label="Response")
227
- clear_btn.click(clear_cache_tool, inputs=[clear_path], outputs=clear_out)
228
- gr.Markdown("---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
  if __name__ == "__main__":
231
 
 
107
  pass
108
 
109
 
110
+ def optimize_rag_tool_(payload: str) -> str:
111
  """🔧 Explicit optimization request: user provides all pipeline configs manually."""
112
  return call_api("/optimize_rag", json.loads(payload))
113
 
114
 
115
+ def autotune_tool_(payload: str) -> str:
116
  """🔧 Autotune RAG: recommends chunk sizes and embedding models automatically."""
117
  return call_api("/autotune_rag", json.loads(payload))
118
 
119
 
120
+ def generate_qa_tool_(payload: str) -> str:
121
  """🧩 Generates a validation QA dataset for RAG evaluation."""
122
  return call_api("/generate_validation_qa", json.loads(payload))
123
 
124
 
125
  # Assign Pydantic docstrings
126
+ optimize_rag_tool_.__doc__ = OptimizeRequest.__doc__
127
+ autotune_tool_.__doc__ = AutotuneRequest.__doc__
128
+ generate_qa_tool_.__doc__ = QARequest.__doc__
129
 
130
 
131
  def model_to_json(model_cls) -> str:
 
140
 
141
 
142
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
143
+ gr.Markdown("# 🤖 Ragmint MCP Server")
144
+
145
+ gr.HTML("""
146
+ <div style="display:flex; gap:5px; flex-wrap:wrap; align-items:center;">
147
+ <a href="https://huggingface.co/spaces/andyolivers/ragmint-mcp-server">
148
+ <img src="https://img.shields.io/badge/HF-Space-blue" alt="HF Space">
149
+ </a>
150
+ <img src="https://img.shields.io/badge/Python-3.9%2B-blue?logo=python" alt="Python">
151
+ <a href="https://pypi.org/project/ragmint/">
152
+ <img src="https://img.shields.io/pypi/v/ragmint?color=blue" alt="HF Space">
153
+ </a>
154
+ <img src="https://img.shields.io/badge/License-Apache%202.0-green" alt="License">
155
+ <img src="https://img.shields.io/badge/MCP-Enabled-green" alt="MCP">
156
+ <img src="https://img.shields.io/badge/Status-Beta-orange" alt="Status">
157
+ <img src="https://img.shields.io/badge/Optuna-Bayesian%20Optimization-6f42c1?logo=optuna&logoColor=white" alt="Optuna">
158
+ <img src="https://img.shields.io/badge/Google%20Gemini-LLM-lightblue?logo=google&logoColor=white" alt="Google Gemini 2.5">
159
+ </div>
160
+ """)
161
+
162
+ gr.Markdown("""
163
+ **AI-Powered Optimization for RAG Pipelines**
164
+
165
+ This server provides **6 MCP Tools** for RAG pipeline tuning, dataset generation & workspace control — all programmatically accessible through MCP clients like **Claude Desktop, Cursor, VS Code MCP Extension**, and more.
166
+
167
+ <br>
168
+
169
+ ## 🔧 MCP Tools (AI-Driven & Automated)
170
+
171
+ - 📄 **Upload Docs**: Upload .txt files to workspace for evaluation
172
+ - 🔗 **Upload URLs**: Import remote .txt docs via URLs
173
+ - 🧠 **Optimize RAG**: Full hyperparameter search (Grid / Random / Bayesian) with metrics
174
+ - ⚙️ **Autotune RAG**: Automated recommendations for best chunking + embeddings
175
+ - ❓ **Generate QA Dataset**: Create validation QA pairs with LLMs for benchmarking
176
+ - 🧹 **Clear Cache**: Reset workspace and delete stored docs
177
+
178
+ <br>
179
+
180
+ ## 🧠 What Ragmint Solves
181
+
182
+ - Automated RAG hyperparameter optimization
183
+ - Retriever, embedding, reranker selection
184
+ - Synthetic validation QA generation
185
+ - Evaluation metrics (faithfulness, latency, etc.)
186
+ - Experiment tracking & reproducible pipeline comparison
187
+
188
+ 🔬 **Built for RAG engineers, researchers, and LLM developers** who want consistent performance improvement without trial-and-error.
189
+
190
+ <br>
191
+
192
+ ## 🧠 Powered by
193
+
194
+ - **Optuna** (Bayesian Optimization)
195
+ - **Google Gemini 2.5 Flash Lite / Pro**
196
+ - **FAISS, Chroma, BM25, scikit-learn retrievers**
197
+ - **Sentence-Transformers / BGE embeddings**
198
+
199
+ <br>
200
+
201
+ ## 🌐 MCP Connection
202
+
203
+ **HuggingFace Space**
204
+ https://huggingface.co/spaces/andyolivers/ragmint-mcp-server
205
+
206
+ **MCP Endpoint (SSE — Recommended)**
207
+ https://andyolivers-ragmint-mcp-server.hf.space/gradio_api/mcp/sse
208
+
209
+ <br>
210
+
211
+ ## 📦 Example MCP Use Cases
212
+
213
+ - 🧠 Run Auto-Optimization for RAG pipelines
214
+ - 📊 Compare embedding + retriever combinations
215
+ - ❓ Automatically generate QA validation datasets
216
+ - 🔁 Rapid experiment iteration inside Claude / Cursor
217
+
218
+ <br>
219
+
220
+ ## 🧩 MCP Tools Overview
221
+
222
+ | MCP Tool | Core Function |
223
+ |----------|---------------|
224
+ | upload_docs | Upload .txt documents |
225
+ | upload_urls | Import documents from external URLs |
226
+ | optimize_rag | Hyperparameter search with metrics |
227
+ | autotune | Automated RAG configuration suggestions |
228
+ | generate_qa | Synthetic QA generation |
229
+ | clear_cache | Clean workspace |
230
+
231
+ ---
232
+
233
+ """)
234
+
235
+ with gr.Tab("📂 Upload"):
236
+ with gr.Row():
237
+ # Upload Documents
238
+ with gr.Column(scale=1):
239
+ gr.Markdown("## Upload Documents")
240
+ gr.Markdown("📂 Upload files (local paths or URLs) to your `data/docs` folder")
241
+ upload_files = gr.File(file_count="multiple", type="filepath")
242
+ upload_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path")
243
+ upload_btn = gr.Button("Upload", variant="primary")
244
+ upload_out = gr.JSON(label="Response")
245
+ upload_btn.click(upload_docs_tool, inputs=[upload_files, upload_path], outputs=upload_out)
246
+
247
+
248
+ # Upload MCP Documents (no file uploader)
249
+ with gr.Column(scale=1):
250
+ gr.Markdown("## Upload Documents from URLs")
251
+ gr.Markdown("📂 Upload files (URLs) to your `data/docs` folder on MCP.")
252
+ '''upload_mcp_input = gr.Textbox(
253
+ lines=5,
254
+ placeholder='Enter list of URLs (e.g., ["https://example.com/example.txt",...])',
255
+ label="Files (JSON list)"
256
+ )'''
257
+
258
+ upload_mcp_input = gr.TextArea(
259
+ placeholder="Paste URLs (one per line without commas)",
260
+ label="URLs"
261
+ )
262
+
263
+
264
+
265
+ def upload_urls_tool(text, path):
266
+ """
267
+ Upload documents to the server's docs folder via FastAPI /upload_docs.
268
+ Accepts:
269
+ - local file paths (str)
270
+ - URLs (str)
271
+ - file-like objects
272
+ """
273
+
274
+ urls = [u.strip() for u in text.split("\n") if u.strip()]
275
+ return upload_docs_tool(urls, path)
276
+
277
+ upload_mcp_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path")
278
+ upload_mcp_btn = gr.Button("Upload", variant="primary")
279
+ upload_mcp_out = gr.JSON(label="Response")
280
+
281
+ # MCP callable function
282
+ '''def upload_urls_tool(files_json, docs_path):
283
+ """
284
+ Upload documents to the server's docs folder via MCP.
285
+ Accepts:
286
+ - URLs (str)
287
+ """
288
+ import ast
289
+ try:
290
+ files = ast.literal_eval(files_json)
291
+ except Exception:
292
+ return {"error": "Invalid JSON list of files"}
293
+ return upload_docs_tool(files, docs_path)'''
294
+
295
+ upload_mcp_btn.click(
296
+ upload_urls_tool,
297
+ inputs=[upload_mcp_input, upload_mcp_path],
298
+ outputs=upload_mcp_out
299
+ )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  gr.Markdown("---")
302
 
 
 
 
 
 
 
 
 
 
303
 
 
 
 
 
 
 
 
 
 
304
 
305
+ with gr.Tab("⚡ Autotune"):
306
+ # Autotune RAG
307
+ with gr.Column():
308
+ gr.Markdown("## Autotune RAG")
309
+ gr.Markdown(" Automatically tunes RAG pipeline parameters based on document analysis.")
310
+
311
+ '''gr.Markdown(AutotuneRequest.__doc__ or "No description available.")
312
+ autotune_input = gr.Textbox(lines=12, value=DEFAULT_AUTOTUNE_JSON, label="AutotuneRequest JSON")
313
+ autotune_btn = gr.Button("Autotune", variant="primary")
314
+ autotune_out = gr.Textbox(lines=15, label="Response")
315
+ autotune_btn.click(autotune_tool, inputs=autotune_input, outputs=autotune_out)'''
316
+
317
+ with gr.Accordion("⚙ Settings", open=False):
318
+ docs_path = gr.Textbox(value="data/docs", label="Docs Path")
319
+
320
+ embedding_model = gr.Textbox(
321
+ value="sentence-transformers/all-MiniLM-L6-v2",
322
+ label="Embedding Model"
323
+ )
324
+
325
+ num_chunk_pairs = gr.Slider(
326
+ minimum=1, maximum=20, step=1, value=5, label="Number of chunk pairs"
327
+ )
328
+
329
+ metric = gr.Dropdown(
330
+ choices=["faithfulness"],
331
+ value="faithfulness",
332
+ label="Metric"
333
+ )
334
+
335
+ search_type = gr.Dropdown(
336
+ choices=["grid", "random", "bayesian"],
337
+ value="grid",
338
+ label="Search Type"
339
+ )
340
+
341
+ trials = gr.Slider(
342
+ minimum=1, maximum=100, step=1, value=5, label="Optimization Trials"
343
+ )
344
+
345
+ validation_choice = gr.Dropdown(
346
+ choices=["generate", ""],
347
+ value="generate",
348
+ label="Validation Choice"
349
+ )
350
+
351
+ llm_model = gr.Textbox(
352
+ value="gemini-2.5-flash-lite",
353
+ label="LLM Model"
354
+ )
355
+
356
+ autotune_btn = gr.Button("Autotune", variant="primary")
357
+ autotune_out = gr.Textbox(label="Response", lines=15)
358
+
359
+
360
+ def autotune_tool(*args):
361
+ (
362
+ docs_path, embedding_model, num_chunk_pairs, metric,
363
+ search_type, trials, validation_choice, llm_model
364
+ ) = args
365
+
366
+ payload = {
367
+ "docs_path": docs_path,
368
+ "embedding_model": embedding_model,
369
+ "num_chunk_pairs": num_chunk_pairs,
370
+ "metric": metric,
371
+ "search_type": search_type,
372
+ "trials": trials,
373
+ "validation_choice": validation_choice,
374
+ "llm_model": llm_model
375
+ }
376
+
377
+ return autotune_tool_(json.dumps(payload))
378
+
379
+
380
+ autotune_tool.__doc__ = AutotuneRequest.__doc__
381
+ autotune_btn.click(
382
+ autotune_tool,
383
+ inputs=[
384
+ docs_path, embedding_model, num_chunk_pairs, metric,
385
+ search_type, trials, validation_choice, llm_model
386
+ ],
387
+ outputs=autotune_out
388
+ )
389
+
390
+ with gr.Accordion("Parameter Information", open=False):
391
+ gr.Markdown(AutotuneRequest.__doc__ or "No description available.")
392
+
393
+ gr.Markdown("---")
394
+
395
+
396
+ with gr.Tab("🔧 Optimize"):
397
+ # Optimize RAG
398
+ with gr.Column():
399
+ gr.Markdown("## Optimize RAG")
400
+ gr.Markdown("🔧 Explicit optimization request for RAG (Retrieval-Augmented Generation) pipelines.")
401
+ '''gr.Markdown(OptimizeRequest.__doc__ or "No description available.")
402
+ optimize_input = gr.Textbox(lines=12, value=DEFAULT_OPTIMIZE_JSON, label="OptimizeRequest JSON")
403
+ optimize_btn = gr.Button("Optimize", variant="primary")
404
+ optimize_out = gr.Textbox(lines=15, label="Response")
405
+ optimize_btn.click(optimize_rag_tool, inputs=optimize_input, outputs=optimize_out)'''
406
+
407
+ # Parameters accordion
408
+ with gr.Accordion("⚙ Settings", open=False):
409
+ docs_path = gr.Textbox(value="data/docs", label="Docs Path")
410
+
411
+ retriever = gr.CheckboxGroup(
412
+ choices=["faiss", "chroma", "numpy", "sklearn","bm25"],
413
+ value="faiss",
414
+ label="Search Type"
415
+ )
416
+
417
+ embedding_model = gr.Textbox(
418
+ value="sentence-transformers/all-MiniLM-L6-v2",
419
+ label="Embedding Model(s) (comma-separated)"
420
+ )
421
+
422
+ strategy = gr.CheckboxGroup(
423
+ choices=["fixed","token","sentence"],
424
+ value="fixed",
425
+ label="RAG Strategy"
426
+ )
427
+
428
+
429
+ chunk_sizes = gr.Textbox(
430
+ value="200,400,600",
431
+ label="Chunk Sizes (comma-separated integers)"
432
+ )
433
+
434
+ overlaps = gr.Textbox(
435
+ value="50,100,200",
436
+ label="Overlaps (comma-separated integers)"
437
+ )
438
+
439
+ rerankers = gr.Dropdown(
440
+ choices=["mmr"],
441
+ value="mmr",
442
+ label="Rerankers"
443
+ )
444
+
445
+
446
+ search_type = gr.Dropdown(
447
+ choices=["grid", "random", "bayesian"],
448
+ value="grid",
449
+ label="Search Type"
450
+ )
451
+
452
+ trials = gr.Slider(
453
+ minimum=1, maximum=100, step=1, value=5,
454
+ label="Number of Trials"
455
+ )
456
+
457
+ metric = gr.Dropdown(
458
+ choices=["faithfulness"],
459
+ value="faithfulness",
460
+ label="Metric"
461
+ )
462
+
463
+ validation_choice = gr.Dropdown(
464
+ choices=["generate", ""],
465
+ value="generate",
466
+ label="Validation Choice"
467
+ )
468
+
469
+ llm_model = gr.Textbox(
470
+ value="gemini-2.5-flash-lite",
471
+ label="LLM Model"
472
+ )
473
+
474
+ optimize_btn = gr.Button("Optimize", variant="primary")
475
+ optimize_out = gr.Textbox(label="Response", lines=15)
476
+
477
+
478
+ # Function to convert inputs into payload and call API
479
+ def optimize_rag_tool(*args):
480
+ (
481
+ docs_path, retriever, embedding_model, strategy, chunk_sizes,
482
+ overlaps, rerankers, search_type, trials, metric,
483
+ validation_choice, llm_model
484
+ ) = args
485
+
486
+ payload = {
487
+ "docs_path": docs_path,
488
+ "retriever": [r.strip() for r in retriever.split(",") if r.strip()],
489
+ "embedding_model": [e.strip() for e in embedding_model.split(",") if e.strip()],
490
+ "strategy": [s.strip() for s in strategy.split(",") if s.strip()],
491
+ "chunk_sizes": [int(c) for c in chunk_sizes.split(",") if c.strip()],
492
+ "overlaps": [int(o) for o in overlaps.split(",") if o.strip()],
493
+ "rerankers": [r.strip() for r in rerankers.split(",") if r.strip()],
494
+ "search_type": search_type,
495
+ "trials": trials,
496
+ "metric": metric,
497
+ "validation_choice": validation_choice,
498
+ "llm_model": llm_model
499
+ }
500
+
501
+ return optimize_rag_tool_(json.dumps(payload))
502
+
503
+
504
+ optimize_rag_tool.__doc__ = OptimizeRequest.__doc__
505
+
506
+ optimize_btn.click(
507
+ optimize_rag_tool,
508
+ inputs=[
509
+ docs_path, retriever, embedding_model, strategy, chunk_sizes,
510
+ overlaps, rerankers, search_type, trials, metric,
511
+ validation_choice, llm_model
512
+ ],
513
+ outputs=optimize_out
514
+ )
515
+
516
+
517
+ with gr.Accordion("Parameter Information", open=False):
518
+ gr.Markdown(OptimizeRequest.__doc__ or "No description available.")
519
+ gr.Markdown("---")
520
+
521
+
522
+ with gr.Tab("🧩 Generate QA"):
523
+ # Generate QA
524
+ with gr.Column():
525
+ '''gr.Markdown("## Generate QA")
526
+ gr.Markdown(QARequest.__doc__ or "No description available.")
527
+ qa_input = gr.Textbox(lines=12, value=DEFAULT_QA_JSON, label="QARequest JSON")
528
+ qa_btn = gr.Button("Submit", variant="primary")
529
+ qa_out = gr.Textbox(lines=15, label="Response")
530
+ qa_btn.click(generate_qa_tool, inputs=qa_input, outputs=qa_out)
531
+ gr.Markdown("---")'''
532
+
533
+ gr.Markdown("## Generate QA")
534
+ gr.Markdown("🧩 Generate a validation QA dataset from documents for RAG evaluation.")
535
+
536
+ with gr.Tab("🧩 Generate QA"):
537
+
538
+ with gr.Accordion("⚙ Settings", open=False):
539
+ docs_path = gr.Textbox(value="data/docs", label="Docs Path")
540
+ llm_model = gr.Textbox(value="gemini-2.5-flash-lite", label="LLM Model")
541
+ batch_size = gr.Slider(1, 50, step=1, value=5, label="Batch Size")
542
+ min_q = gr.Slider(1, 20, step=1, value=3, label="Min Questions")
543
+ max_q = gr.Slider(1, 50, step=1, value=25, label="Max Questions")
544
+
545
+ qa_btn = gr.Button("Generate QA", variant="primary")
546
+ qa_out = gr.Textbox(lines=15, label="Response")
547
+
548
+
549
+ def generate_qa_tool(*args):
550
+ docs_path, llm_model, batch_size, min_q, max_q = args
551
+ return generate_qa_tool_(json.dumps({
552
+ "docs_path": docs_path,
553
+ "llm_model": llm_model,
554
+ "batch_size": batch_size,
555
+ "min_q": min_q,
556
+ "max_q": max_q
557
+ }))
558
+
559
+
560
+ generate_qa_tool.__doc__ = QARequest.__doc__
561
+
562
+ qa_btn.click(
563
+ generate_qa_tool,
564
+ inputs=[docs_path, llm_model, batch_size, min_q, max_q],
565
+ outputs=qa_out
566
+ )
567
+
568
+ with gr.Accordion("Parameter Information", open=False):
569
+ gr.Markdown(QARequest.__doc__ or "No description available.")
570
+
571
+ gr.Markdown("---")
572
+
573
+
574
+ with gr.Tab("🧹 Clear Cache"):
575
+ # Clear Cache
576
+ with gr.Column():
577
+ gr.Markdown("## Clear Cache")
578
+ gr.Markdown("🧹 Deletes all files and directories inside docs_path on the server.")
579
+ clear_path = gr.Textbox(value=DEFAULT_UPLOAD_PATH, label="Docs Path to Clear")
580
+ clear_btn = gr.Button("Clear Cache", variant="primary")
581
+ clear_out = gr.JSON(label="Response")
582
+ clear_btn.click(clear_cache_tool, inputs=[clear_path], outputs=clear_out)
583
+ gr.Markdown("---")
584
 
585
  if __name__ == "__main__":
586