feat: add digital-intern live-qa endpoints for pinpoint hearing assistance

This commit is contained in:
mstfyldz
2026-08-14 11:48:49 +03:00
parent d3f91d4da6
commit c4947422dc
3 changed files with 80 additions and 2 deletions
+49 -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, runMediationAnalysis } from './document.controller';
import { runIddianameAnalysis, runCaseNarrativeAnalysis, runStatementAnalysis, runDeficiencyAnalysis, runStrategyAnalysis, runMediationAnalysis, runDigitalInternQa } from './document.controller';
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
@@ -385,3 +385,51 @@ export const deleteCase = async (req: AuthenticatedRequest, res: Response) => {
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};
export const analyzeDigitalIntern = async (req: AuthenticatedRequest, res: Response) => {
try {
const { caseId } = req.params;
const { question, query } = req.body || {};
const questionToUse = question || query;
if (!caseId) {
return res.status(400).json({ error: 'Geçersiz caseId' });
}
if (!questionToUse || !String(questionToUse).trim()) {
return res.status(400).json({ error: 'Soru (question) girmelisiniz.' });
}
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 targetDocs = (docs || []).filter(d => d.extracted_text && String(d.extracted_text).trim());
if (targetDocs.length === 0) {
return res.status(400).json({ error: 'Bu dosyada arama yapılabilecek evrak bulunamadı.' });
}
const perDocLimit = Math.max(1000, Math.floor(30000 / 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 runDigitalInternQa(analysisInput, questionToUse);
// İsteğe bağlı olarak arama sonucunu da 'analyses' tablosuna kaydet
await supabase
.from('analyses')
.insert([{ case_id: caseId, document_id: null, summary_json: { digitalInternResult: summaryJson, question: questionToUse }, model_used: aiModel }]);
res.json({ result: summaryJson, modelUsed: aiModel });
} catch (error: any) {
console.error('Digital Intern Error:', error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};
+28
View File
@@ -564,3 +564,31 @@ export const uploadDocument = async (req: AuthenticatedRequest, res: Response) =
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};
// Dijital Stajyer (Duruşma Asistanı - Canlı ve Nokta Atışı Soru/Cevap)
export async function runDigitalInternQa(combinedText: string, question: string): Promise<{ summaryJson: any; aiModel: string }> {
const prompt = `Sen duruşma salonundaki avukatın yanında duran, saniyeler içinde nokta atışı cevap veren kıdemli DİJİTAL STAJYERSİN.
AVUKATIN SORUSU: "${question}"
GÖREVİN & SIKI İLKELERİN:
1. Duruşma anında avukatın saniyeler içinde okuyabileceği NOKTA ATIŞI ve NET cevabı ver.
2. Uzun giriş paragrafı, merhaba mesajı veya lakırdı KESİNLİKLE YASAKTIR. Doğrudan sonuca gir.
3. Bulduğun veriyi (Tarih, Saat, Belge Adı/No, İsim, Tutar, Sayfa) açıkça yaz.
4. Aranan bilgi dava evraklarında açıkça yer almıyorsa: "found": false yaz ve "Bu bilgi dosyadaki evraklarda bulunmamaktadır" de.
ÇIKTI FORMATI (SADECE GEÇERLİ JSON):
{
"found": true,
"answer": "📌 12 Ekim 2021 tarihinde düzenlenen Marmara Devlet Hastanesi Adli Muayene Raporu'nda altta kalça kırığı tespit edilmiştir.",
"dateInfo": "12 Ekim 2021",
"documentRef": "Marmara Devlet Hastanesi Adli Muayene Raporu (Belge No: 45)",
"exactExcerpt": "Dosyadan alınan birebir pasaj veya ilgili cümle...",
"confidenceScore": "%95"
}
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 };
}
+3 -1
View File
@@ -1,6 +1,6 @@
import { Router } from 'express';
import { requireAuth } from '../middleware/auth';
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies, analyzeStrategy, analyzeMediation } from '../controllers/case.controller';
import { createCase, deleteCase, summarizeCase, updateCaseParties, analyzeStatements, analyzeDeficiencies, analyzeStrategy, analyzeMediation, analyzeDigitalIntern } from '../controllers/case.controller';
const router = Router();
@@ -15,6 +15,8 @@ router.post('/:caseId/analyze-strategy', requireAuth, analyzeStrategy);
router.post('/:caseId/strategy', requireAuth, analyzeStrategy);
router.post('/:caseId/analyze-mediation', requireAuth, analyzeMediation);
router.post('/:caseId/mediation', requireAuth, analyzeMediation);
router.post('/:caseId/digital-intern', requireAuth, analyzeDigitalIntern);
router.post('/:caseId/live-qa', requireAuth, analyzeDigitalIntern);
router.post('/parties', requireAuth, updateCaseParties);
export default router;