om4r932 commited on
Commit
b10b6fd
·
1 Parent(s): 21df229

First version

Browse files
Files changed (3) hide show
  1. Dockerfile +13 -0
  2. app.py +83 -0
  3. requirements.txt +4 -0
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11.3
2
+
3
+ RUN useradd -m -u 1000 user
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
+
7
+ WORKDIR /app
8
+
9
+ COPY --chown=user ./requirements.txt requirements.txt
10
+ RUN pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --no-cache-dir --upgrade -r requirements.txt
11
+
12
+ COPY --chown=user . /app
13
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import *
2
+ import httpx
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+ server = FastMCP(name="streamable-http-mcp-server-test", json_response=False, stateless_http=False)
6
+
7
+ async def make_request(url: str, data: Dict[str, Any]):
8
+ headers = {"Accept": "application/json"}
9
+ async with httpx.AsyncClient(verify=False) as client:
10
+ try:
11
+ response = await client.post(url, headers=headers, json=data)
12
+ response.raise_for_status()
13
+ return response.json()
14
+ except:
15
+ return None
16
+
17
+ @server.tool()
18
+ async def search_academic_papers_arxiv(keyword: str, limit: int = 5) -> str:
19
+ """
20
+ Search papers from arXiv database with specified keywords [optional: a limit of papers the user wants]
21
+ Args: keyword: string, [optional: limit: integer, set limit to 5 if not specified]
22
+ """
23
+ response = await make_request("https://organizedprogrammers-arxiv.hf.space/search", {"keyword": keyword, "limit": limit})
24
+ if not response:
25
+ return "Unable to find papers | No papers has been found"
26
+ 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()])
27
+
28
+ @server.tool()
29
+ async def get_arxiv_pub_text(arxiv_id: str) -> str:
30
+ """
31
+ Extract publication PDF via arXiv ID
32
+ Returns the full content of the publication
33
+ Args: arxiv_id -> string
34
+ """
35
+ response = await make_request("https://organizedprogrammers-arxiv.hf.space/extract_pdf/arxiv_id", {"doc_id": arxiv_id})
36
+ if not response:
37
+ return "Unable to extract PDF | arXiv PDF not found"
38
+ return response["message"]["text"]
39
+
40
+ @server.tool()
41
+ async def get_document_url(doc_id: str) -> str:
42
+ """
43
+ Find technical document or specification from 3GPP / ETSI / GP by a document ID
44
+ Returns the URL (also scope + version if doc is a specification [not all specifications have a version or scope])
45
+ Arguments: doc_id -> string
46
+ """
47
+ response = await make_request('https://organizedprogrammers-docfinder.hf.space/find/single', {"doc_id": doc_id})
48
+ if not response:
49
+ return "Unable to find document/specification"
50
+ version = response.get('version', 'unavailable')
51
+ scope = response.get('scope', 'unavailable')
52
+ return f'Downloadable !\nDoc No. {doc_id}\nURL : {response.get("url")}\nVersion : {version}\nScope : {scope}'
53
+
54
+ @server.tool()
55
+ async def search_specifications_with_keywords(keywords: str, threshold: int = 60, source: Literal["3GPP", "ETSI", "all"] = "all", spec_type: Optional[Literal["TS", "TR"]] = None):
56
+ """
57
+ Search specifications from 3GPP and/or ETSI with keywoeds (Based off BM25 scoring)
58
+ Returns a list of specifications metadata that matches the similarity score threshold, the keywords, the source and specification type
59
+ Arguments:
60
+ - keywords -> string
61
+ - threshold -> integer (by default, set to 60) [between 0-100]
62
+ - source -> string (either '3GPP', 'ETSI' or 'all', by default, set to 'all')
63
+ - spec_type -> string (either 'TS' or 'TR' or None, by default, set to None)
64
+ """
65
+ response = await make_request('https://organizedprogrammers-docfinder.hf.space/search/bm25', {"keywords": keywords, "threshold": threshold, "source": source, "spec_type": spec_type})
66
+ if not response:
67
+ return "Unable to search specifications | No specifications has been found"
68
+ results = response["results"]
69
+ 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])
70
+
71
+ @server.tool()
72
+ async def get_spec_text(spec_id: str) -> Union[Dict[str, str], str]:
73
+ """
74
+ Extract specification from 3GPP or ETSI
75
+ 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
76
+ Args: spec_id -> string
77
+ """
78
+ response = await make_request('https://organizedprogrammers-specsplitter.hf.space/extract_text/structured', {"spec_id": spec_id})
79
+ if not response:
80
+ return "Unable to extract specification text"
81
+ return response
82
+
83
+ app = server.streamable_http_app
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ httpx
2
+ uvicorn[standard]
3
+ fastapi
4
+ mcp[cli]