academia-mcp 1.11.2__tar.gz → 1.11.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/PKG-INFO +12 -8
  2. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/README.md +6 -2
  3. academia_mcp-1.11.4/academia_mcp/files.py +15 -0
  4. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/server.py +1 -1
  5. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/__init__.py +1 -1
  6. academia_mcp-1.11.2/academia_mcp/tools/show_image.py → academia_mcp-1.11.4/academia_mcp/tools/image_processing.py +74 -6
  7. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/PKG-INFO +12 -8
  8. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/SOURCES.txt +2 -2
  9. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/requires.txt +5 -5
  10. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/pyproject.toml +6 -6
  11. academia_mcp-1.11.2/tests/test_show_image.py → academia_mcp-1.11.4/tests/test_image_processing.py +6 -0
  12. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_visit_webpage.py +0 -2
  13. academia_mcp-1.11.2/academia_mcp/files.py +0 -30
  14. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/LICENSE +0 -0
  15. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/__init__.py +0 -0
  16. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/__main__.py +0 -0
  17. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/latex_templates/agents4science_2025/agents4science_2025.sty +0 -0
  18. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/latex_templates/agents4science_2025/agents4science_2025.tex +0 -0
  19. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/llm.py +0 -0
  20. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/pdf.py +0 -0
  21. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/py.typed +0 -0
  22. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/settings.py +0 -0
  23. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/anthology_search.py +0 -0
  24. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/arxiv_download.py +0 -0
  25. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/arxiv_search.py +0 -0
  26. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/bitflip.py +0 -0
  27. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/document_qa.py +0 -0
  28. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/hf_datasets_search.py +0 -0
  29. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/latex.py +0 -0
  30. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/py.typed +0 -0
  31. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/review.py +0 -0
  32. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/s2.py +0 -0
  33. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/speech_to_text.py +0 -0
  34. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/visit_webpage.py +0 -0
  35. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/web_search.py +0 -0
  36. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/tools/yt_transcript.py +0 -0
  37. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp/utils.py +0 -0
  38. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/dependency_links.txt +0 -0
  39. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/entry_points.txt +0 -0
  40. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/academia_mcp.egg-info/top_level.txt +0 -0
  41. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/setup.cfg +0 -0
  42. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_anthology_search.py +0 -0
  43. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_arxiv_download.py +0 -0
  44. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_arxiv_search.py +0 -0
  45. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_bitflip.py +0 -0
  46. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_document_qa.py +0 -0
  47. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_extract_json.py +0 -0
  48. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_hf_dataset_search.py +0 -0
  49. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_latex.py +0 -0
  50. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_review.py +0 -0
  51. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_s2.py +0 -0
  52. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_server.py +0 -0
  53. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_speech_to_text.py +0 -0
  54. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_web_search.py +0 -0
  55. {academia_mcp-1.11.2 → academia_mcp-1.11.4}/tests/test_yt_transcript.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: academia-mcp
3
- Version: 1.11.2
3
+ Version: 1.11.4
4
4
  Summary: MCP server that provides different tools to search for scientific publications
5
5
  Author-email: Ilya Gusev <phoenixilya@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/IlyaGusev/academia_mcp
@@ -12,16 +12,14 @@ Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: mcp>=1.10.1
14
14
  Requires-Dist: xmltodict>=0.14.0
15
- Requires-Dist: types-xmltodict>=0.14.0
16
15
  Requires-Dist: requests>=2.32.0
17
- Requires-Dist: types-requests>=2.32.0
18
16
  Requires-Dist: pypdf>=5.1.0
19
17
  Requires-Dist: beautifulsoup4>=4.12.0
20
- Requires-Dist: types-beautifulsoup4>=4.12.0
21
18
  Requires-Dist: markdownify==0.14.1
19
+ Requires-Dist: types-xmltodict>=0.14.0
20
+ Requires-Dist: types-requests>=2.32.0
21
+ Requires-Dist: types-beautifulsoup4>=4.12.0
22
22
  Requires-Dist: acl-anthology==0.5.2
23
- Requires-Dist: markdown==3.7.0
24
- Requires-Dist: types-markdown==3.7.0.20250322
25
23
  Requires-Dist: huggingface-hub>=0.32.4
26
24
  Requires-Dist: fire>=0.7.0
27
25
  Requires-Dist: openai>=1.97.1
@@ -31,6 +29,8 @@ Requires-Dist: pymupdf>=1.26.4
31
29
  Requires-Dist: pillow>=11.3.0
32
30
  Requires-Dist: pydantic-settings>=2.6.0
33
31
  Requires-Dist: youtube-transcript-api>=1.2.2
32
+ Requires-Dist: paddlepaddle>=3.2.0
33
+ Requires-Dist: paddleocr>=3.2.0
34
34
  Dynamic: license-file
35
35
 
36
36
  # Academia MCP
@@ -70,12 +70,16 @@ make install
70
70
  ### Quickstart
71
71
  - Run over HTTP (default transport):
72
72
  ```bash
73
+ python -m academia_mcp --transport streamable-http
74
+ # OR
73
75
  uv run -m academia_mcp --transport streamable-http
74
76
  ```
75
77
 
76
78
  - Run over stdio (for local MCP clients like Claude Desktop):
77
79
  ```bash
78
80
  python -m academia_mcp --transport stdio
81
+ # OR
82
+ uv run -m academia_mcp --transport stdio
79
83
  ```
80
84
 
81
85
  Notes:
@@ -122,7 +126,7 @@ Availability notes:
122
126
  - Set one or more of `EXA_API_KEY`, `BRAVE_API_KEY`, `TAVILY_API_KEY` to enable `web_search` and provider tools.
123
127
 
124
128
  ### Environment variables
125
- Set as needed depending on which tools you use:
129
+ Set as needed, depending on which tools you use:
126
130
 
127
131
  - `OPENROUTER_API_KEY`: required for LLM-related tools.
128
132
  - `BASE_URL`: override OpenRouter base URL.
@@ -152,7 +156,7 @@ docker run --rm -p 5056:5056 \
152
156
  academia_mcp
153
157
  ```
154
158
 
155
- Or use existing image: `phoenix120/academia_mcp`
159
+ Or use existing image: [`phoenix120/academia_mcp`](https://hub.docker.com/repository/docker/phoenix120/academia_mcp)
156
160
 
157
161
  ### Examples
158
162
  - [Comprehensive report screencast (YouTube)](https://www.youtube.com/watch?v=4bweqQcN6w8)
@@ -35,12 +35,16 @@ make install
35
35
  ### Quickstart
36
36
  - Run over HTTP (default transport):
37
37
  ```bash
38
+ python -m academia_mcp --transport streamable-http
39
+ # OR
38
40
  uv run -m academia_mcp --transport streamable-http
39
41
  ```
40
42
 
41
43
  - Run over stdio (for local MCP clients like Claude Desktop):
42
44
  ```bash
43
45
  python -m academia_mcp --transport stdio
46
+ # OR
47
+ uv run -m academia_mcp --transport stdio
44
48
  ```
45
49
 
46
50
  Notes:
@@ -87,7 +91,7 @@ Availability notes:
87
91
  - Set one or more of `EXA_API_KEY`, `BRAVE_API_KEY`, `TAVILY_API_KEY` to enable `web_search` and provider tools.
88
92
 
89
93
  ### Environment variables
90
- Set as needed depending on which tools you use:
94
+ Set as needed, depending on which tools you use:
91
95
 
92
96
  - `OPENROUTER_API_KEY`: required for LLM-related tools.
93
97
  - `BASE_URL`: override OpenRouter base URL.
@@ -117,7 +121,7 @@ docker run --rm -p 5056:5056 \
117
121
  academia_mcp
118
122
  ```
119
123
 
120
- Or use existing image: `phoenix120/academia_mcp`
124
+ Or use existing image: [`phoenix120/academia_mcp`](https://hub.docker.com/repository/docker/phoenix120/academia_mcp)
121
125
 
122
126
  ### Examples
123
127
  - [Comprehensive report screencast (YouTube)](https://www.youtube.com/watch?v=4bweqQcN6w8)
@@ -0,0 +1,15 @@
1
+ from pathlib import Path
2
+
3
+ from academia_mcp.settings import settings
4
+
5
+ DIR_PATH = Path(__file__).parent
6
+ ROOT_PATH = DIR_PATH.parent
7
+ DEFAULT_LATEX_TEMPLATES_DIR_PATH: Path = DIR_PATH / "latex_templates"
8
+
9
+
10
+ def get_workspace_dir() -> Path:
11
+ assert settings.WORKSPACE_DIR is not None, "Please set the WORKSPACE_DIR environment variable"
12
+ directory = Path(settings.WORKSPACE_DIR)
13
+ if not directory.exists():
14
+ directory.mkdir(parents=True, exist_ok=True)
15
+ return directory
@@ -40,7 +40,7 @@ from academia_mcp.tools.bitflip import (
40
40
  score_research_proposals,
41
41
  )
42
42
  from academia_mcp.tools.review import review_pdf_paper, download_pdf_paper
43
- from academia_mcp.tools.show_image import show_image, describe_image
43
+ from academia_mcp.tools.image_processing import show_image, describe_image
44
44
  from academia_mcp.tools.speech_to_text import speech_to_text
45
45
  from academia_mcp.tools.yt_transcript import yt_transcript
46
46
 
@@ -14,7 +14,7 @@ from .web_search import web_search, tavily_web_search, exa_web_search, brave_web
14
14
  from .visit_webpage import visit_webpage
15
15
  from .bitflip import extract_bitflip_info, generate_research_proposals, score_research_proposals
16
16
  from .review import review_pdf_paper, download_pdf_paper, review_pdf_paper_by_url
17
- from .show_image import show_image, describe_image
17
+ from .image_processing import show_image, describe_image
18
18
  from .speech_to_text import speech_to_text
19
19
  from .yt_transcript import yt_transcript
20
20
 
@@ -1,16 +1,28 @@
1
+ import asyncio
1
2
  import base64
2
- from pathlib import Path
3
+ import contextlib
4
+ import json
5
+ import logging
6
+ import os
7
+ import threading
3
8
  from io import BytesIO
4
- from typing import Dict, Optional
9
+ from pathlib import Path
5
10
  from textwrap import dedent
11
+ from typing import Dict, List, Optional, Any
6
12
 
7
13
  import httpx
14
+ from paddleocr import PaddleOCR # type: ignore
8
15
  from PIL import Image
16
+ from pydantic import BaseModel
9
17
 
10
18
  from academia_mcp.files import get_workspace_dir
19
+ from academia_mcp.llm import ChatMessage, llm_acall
11
20
  from academia_mcp.settings import settings
12
- from academia_mcp.llm import llm_acall, ChatMessage
13
21
 
22
+ paddlex_logger = logging.getLogger("paddlex")
23
+ paddleocr_logger = logging.getLogger("paddleocr")
24
+ paddlex_logger.setLevel(logging.ERROR)
25
+ paddleocr_logger.setLevel(logging.ERROR)
14
26
 
15
27
  DESCRIBE_PROMPTS = {
16
28
  "general": "Provide a general description of this image. Focus on the main subjects, colors, and overall scene.",
@@ -37,16 +49,64 @@ DESCRIBE_PROMPTS = {
37
49
  - If layout is multi-column or tabular, reconstruct lines top-to-bottom, left-to-right; use line breaks between blocks.
38
50
  - For any uncertain or low-confidence characters, mark with a '?' and include a note.
39
51
  - After the raw extraction, provide a clean, normalized version (fixing obvious OCR artifacts) as a separate section.
40
- Return two sections:
52
+ Return three sections:
53
+ [GENERAL IMAGE DESCRIPTION]
54
+ ...
41
55
  [RAW TRANSCRIPTION]
42
56
  ...
43
- [NORMALIZED]
57
+ [NORMALIZED TRANSCRIPTION]
44
58
  ...
45
59
  """
46
60
  ),
47
61
  }
48
62
 
49
63
 
64
+ class OCRBox(BaseModel): # type: ignore
65
+ poly: List[List[float]]
66
+ text: str
67
+ score: float
68
+
69
+
70
+ class OCRSingleton:
71
+ instance: Optional[PaddleOCR] = None
72
+ lock: threading.Lock = threading.Lock()
73
+
74
+ @classmethod
75
+ def get(cls) -> PaddleOCR:
76
+ if cls.instance is not None:
77
+ return cls.instance
78
+ with cls.lock:
79
+ if cls.instance is None:
80
+ with open(os.devnull, "w") as devnull:
81
+ with contextlib.redirect_stderr(devnull):
82
+ cls.instance = PaddleOCR(
83
+ use_doc_orientation_classify=False,
84
+ use_doc_unwarping=False,
85
+ use_textline_orientation=False,
86
+ )
87
+ return cls.instance
88
+
89
+
90
+ async def _run_ocr(path: str) -> Dict[str, Any]:
91
+ def _sync_ocr(path: str) -> Dict[str, Any]:
92
+ try:
93
+ ocr = OCRSingleton.get()
94
+ with open(os.devnull, "w") as devnull:
95
+ with contextlib.redirect_stderr(devnull):
96
+ result = ocr.predict(input=path)[0]
97
+ rec_texts = result["rec_texts"]
98
+ rec_scores = result["rec_scores"]
99
+ rec_polys = result["rec_polys"]
100
+ except Exception as e:
101
+ return {"error": str(e)}
102
+ items = []
103
+ for poly, text, score in zip(rec_polys, rec_texts, rec_scores):
104
+ items.append(OCRBox(poly=poly, text=text, score=score).model_dump())
105
+ return {"boxes": items}
106
+
107
+ return await asyncio.to_thread(_sync_ocr, path)
108
+
109
+
50
110
  def show_image(path: str) -> Dict[str, str]:
51
111
  """
52
112
  Reads an image from the specified URL or from the current work directory.
@@ -91,7 +151,7 @@ async def describe_image(
91
151
  - "general": General description of the image
92
152
  - "detailed": Detailed analysis of the image
93
153
  - "chess": Analysis of a chess position
94
- - "text": Extract and describe text or numbers from the image
154
+ - "text": Extract and describe text or numbers with an OCR pipeline.
95
155
  - "custom": Custom description based on user prompt
96
156
  """
97
157
  image_base64 = show_image(path)["image_base64"]
@@ -116,4 +176,12 @@ async def describe_image(
116
176
  messages=[ChatMessage(role="user", content=content)],
117
177
  **llm_kwargs,
118
178
  )
179
+ if description_type == "text":
180
+ ocr_response = await _run_ocr(path)
181
+ response = json.dumps(
182
+ {
183
+ "vlm_response": response,
184
+ "ocr_response": ocr_response if ocr_response else [],
185
+ }
186
+ )
119
187
  return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: academia-mcp
3
- Version: 1.11.2
3
+ Version: 1.11.4
4
4
  Summary: MCP server that provides different tools to search for scientific publications
5
5
  Author-email: Ilya Gusev <phoenixilya@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/IlyaGusev/academia_mcp
@@ -12,16 +12,14 @@ Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: mcp>=1.10.1
14
14
  Requires-Dist: xmltodict>=0.14.0
15
- Requires-Dist: types-xmltodict>=0.14.0
16
15
  Requires-Dist: requests>=2.32.0
17
- Requires-Dist: types-requests>=2.32.0
18
16
  Requires-Dist: pypdf>=5.1.0
19
17
  Requires-Dist: beautifulsoup4>=4.12.0
20
- Requires-Dist: types-beautifulsoup4>=4.12.0
21
18
  Requires-Dist: markdownify==0.14.1
19
+ Requires-Dist: types-xmltodict>=0.14.0
20
+ Requires-Dist: types-requests>=2.32.0
21
+ Requires-Dist: types-beautifulsoup4>=4.12.0
22
22
  Requires-Dist: acl-anthology==0.5.2
23
- Requires-Dist: markdown==3.7.0
24
- Requires-Dist: types-markdown==3.7.0.20250322
25
23
  Requires-Dist: huggingface-hub>=0.32.4
26
24
  Requires-Dist: fire>=0.7.0
27
25
  Requires-Dist: openai>=1.97.1
@@ -31,6 +29,8 @@ Requires-Dist: pymupdf>=1.26.4
31
29
  Requires-Dist: pillow>=11.3.0
32
30
  Requires-Dist: pydantic-settings>=2.6.0
33
31
  Requires-Dist: youtube-transcript-api>=1.2.2
32
+ Requires-Dist: paddlepaddle>=3.2.0
33
+ Requires-Dist: paddleocr>=3.2.0
34
34
  Dynamic: license-file
35
35
 
36
36
  # Academia MCP
@@ -70,12 +70,16 @@ make install
70
70
  ### Quickstart
71
71
  - Run over HTTP (default transport):
72
72
  ```bash
73
+ python -m academia_mcp --transport streamable-http
74
+ # OR
73
75
  uv run -m academia_mcp --transport streamable-http
74
76
  ```
75
77
 
76
78
  - Run over stdio (for local MCP clients like Claude Desktop):
77
79
  ```bash
78
80
  python -m academia_mcp --transport stdio
81
+ # OR
82
+ uv run -m academia_mcp --transport stdio
79
83
  ```
80
84
 
81
85
  Notes:
@@ -122,7 +126,7 @@ Availability notes:
122
126
  - Set one or more of `EXA_API_KEY`, `BRAVE_API_KEY`, `TAVILY_API_KEY` to enable `web_search` and provider tools.
123
127
 
124
128
  ### Environment variables
125
- Set as needed depending on which tools you use:
129
+ Set as needed, depending on which tools you use:
126
130
 
127
131
  - `OPENROUTER_API_KEY`: required for LLM-related tools.
128
132
  - `BASE_URL`: override OpenRouter base URL.
@@ -152,7 +156,7 @@ docker run --rm -p 5056:5056 \
152
156
  academia_mcp
153
157
  ```
154
158
 
155
- Or use existing image: `phoenix120/academia_mcp`
159
+ Or use existing image: [`phoenix120/academia_mcp`](https://hub.docker.com/repository/docker/phoenix120/academia_mcp)
156
160
 
157
161
  ### Examples
158
162
  - [Comprehensive report screencast (YouTube)](https://www.youtube.com/watch?v=4bweqQcN6w8)
@@ -25,11 +25,11 @@ academia_mcp/tools/arxiv_search.py
25
25
  academia_mcp/tools/bitflip.py
26
26
  academia_mcp/tools/document_qa.py
27
27
  academia_mcp/tools/hf_datasets_search.py
28
+ academia_mcp/tools/image_processing.py
28
29
  academia_mcp/tools/latex.py
29
30
  academia_mcp/tools/py.typed
30
31
  academia_mcp/tools/review.py
31
32
  academia_mcp/tools/s2.py
32
- academia_mcp/tools/show_image.py
33
33
  academia_mcp/tools/speech_to_text.py
34
34
  academia_mcp/tools/visit_webpage.py
35
35
  academia_mcp/tools/web_search.py
@@ -41,11 +41,11 @@ tests/test_bitflip.py
41
41
  tests/test_document_qa.py
42
42
  tests/test_extract_json.py
43
43
  tests/test_hf_dataset_search.py
44
+ tests/test_image_processing.py
44
45
  tests/test_latex.py
45
46
  tests/test_review.py
46
47
  tests/test_s2.py
47
48
  tests/test_server.py
48
- tests/test_show_image.py
49
49
  tests/test_speech_to_text.py
50
50
  tests/test_visit_webpage.py
51
51
  tests/test_web_search.py
@@ -1,15 +1,13 @@
1
1
  mcp>=1.10.1
2
2
  xmltodict>=0.14.0
3
- types-xmltodict>=0.14.0
4
3
  requests>=2.32.0
5
- types-requests>=2.32.0
6
4
  pypdf>=5.1.0
7
5
  beautifulsoup4>=4.12.0
8
- types-beautifulsoup4>=4.12.0
9
6
  markdownify==0.14.1
7
+ types-xmltodict>=0.14.0
8
+ types-requests>=2.32.0
9
+ types-beautifulsoup4>=4.12.0
10
10
  acl-anthology==0.5.2
11
- markdown==3.7.0
12
- types-markdown==3.7.0.20250322
13
11
  huggingface-hub>=0.32.4
14
12
  fire>=0.7.0
15
13
  openai>=1.97.1
@@ -19,3 +17,5 @@ pymupdf>=1.26.4
19
17
  pillow>=11.3.0
20
18
  pydantic-settings>=2.6.0
21
19
  youtube-transcript-api>=1.2.2
20
+ paddlepaddle>=3.2.0
21
+ paddleocr>=3.2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "academia-mcp"
7
- version = "1.11.2"
7
+ version = "1.11.4"
8
8
  description = "MCP server that provides different tools to search for scientific publications"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -19,16 +19,14 @@ classifiers = [
19
19
  dependencies = [
20
20
  "mcp>=1.10.1",
21
21
  "xmltodict>=0.14.0",
22
- "types-xmltodict>=0.14.0",
23
22
  "requests>=2.32.0",
24
- "types-requests>=2.32.0",
25
23
  "pypdf>=5.1.0",
26
24
  "beautifulsoup4>=4.12.0",
27
- "types-beautifulsoup4>=4.12.0",
28
25
  "markdownify==0.14.1",
26
+ "types-xmltodict>=0.14.0",
27
+ "types-requests>=2.32.0",
28
+ "types-beautifulsoup4>=4.12.0",
29
29
  "acl-anthology==0.5.2",
30
- "markdown==3.7.0",
31
- "types-markdown==3.7.0.20250322",
32
30
  "huggingface-hub>=0.32.4",
33
31
  "fire>=0.7.0",
34
32
  "openai>=1.97.1",
@@ -38,6 +36,8 @@ dependencies = [
38
36
  "pillow>=11.3.0",
39
37
  "pydantic-settings>=2.6.0",
40
38
  "youtube-transcript-api>=1.2.2",
39
+ "paddlepaddle>=3.2.0",
40
+ "paddleocr>=3.2.0",
41
41
  ]
42
42
 
43
43
  [dependency-groups]
@@ -29,3 +29,9 @@ async def test_describe_image_base(test_image_url: str) -> None:
29
29
  result = await describe_image(test_image_url)
30
30
  assert result is not None
31
31
  assert "Interrogator" in result
32
+
33
+
34
+ async def test_describe_image_text(test_image_url: str) -> None:
35
+ result = await describe_image(test_image_url, description_type="text")
36
+ assert result is not None
37
+ assert '"text": "Interrogator"' in result
@@ -7,7 +7,6 @@ def test_visit_webpage_basic() -> None:
7
7
  assert content.id == "https://example.com/"
8
8
  assert content.provider == "basic"
9
9
  assert "Example Domain" in content.text
10
- assert "illustrative" in content.text
11
10
 
12
11
 
13
12
  def test_visit_webpage_exa() -> None:
@@ -16,7 +15,6 @@ def test_visit_webpage_exa() -> None:
16
15
  assert content.id == "https://example.com/"
17
16
  assert content.provider == "exa"
18
17
  assert "Example Domain" in content.text
19
- assert "illustrative" in content.text
20
18
 
21
19
 
22
20
  def test_visit_webpage_pdf() -> None:
@@ -1,30 +0,0 @@
1
- from typing import Optional
2
- from pathlib import Path
3
-
4
- from academia_mcp.settings import settings
5
-
6
- DIR_PATH = Path(__file__).parent
7
- ROOT_PATH = DIR_PATH.parent
8
- DEFAULT_WORKSPACE_DIR_PATH: Path = DIR_PATH / "workdir"
9
- DEFAULT_LATEX_TEMPLATES_DIR_PATH: Path = DIR_PATH / "latex_templates"
10
-
11
-
12
- class WorkspaceDirectory:
13
- workspace_dir: Optional[Path] = None
14
-
15
- @classmethod
16
- def get_dir(cls) -> Path:
17
- if cls.workspace_dir is None:
18
- return Path(settings.WORKSPACE_DIR)
19
- return cls.workspace_dir
20
-
21
- @classmethod
22
- def set_dir(cls, workspace_dir: Path) -> None:
23
- cls.workspace_dir = workspace_dir
24
-
25
-
26
- def get_workspace_dir() -> Path:
27
- directory = WorkspaceDirectory.get_dir()
28
- if not directory.exists():
29
- directory.mkdir(parents=True, exist_ok=True)
30
- return directory
File without changes
File without changes