|
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. |
|
""" |
|
|
|
sig = inspect.signature(func) |
|
type_hints = get_type_hints(func) |
|
|
|
|
|
docstring = inspect.getdoc(func) or "" |
|
|
|
|
|
title = func.__name__.replace("_", " ").title() |
|
|
|
if docstring.strip(): |
|
description = docstring.strip().replace("\n", "<br>") |
|
else: |
|
description = f"Interface for {func.__name__}" |
|
|
|
|
|
inputs = [] |
|
for param_name, param in sig.parameters.items(): |
|
param_type = type_hints.get(param_name, str) |
|
|
|
|
|
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: |
|
|
|
inputs.append( |
|
gr.Textbox( |
|
label=label, |
|
value=(str(default_value) if default_value is not None else ""), |
|
) |
|
) |
|
|
|
|
|
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: |
|
|
|
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) |
|
|