feat: dava stratejisi olusturucu - analyzeStrategy endpoint

This commit is contained in:
mstfyldz
2026-08-11 17:02:18 +03:00
parent 5c8c676d45
commit 6299a269a1
3 changed files with 85 additions and 3 deletions
+57 -1
View File
@@ -1,7 +1,7 @@
import { Response } from 'express'; import { Response } from 'express';
import { supabase } from '../lib/supabase'; import { supabase } from '../lib/supabase';
import { AuthenticatedRequest } from '../middleware/auth'; import { AuthenticatedRequest } from '../middleware/auth';
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis } from './document.controller'; import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis, runStrategyAnalysis } from './document.controller';
import { findOrCreateCaseByTitle } from '../lib/caseLookup'; import { findOrCreateCaseByTitle } from '../lib/caseLookup';
export const createCase = async (req: AuthenticatedRequest, res: Response) => { export const createCase = async (req: AuthenticatedRequest, res: Response) => {
@@ -221,6 +221,62 @@ export const analyzeDeficiencies = async (req: AuthenticatedRequest, res: Respon
} }
}; };
export const analyzeStrategy = 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;
// Gereksiz makbuz, pul vb. hariç tüm evrakları strateji için kullan
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 = normalizeTr(d.filename);
return !trashKeywords.some(kw => fn.includes(kw));
});
if (targetDocs.length === 0) {
return res.status(400).json({ error: 'Bu dosyada strateji analizi yapılabilecek evrak bulunamadı.' });
}
const perDocLimit = Math.max(1000, Math.floor(25000 / targetDocs.length)); // Strateji için context biraz daha geniş (25k)
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 runStrategyAnalysis(analysisInput, clientName);
// Strateji analizi sonucunu 'analyses' tablosuna kaydet
const { data: analysisRecord, error: analysisError } = await supabase
.from('analyses')
.insert([{ case_id: caseId, document_id: null, summary_json: { strategyAnalysis: summaryJson, clientName }, model_used: aiModel }])
.select()
.single();
if (analysisError) throw analysisError;
res.json({ analysis: analysisRecord });
} catch (error: any) {
console.error('Analyze Strategy Error:', error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};
// UYAP Evrak İndirici eklentisinin "Taraf Bilgileri" sekmesinden yakaladığı // UYAP Evrak İndirici eklentisinin "Taraf Bilgileri" sekmesinden yakaladığı
// davacı/davalı/sanık + vekil bilgisini kaydeder. AI'nin OCR metninden tahmin // 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ış // ettiği "Taraflar" alanından çok daha güvenilir — doğrudan UYAP'ın yapılandırılmış
+26 -1
View File
@@ -143,12 +143,37 @@ export async function runCaseNarrativeAnalysis(combinedText: string): Promise<{
return { summaryJson: { ozet: aiContent }, aiModel }; return { summaryJson: { ozet: aiContent }, aiModel };
} }
// Yeni İfade Analizi ve Çelişki Avcısı adımı
export async function runStatementAnalysis(combinedText: string): Promise<{ summaryJson: any; aiModel: string }> { export async function runStatementAnalysis(combinedText: string): Promise<{ summaryJson: any; aiModel: string }> {
const { resultJson, aiModel } = await callAiModel(STATEMENT_ANALYSIS_SYSTEM_PROMPT, combinedText); const { resultJson, aiModel } = await callAiModel(STATEMENT_ANALYSIS_SYSTEM_PROMPT, combinedText);
return { summaryJson: resultJson, aiModel }; return { summaryJson: resultJson, aiModel };
} }
// Yeni Dava Stratejisi Oluşturucu adımı
export async function runStrategyAnalysis(combinedText: string, clientName: string): Promise<{ summaryJson: any; aiModel: string }> {
const prompt = `Sen kıdemli bir Türk avukatısın. Aşağıda sunulan dava dosyasındaki evrakları detaylıca inceleyerek, müvekkilimiz "${clientName}" perspektifinden bir savunma veya iddia stratejisi (hukuki yol haritası) oluşturacaksın.
Dosyanın zayıf noktalarını (hem bizim açımızdan riskler hem de karşı tarafın açıkları), tespit edilen usul hatalarını ve toplanması gereken veya lehimize kullanılabilecek delilleri avukat diliyle, birinci çoğul şahıs ("bizim açımızdan", "müvekkilimiz lehine" vb.) kullanarak yaz.
Çıktıyı KESİNLİKLE aşağıdaki geçerli JSON formatında ver:
{
"weaknesses": [
"Karşı tarafın açık verdiği nokta veya bizim açımızdan zayıf/riskli olan nokta 1"
],
"proceduralErrors": [
"Usul hatası veya eksik işlem 1"
],
"requiredEvidence": [
"Toplanması veya mahkemeden talep edilmesi gereken delil 1"
],
"strategy": "Dosyanın bütününe yönelik, müvekkilimiz lehine izlenecek genel hukuki strateji ve argümanların özeti (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 }> { export async function runDeficiencyAnalysis(combinedText: string): Promise<{ summaryJson: any; aiModel: string }> {
const { resultJson, aiModel } = await callAiModel(DEFICIENCY_ANALYSIS_SYSTEM_PROMPT, combinedText); const { resultJson, aiModel } = await callAiModel(DEFICIENCY_ANALYSIS_SYSTEM_PROMPT, combinedText);
return { summaryJson: resultJson, aiModel }; return { summaryJson: resultJson, aiModel };
+2 -1
View File
@@ -1,6 +1,6 @@
import { Router } from 'express'; import { Router } from 'express';
import { requireAuth } from '../middleware/auth'; import { requireAuth } from '../middleware/auth';
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies } from '../controllers/case.controller'; import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies, analyzeStrategy } from '../controllers/case.controller';
const router = Router(); const router = Router();
@@ -9,6 +9,7 @@ router.delete('/:caseId', requireAuth, deleteCase);
router.post('/:caseId/summarize', requireAuth, summarizeCase); router.post('/:caseId/summarize', requireAuth, summarizeCase);
router.post('/:caseId/analyze-statements', requireAuth, analyzeStatements); router.post('/:caseId/analyze-statements', requireAuth, analyzeStatements);
router.post('/:caseId/analyze-deficiencies', requireAuth, analyzeDeficiencies); router.post('/:caseId/analyze-deficiencies', requireAuth, analyzeDeficiencies);
router.post('/:caseId/analyze-strategy', requireAuth, analyzeStrategy);
router.post('/parties', requireAuth, updateCaseParties); router.post('/parties', requireAuth, updateCaseParties);
export default router; export default router;