Initial commit
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import { Response } from 'express';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { AuthenticatedRequest } from '../middleware/auth';
|
||||
import * as officeParser from 'officeparser';
|
||||
import Tesseract from 'tesseract.js';
|
||||
const heicConvert = require('heic-convert');
|
||||
|
||||
export const uploadDocument = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const file = req.file;
|
||||
const { case_id } = req.body;
|
||||
const user_id = req.user?.id;
|
||||
|
||||
if (!file || !case_id || !user_id) {
|
||||
return res.status(400).json({ error: 'Missing file or case_id' });
|
||||
}
|
||||
|
||||
let extractedText = '';
|
||||
const mimeType = file.mimetype.toLowerCase();
|
||||
|
||||
// IMAGE & OCR LOGIC
|
||||
if (mimeType.includes('image/')) {
|
||||
let imageBuffer = file.buffer;
|
||||
|
||||
// Convert HEIC to JPEG
|
||||
if (mimeType === 'image/heic' || file.originalname.toLowerCase().endsWith('.heic')) {
|
||||
imageBuffer = await heicConvert({
|
||||
buffer: file.buffer,
|
||||
format: 'JPEG',
|
||||
quality: 1
|
||||
});
|
||||
}
|
||||
|
||||
// Run Tesseract OCR (Turkish language)
|
||||
const { data: { text } } = await Tesseract.recognize(imageBuffer, 'tur');
|
||||
extractedText = text;
|
||||
|
||||
// DOCUMENT LOGIC
|
||||
} else {
|
||||
try {
|
||||
// officeParser natively supports pdf, docx, doc, rtf, txt, etc.
|
||||
extractedText = await officeParser.parseOffice(file.buffer);
|
||||
} catch (err: any) {
|
||||
console.error('officeParser Error:', err);
|
||||
return res.status(400).json({ error: 'Dosya formatı okunamadı veya desteklenmiyor.' });
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Upload File to Supabase Storage
|
||||
const filePath = `${user_id}/${Date.now()}_${file.originalname}`;
|
||||
const { error: uploadError } = await supabase.storage
|
||||
.from('case-documents')
|
||||
.upload(filePath, file.buffer, {
|
||||
contentType: file.mimetype,
|
||||
});
|
||||
|
||||
if (uploadError) {
|
||||
console.error('Storage Upload Error:', uploadError);
|
||||
return res.status(500).json({ error: 'Failed to upload document to storage' });
|
||||
}
|
||||
|
||||
// 3. Veritabanına Dosya Bilgisini Kaydet (documents tablosu)
|
||||
const { data: documentRecord, error: docError } = await supabase
|
||||
.from('documents')
|
||||
.insert([{
|
||||
case_id,
|
||||
user_id,
|
||||
storage_path: filePath,
|
||||
filename: file.originalname,
|
||||
mime_type: file.mimetype,
|
||||
file_size: file.size,
|
||||
ocr_status: 'done',
|
||||
extracted_text: extractedText
|
||||
}])
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (docError) throw docError;
|
||||
|
||||
// 3. DeepSeek (OpenAI) ile Hukuki Analiz Çıkarımı
|
||||
// Promptu tasarlıyoruz. JSON dönmesini istiyoruz.
|
||||
const systemPrompt = `
|
||||
Sen uzman bir Türk avukatısın. Sana verilen dava dosyasını/belgeyi okuyup analiz edeceksin.
|
||||
Çıktıyı KESİNLİKLE geçerli bir JSON formatında vermelisin. JSON şu anahtarları içermelidir:
|
||||
- "taraflar": (string) Davacı ve Davalı bilgileri
|
||||
- "tarihler": (string) Belgedeki kritik tarihler (Dava tarihi, tebliğ vb.)
|
||||
- "hukukiDayanak": (string) Belgedeki ilgili kanun maddeleri ve hukuki temeller
|
||||
- "ilkDegerlendirme": (string) Dosyaya dair ilk stratejik ve hukuki değerlendirmen
|
||||
|
||||
Sadece ve sadece JSON döndür, başka hiçbir açıklama ekleme.
|
||||
`;
|
||||
|
||||
const aiModel = process.env.AI_MODEL || 'mizan-fixed';
|
||||
const runpodUrl = process.env.RUNPOD_API_BASE_URL || 'https://q190env94stwis-11434.proxy.runpod.net';
|
||||
|
||||
const response = await fetch(`${runpodUrl}/v1/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
model: aiModel,
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: extractedText.substring(0, 15000) }
|
||||
],
|
||||
think: false,
|
||||
stream: false,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`AI Model request failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
// Support both custom (data.message.content) and OpenAI standard (data.choices[0].message.content) formats just in case
|
||||
const aiContent = data.message?.content || (data.choices && data.choices[0]?.message?.content);
|
||||
let summaryJson = {};
|
||||
try {
|
||||
summaryJson = JSON.parse(aiContent || '{}');
|
||||
} catch (e) {
|
||||
console.error('Failed to parse AI response as JSON:', aiContent);
|
||||
summaryJson = { error: 'AI did not return valid JSON', raw: aiContent };
|
||||
}
|
||||
|
||||
// 4. Analiz sonucunu veritabanına kaydet (analyses tablosu)
|
||||
const { data: analysisRecord, error: analysisError } = await supabase
|
||||
.from('analyses')
|
||||
.insert([{
|
||||
case_id,
|
||||
document_id: documentRecord.id,
|
||||
summary_json: summaryJson,
|
||||
model_used: aiModel
|
||||
}])
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (analysisError) throw analysisError;
|
||||
|
||||
// Başarıyla frontend'e döndür
|
||||
res.json({
|
||||
message: 'Document processed successfully',
|
||||
document: documentRecord,
|
||||
analysis: analysisRecord
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('Upload Error:', error);
|
||||
res.status(500).json({ error: error.message || 'Internal Server Error' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user