IlyaGusev's picture
Update app.py
93f24a6 verified
import gradio as gr
import inspect
import typing
from typing import get_type_hints
from academia_mcp.tools import (
arxiv_search,
arxiv_download,
s2_citations,
hf_datasets_search,
anthology_search,
)
def infer_gradio_interface(func):
"""
Automatically infer Gradio interface parameters from function signature
and docstring.
"""
# Get function signature
sig = inspect.signature(func)
type_hints = get_type_hints(func)
# Parse docstring
docstring = inspect.getdoc(func) or ""
# Extract title and description
title = func.__name__.replace("_", " ").title()
# Use the full docstring as description, convert newlines to HTML breaks
if docstring.strip():
description = docstring.strip().replace("\n", "<br>")
else:
description = f"Interface for {func.__name__}"
# Infer inputs
inputs = []
for param_name, param in sig.parameters.items():
param_type = type_hints.get(param_name, str)
# Get default value if available
default_value = None
if param.default is not inspect.Parameter.empty:
default_value = param.default
label = param_name.replace("_", " ").title()
if param_type == str or param_type == typing.Optional[str]:
inputs.append(
gr.Textbox(
label=label,
placeholder=f"Enter {param_name}",
value=default_value if default_value is not None else "",
)
)
elif param_type == int or param_type == typing.Optional[int]:
inputs.append(
gr.Number(
label=label,
precision=0,
value=default_value if default_value is not None else 0,
)
)
elif param_type == float or param_type == typing.Optional[float]:
inputs.append(
gr.Number(
label=label,
value=default_value if default_value is not None else 0.0,
)
)
elif param_type == bool or param_type == typing.Optional[bool]:
inputs.append(
gr.Checkbox(
label=label,
value=default_value if default_value is not None else False,
)
)
else:
# Default to textbox for unknown types
inputs.append(
gr.Textbox(
label=label,
value=(str(default_value) if default_value is not None else ""),
)
)
# Infer outputs
return_type = type_hints.get("return", str)
if return_type == str:
outputs = gr.Textbox(label="Result")
elif return_type == int:
outputs = gr.Number(label="Result", precision=0)
elif return_type == float:
outputs = gr.Number(label="Result")
elif return_type == list:
outputs = gr.JSON(label="Results")
elif return_type == dict:
outputs = gr.JSON(label="Result")
else:
# Default to textbox for unknown return types
outputs = gr.Textbox(label="Result")
return {
"fn": func,
"inputs": inputs,
"outputs": outputs,
"title": title,
"description": description,
}
arxiv_search_interface = infer_gradio_interface(arxiv_search)
arxiv_download_interface = infer_gradio_interface(arxiv_download)
s2_citations_interface = infer_gradio_interface(s2_citations)
hf_datasets_search_interface = infer_gradio_interface(hf_datasets_search)
anthology_search_interface = infer_gradio_interface(anthology_search)
search_demo = gr.Interface(**arxiv_search_interface)
download_demo = gr.Interface(**arxiv_download_interface)
s2_citations_demo = gr.Interface(**s2_citations_interface)
hf_datasets_search_demo = gr.Interface(**hf_datasets_search_interface)
anthology_search_demo = gr.Interface(**anthology_search_interface)
demo = gr.TabbedInterface(
[
search_demo,
download_demo,
s2_citations_demo,
hf_datasets_search_demo,
anthology_search_demo,
],
[
"ArXiv Search",
"ArXiv Download",
"S2 Citations",
"HF Datasets Search",
"Anthology Search",
],
title="Academia MCP Tools",
)
if __name__ == "__main__":
demo.launch(mcp_server=True)