File size: 6,794 Bytes
b10b6fd
 
 
 
 
 
0ce2aaa
b10b6fd
 
 
0ce2aaa
 
 
 
 
 
 
b10b6fd
 
 
 
f72945a
 
b10b6fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f72945a
b10b6fd
 
 
 
 
 
 
0ce2aaa
b10b6fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ce2aaa
b10b6fd
 
 
 
 
f72945a
b10b6fd
f72945a
b10b6fd
 
 
 
 
0ce2aaa
b10b6fd
 
f72945a
 
 
b10b6fd
f72945a
 
 
 
 
 
 
 
0ce2aaa
f72945a
 
 
0ce2aaa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b10b6fd
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
from typing import *
import httpx
from mcp.server.fastmcp import FastMCP

server = FastMCP(name="streamable-http-mcp-server-test", json_response=False, stateless_http=False)

async def make_request(url: str, method: Literal["GET", "POST"], data: Dict[str, Any] = {}):
    headers = {"Accept": "application/json"}
    async with httpx.AsyncClient(verify=False) as client:
        try:
            if method == "GET":
                response = await client.get(url, headers=headers)
            elif method == "POST":
                response = await client.post(url, headers=headers, json=data)
            else:
                print("Method not allowed !")
                return None
            response.raise_for_status()
            return response.json()
        except:
            return None

# arXiv
@server.tool()
async def search_academic_papers_arxiv(keyword: str, limit: int = 5) -> str:
    """
    Search papers from arXiv database with specified keywords [optional: a limit of papers the user wants]
    Args: keyword: string, [optional: limit: integer, set limit to 5 if not specified]
    """
    response = await make_request("https://organizedprogrammers-arxiv.hf.space/search", {"keyword": keyword, "limit": limit})
    if not response:
        return "Unable to find papers | No papers has been found"
    return "\n".join([f"arXiv n°{paper_id} - {paper_meta['title']} by {paper_meta['authors']} : {paper_meta['abstract']}" for paper_id, paper_meta in response['message'].items()])

@server.tool()
async def get_arxiv_pub_text(arxiv_id: str) -> str:
    """
    Extract publication PDF via arXiv ID
    Returns the full content of the publication
    Args: arxiv_id -> string
    """
    response = await make_request("https://organizedprogrammers-arxiv.hf.space/extract_pdf/arxiv_id", {"doc_id": arxiv_id})
    if not response:
        return "Unable to extract PDF | arXiv PDF not found"
    return response["message"]["text"]

# DocFinder
@server.tool()
async def get_document_url(doc_id: str) -> str:
    """
    Find technical document or specification from 3GPP / ETSI / GP by a document ID
    Returns the URL (also scope + version if doc is a specification [not all specifications have a version or scope])
    Arguments: doc_id -> string
    """
    response = await make_request('https://organizedprogrammers-docfinder.hf.space/find/single', "POST", {"doc_id": doc_id})
    if not response:
        return "Unable to find document/specification"
    version = response.get('version', 'unavailable')
    scope = response.get('scope', 'unavailable')
    return f'Downloadable !\nDoc No. {doc_id}\nURL : {response.get("url")}\nVersion : {version}\nScope : {scope}'

@server.tool()
async def search_specifications_with_keywords(keywords: str, threshold: int = 60, source: Literal["3GPP", "ETSI", "all"] = "all", spec_type: Optional[Literal["TS", "TR"]] = None):
    """
    Search specifications from 3GPP and/or ETSI with keywoeds (Based off BM25 scoring)
    Returns a list of specifications metadata that matches the similarity score threshold, the keywords, the source and specification type
    Arguments:
        - keywords -> string
        - threshold -> integer (by default, set to 60) [between 0-100]
        - source -> string (either '3GPP', 'ETSI' or 'all', by default, set to 'all')
        - spec_type -> string (either 'TS' or 'TR' or None, by default, set to None)
    """
    response = await make_request('https://organizedprogrammers-docfinder.hf.space/search/bm25', "POST", {"keywords": keywords, "threshold": threshold, "source": source, "spec_type": spec_type})
    if not response:
        return "Unable to search specifications | No specifications has been found"
    results = response["results"]
    return "\n---\n".join([f"Specification ID: {spec['id']}\nTitle: {spec['title']}\nType: {'Technical Specification' if spec['spec_type'] == 'TS' else 'Technical Report'}\nVersion: {spec.get('version', 'unavailable')}\nScope: {spec.get('scope', 'unavailable')}\nWorking Group: {spec.get('working_group', 'not defined')}\nURL: {spec.get('url', 'unavailable')}" for spec in results])

# SpecSplitter
@server.tool()
async def get_spec_text(spec_id: str) -> str:
    """
    Extract specification from 3GPP or ETSI
    Returns a dictionary k:v where k is the section (1., 2.2.1, ...) and v, the content of k, or a string if failed
    Args: spec_id -> string
    """
    response = await make_request('https://organizedprogrammers-specsplitter.hf.space/extract_text/structured', "POST", {"spec_id": spec_id})
    if not response:
        return "Unable to extract specification text"
    return "\n".join([f"{k}: {v}" for k, v in response.keys()])

# SERPent

@server.tool()
async def search_google_patents(queries: List[str], n_results: int) -> str:
    """
    Search patents from Google Patents
    You can generate multiple queries (at least 1)
    Returns a list of patents from queries, for each query, {n_results} patents will be retrieved
    Args: queries -> list of string, n_results -> integer [by default: 10]
    """
    response = await make_request("https://organizedprogrammers-serpent.hf.space/serp/search_patents", "POST", {"queries": queries, "n_results": n_results})
    if not response:
        return "Unable to fetch patents"
    return "\n".join(f"[Patent ID: {patent['id']} | Title: {patent['title']} | Body: {patent['body']}]" for patent in response.results)

@server.tool()
async def scrap_google_patents(patent_ids: List[str]) -> str:
    """
    Scrap patents from one or many patents from Google Patents
    Returns a list of patents with their title, abstract, description, claims, field of invention and background
    Args: patent_ids -> list of strings corresponding to Google Patent ID [min. 1]
    """
    if len(patent_ids) > 1:
        response = await make_request("https://organizedprogrammers-serpent.hf.space/scrap/scrap_patents_bulk", "POST", {"patent_ids": patent_ids})
        if not response:
            return "Unable to scrap patents"
        return "\n---\n".join([f"Title: {pat['title']}\nAbstract: {pat['abstract']}\nDescription: {pat['description']}\nClaims: {pat['claims']}\nField of invention{pat['field_of_invention']}\nBackground: {pat['background']}" for pat in response['patents']])
    elif len(patent_ids) == 1:
        response = await make_request("https://organizedprogrammers-serpent.hf.space/scrap/scrap_patent/"+patent_ids[0], "GET")
        if not response:
            return "Unable to scrap patent"
        return f"Title: {response['title']}\nAbstract: {response['abstract']}\nDescription: {response['description']}\nClaims: {response['claims']}\nField of invention{response['field_of_invention']}\nBackground: {response['background']}"

app = server.streamable_http_app