lightpdf-aipdf-mcp 0.1.143__py3-none-any.whl → 0.1.145__py3-none-any.whl
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.
- lightpdf_aipdf_mcp/common.py +1 -0
- lightpdf_aipdf_mcp/create_pdf.py +321 -50
- lightpdf_aipdf_mcp/server.py +36 -10
- lightpdf_aipdf_mcp/summarizer.py +6 -43
- {lightpdf_aipdf_mcp-0.1.143.dist-info → lightpdf_aipdf_mcp-0.1.145.dist-info}/METADATA +1 -1
- lightpdf_aipdf_mcp-0.1.145.dist-info/RECORD +13 -0
- lightpdf_aipdf_mcp-0.1.143.dist-info/RECORD +0 -13
- {lightpdf_aipdf_mcp-0.1.143.dist-info → lightpdf_aipdf_mcp-0.1.145.dist-info}/WHEEL +0 -0
- {lightpdf_aipdf_mcp-0.1.143.dist-info → lightpdf_aipdf_mcp-0.1.145.dist-info}/entry_points.txt +0 -0
lightpdf_aipdf_mcp/common.py
CHANGED
@@ -249,4 +249,5 @@ class BaseApiClient:
|
|
249
249
|
if "data" not in result or "task_id" not in result["data"]:
|
250
250
|
await self.logger.error(f"无法获取任务ID。API响应:{json.dumps(result, ensure_ascii=False)}")
|
251
251
|
|
252
|
+
await self.logger.log("debug", f"API响应:{json.dumps(result, ensure_ascii=False)}")
|
252
253
|
return result["data"]["task_id"]
|
lightpdf_aipdf_mcp/create_pdf.py
CHANGED
@@ -1,62 +1,333 @@
|
|
1
|
-
"""
|
1
|
+
"""根据用户输入请求创建PDF文件的接口"""
|
2
|
+
from dataclasses import dataclass
|
2
3
|
from typing import Optional
|
3
4
|
import os
|
4
5
|
import uuid
|
5
|
-
|
6
|
+
import httpx
|
7
|
+
from .common import Logger, FileHandler, BaseResult, BaseApiClient
|
6
8
|
from .editor import Editor, EditResult, EditType
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
@dataclass
|
11
|
+
class CreatePdfResult(BaseResult):
|
12
|
+
"""PDF创建结果数据类"""
|
13
|
+
pass
|
14
|
+
|
15
|
+
class PDFCreator(BaseApiClient):
|
16
|
+
"""PDF文档创建器"""
|
17
|
+
def __init__(self, logger: Logger, file_handler: FileHandler):
|
18
|
+
super().__init__(logger, file_handler)
|
19
|
+
self.api_base_url = f"https://{self.api_endpoint}/tasks/llm/chats"
|
20
|
+
# 语言代码到语言名称的映射
|
21
|
+
self.language_map = {
|
22
|
+
"zh": "简体中文", "en": "English", "de": "Deutsch", "es": "Español",
|
23
|
+
"fr": "Français", "ja": "日本語", "pt": "Português", "zh-tw": "繁體中文",
|
24
|
+
"ar": "العربية", "cs": "Čeština", "da": "Dansk", "fi": "Suomi",
|
25
|
+
"el": "Ελληνικά", "hu": "Magyar", "it": "Italiano", "nl": "Nederlands",
|
26
|
+
"no": "Norsk", "pl": "Polski", "sv": "Svenska", "tr": "Türkçe"
|
27
|
+
}
|
28
|
+
|
29
|
+
async def create_pdf_from_prompt(
|
30
|
+
self,
|
31
|
+
prompt: str,
|
32
|
+
language: str,
|
33
|
+
enable_web_search: bool = False,
|
34
|
+
original_name: Optional[str] = None
|
35
|
+
) -> CreatePdfResult:
|
36
|
+
"""
|
37
|
+
根据用户输入请求创建PDF文件。
|
38
|
+
|
39
|
+
参数:
|
40
|
+
prompt (str): 用户的输入请求或提示词,仅支持文字描述,不支持文件附件等。
|
41
|
+
language (str): 生成PDF的语言,必需参数。
|
42
|
+
enable_web_search (bool): 是否启用联网搜索,默认False。
|
43
|
+
original_name (Optional[str]): 可选,原始文件名。
|
44
|
+
返回:
|
45
|
+
CreatePdfResult: 包含生成结果的信息。
|
46
|
+
"""
|
47
|
+
tex_path = None
|
23
48
|
try:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
49
|
+
# 1. 根据prompt生成latex代码
|
50
|
+
latex_code = await self._generate_latex_code(prompt, language, enable_web_search)
|
51
|
+
if not latex_code:
|
52
|
+
return CreatePdfResult(
|
53
|
+
success=False,
|
54
|
+
file_path="",
|
55
|
+
error_message="生成的latex代码为空",
|
56
|
+
original_name=original_name
|
57
|
+
)
|
58
|
+
|
59
|
+
# 2. 保存latex_code为本地.tex文件
|
60
|
+
tex_path = await self._save_latex_to_file(latex_code)
|
61
|
+
|
62
|
+
# 3. 调用Editor.edit_pdf并传递oss://tex2pdf参数生成PDF
|
63
|
+
result = await self._convert_tex_to_pdf(tex_path, original_name)
|
64
|
+
|
65
|
+
# 转换EditResult到CreatePdfResult
|
66
|
+
return CreatePdfResult(
|
67
|
+
success=result.success,
|
68
|
+
file_path=result.file_path,
|
69
|
+
error_message=result.error_message,
|
70
|
+
download_url=result.download_url,
|
71
|
+
original_name=result.original_name,
|
72
|
+
task_id=result.task_id
|
73
|
+
)
|
74
|
+
|
30
75
|
except Exception as e:
|
31
|
-
return
|
32
|
-
|
76
|
+
return CreatePdfResult(
|
77
|
+
success=False,
|
78
|
+
file_path="",
|
79
|
+
error_message=f"PDF创建过程中发生错误: {e}",
|
80
|
+
original_name=original_name
|
33
81
|
)
|
82
|
+
finally:
|
83
|
+
# 清理临时文件
|
84
|
+
if tex_path and os.path.exists(tex_path):
|
85
|
+
self._schedule_file_cleanup(tex_path)
|
86
|
+
|
87
|
+
async def _generate_latex_code(self, prompt: str, language: str, enable_web_search: bool) -> str:
|
88
|
+
"""根据用户输入生成LaTeX代码"""
|
89
|
+
lang_str = self.language_map.get(language)
|
90
|
+
await self.logger.log("debug", f"开始为语言 {lang_str} 生成LaTeX代码,联网搜索: {enable_web_search}")
|
91
|
+
|
92
|
+
# 这里应该是实际的代码生成逻辑
|
93
|
+
# 暂时返回空字符串,需要后续实现
|
94
|
+
async with httpx.AsyncClient(timeout=3600.0) as client:
|
95
|
+
template_variables = {
|
96
|
+
"PROMPT": prompt
|
97
|
+
}
|
98
|
+
if lang_str:
|
99
|
+
template_variables["LANGUAGE"] = lang_str
|
100
|
+
|
101
|
+
headers = {"X-API-KEY": self.api_key}
|
102
|
+
data = {
|
103
|
+
"po": "lightpdf",
|
104
|
+
"response_type": 0,
|
105
|
+
"template_id": "48a62054-9cf0-483d-9787-b31afc32e079",
|
106
|
+
"template_variables": template_variables
|
107
|
+
}
|
108
|
+
if enable_web_search:
|
109
|
+
# 获取真实的用户信息
|
110
|
+
plugin_options = await self._get_real_user_info(language)
|
111
|
+
data["plugins"] = [
|
112
|
+
{
|
113
|
+
"function": {
|
114
|
+
"id": 1001,
|
115
|
+
"options": plugin_options
|
116
|
+
},
|
117
|
+
"callback": None
|
118
|
+
}
|
119
|
+
]
|
120
|
+
|
121
|
+
await self.logger.log("debug", f"正在提交生成LaTeX代码...{data}")
|
122
|
+
response = await client.post(self.api_base_url, json=data, headers=headers)
|
123
|
+
|
124
|
+
task_id = await self._handle_api_response(response, "生成LaTeX代码")
|
125
|
+
await self.logger.log("debug", f"生成LaTeX代码,task_id: {task_id}")
|
126
|
+
|
127
|
+
content = await self._wait_for_task(client, task_id, "生成LaTeX代码", is_raw=True)
|
34
128
|
|
35
|
-
|
129
|
+
return content.get("text", "")
|
130
|
+
|
131
|
+
async def _save_latex_to_file(self, latex_code: str) -> str:
|
132
|
+
"""保存LaTeX代码到临时文件"""
|
133
|
+
temp_dir = "./tmp"
|
134
|
+
os.makedirs(temp_dir, exist_ok=True)
|
135
|
+
tex_filename = f"latex_code_{uuid.uuid4().hex}.tex"
|
136
|
+
tex_path = os.path.join(temp_dir, tex_filename)
|
137
|
+
|
138
|
+
# 清理markdown代码块标记
|
139
|
+
cleaned_code = self._clean_latex_code(latex_code)
|
140
|
+
|
141
|
+
with open(tex_path, "w", encoding="utf-8") as f:
|
142
|
+
f.write(cleaned_code)
|
143
|
+
|
144
|
+
return tex_path
|
145
|
+
|
146
|
+
def _clean_latex_code(self, latex_code: str) -> str:
|
147
|
+
"""清理LaTeX代码中的markdown标记"""
|
148
|
+
if not latex_code:
|
149
|
+
return latex_code
|
150
|
+
|
151
|
+
# 去除首行和尾行的markdown代码块标记
|
152
|
+
lines = latex_code.strip().split('\n')
|
153
|
+
|
154
|
+
# 检查并移除首行的```latex标记
|
155
|
+
if lines and lines[0].strip().startswith('```'):
|
156
|
+
lines = lines[1:]
|
157
|
+
|
158
|
+
# 检查并移除尾行的```标记
|
159
|
+
if lines and lines[-1].strip() == '```':
|
160
|
+
lines = lines[:-1]
|
161
|
+
|
162
|
+
# 重新组合代码
|
163
|
+
cleaned_code = '\n'.join(lines)
|
164
|
+
|
165
|
+
return cleaned_code.strip()
|
166
|
+
|
167
|
+
async def _get_real_user_info(self, language: str) -> dict:
|
168
|
+
"""获取真实的用户信息"""
|
169
|
+
import platform
|
170
|
+
import socket
|
171
|
+
|
172
|
+
# 获取真实的用户代理字符串
|
173
|
+
system = platform.system()
|
174
|
+
version = platform.version()
|
175
|
+
architecture = platform.machine()
|
176
|
+
|
177
|
+
# 构建更真实的User-Agent
|
178
|
+
if system == "Darwin": # macOS
|
179
|
+
user_agent = f"Mozilla/5.0 (Macintosh; Intel Mac OS X {version.replace('.', '_')}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
180
|
+
elif system == "Windows":
|
181
|
+
user_agent = f"Mozilla/5.0 (Windows NT {version}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
182
|
+
elif system == "Linux":
|
183
|
+
user_agent = f"Mozilla/5.0 (X11; Linux {architecture}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
184
|
+
else:
|
185
|
+
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
186
|
+
|
187
|
+
# 获取真实的IP地址
|
188
|
+
local_ip = self._get_local_ip()
|
189
|
+
|
190
|
+
# 根据语言参数动态生成accept_language
|
191
|
+
accept_language = self._get_accept_language(language)
|
192
|
+
|
193
|
+
return {
|
194
|
+
"user_agent": user_agent,
|
195
|
+
"accept_language": accept_language,
|
196
|
+
"ip": local_ip
|
197
|
+
}
|
198
|
+
|
199
|
+
def _get_accept_language(self, language: str) -> str:
|
200
|
+
"""根据语言代码生成对应的accept_language字符串"""
|
201
|
+
# 语言代码到HTTP Accept-Language的映射
|
202
|
+
language_codes = {
|
203
|
+
"zh": "zh-CN,zh;q=0.9,en;q=0.8",
|
204
|
+
"en": "en-US,en;q=0.9",
|
205
|
+
"de": "de-DE,de;q=0.9,en;q=0.8",
|
206
|
+
"es": "es-ES,es;q=0.9,en;q=0.8",
|
207
|
+
"fr": "fr-FR,fr;q=0.9,en;q=0.8",
|
208
|
+
"ja": "ja-JP,ja;q=0.9,en;q=0.8",
|
209
|
+
"pt": "pt-PT,pt;q=0.9,en;q=0.8",
|
210
|
+
"zh-tw": "zh-TW,zh;q=0.9,en;q=0.8",
|
211
|
+
"ar": "ar-SA,ar;q=0.9,en;q=0.8",
|
212
|
+
"cs": "cs-CZ,cs;q=0.9,en;q=0.8",
|
213
|
+
"da": "da-DK,da;q=0.9,en;q=0.8",
|
214
|
+
"fi": "fi-FI,fi;q=0.9,en;q=0.8",
|
215
|
+
"el": "el-GR,el;q=0.9,en;q=0.8",
|
216
|
+
"hu": "hu-HU,hu;q=0.9,en;q=0.8",
|
217
|
+
"it": "it-IT,it;q=0.9,en;q=0.8",
|
218
|
+
"nl": "nl-NL,nl;q=0.9,en;q=0.8",
|
219
|
+
"no": "no-NO,no;q=0.9,en;q=0.8",
|
220
|
+
"pl": "pl-PL,pl;q=0.9,en;q=0.8",
|
221
|
+
"sv": "sv-SE,sv;q=0.9,en;q=0.8",
|
222
|
+
"tr": "tr-TR,tr;q=0.9,en;q=0.8"
|
223
|
+
}
|
224
|
+
|
225
|
+
return language_codes.get(language, "en-US,en;q=0.9")
|
226
|
+
|
227
|
+
def _get_local_ip(self) -> str:
|
228
|
+
"""获取本地IP地址的稳定方法"""
|
229
|
+
import socket
|
230
|
+
|
231
|
+
# 方法1: 尝试连接外部DNS服务器
|
232
|
+
try:
|
233
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
234
|
+
# 使用多个DNS服务器进行尝试
|
235
|
+
for dns_server in ["8.8.8.8", "1.1.1.1", "208.67.222.222", "114.114.114.114", "101.101.101.101", "1.2.4.8"]:
|
236
|
+
try:
|
237
|
+
s.connect((dns_server, 80))
|
238
|
+
ip = s.getsockname()[0]
|
239
|
+
# 验证是否为私有IP地址
|
240
|
+
if self._is_valid_local_ip(ip):
|
241
|
+
return ip
|
242
|
+
except Exception:
|
243
|
+
continue
|
244
|
+
except Exception:
|
245
|
+
pass
|
246
|
+
|
247
|
+
# 方法2: 获取本机所有网络接口
|
36
248
|
try:
|
37
|
-
|
38
|
-
|
39
|
-
|
249
|
+
hostname = socket.gethostname()
|
250
|
+
ip_list = socket.gethostbyname_ex(hostname)[2]
|
251
|
+
for ip in ip_list:
|
252
|
+
if self._is_valid_local_ip(ip):
|
253
|
+
return ip
|
254
|
+
except Exception:
|
255
|
+
pass
|
256
|
+
|
257
|
+
# 方法3: 遍历网络接口
|
258
|
+
try:
|
259
|
+
import subprocess
|
260
|
+
import platform
|
261
|
+
|
262
|
+
if platform.system() == "Windows":
|
263
|
+
# Windows系统
|
264
|
+
result = subprocess.run(['ipconfig'], capture_output=True, text=True)
|
265
|
+
for line in result.stdout.split('\n'):
|
266
|
+
if 'IPv4' in line and 'Address' in line:
|
267
|
+
ip = line.split(':')[-1].strip()
|
268
|
+
if self._is_valid_local_ip(ip):
|
269
|
+
return ip
|
270
|
+
else:
|
271
|
+
# Unix/Linux/macOS系统
|
272
|
+
result = subprocess.run(['hostname', '-I'], capture_output=True, text=True)
|
273
|
+
if result.returncode == 0:
|
274
|
+
ips = result.stdout.strip().split()
|
275
|
+
for ip in ips:
|
276
|
+
if self._is_valid_local_ip(ip):
|
277
|
+
return ip
|
278
|
+
except Exception:
|
279
|
+
pass
|
280
|
+
|
281
|
+
# 方法4: 尝试绑定本地socket
|
282
|
+
try:
|
283
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
284
|
+
s.bind(('', 0))
|
285
|
+
ip = s.getsockname()[0]
|
286
|
+
if self._is_valid_local_ip(ip):
|
287
|
+
return ip
|
288
|
+
except Exception:
|
289
|
+
pass
|
290
|
+
|
291
|
+
# 最后的后备方案
|
292
|
+
return "127.0.0.1"
|
293
|
+
|
294
|
+
def _is_valid_local_ip(self, ip: str) -> bool:
|
295
|
+
"""验证IP地址是否为有效的本地IP"""
|
296
|
+
import ipaddress
|
297
|
+
|
298
|
+
try:
|
299
|
+
ip_obj = ipaddress.ip_address(ip)
|
300
|
+
# 排除回环地址和链路本地地址
|
301
|
+
if ip_obj.is_loopback or ip_obj.is_link_local:
|
302
|
+
return False
|
303
|
+
# 接受私有地址和公网地址
|
304
|
+
return True
|
305
|
+
except ValueError:
|
306
|
+
return False
|
40
307
|
|
41
|
-
|
42
|
-
|
308
|
+
async def _convert_tex_to_pdf(self, tex_path: str, original_name: Optional[str]) -> EditResult:
|
309
|
+
"""将TEX文件转换为PDF"""
|
310
|
+
editor = Editor(self.logger, self.file_handler)
|
311
|
+
extra_params = {"pages": '[{"url": "oss://tex2pdf", "oss_file": ""}]'}
|
312
|
+
|
313
|
+
tex_filename = os.path.basename(tex_path)
|
314
|
+
return await editor.edit_pdf(
|
315
|
+
tex_path,
|
316
|
+
edit_type=EditType.EDIT,
|
317
|
+
extra_params=extra_params,
|
318
|
+
original_name=original_name or tex_filename
|
319
|
+
)
|
43
320
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
os.remove(path)
|
58
|
-
except Exception:
|
59
|
-
pass
|
60
|
-
timer = threading.Timer(300, delayed_remove, args=(tex_path,))
|
61
|
-
timer.daemon = True
|
62
|
-
timer.start()
|
321
|
+
def _schedule_file_cleanup(self, file_path: str, delay: int = 300):
|
322
|
+
"""安排文件清理"""
|
323
|
+
import threading
|
324
|
+
|
325
|
+
def delayed_remove(path):
|
326
|
+
try:
|
327
|
+
os.remove(path)
|
328
|
+
except Exception:
|
329
|
+
pass
|
330
|
+
|
331
|
+
timer = threading.Timer(delay, delayed_remove, args=(file_path,))
|
332
|
+
timer.daemon = True
|
333
|
+
timer.start()
|
lightpdf_aipdf_mcp/server.py
CHANGED
@@ -1204,20 +1204,30 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
1204
1204
|
),
|
1205
1205
|
types.Tool(
|
1206
1206
|
name="create_pdf",
|
1207
|
-
description="
|
1207
|
+
description="Generate PDF documents from text-only instructions or descriptions. The tool creates PDFs based on written prompts such as 'create a business report', 'generate meeting minutes', etc. Only accepts plain text input - no file uploads or multimedia content supported.",
|
1208
1208
|
inputSchema={
|
1209
1209
|
"type": "object",
|
1210
1210
|
"properties": {
|
1211
|
-
"
|
1211
|
+
"prompt": {
|
1212
1212
|
"type": "string",
|
1213
|
-
"description": "
|
1213
|
+
"description": "A text-only description or instruction of what PDF content to generate (e.g., 'Create a business report about market analysis', 'Generate a technical documentation for API usage'). Must be plain text input only - no file uploads, attachments, images, or multimedia content are supported."
|
1214
1214
|
},
|
1215
1215
|
"filename": {
|
1216
1216
|
"type": "string",
|
1217
1217
|
"description": "The filename for the generated PDF"
|
1218
|
+
},
|
1219
|
+
"language": {
|
1220
|
+
"type": "string",
|
1221
|
+
"description": "The language for the generated PDF content.",
|
1222
|
+
"enum": ["zh", "en", "de", "es", "fr", "ja", "pt", "zh-tw", "ar", "cs", "da", "fi", "el", "hu", "it", "nl", "no", "pl", "sv", "tr"]
|
1223
|
+
},
|
1224
|
+
"enable_web_search": {
|
1225
|
+
"type": "boolean",
|
1226
|
+
"description": "Whether to enable web search to gather additional information for content generation",
|
1227
|
+
"default": False
|
1218
1228
|
}
|
1219
1229
|
},
|
1220
|
-
"required": ["
|
1230
|
+
"required": ["prompt", "filename", "language"]
|
1221
1231
|
}
|
1222
1232
|
),
|
1223
1233
|
types.Tool(
|
@@ -1271,7 +1281,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
1271
1281
|
),
|
1272
1282
|
types.Tool(
|
1273
1283
|
name="ocr_document",
|
1274
|
-
description="Perform OCR (Optical Character Recognition) on documents to recognize and extract text from scanned
|
1284
|
+
description="Perform OCR (Optical Character Recognition) on documents to recognize and extract text from scanned PDF documents. Output as the specified format file. Note: Use this tool for scanned documents or image-based PDFs where text needs to be recognized. For regular PDF text extraction, use convert_document PDF-to-TXT conversion instead.",
|
1275
1285
|
inputSchema={
|
1276
1286
|
"type": "object",
|
1277
1287
|
"properties": {
|
@@ -1571,19 +1581,35 @@ async def handle_call_tool(name: str, arguments: dict | None) -> list[types.Text
|
|
1571
1581
|
return [result]
|
1572
1582
|
|
1573
1583
|
elif name == "create_pdf":
|
1574
|
-
from .create_pdf import
|
1575
|
-
|
1584
|
+
from .create_pdf import PDFCreator
|
1585
|
+
prompt = arguments.get("prompt")
|
1576
1586
|
filename = arguments.get("filename")
|
1577
|
-
|
1578
|
-
|
1587
|
+
language = arguments.get("language")
|
1588
|
+
enable_web_search = arguments.get("enable_web_search", False)
|
1589
|
+
|
1590
|
+
if not prompt:
|
1591
|
+
error_msg = "prompt参数不能为空"
|
1579
1592
|
await logger.error(error_msg)
|
1580
1593
|
return [types.TextContent(type="text", text=error_msg)]
|
1581
1594
|
if not filename:
|
1582
1595
|
error_msg = "filename参数不能为空"
|
1583
1596
|
await logger.error(error_msg)
|
1584
1597
|
return [types.TextContent(type="text", text=error_msg)]
|
1598
|
+
if not language:
|
1599
|
+
error_msg = "language参数不能为空"
|
1600
|
+
await logger.error(error_msg)
|
1601
|
+
return [types.TextContent(type="text", text=error_msg)]
|
1585
1602
|
|
1586
|
-
|
1603
|
+
# 创建PDF创建器
|
1604
|
+
file_handler = FileHandler(logger)
|
1605
|
+
pdf_creator = PDFCreator(logger, file_handler)
|
1606
|
+
|
1607
|
+
result = await pdf_creator.create_pdf_from_prompt(
|
1608
|
+
prompt=prompt,
|
1609
|
+
language=language,
|
1610
|
+
enable_web_search=enable_web_search,
|
1611
|
+
original_name=filename
|
1612
|
+
)
|
1587
1613
|
# 构建结果报告
|
1588
1614
|
report_msg = generate_result_report(
|
1589
1615
|
[result]
|
lightpdf_aipdf_mcp/summarizer.py
CHANGED
@@ -38,45 +38,8 @@ class Summarizer(BaseApiClient):
|
|
38
38
|
|
39
39
|
data = extra_params.copy() if extra_params else {}
|
40
40
|
|
41
|
-
await self.
|
42
|
-
|
43
|
-
if self.file_handler.is_oss_id(file_path):
|
44
|
-
data = data.copy()
|
45
|
-
data["resource_id"] = file_path.split("oss_id://")[1]
|
46
|
-
headers["Content-Type"] = "application/json"
|
47
|
-
response = await client.post(
|
48
|
-
self.api_base_url,
|
49
|
-
json=data,
|
50
|
-
headers=headers
|
51
|
-
)
|
52
|
-
elif self.file_handler.is_url(file_path):
|
53
|
-
file_path_mod = file_path
|
54
|
-
if isinstance(file_path, str) and "arxiv.org/pdf/" in file_path:
|
55
|
-
from urllib.parse import urlparse, urlunparse
|
56
|
-
url_obj = urlparse(file_path)
|
57
|
-
if not url_obj.path.endswith(".pdf"):
|
58
|
-
new_path = url_obj.path + ".pdf"
|
59
|
-
file_path_mod = urlunparse(url_obj._replace(path=new_path))
|
60
|
-
data = data.copy()
|
61
|
-
data["url"] = file_path_mod
|
62
|
-
headers["Content-Type"] = "application/json"
|
63
|
-
response = await client.post(
|
64
|
-
self.api_base_url,
|
65
|
-
json=data,
|
66
|
-
headers=headers
|
67
|
-
)
|
68
|
-
else:
|
69
|
-
with open(file_path, "rb") as f:
|
70
|
-
files = {"file": f}
|
71
|
-
response = await client.post(
|
72
|
-
self.api_base_url,
|
73
|
-
files=files,
|
74
|
-
data=data,
|
75
|
-
headers=headers
|
76
|
-
)
|
77
|
-
|
78
|
-
task_id = await self._handle_api_response(response, response_action)
|
79
|
-
await self.logger.log("info", f"摘要任务1,task_id: {task_id}")
|
41
|
+
task_id = await self._create_task(client, file_path, data, response_action)
|
42
|
+
await self.logger.log("debug", f"摘要任务1,task_id: {task_id}")
|
80
43
|
|
81
44
|
file_hash = await self._wait_for_task(client, task_id, "摘要1")
|
82
45
|
|
@@ -86,12 +49,12 @@ class Summarizer(BaseApiClient):
|
|
86
49
|
|
87
50
|
data = extra_params.copy() if extra_params else {}
|
88
51
|
data["template_id"] = "63357fa3-ba37-47d5-b9c3-8b10ed0a59d6"
|
89
|
-
data["response_type"] =
|
52
|
+
data["response_type"] = 0
|
90
53
|
data["file_hash"] = file_hash
|
91
54
|
data["prompt"] = prompt
|
92
55
|
data["language"] = language
|
93
56
|
|
94
|
-
await self.logger.log("
|
57
|
+
await self.logger.log("debug", f"正在提交{response_action}...{data}")
|
95
58
|
response = await client.post(
|
96
59
|
self.api_base_url,
|
97
60
|
json=data,
|
@@ -99,13 +62,13 @@ class Summarizer(BaseApiClient):
|
|
99
62
|
)
|
100
63
|
|
101
64
|
task_id = await self._handle_api_response(response, response_action)
|
102
|
-
await self.logger.log("
|
65
|
+
await self.logger.log("debug", f"摘要任务2,task_id: {task_id}")
|
103
66
|
|
104
67
|
content = await self._wait_for_task(client, task_id, "摘要2", is_raw=True)
|
105
68
|
|
106
69
|
summary = content.get("answer", {}).get("text", "")
|
107
70
|
|
108
|
-
await self.logger.log("
|
71
|
+
await self.logger.log("debug", f"摘要完成。")
|
109
72
|
return SummarizeResult(
|
110
73
|
success=True,
|
111
74
|
file_path=file_path,
|
@@ -0,0 +1,13 @@
|
|
1
|
+
lightpdf_aipdf_mcp/__init__.py,sha256=PPnAgpvJLYLVOTxnHDmJAulFnHJD6wuTwS6tRGjqq6s,141
|
2
|
+
lightpdf_aipdf_mcp/common.py,sha256=VOipRuz2veRMhpvr0lJ2nZwuEZntx1MiRxDSNx0fSWs,9310
|
3
|
+
lightpdf_aipdf_mcp/converter.py,sha256=r8iO5R5vLNNKWdb6WSnwzTwwmp2TvgLXSIvvA4y___o,15336
|
4
|
+
lightpdf_aipdf_mcp/create_pdf.py,sha256=JC8VIkmc5Hg1-q2M-DCbf0bGRaZDCem1D4qrqAfeD1Q,13062
|
5
|
+
lightpdf_aipdf_mcp/editor.py,sha256=BR-sWW9L7tybEPOhdc8W-uwdBoom19EPTmGDvy_2gMc,27941
|
6
|
+
lightpdf_aipdf_mcp/ocr.py,sha256=IyzxisA6qtXcGTHZofpUYXYDdcIjUaaHcVUKpM7DH9A,2832
|
7
|
+
lightpdf_aipdf_mcp/server.py,sha256=vOWDu2j-m7sumNt_cVCPAu1xXO2N6Z5jfyO1yDtvGZ4,80747
|
8
|
+
lightpdf_aipdf_mcp/summarizer.py,sha256=UPAftDKjp2NFE2Wfoi2yAsGfaWqihu-c_W_BwfhVy0c,3671
|
9
|
+
lightpdf_aipdf_mcp/translator.py,sha256=nuZa4FpsA0xeRWAEGqSPIM55aJuazJX1m32uajowo7I,2778
|
10
|
+
lightpdf_aipdf_mcp-0.1.145.dist-info/METADATA,sha256=8un8BLPQd6FZfLYKpIEu3CmRPh22WeE_SsI-AhOswdg,8120
|
11
|
+
lightpdf_aipdf_mcp-0.1.145.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
+
lightpdf_aipdf_mcp-0.1.145.dist-info/entry_points.txt,sha256=X7TGUe52N4sYH-tYt0YUGApeJgw-efQlZA6uAZmlmr4,63
|
13
|
+
lightpdf_aipdf_mcp-0.1.145.dist-info/RECORD,,
|
@@ -1,13 +0,0 @@
|
|
1
|
-
lightpdf_aipdf_mcp/__init__.py,sha256=PPnAgpvJLYLVOTxnHDmJAulFnHJD6wuTwS6tRGjqq6s,141
|
2
|
-
lightpdf_aipdf_mcp/common.py,sha256=T4WKhtoWvDEosoU36ryZ-7IS62iNm_TL8H_jo6nFf7c,9214
|
3
|
-
lightpdf_aipdf_mcp/converter.py,sha256=r8iO5R5vLNNKWdb6WSnwzTwwmp2TvgLXSIvvA4y___o,15336
|
4
|
-
lightpdf_aipdf_mcp/create_pdf.py,sha256=oALIhOBo60D3Gu_li7d7FF0COhFfSTM-BJpc63r9iAs,2465
|
5
|
-
lightpdf_aipdf_mcp/editor.py,sha256=BR-sWW9L7tybEPOhdc8W-uwdBoom19EPTmGDvy_2gMc,27941
|
6
|
-
lightpdf_aipdf_mcp/ocr.py,sha256=IyzxisA6qtXcGTHZofpUYXYDdcIjUaaHcVUKpM7DH9A,2832
|
7
|
-
lightpdf_aipdf_mcp/server.py,sha256=rBSp_x51nkEWn8L95qOXeXVKAJY-8v6Uc2QQt3GNdoo,79530
|
8
|
-
lightpdf_aipdf_mcp/summarizer.py,sha256=2QMMgo_xxlEDSd_STPh7-1lBc4VRsL4SPSTijJPyb3I,5456
|
9
|
-
lightpdf_aipdf_mcp/translator.py,sha256=nuZa4FpsA0xeRWAEGqSPIM55aJuazJX1m32uajowo7I,2778
|
10
|
-
lightpdf_aipdf_mcp-0.1.143.dist-info/METADATA,sha256=6cFx5rhLHrIpUtPcvmkLXkFlBQViQjH0ZGISIsie6ac,8120
|
11
|
-
lightpdf_aipdf_mcp-0.1.143.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
-
lightpdf_aipdf_mcp-0.1.143.dist-info/entry_points.txt,sha256=X7TGUe52N4sYH-tYt0YUGApeJgw-efQlZA6uAZmlmr4,63
|
13
|
-
lightpdf_aipdf_mcp-0.1.143.dist-info/RECORD,,
|
File without changes
|
{lightpdf_aipdf_mcp-0.1.143.dist-info → lightpdf_aipdf_mcp-0.1.145.dist-info}/entry_points.txt
RENAMED
File without changes
|