markpdfdown 0.1.0
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.
- package/LICENSE +201 -0
- package/README.md +128 -0
- package/bin/cli.js +130 -0
- package/dist/main/AnthropicClient-CTbHYiqm.js +193 -0
- package/dist/main/GeminiClient-CrtYbwaF.js +196 -0
- package/dist/main/OllamaClient-DKJsnvIt.js +197 -0
- package/dist/main/OpenAIClient-gyy2nFkw.js +214 -0
- package/dist/main/OpenAIResponsesClient-DETYz2nL.js +297 -0
- package/dist/main/index.js +3523 -0
- package/dist/preload/index.js +102 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/renderer/assets/MarkPDFdown-C6Sb1T4M.png +0 -0
- package/dist/renderer/assets/index-CbMlWqbh.css +327 -0
- package/dist/renderer/assets/index-DeDe7lry.js +123956 -0
- package/dist/renderer/index.html +14 -0
- package/package.json +156 -0
- package/src/core/infrastructure/db/migrations/20250414154412_/migration.sql +24 -0
- package/src/core/infrastructure/db/migrations/20250419090345_/migration.sql +29 -0
- package/src/core/infrastructure/db/migrations/20250419104636_/migration.sql +47 -0
- package/src/core/infrastructure/db/migrations/20260121154536_add_worker_fields/migration.sql +50 -0
- package/src/core/infrastructure/db/migrations/20260124014806_/migration.sql +55 -0
- package/src/core/infrastructure/db/migrations/migration_lock.toml +3 -0
- package/src/core/infrastructure/db/schema.prisma +104 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { L as LLMClient } from "./index.js";
|
|
2
|
+
class OpenAIResponsesClient extends LLMClient {
|
|
3
|
+
constructor(apiKey, baseUrl) {
|
|
4
|
+
super(apiKey, baseUrl || "https://api.openai.com/v1/responses");
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 执行OpenAI Responses API补全
|
|
8
|
+
*/
|
|
9
|
+
async completion(options) {
|
|
10
|
+
try {
|
|
11
|
+
const normalizedOptions = this.normalizeOptions(options);
|
|
12
|
+
const { input, instructions } = this.convertMessagesToResponsesFormat(normalizedOptions.messages);
|
|
13
|
+
const requestBody = {
|
|
14
|
+
model: normalizedOptions.model || "gpt-4o",
|
|
15
|
+
input,
|
|
16
|
+
temperature: normalizedOptions.temperature ?? 0.7,
|
|
17
|
+
max_tokens: normalizedOptions.maxTokens,
|
|
18
|
+
stream: normalizedOptions.stream || false
|
|
19
|
+
};
|
|
20
|
+
if (instructions) {
|
|
21
|
+
requestBody.instructions = instructions;
|
|
22
|
+
}
|
|
23
|
+
if (normalizedOptions.tools && normalizedOptions.tools.length > 0) {
|
|
24
|
+
requestBody.tools = normalizedOptions.tools;
|
|
25
|
+
if (normalizedOptions.tool_choice) {
|
|
26
|
+
requestBody.tool_choice = normalizedOptions.tool_choice;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (normalizedOptions.response_format) {
|
|
30
|
+
requestBody.response_format = normalizedOptions.response_format;
|
|
31
|
+
}
|
|
32
|
+
const response = await fetch(`${this.baseUrl}`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"Authorization": `Bearer ${normalizedOptions.apiKey || this.apiKey}`,
|
|
37
|
+
"X-Title": "MarkPDFdown",
|
|
38
|
+
"HTTP-Referer": "https://github.com/MarkPDFdown"
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(requestBody)
|
|
41
|
+
});
|
|
42
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] POST ${this.baseUrl} (model: ${requestBody.model}) ${response.status} - ${response.statusText}`);
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const error = await response.json();
|
|
45
|
+
throw new Error(`OpenAI Responses API错误: ${error.error?.message || response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
if (normalizedOptions.stream && response.body && normalizedOptions.onUpdate) {
|
|
48
|
+
return this.handleResponsesStreaming(response, normalizedOptions);
|
|
49
|
+
} else {
|
|
50
|
+
const data = await response.json();
|
|
51
|
+
return this.parseResponsesOutput(data, normalizedOptions);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
55
|
+
throw new Error(`OpenAI Responses API补全请求失败: ${errorMessage}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 将消息转换为Responses API格式
|
|
60
|
+
* 提取system消息作为instructions,其他消息放入input
|
|
61
|
+
*/
|
|
62
|
+
convertMessagesToResponsesFormat(messages) {
|
|
63
|
+
const systemMessages = [];
|
|
64
|
+
const inputMessages = [];
|
|
65
|
+
for (const message of messages) {
|
|
66
|
+
if (message.role === "system") {
|
|
67
|
+
if (typeof message.content === "string") {
|
|
68
|
+
systemMessages.push(message.content);
|
|
69
|
+
} else if (Array.isArray(message.content)) {
|
|
70
|
+
for (const content of message.content) {
|
|
71
|
+
if (content.type === "text") {
|
|
72
|
+
systemMessages.push(content.text);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else if (message.content.type === "text") {
|
|
76
|
+
systemMessages.push(message.content.text);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const inputMessage = {
|
|
80
|
+
role: message.role
|
|
81
|
+
};
|
|
82
|
+
if (message.name) {
|
|
83
|
+
inputMessage.name = message.name;
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(message.content)) {
|
|
86
|
+
const allText = message.content.every((c) => c.type === "text");
|
|
87
|
+
if (allText) {
|
|
88
|
+
inputMessage.content = message.content.map((c) => c.text).join("");
|
|
89
|
+
} else {
|
|
90
|
+
inputMessage.content = message.content.map((content) => this.convertContentToResponsesAPIFormat(content));
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
if (typeof message.content === "string") {
|
|
94
|
+
inputMessage.content = message.content;
|
|
95
|
+
} else if (message.content.type === "text") {
|
|
96
|
+
inputMessage.content = message.content.text;
|
|
97
|
+
} else {
|
|
98
|
+
inputMessage.content = [this.convertContentToResponsesAPIFormat(message.content)];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
inputMessages.push(inputMessage);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const result = {
|
|
105
|
+
input: inputMessages
|
|
106
|
+
};
|
|
107
|
+
if (systemMessages.length > 0) {
|
|
108
|
+
result.instructions = systemMessages.join("\n\n");
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 将内容对象转换为Responses API格式(用于数组内容)
|
|
114
|
+
* Responses API有不同的内容类型命名
|
|
115
|
+
*/
|
|
116
|
+
convertContentToResponsesAPIFormat(content) {
|
|
117
|
+
switch (content.type) {
|
|
118
|
+
case "text":
|
|
119
|
+
return {
|
|
120
|
+
type: "input_text",
|
|
121
|
+
text: content.text
|
|
122
|
+
};
|
|
123
|
+
case "image_url": {
|
|
124
|
+
const imageContent = content;
|
|
125
|
+
return {
|
|
126
|
+
type: "input_image",
|
|
127
|
+
// Responses API uses 'input_image' for user-provided images
|
|
128
|
+
image_url: imageContent.image_url.url
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
case "tool_call": {
|
|
132
|
+
const toolCallContent = content;
|
|
133
|
+
return {
|
|
134
|
+
type: "function_call",
|
|
135
|
+
// Responses API uses 'function_call'
|
|
136
|
+
call_id: toolCallContent.tool_call_id,
|
|
137
|
+
name: toolCallContent.function.name,
|
|
138
|
+
arguments: toolCallContent.function.arguments
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
case "tool_result": {
|
|
142
|
+
const toolResultContent = content;
|
|
143
|
+
return {
|
|
144
|
+
type: "function_call_output",
|
|
145
|
+
// Responses API uses 'function_call_output'
|
|
146
|
+
call_id: toolResultContent.tool_call_id,
|
|
147
|
+
output: toolResultContent.content
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
default:
|
|
151
|
+
throw new Error(`不支持的内容类型: ${content.type}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 解析Responses API的输出
|
|
156
|
+
*/
|
|
157
|
+
parseResponsesOutput(data, options) {
|
|
158
|
+
let responseContent = "";
|
|
159
|
+
const toolCalls = [];
|
|
160
|
+
if (data.output && data.output.length > 0) {
|
|
161
|
+
const outputItem = data.output[0];
|
|
162
|
+
if (outputItem.content) {
|
|
163
|
+
if (typeof outputItem.content === "string") {
|
|
164
|
+
responseContent = outputItem.content;
|
|
165
|
+
} else if (Array.isArray(outputItem.content)) {
|
|
166
|
+
responseContent = outputItem.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (outputItem.tool_calls && outputItem.tool_calls.length > 0) {
|
|
170
|
+
for (const toolCall of outputItem.tool_calls) {
|
|
171
|
+
toolCalls.push({
|
|
172
|
+
id: toolCall.id,
|
|
173
|
+
type: toolCall.type,
|
|
174
|
+
function: {
|
|
175
|
+
name: toolCall.function.name,
|
|
176
|
+
arguments: toolCall.function.arguments
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
content: responseContent,
|
|
184
|
+
model: data.model,
|
|
185
|
+
finishReason: data.output?.[0]?.finish_reason || "stop",
|
|
186
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
187
|
+
responseFormat: options.response_format?.type,
|
|
188
|
+
rawResponse: data
|
|
189
|
+
// 保留原始响应以便调试
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 处理Responses API的流式响应
|
|
194
|
+
* 使用SSE格式: event: <type>\ndata: <json>\n\n
|
|
195
|
+
*/
|
|
196
|
+
async handleResponsesStreaming(response, options) {
|
|
197
|
+
const reader = response.body.getReader();
|
|
198
|
+
const decoder = new TextDecoder("utf-8");
|
|
199
|
+
let content = "";
|
|
200
|
+
const toolCalls = [];
|
|
201
|
+
let finishReason;
|
|
202
|
+
let model = options.model || "gpt-4o";
|
|
203
|
+
let buffer = "";
|
|
204
|
+
const processStream = async () => {
|
|
205
|
+
const { done, value } = await reader.read();
|
|
206
|
+
if (done) {
|
|
207
|
+
return {
|
|
208
|
+
content,
|
|
209
|
+
model,
|
|
210
|
+
finishReason: finishReason || "stop",
|
|
211
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
212
|
+
responseFormat: options.response_format?.type
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
buffer += decoder.decode(value, { stream: true });
|
|
216
|
+
const lines = buffer.split("\n");
|
|
217
|
+
buffer = lines.pop() || "";
|
|
218
|
+
let currentEvent = null;
|
|
219
|
+
for (const line of lines) {
|
|
220
|
+
const trimmedLine = line.trim();
|
|
221
|
+
if (trimmedLine === "") {
|
|
222
|
+
currentEvent = null;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (trimmedLine.startsWith("event:")) {
|
|
226
|
+
currentEvent = trimmedLine.substring(6).trim();
|
|
227
|
+
} else if (trimmedLine.startsWith("data:")) {
|
|
228
|
+
const dataStr = trimmedLine.substring(5).trim();
|
|
229
|
+
if (dataStr === "[DONE]") {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
const data = JSON.parse(dataStr);
|
|
234
|
+
if (currentEvent === "response.output_text.delta") {
|
|
235
|
+
if (data.delta) {
|
|
236
|
+
content += data.delta;
|
|
237
|
+
if (options.onUpdate) {
|
|
238
|
+
options.onUpdate(content);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} else if (currentEvent === "response.output_item.done") {
|
|
242
|
+
if (data.item) {
|
|
243
|
+
if (data.item.tool_calls && data.item.tool_calls.length > 0) {
|
|
244
|
+
for (const toolCall of data.item.tool_calls) {
|
|
245
|
+
toolCalls.push({
|
|
246
|
+
id: toolCall.id,
|
|
247
|
+
type: toolCall.type,
|
|
248
|
+
function: {
|
|
249
|
+
name: toolCall.function.name,
|
|
250
|
+
arguments: toolCall.function.arguments
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
} else if (currentEvent === "response.completed") {
|
|
257
|
+
if (data.response) {
|
|
258
|
+
model = data.response.model || model;
|
|
259
|
+
finishReason = data.response.output?.[0]?.finish_reason;
|
|
260
|
+
}
|
|
261
|
+
} else if (currentEvent === "response.tool_calls.delta") {
|
|
262
|
+
if (data.delta && data.index !== void 0) {
|
|
263
|
+
let toolCall = toolCalls[data.index];
|
|
264
|
+
if (!toolCall && data.delta.id) {
|
|
265
|
+
toolCall = {
|
|
266
|
+
id: data.delta.id,
|
|
267
|
+
type: "function",
|
|
268
|
+
function: {
|
|
269
|
+
name: "",
|
|
270
|
+
arguments: ""
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
toolCalls[data.index] = toolCall;
|
|
274
|
+
}
|
|
275
|
+
if (toolCall && data.delta.function) {
|
|
276
|
+
if (data.delta.function.name) {
|
|
277
|
+
toolCall.function.name = data.delta.function.name;
|
|
278
|
+
}
|
|
279
|
+
if (data.delta.function.arguments) {
|
|
280
|
+
toolCall.function.arguments += data.delta.function.arguments;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.warn("Failed to parse SSE data:", dataStr, e);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return processStream();
|
|
291
|
+
};
|
|
292
|
+
return processStream();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export {
|
|
296
|
+
OpenAIResponsesClient
|
|
297
|
+
};
|