Spaces:
Sleeping
Sleeping
File size: 6,186 Bytes
2e3520f 55d52e5 57e7291 55d52e5 57e7291 55d52e5 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 55d52e5 57e7291 55d52e5 57e7291 2e3520f 57e7291 2e3520f 57e7291 2e3520f 55d52e5 2e3520f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | """
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()
|