import fs from "fs/promises";
import path from "path";
// @ts-ignore
import pdfParse from "pdf-parse";
import { db } from "../database.js";
import { structureParser } from "./structure_parser.js";
import { summarizer } from "./summarizer.js";
import { mathExplainer } from "./math_explainer.js";
import { codeGenerator } from "./code_generator.js";
import { visualization } from "./visualization.js";
export const reportGenerator = {
definition: {
name: "generate_report",
description: "生成完整的论文分析报告(Markdown格式),包含摘要、结构、公式、代码与可视化",
inputSchema: {
type: "object",
properties: {
paper_path: { type: "string", description: "PDF文件的绝对路径" },
output_path: { type: "string", description: "输出Markdown文件的路径(可选)" },
},
required: ["paper_path"],
additionalProperties: false,
},
},
handler: async (input: any) => {
const { paper_path, output_path } = input;
// 1. Read PDF
let pdfData;
try {
const buf = await fs.readFile(paper_path);
pdfData = await pdfParse(buf);
} catch (e) {
return { content: [{ type: "text", text: `Error reading PDF: ${e}` }] };
}
const fullText = pdfData.text;
const meta = pdfData.info || {};
const title = meta.Title || path.basename(paper_path);
// 2. Run Tools
// Structure
const structRes = await structureParser.handler({ text: fullText });
const sections = JSON.parse(structRes.content[0].text);
// Summarizer - General
const summaryRes = await summarizer.handler({ text: fullText, mode: "summary" });
const summary = summaryRes.content[0].text;
// Summarizer - Methodology
const methodRes = await summarizer.handler({ text: fullText, mode: "methodology" });
const methodSummary = methodRes.content[0].text;
// Math Explainer (Extract from Method section if possible, else full text)
const methodText = sections["Method"] || sections["Introduction"] || fullText.slice(0, 2000);
const mathRes = await mathExplainer.handler({ text: methodText });
const mathInfo = JSON.parse(mathRes.content[0].text);
// Code Generator (Extract from Experiments)
const expText = sections["Experiments"] || fullText.slice(-3000);
const codeRes = await codeGenerator.handler({ task_type: "config_yaml", context: expText });
const codeConfig = codeRes.content[0].text;
// Visualization
const vizRes = await visualization.handler({ text: summary, type: "flowchart" });
const mermaidCode = vizRes.content[0].text;
// 3. Assemble Markdown
const mdContent = `
# ${title}
**Metadata**
- **Path**: \`${paper_path}\`
- **Authors**: ${meta.Author || "Unknown"}
- **Year**: ${meta.CreationDate ? meta.CreationDate.slice(2, 6) : "Unknown"}
---
## 1. Intelligent Summary
${summary}
---
## 2. Methodology Overview
${methodSummary}
---
## 3. Structure Analysis
The paper is structured into the following detected sections:
${Object.keys(sections).map(k => `- **${k}**: ${sections[k].slice(0, 100).replace(/\n/g, " ")}...`).join("\n")}
---
## 4. Mathematical Analysis
**Key Variables & Formulas**
> Note: Formulas are extracted and rendered. Complex PDF math may require verification.
${mathInfo.variables ? mathInfo.variables.map((v: string) => `- $${v}$`).join("\n") : "No explicit variables detected."}
**Explained Expressions**:
${mathInfo.expressions ? mathInfo.expressions.map((e: string) => `
$$
${e}
$$
`).join("\n") : "No expressions extracted."}
---
## 5. Visualization (Mermaid)
\`\`\`mermaid
${mermaidCode}
\`\`\`
---
## 6. Experiment Configuration (Generated)
Based on the extracted parameters, here is a suggested configuration:
\`\`\`yaml
${codeConfig}
\`\`\`
---
*Generated by Trae MCP Researcher*
`.trim();
// 4. Write to File
const finalPath = output_path || path.join(path.dirname(paper_path), `${path.basename(paper_path, ".pdf")}_report.md`);
await fs.writeFile(finalPath, mdContent, "utf-8");
return {
content: [
{
type: "text",
text: `Report generated successfully at: ${finalPath}\n\nPreview:\n${mdContent.slice(0, 500)}...`
}
]
};
},
};