File size: 6,810 Bytes
b10b6fd
 
 
 
 
 
0ce2aaa
b10b6fd
 
 
0ce2aaa
 
 
 
 
 
 
b10b6fd
 
 
 
f72945a
 
b10b6fd
 
 
 
 
 
423e2c9
b10b6fd
 
 
 
 
 
 
 
 
 
 
423e2c9
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", "POST", {"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", "POST", {"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