From 6dd34fe70354891a57b717f422d10b233ce27b3f Mon Sep 17 00:00:00 2001 From: mstfyldz Date: Fri, 14 Aug 2026 13:13:37 +0300 Subject: [PATCH] feat: enhance UDF file extraction pipeline to unzip container and handle content.xml or embedded PDF files --- src/controllers/document.controller.ts | 49 ++++++++++++++++++++----- src/controllers/precedent.controller.ts | 8 ++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/controllers/document.controller.ts b/src/controllers/document.controller.ts index bb65744..ddb2b74 100644 --- a/src/controllers/document.controller.ts +++ b/src/controllers/document.controller.ts @@ -407,17 +407,48 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety try { const zip = new AdmZip(file.buffer); const zipEntries = zip.getEntries(); - const contentEntry = zipEntries.find((entry: any) => entry.entryName === "content.xml" || entry.entryName.endsWith(".xml")); - if (!contentEntry) { - throw new Error("No XML content found inside UDF/ZIP"); + + // 1. Önce XML dosyasını kontrol et (content.xml veya *.xml) + const xmlEntry = zipEntries.find((entry: any) => + !entry.isDirectory && (entry.entryName === "content.xml" || entry.entryName.toLowerCase().endsWith(".xml")) + ); + + // 2. İçerisinde gömülü PDF dosyası var mı kontrol et (*.pdf) + const pdfEntry = zipEntries.find((entry: any) => + !entry.isDirectory && entry.entryName.toLowerCase().endsWith(".pdf") + ); + + // Eğer XML bulunmuşsa XML üzerinden devam et + if (xmlEntry) { + const xmlData = zip.readAsText(xmlEntry); + if (xmlData && xmlData.trim()) { + const plainText = xmlData.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim(); + if (plainText.length > 20) { + return plainText; + } + } } - const xmlData = zip.readAsText(contentEntry); - // Remove XML tags and replace with space, then replace multiple spaces with single space - const plainText = xmlData.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim(); - return plainText; - } catch (err) { + + // Eğer UDF içerisinden PDF çıktıysa PDF ayrıştırıcı (officeParser) üzerinden devam et + if (pdfEntry) { + const pdfBuffer = pdfEntry.getData(); + const pdfResult: any = await officeParser.parseOffice(pdfBuffer); + const pdfText = typeof pdfResult === 'string' ? pdfResult : (pdfResult?.toText ? pdfResult.toText() : String(pdfResult || '')); + if (pdfText && pdfText.trim()) { + return pdfText.trim(); + } + } + + // Yedek durum: Son çare XML metnini döndür + if (xmlEntry) { + const xmlData = zip.readAsText(xmlEntry); + return xmlData.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim(); + } + + throw new Error("UDF/ZIP arşivinde okunabilir XML veya PDF içeriği bulunamadı."); + } catch (err: any) { console.error("UDF parse error:", err); - throw new Error("UDF dosyası okunamadı veya bozuk."); + throw new Error(`UDF dosyası ayrıştırılamadı: ${err.message || 'Bozuk arşiv'}`); } } diff --git a/src/controllers/precedent.controller.ts b/src/controllers/precedent.controller.ts index 827dc66..196cf05 100644 --- a/src/controllers/precedent.controller.ts +++ b/src/controllers/precedent.controller.ts @@ -60,15 +60,15 @@ SADECE anahtar kelimeleri aralarına boşluk koyarak yaz. Noktalama işareti, a return res.status(mcpResponse.status).json({ error: 'Arama servisi hata döndürdü', details: errorData }); } - const data = await mcpResponse.json(); + let data = await mcpResponse.json(); // Hukuki niyet ve sonuç (örn. beraat, bozma) odaklı akıllı yeniden sıralama ve puanlama let rawItems: any[] = data.decisions || data.results || data.data || data.hits || (Array.isArray(data) ? data : []); if (Array.isArray(rawItems) && rawItems.length > 0) { - const searchTerms = phrase.toLowerCase().split(/\s+/).filter(Boolean); - const isBeraatSearch = searchTerms.some(t => t.includes('beraat')); - const isBozmaSearch = searchTerms.some(t => t.includes('bozma') || t.includes('bozulması')); + const searchTerms = phrase.toLowerCase().split(/\s+/).filter((Boolean) as (value: string) => boolean); + const isBeraatSearch = searchTerms.some((t: string) => t.includes('beraat')); + const isBozmaSearch = searchTerms.some((t: string) => t.includes('bozma') || t.includes('bozulması')); const scoredItems = rawItems.map((item: any) => { const fullText = (