pdf-project-extractor
Version:
PDF dosyalarından proje bilgilerini otomatik olarak çıkaran bir TypeScript/Node.js paketi
153 lines (149 loc) • 5.67 kB
JavaScript
import fs from 'fs';
import pdfParse from 'pdf-parse-fork';
const GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent";
export class ProjectExtractor {
constructor(options) {
if (!options.apiKey) {
throw new Error("API anahtarı gereklidir");
}
this.apiKey = options.apiKey;
this.pdfFile = options.pdfFile;
this.logger = this.createLogger();
}
createLogger() {
return {
info: (message) => {
const timestamp = new Date().toLocaleTimeString("tr-TR");
console.log(`\x1b[36m[${timestamp}] INFO:\x1b[0m ${message}`);
},
success: (message) => {
const timestamp = new Date().toLocaleTimeString("tr-TR");
console.log(`\x1b[32m[${timestamp}] BAŞARILI:\x1b[0m ${message}`);
},
error: (message) => {
const timestamp = new Date().toLocaleTimeString("tr-TR");
console.error(`\x1b[31m[${timestamp}] HATA:\x1b[0m ${message}`);
},
};
}
async extractFromPDF(pdfInput) {
try {
this.logger.info(`PDF analizi başlatılıyor...`);
let dataBuffer;
if (typeof pdfInput === 'string') {
if (!fs.existsSync(pdfInput)) {
throw new Error("PDF dosyası bulunamadı");
}
dataBuffer = fs.readFileSync(pdfInput);
}
else {
dataBuffer = pdfInput;
}
const data = await pdfParse(dataBuffer);
this.logger.success("PDF başarıyla ayrıştırıldı");
const text = data.text;
if (!text || text.trim().length === 0) {
throw new Error("PDF dosyası boş veya metin içermiyor");
}
this.logger.info("Metin analizi başlatılıyor...");
const analysis = await this.analyzeWithGemini(text);
return analysis;
}
catch (error) {
this.logger.error(`PDF okuma hatası: ${error.message}`);
throw new Error(`PDF okuma hatası: ${error.message}`);
}
}
async analyzeWithGemini(text) {
if (!text || typeof text !== "string") {
throw new Error("Analiz için geçerli bir metin gereklidir");
}
try {
const response = await fetch(`${GEMINI_API_URL}?key=${this.apiKey}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
contents: [
{
parts: [
{
text: this.getPromptTemplate().replace("{text}", text),
},
],
},
],
generationConfig: {
temperature: 0.1,
maxOutputTokens: 2000,
topP: 0.3,
topK: 20,
},
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || "API hatası");
}
const result = await response.json();
if (result.candidates && result.candidates[0]?.content?.parts?.[0]?.text) {
const jsonText = result.candidates[0].content.parts[0].text.trim()
.replace(/```json\n?/g, "")
.replace(/```\n?/g, "")
.trim();
return JSON.parse(jsonText);
}
throw new Error("API'den geçerli bir yanıt alınamadı");
}
catch (error) {
this.logger.error(`Analiz hatası: ${error.message}`);
throw new Error(`Analiz hatası: ${error.message}`);
}
}
getPromptTemplate() {
return `Aşağıdaki metni analiz et ve SADECE metinde açıkça belirtilen veya doğrudan çıkarılabilen bilgileri JSON formatında döndür.
Metni detaylı bir şekilde analiz et ve özellikle proje özeti ve yazar bilgisine odaklan.
Metinde olmayan bilgileri ASLA ekleme veya tahmin etme.
Metin: {text}
İstenen JSON formatı şu şekilde olmalıdır (tüm alanlar zorunludur, eğer bilgi yoksa null veya boş array kullanın):
{
"projectName": string | null,
"projectSummary": string,
"author": {
"name": string | null,
"title": string | null,
"organization": string | null
},
"startDate": string | null,
"country": string | null,
"teamSize": number | null,
"category": string | null,
"features": [],
"technologies": [],
"targetAudience": [],
"applicationAreas": [],
"challenges": [],
"benefits": [],
"implementation": {
"phases": [],
"requirements": [],
"constraints": []
},
"links": [],
"images": [],
"metrics": {
"performance": [],
"quality": [],
"success": []
}
}`;
}
static async extractInfo(file) {
const extractor = new ProjectExtractor({
apiKey: process.env.NEXT_PUBLIC_GEMINI_API_KEY || '',
pdfFile: file instanceof File ? Buffer.from(await file.arrayBuffer()) : file
});
return extractor.extractFromPDF(extractor.pdfFile);
}
}