The draft prompt didn't say anything about output format, so the model would sometimes emit **bold**/## headers like it does elsewhere - wrong for a document meant to go straight into a court filing. Now explicitly instructed to use plain text with conventional Turkish petition section labels (AÇIKLAMALAR:, SONUÇ VE İSTEM: etc.) instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
96 lines
4.4 KiB
TypeScript
96 lines
4.4 KiB
TypeScript
import { Response } from 'express';
|
||
import { supabase } from '../lib/supabase';
|
||
import { AuthenticatedRequest } from '../middleware/auth';
|
||
import { callAiModelRaw } from './document.controller';
|
||
|
||
const DRAFT_SYSTEM_PROMPT = `
|
||
Sen uzman bir Türk avukatısın. Sana verilen dosya bilgilerine göre, istenen türde
|
||
bir dilekçe TASLAĞI yazacaksın. Türk hukuk uygulamasına uygun, resmî bir dille yaz
|
||
(hitap, hususlar, netice-i talep gibi standart dilekçe yapısını kullan).
|
||
|
||
EĞER sana bir "BÜRO ŞABLONU" verilmişse: bu şablon, bu hukuk bürosunun kendi imzası
|
||
olan format/dil/üslup tercihidir — YALNIZCA bunun yapısını, dilini, başlıklandırmasını
|
||
ve üslubunu takip et. Şablondaki taraf isimleri, esas no'su, tarihler, mahkeme adı gibi
|
||
ESKİ dosyaya ait somut bilgileri ASLA kullanma veya kopyalama — onların yerine SADECE
|
||
aşağıda verilen YENİ dosyanın gerçek bilgilerini koy.
|
||
|
||
ÖNEMLİ — BİÇİMLENDİRME: Bu çıktı doğrudan bir dilekçe belgesine dönüştürülecek, o yüzden
|
||
KESİNLİKLE Markdown biçimlendirmesi kullanma (**, ##, -, *, 1. gibi işaretler YASAK).
|
||
Sadece düz metin yaz. Başlık/vurgu gerekiyorsa BÜYÜK HARF veya standart dilekçe
|
||
başlıkları (örn. "AÇIKLAMALAR:", "HUKUKİ SEBEPLER:", "SONUÇ VE İSTEM:") kullan,
|
||
yıldız veya diyez işareti asla kullanma.
|
||
|
||
Sadece dilekçe taslağının kendisini döndür — başlık, açıklama veya ek yorum ekleme.
|
||
`;
|
||
|
||
// Dilekçe Hazırlama ekranındaki "AI ile Taslak Oluştur" — dosyanın gerçek bilgilerini
|
||
// (başlık, UYAP'tan gelen taraflar, varsa Dosya Özeti) ve kullanıcının notlarını,
|
||
// isteğe bağlı olarak seçilen büro şablonunun DİLİNİ/FORMATINI referans alarak
|
||
// gerçek bir AI taslağı üretir.
|
||
export const generateDraft = async (req: AuthenticatedRequest, res: Response) => {
|
||
try {
|
||
const { case_id, petition_type, notes, template_id } = req.body || {};
|
||
const userId = req.user?.id;
|
||
|
||
if (!case_id || !petition_type) {
|
||
return res.status(400).json({ error: 'case_id ve petition_type zorunludur.' });
|
||
}
|
||
|
||
const { data: caseRow, error: caseError } = await supabase
|
||
.from('cases')
|
||
.select('id, title, parties, user_id')
|
||
.eq('id', case_id)
|
||
.single();
|
||
if (caseError || !caseRow) {
|
||
return res.status(404).json({ error: 'Dava dosyası bulunamadı.' });
|
||
}
|
||
if (caseRow.user_id !== userId) {
|
||
return res.status(403).json({ error: 'Bu dosyaya erişim yetkiniz yok.' });
|
||
}
|
||
|
||
const { data: lastAnalysis } = await supabase
|
||
.from('analyses')
|
||
.select('summary_json')
|
||
.eq('case_id', case_id)
|
||
.order('created_at', { ascending: false })
|
||
.limit(1)
|
||
.maybeSingle();
|
||
|
||
let template: { name: string; extracted_text: string | null } | null = null;
|
||
if (template_id) {
|
||
const { data: templateRow } = await supabase
|
||
.from('templates')
|
||
.select('name, extracted_text, user_id')
|
||
.eq('id', template_id)
|
||
.single();
|
||
if (templateRow && templateRow.user_id === userId) {
|
||
template = templateRow;
|
||
}
|
||
}
|
||
|
||
const partiesText = Array.isArray(caseRow.parties) && caseRow.parties.length > 0
|
||
? caseRow.parties.map((p: any) => `${p.adi || ''} (${p.rol || ''}${p.vekil ? `, Vekil: ${p.vekil}` : ''})`).join('; ')
|
||
: 'Belirtilmemiş — UYAP Taraf Bilgileri sekmesi henüz çekilmemiş olabilir.';
|
||
|
||
const ozet = lastAnalysis?.summary_json?.ozet;
|
||
|
||
let userContent = `YENİ DOSYA BİLGİLERİ:\nDosya: ${caseRow.title}\nTaraflar: ${partiesText}\nDilekçe Türü: ${petition_type}\n`;
|
||
if (notes && String(notes).trim()) {
|
||
userContent += `Vurgulanmasını istediğiniz noktalar: ${String(notes).trim()}\n`;
|
||
}
|
||
if (ozet && typeof ozet === 'string') {
|
||
userContent += `\nDosya Özeti (bağlam için):\n${ozet.slice(0, 4000)}\n`;
|
||
}
|
||
if (template?.extracted_text) {
|
||
userContent += `\n---\nBÜRO ŞABLONU "${template.name}" (SADECE dil/format/üslup referansı — içeriğini kopyalama):\n${template.extracted_text.slice(0, 6000)}\n`;
|
||
}
|
||
|
||
const { aiContent, aiModel } = await callAiModelRaw(DRAFT_SYSTEM_PROMPT, userContent);
|
||
|
||
res.json({ draft: aiContent, model: aiModel, usedTemplate: !!template });
|
||
} catch (error: any) {
|
||
console.error('Generate Draft Error:', error);
|
||
res.status(500).json({ error: error.message || 'Internal Server Error' });
|
||
}
|
||
};
|