gusdelact's picture
Upload folder using huggingface_hub
57e7291 verified
Raw
History Blame
6.19 kB
"""
Gradio app v2 que expone las 4 tools como MCP Server (streamable HTTP).
Diferencia con v1: la base ChromaDB se descarga del dataset HF Hub al primer
uso. La carga del modelo de embeddings + descarga del snapshot se hace lazy
en la primera tool call, no al arrancar el Space.
Local:
uv run python -m rag_books_mcp.app
HF Spaces:
Ver `deploy_to_hf_space.py`.
"""
from __future__ import annotations
import gradio as gr
from rag_books_mcp.tools import (
cite_foundation,
get_section,
list_available_topics,
search_theory,
)
def _build_search_tab() -> gr.Interface:
return gr.Interface(
fn=search_theory,
inputs=[
gr.Textbox(
label="query",
value="bias-variance tradeoff",
placeholder="Consulta en lenguaje natural",
),
gr.Radio(
choices=["all", "both", "esl", "islp", "fes", "pdsh", "r4ds"],
value="all",
label="book",
info="R4DS está en R/tidyverse; los principios se traducen a pandas/seaborn.",
),
gr.Slider(minimum=1, maximum=10, step=1, value=5, label="top_k"),
],
outputs=gr.Markdown(label="Resultados"),
title="🔎 search_theory",
description=(
"Búsqueda semántica en ESL, ISLP, FES, PDSH y R4DS. Devuelve los "
"fragmentos más relevantes ordenados por similitud."
),
api_name="search_theory",
)
def _build_get_section_tab() -> gr.Interface:
return gr.Interface(
fn=get_section,
inputs=[
gr.Radio(choices=["esl", "islp", "fes", "pdsh", "r4ds"], value="islp", label="book"),
gr.Textbox(
label="chapter",
value="8 Tree-Based Methods",
placeholder="Nombre del capítulo (búsqueda parcial soportada)",
),
gr.Textbox(
label="section",
value="",
placeholder="(Opcional) Nombre de la sección",
),
gr.Slider(minimum=1, maximum=15, step=1, value=5, label="max_chunks"),
],
outputs=gr.Markdown(label="Sección"),
title="📑 get_section",
description=(
"Recupera una sección específica de ESL, ISLP, FES, PDSH o R4DS. Si "
"no se encuentra por metadata, hace fallback a búsqueda semántica."
),
api_name="get_section",
)
def _build_cite_tab() -> gr.Interface:
return gr.Interface(
fn=cite_foundation,
inputs=[
gr.Textbox(
label="topic",
value="ridge regression",
placeholder="Tema a fundamentar (ej: 'bagging', 'feature selection', 'EDA')",
),
gr.Radio(
choices=["brief", "medium", "deep"],
value="medium",
label="detail_level",
),
],
outputs=gr.Markdown(label="Fundamentación"),
title="📚 cite_foundation",
description=(
"Fundamentación teórica que cita los 5 libros: ISLP (intuitivo), "
"ESL (riguroso), FES (feature engineering), PDSH (código Python) y "
"R4DS (workflow iterativo de EDA y data wrangling)."
),
api_name="cite_foundation",
)
def _build_list_topics_tab() -> gr.Interface:
return gr.Interface(
fn=list_available_topics,
inputs=[],
outputs=gr.Markdown(label="Contenido indexado"),
title="🗂️ list_available_topics",
description="Lista los capítulos y secciones indexados en ChromaDB.",
api_name="list_available_topics",
)
def build_demo() -> gr.Blocks:
"""Construye la UI tabulada del MCP Server v2."""
with gr.Blocks(title="rag-books-mcp v2 · ESL + ISLP + FES + PDSH + R4DS") as demo:
gr.Markdown(
"""
# 📖 RAG Books MCP v2 — ESL + ISLP + FES + PDSH + R4DS
Servidor MCP que expone búsqueda semántica sobre cinco libros de
referencia de Statistical Learning, Data Science y Data Wrangling:
- **ESL** — *The Elements of Statistical Learning* (Hastie, Tibshirani, Friedman)
- **ISLP** — *An Introduction to Statistical Learning with Python* (James, Witten, Hastie, Tibshirani)
- **FES** — *Feature Engineering and Selection* (Kuhn, Johnson)
- **PDSH** — *Python Data Science Handbook* (VanderPlas)
- **R4DS** — *R for Data Science, 2nd Ed.* (Wickham, Çetinkaya-Rundel, Grolemund) — _ejemplos en R/tidyverse, principios universales para EDA y data wrangling_
> ℹ️ R4DS está bajo licencia CC BY-NC-ND 3.0 US y está incluido en
> este dataset bajo uso académico. Detalles, atribución y mecanismo
> de takedown en el [DATA_CARD del dataset](https://huggingface.co/datasets/gusdelact/rag-esl-islp-chromadb).
**v2 vs v1:** la base ChromaDB se carga desde el dataset HF
`gusdelact/rag-esl-islp-chromadb` (tag `v2.2.0`) en lugar de
empaquetarla con el código. Permite versionar el índice
independientemente y reusarlo desde otros clientes.
**Endpoint MCP:** `/gradio_api/mcp/` (streamable HTTP).
**Embeddings:** `sentence-transformers/all-MiniLM-L6-v2` (local, sin API key).
**Vector store:** ChromaDB con 3689 chunks (1093 ESL + 884 ISLP + 465 FES + 563 PDSH + 684 R4DS).
La primera tool call descarga el dataset (~95 MB). Las siguientes
son cache hit.
"""
)
gr.TabbedInterface(
interface_list=[
_build_search_tab(),
_build_cite_tab(),
_build_get_section_tab(),
_build_list_topics_tab(),
],
tab_names=["search_theory", "cite_foundation", "get_section", "list_available_topics"],
)
return demo
def main() -> None:
demo = build_demo()
demo.launch(mcp_server=True, server_name="0.0.0.0")
if __name__ == "__main__":
main()