如何用Node.js+TypeScript通过OpenAI API关联上传的PDF提取数据为JSON?
问题根源
你当前的代码错误在于:上传文件时指定了purpose: "assistants",但调用的是普通的chat.completions.create接口——这个接口无法访问通过Assistants API上传的文件,两者属于不同工作流,因此模型无法获取PDF内容。
方法一:使用OpenAI Assistants API(推荐,原生支持文件处理)
Assistants API专门设计用于文件交互,流程为创建助手、线程、关联文件的消息,最后运行助手获取结果。
完整TypeScript代码示例:
import express, { Request, Response } from 'express'; import fs from 'fs'; import { OpenAI } from 'openai'; const app = express(); const port = 3000; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY // 从环境变量读取API密钥 }); app.get("/", async (req: Request, res: Response) => { if (!openai) { res.status(500).send("OpenAI object not created"); return; } try { // 1. 上传PDF文件 const file = await openai.files.create({ purpose: "assistants", file: fs.createReadStream("./test.pdf"), }); // 2. 创建具备文件处理能力的助手 const assistant = await openai.beta.assistants.create({ name: "PDF数据提取助手", instructions: "提取上传PDF中的所有数据,返回严格格式的JSON对象,键名需准确反映数据含义", model: "gpt-4o", tools: [{ type: "file_search" }], // 启用文件搜索工具以读取PDF内容 }); // 3. 创建线程并添加关联文件的用户消息 const thread = await openai.beta.threads.create({ messages: [ { role: "user", content: "提取这个PDF里的所有数据,返回严格JSON格式", attachments: [{ file_id: file.id, tools: [{ type: "file_search" }] }], }, ], }); // 4. 运行助手并等待处理完成 const run = await openai.beta.threads.runs.createAndPoll( thread.id, { assistant_id: assistant.id } ); // 5. 获取并返回结果 if (run.status === "completed") { const messages = await openai.beta.threads.messages.list(thread.id); const responseMessage = messages.data[0].content[0] as { text: { value: string } }; const extractedData = responseMessage.text.value; // 可选:清理资源,避免占用存储空间 await openai.files.delete(file.id); await openai.beta.assistants.delete(assistant.id); res.send({ extracted_data: extractedData }); } else { res.status(500).send(`助手运行失败,状态:${run.status}`); } } catch (error) { console.error(error); res.status(500).send("处理PDF时发生错误"); } }); app.listen(port, () => { console.log(`服务器运行在 http://localhost:${port}`); });
关键说明
- 必须启用
file_search工具,否则助手无法读取上传的文件内容 createAndPoll方法会自动等待助手完成处理,无需手动轮询状态- 处理完成后建议清理文件和助手资源,减少不必要的存储占用
方法二:先提取PDF文本,再传给Chat Completions接口
若不想使用Assistants API,可先通过第三方库提取PDF文本,再将文本作为prompt传入Chat Completions。
步骤1:安装PDF文本提取库
npm install pdf-parse @types/pdf-parse --save
步骤2:完整TypeScript代码示例
import express, { Request, Response } from 'express'; import fs from 'fs'; import pdf from 'pdf-parse'; import { OpenAI } from 'openai'; const app = express(); const port = 3000; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); app.get("/", async (req: Request, res: Response) => { if (!openai) { res.status(500).send("OpenAI object not created"); return; } try { // 1. 读取PDF并提取文本内容 const pdfBuffer = fs.readFileSync("./test.pdf"); const pdfData = await pdf(pdfBuffer); const pdfText = pdfData.text; // 2. 将文本传入Chat Completions,强制返回JSON格式 const completion = await openai.chat.completions.create({ model: "gpt-4o", messages: [ { role: "system", content: "接收一段PDF提取的文本,将其中所有数据转换为严格的JSON对象,仅返回JSON,无需额外解释" }, { role: "user", content: `PDF文本内容:\n${pdfText}` } ], temperature: 0.1, // 降低随机性,保证JSON格式稳定 response_format: { type: "json_object" } // 强制模型输出标准JSON }); const jsonData = completion.choices[0].message.content; res.send(JSON.parse(jsonData)); } catch (error) { console.error(error); res.status(500).send("处理PDF时发生错误"); } }); app.listen(port, () => { console.log(`服务器运行在 http://localhost:${port}`); });
关键说明
response_format: { type: "json_object" }可强制模型返回标准JSON,避免格式错误- 降低
temperature值能减少输出随机性,提升JSON结构稳定性 - 对于扫描版PDF,
pdf-parse无法提取文本,需额外搭配OCR工具(如tesseract.js)
内容的提问来源于stack exchange,提问作者Noam Azoulay
相关产品推荐
相关产品推荐

