feat: add deficiency analysis route
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Response } from 'express';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { AuthenticatedRequest } from '../middleware/auth';
|
||||
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis } from './document.controller';
|
||||
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis } from './document.controller';
|
||||
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
|
||||
|
||||
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
|
||||
@@ -160,6 +160,67 @@ export const analyzeStatements = async (req: AuthenticatedRequest, res: Response
|
||||
}
|
||||
};
|
||||
|
||||
export const analyzeDeficiencies = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const { caseId } = req.params;
|
||||
if (!caseId) {
|
||||
return res.status(400).json({ error: 'Geçersiz caseId' });
|
||||
}
|
||||
|
||||
const { data: docs, error: docsError } = await supabase
|
||||
.from('documents')
|
||||
.select('filename, extracted_text')
|
||||
.eq('case_id', caseId)
|
||||
.order('uploaded_at', { ascending: true });
|
||||
if (docsError) throw docsError;
|
||||
|
||||
// Sadece tensip, zaptı, tutanak, karar, müzekkere gibi evrakları filtrele
|
||||
const keywords = ['tensip', 'zaptı', 'tutanak', 'duruşma', 'müzekkere', 'karar', 'iddianame'];
|
||||
const deficiencyDocs = (docs || []).filter((d) => {
|
||||
if (!d.extracted_text || !String(d.extracted_text).trim()) return false;
|
||||
const fn = normalizeTr(d.filename);
|
||||
return keywords.some(kw => fn.includes(kw));
|
||||
});
|
||||
|
||||
// Eğer hiç spesifik evrak yoksa, çöp olmayanları al
|
||||
let targetDocs = deficiencyDocs;
|
||||
if (targetDocs.length === 0) {
|
||||
const trashKeywords = ['tebligat', 'makbuz', 'pul', 'zarf', 'masraf', 'havale', 'barkod', 'alındı', 'görüldü', 'ilan', 'talimat', 'nüfus', 'sicil', 'sabıka'];
|
||||
targetDocs = (docs || []).filter(d => {
|
||||
if (!d.extracted_text || !String(d.extracted_text).trim()) return false;
|
||||
const fn = normalizeTr(d.filename);
|
||||
return !trashKeywords.some(kw => fn.includes(kw));
|
||||
});
|
||||
}
|
||||
|
||||
if (targetDocs.length === 0) {
|
||||
return res.status(400).json({ error: 'Bu dosyada analiz edilecek uygun evrak bulunamadı.' });
|
||||
}
|
||||
|
||||
const perDocLimit = Math.max(1000, Math.floor(15000 / targetDocs.length));
|
||||
const combinedText = targetDocs
|
||||
.map((d) => `--- ${d.filename} ---\n${String(d.extracted_text).slice(0, perDocLimit)}`)
|
||||
.join('\n\n');
|
||||
|
||||
const analysisInput = `Aşağıdaki belgeler dava dosyasına aittir:\n\n${combinedText}`;
|
||||
|
||||
const { summaryJson, aiModel } = await runDeficiencyAnalysis(analysisInput);
|
||||
|
||||
// Eksiklik analizi sonucunu 'analyses' tablosuna kaydet
|
||||
const { data: analysisRecord, error: analysisError } = await supabase
|
||||
.from('analyses')
|
||||
.insert([{ case_id: caseId, document_id: null, summary_json: { deficiencyAnalysis: summaryJson }, model_used: aiModel }])
|
||||
.select()
|
||||
.single();
|
||||
if (analysisError) throw analysisError;
|
||||
|
||||
res.json({ analysis: analysisRecord });
|
||||
} catch (error: any) {
|
||||
console.error('Analyze Deficiencies Error:', error);
|
||||
res.status(500).json({ error: error.message || 'Internal Server Error' });
|
||||
}
|
||||
};
|
||||
|
||||
// UYAP Evrak İndirici eklentisinin "Taraf Bilgileri" sekmesinden yakaladığı
|
||||
// davacı/davalı/sanık + vekil bilgisini kaydeder. AI'nin OCR metninden tahmin
|
||||
// ettiği "Taraflar" alanından çok daha güvenilir — doğrudan UYAP'ın yapılandırılmış
|
||||
|
||||
@@ -57,6 +57,26 @@ const CASE_NARRATIVE_SYSTEM_PROMPT = `
|
||||
veya başka bir açıklama ekleme.
|
||||
`;
|
||||
|
||||
const DEFICIENCY_ANALYSIS_SYSTEM_PROMPT = `Sen kıdemli bir avukatsın. Dosyadaki evrakları (özellikle tensip tutanakları, müzekkereler, duruşma zabıtları) inceleyerek dosyanın röntgenini çekeceksin.
|
||||
Görevin, dosyadaki süreçte ne aşamada olunduğunu özetlemek ve EKSİK olan işlemleri veya beklenen evrakları (örn: bilirkişi raporu bekleniyor, tanıklar dinlenmedi, harç yatırılmadı vb.) tespit etmektir.
|
||||
|
||||
Çıktını SADECE aşağıdaki JSON formatında ver, fazladan tek kelime etme:
|
||||
{
|
||||
"currentStage": "Dosyanın şu anki aşaması (örn: Ön inceleme aşamasında, Tahkikat aşamasında vb.)",
|
||||
"deficiencies": [
|
||||
{
|
||||
"type": "Eksik türü (örn: Belge, İşlem, Ara Karar)",
|
||||
"description": "Eksiğin açıklaması (örn: Trafik şubesinden hasar kayıtları bekleniyor)",
|
||||
"urgency": "high" | "medium" | "low" (Eksikliğin aciliyet veya önem derecesi)
|
||||
}
|
||||
],
|
||||
"completedSteps": [
|
||||
"Tamamlanmış önemli işlemler (örn: Tensip zaptı düzenlendi, Harçlar yatırıldı)"
|
||||
]
|
||||
}
|
||||
DİKKAT: JSON formatı tam ve geçerli olmalıdır.
|
||||
`;
|
||||
|
||||
const STATEMENT_ANALYSIS_SYSTEM_PROMPT = `
|
||||
Sen uzman bir Türk ceza avukatısın. Sana bir dava dosyasındaki "ifade", "sorgu" veya "beyan" içeren çeşitli belgelerin metinleri verilecek.
|
||||
Amacın, bu belgelerdeki kişi beyanlarını analiz edip "Yalan Dedektörü" mantığıyla çelişkileri bulmaktır.
|
||||
@@ -129,6 +149,11 @@ export async function runStatementAnalysis(combinedText: string): Promise<{ summ
|
||||
return { summaryJson: resultJson, aiModel };
|
||||
}
|
||||
|
||||
export async function runDeficiencyAnalysis(combinedText: string): Promise<{ summaryJson: any; aiModel: string }> {
|
||||
const { resultJson, aiModel } = await callAiModel(DEFICIENCY_ANALYSIS_SYSTEM_PROMPT, combinedText);
|
||||
return { summaryJson: resultJson, aiModel };
|
||||
}
|
||||
|
||||
// UYAP Evrak İndirici eklentisinden gelen, Electron ana sürecinde YERELDE metni
|
||||
// çıkarılmış belgeleri kaydeder. Ham dosya baytları bu isteğe hiç dahil değil —
|
||||
// sadece çıkarılan metin (JSON) geliyor, Supabase Storage'a hiçbir yükleme yapılmıyor.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router } from 'express';
|
||||
import { requireAuth } from '../middleware/auth';
|
||||
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements } from '../controllers/case.controller';
|
||||
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies } from '../controllers/case.controller';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -8,6 +8,7 @@ router.post('/', requireAuth, createCase);
|
||||
router.delete('/:caseId', requireAuth, deleteCase);
|
||||
router.post('/:caseId/summarize', requireAuth, summarizeCase);
|
||||
router.post('/:caseId/analyze-statements', requireAuth, analyzeStatements);
|
||||
router.post('/:caseId/analyze-deficiencies', requireAuth, analyzeDeficiencies);
|
||||
router.post('/parties', requireAuth, updateCaseParties);
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user