const fs = require('fs'); const path = require('path'); const { execFile } = require('child_process'); const { v4: uuidv4 } = require('uuid'); const express = require('express'); // JSON解析用にexpressをインポート const { API_KEY } = require('../config.js'); // API_KEYをインポート // tmpディレクトリのパス const tmpDir = path.join(__dirname, 'tmp'); // tmpディレクトリが存在しない場合は作成 if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir); } // POSTエンドポイント module.exports = (app) => { app.post('/pdfToText', express.json({ limit: '30mb' }), async (req, res) => { try { // APIキーのチェック const apiKey = req.headers['x-api-key']; if (!apiKey || apiKey !== API_KEY) { console.log('APIキーが不正です'); return res.status(401).json({ error: 'APIキーが不正です' }); } // base64, fileName の3つをチェック const { base64, fileName } = req.body; if (!base64 || !fileName) { return res.status(400).json({ error: 'base64とfileNameは必須です' }); } const txtBuffer = await pdfToTextConvert(base64, fileName); const safeFileName = encodeURIComponent(path.parse(fileName).name); // ファイル名をエスケープ res.set({ 'Content-Type': 'text/plain', 'Content-Disposition': `attachment; filename="${safeFileName}.txt"` }); res.send(txtBuffer); } catch (err) { console.error('変換エラー:', err.message); res.status(500).json({ error: err.message }); } }); }; // PDF テキスト変換処理 async function pdfToTextConvert(base64) { const tempId = uuidv4(); // 一意のIDを生成 const pdfPath = path.join(tmpDir, `${tempId}.pdf`); const outputPath = path.join(tmpDir, `${tempId}.txt`); // base64データをファイルに保存 fs.writeFileSync(pdfPath, Buffer.from(base64, 'base64')); // pdfuniteでテキストに変換 await new Promise((resolve, reject) => { const child = execFile( 'pdftotext', [ '-layout', '-nopgbrk', pdfPath, outputPath ], (error, stdout, stderr) => { if (error) { console.error('stderr:', stderr); reject(error); } else { resolve(); } } ); // 60秒タイムアウト const timeout = setTimeout(() => { child.kill('SIGTERM'); // SIGTERMを使用してプロセスを終了 reject(new Error('テキストへの変換がタイムアウトしました(60秒経過)')); }, 60000); child.on('exit', () => clearTimeout(timeout)); }); // 変換されたテキストファイルを読み込み if (!fs.existsSync(outputPath)) { // cleanup fs.unlinkSync(pdfPath);; throw new Error('テキストへの変換に失敗しました'); } const txtBuffer = fs.readFileSync(outputPath); // cleanup fs.unlinkSync(pdfPath); fs.unlinkSync(outputPath); return txtBuffer; }