revision
This commit is contained in:
@@ -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 } from './document.controller';
|
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis } 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) => {
|
||||||
@@ -109,6 +109,57 @@ export const summarizeCase = async (req: AuthenticatedRequest, res: Response) =>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Çelişki Avcısı: İfade ve sorgu evraklarını alıp analiz eder.
|
||||||
|
export const analyzeStatements = 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 ifade, sorgu, beyan, tutanak, duruşma içeren belgeleri filtrele
|
||||||
|
const keywords = ['ifade', 'sorgu', 'beyan', 'tutanak', 'duruşma'];
|
||||||
|
const statementDocs = (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));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (statementDocs.length === 0) {
|
||||||
|
return res.status(400).json({ error: 'Bu dosyada ifade/beyan evrakı bulunamadı.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const perDocLimit = Math.max(1000, Math.floor(15000 / statementDocs.length));
|
||||||
|
const combinedText = statementDocs
|
||||||
|
.map((d) => `--- ${d.filename} ---\n${String(d.extracted_text).slice(0, perDocLimit)}`)
|
||||||
|
.join('\n\n');
|
||||||
|
|
||||||
|
const analysisInput = `Aşağıdaki belgeler sadece ifade ve sorgu evraklarıdır:\n\n${combinedText}`;
|
||||||
|
|
||||||
|
const { summaryJson, aiModel } = await runStatementAnalysis(analysisInput);
|
||||||
|
|
||||||
|
// Çelişki analizi sonucunu 'analyses' tablosuna kaydet
|
||||||
|
const { data: analysisRecord, error: analysisError } = await supabase
|
||||||
|
.from('analyses')
|
||||||
|
.insert([{ case_id: caseId, document_id: null, summary_json: { statementAnalysis: summaryJson }, model_used: aiModel }])
|
||||||
|
.select()
|
||||||
|
.single();
|
||||||
|
if (analysisError) throw analysisError;
|
||||||
|
|
||||||
|
res.json({ analysis: analysisRecord });
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Analyze Statements 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ış
|
||||||
|
|||||||
@@ -57,6 +57,32 @@ const CASE_NARRATIVE_SYSTEM_PROMPT = `
|
|||||||
veya başka bir açıklama ekleme.
|
veya başka bir açıklama ekleme.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Çıktıyı KESİNLİKLE geçerli bir JSON formatında vermelisin. JSON yapısı tam olarak şu şekilde olmalıdır:
|
||||||
|
{
|
||||||
|
"persons": [
|
||||||
|
{
|
||||||
|
"name": "Kişinin Adı Soyadı",
|
||||||
|
"role": "Müşteki, Şüpheli, Sanık, Tanık vb.",
|
||||||
|
"statements": [
|
||||||
|
{
|
||||||
|
"stage": "Karakol / Savcılık / Mahkeme / Diğer",
|
||||||
|
"summary": "Bu aşamadaki beyanının çok kısa özeti"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contradictions": [
|
||||||
|
"Eğer aynı kişinin farklı aşamalardaki ifadelerinde veya somut delillerle çelişen bir durumu varsa buraya yaz. Yoksa boş bırak."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Sadece ve sadece JSON döndür, kod bloğu işareti (\`\`\`) veya başka bir açıklama ekleme.
|
||||||
|
`;
|
||||||
|
|
||||||
async function callAiModel(systemPrompt: string, userText: string): Promise<{ resultJson: any; aiModel: string }> {
|
async function callAiModel(systemPrompt: string, userText: string): Promise<{ resultJson: any; aiModel: string }> {
|
||||||
const { aiContent, aiModel } = await callAiModelRaw(systemPrompt, userText);
|
const { aiContent, aiModel } = await callAiModelRaw(systemPrompt, userText);
|
||||||
let resultJson: any = {};
|
let resultJson: any = {};
|
||||||
@@ -97,6 +123,12 @@ 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 }> {
|
||||||
|
const { resultJson, aiModel } = await callAiModel(STATEMENT_ANALYSIS_SYSTEM_PROMPT, combinedText);
|
||||||
|
return { summaryJson: resultJson, aiModel };
|
||||||
|
}
|
||||||
|
|
||||||
// UYAP Evrak İndirici eklentisinden gelen, Electron ana sürecinde YERELDE metni
|
// 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 —
|
// çı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.
|
// sadece çıkarılan metin (JSON) geliyor, Supabase Storage'a hiçbir yükleme yapılmıyor.
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { requireAuth } from '../middleware/auth';
|
import { requireAuth } from '../middleware/auth';
|
||||||
import { createCase, deleteCase, summarizeCase, updateCaseParties } from '../controllers/case.controller';
|
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements } from '../controllers/case.controller';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.post('/', requireAuth, createCase);
|
router.post('/', requireAuth, createCase);
|
||||||
router.delete('/:caseId', requireAuth, deleteCase);
|
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('/parties', requireAuth, updateCaseParties);
|
router.post('/parties', requireAuth, updateCaseParties);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user