feat: Arabuluculuk & Müzakere Asistanı analiz endpoint'leri eklendi

This commit is contained in:
mstfyldz
2026-08-12 10:58:44 +03:00
parent 6916a7d9ba
commit 571e1f63d1
3 changed files with 78 additions and 2 deletions
+55 -1
View File
@@ -1,7 +1,7 @@
import { Response } from 'express';
import { supabase } from '../lib/supabase';
import { AuthenticatedRequest } from '../middleware/auth';
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis, runStrategyAnalysis } from './document.controller';
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis, runStrategyAnalysis, runMediationAnalysis } from './document.controller';
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
@@ -277,6 +277,60 @@ export const analyzeStrategy = async (req: AuthenticatedRequest, res: Response)
}
};
export const analyzeMediation = async (req: AuthenticatedRequest, res: Response) => {
try {
const { caseId } = req.params;
const { clientName } = req.body;
if (!caseId) {
return res.status(400).json({ error: 'Geçersiz caseId' });
}
if (!clientName) {
return res.status(400).json({ error: 'clientName (Müvekkil Adı) zorunludur' });
}
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;
const trashKeywords = ['tebligat', 'makbuz', 'pul', 'zarf', 'masraf', 'havale', 'barkod', 'alındı', 'görüldü', 'ilan', 'talimat', 'nüfus', 'sicil', 'sabıka'];
const targetDocs = (docs || []).filter(d => {
if (!d.extracted_text || !String(d.extracted_text).trim()) return false;
const fn = (d.filename || '').toLowerCase().replace(/ı/g, 'i').replace(/ğ/g, 'g').replace(/ü/g, 'u').replace(/ş/g, 's').replace(/ö/g, 'o').replace(/ç/g, 'c');
return !trashKeywords.some(kw => fn.includes(kw));
});
if (targetDocs.length === 0) {
return res.status(400).json({ error: 'Bu dosyada arabuluculuk analizi yapılabilecek evrak bulunamadı.' });
}
const perDocLimit = Math.max(1000, Math.floor(25000 / 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 runMediationAnalysis(analysisInput, clientName);
const { data: analysisRecord, error: analysisError } = await supabase
.from('analyses')
.insert([{ case_id: caseId, document_id: null, summary_json: { mediationAnalysis: summaryJson, clientName }, analysis_type: 'mediation', model_used: aiModel }])
.select()
.single();
if (analysisError) throw analysisError;
res.json({ analysis: analysisRecord });
} catch (error: any) {
console.error('Analyze Mediation 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ış
+21
View File
@@ -175,6 +175,27 @@ Sadece ve sadece JSON döndür, kod bloğu işareti (\`\`\`) veya başka bir aç
return { summaryJson: resultJson, aiModel };
}
export async function runMediationAnalysis(combinedText: string, clientName: string): Promise<{ summaryJson: any; aiModel: string }> {
const prompt = `Sen uzman bir müzakereci ve arabuluculuk asistanısın. Aşağıda sunulan dava dosyasındaki evrakları detaylıca inceleyerek, müvekkilimiz "${clientName}" perspektifinden davanın kazanılma olasılığını ve en uygun pazarlık marjını hesaplayacaksın.
Dosyadaki delilleri, iddiaları ve varsa zayıf noktaları objektif bir şekilde değerlendir. Yargılama giderleri, avukatlık ücretleri ve sürecin uzunluğunu göz önüne alarak masada anlaşılabilecek "karlı" bir matematiksel/hukuki pazarlık marjı sun.
Çıktıyı KESİNLİKLE aşağıdaki geçerli JSON formatında ver:
{
"winProbability": "Örn: %60",
"riskAnalysis": [
"Davanın kaybedilmesine veya uzamasına neden olabilecek risk 1"
],
"negotiationMargin": "Önerilen pazarlık aralığı ve gerekçesi (Örn: X TL ile Y TL arası makuldür çünkü yargılama giderleri Z TL tutacaktır.)",
"strategy": "Arabuluculuk masasında veya müzakerede kullanılacak temel psikolojik/hukuki argüman (1-2 paragraf)."
}
Sadece ve sadece JSON döndür, kod bloğu işareti (\`\`\`) veya başka bir açıklama ekleme.`;
const { resultJson, aiModel } = await callAiModel(prompt, combinedText);
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 };
+2 -1
View File
@@ -1,6 +1,6 @@
import { Router } from 'express';
import { requireAuth } from '../middleware/auth';
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies, analyzeStrategy } from '../controllers/case.controller';
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies, analyzeStrategy, analyzeMediation } from '../controllers/case.controller';
const router = Router();
@@ -10,6 +10,7 @@ router.post('/:caseId/summarize', requireAuth, summarizeCase);
router.post('/:caseId/analyze-statements', requireAuth, analyzeStatements);
router.post('/:caseId/analyze-deficiencies', requireAuth, analyzeDeficiencies);
router.post('/:caseId/analyze-strategy', requireAuth, analyzeStrategy);
router.post('/:caseId/analyze-mediation', requireAuth, analyzeMediation);
router.post('/parties', requireAuth, updateCaseParties);
export default router;