perf: switch all AI calls to native Ollama endpoint, add streaming + keep_alive

Tüm AI çağrıları artık ortak lib/aiClient.ts üzerinden gidiyor:
- /v1/chat/completions yerine native /api/chat (think:false burada
  güvenilir çalışıyor)
- keep_alive:30m ile model her istekte bellekten atılıp soğuk
  başlamıyor
- num_predict ile öngörülemez uzunlukta üretime üst sınır
- İnteraktif sohbet uç noktaları (chatMessage, sendThreadMessage)
  artık SSE ile token token akıtıyor
- Dosya sohbetinde varsayılan olarak belgenin tam metni değil analiz
  özeti gönderiliyor; tam metin sadece kullanıcı açıkça isterse
  eklenir

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
mstfyldz
2026-08-10 00:21:49 +03:00
co-authored by Claude Sonnet 5
parent 0318f2ac77
commit bcc78ce304
5 changed files with 239 additions and 150 deletions
+15 -48
View File
@@ -1,6 +1,6 @@
import { Request, Response } from 'express';
import { AuthenticatedRequest } from '../middleware/auth';
import { getAiConfig } from '../lib/aiConfig';
import { callOllama } from '../lib/aiClient';
export const searchPrecedents = async (req: Request, res: Response) => {
try {
@@ -21,34 +21,19 @@ SADECE anahtar kelimeleri aralarına boşluk koyarak yaz. Noktalama işareti, a
// AI ile sorgu optimizasyonu isteğe bağlı bir iyileştirme — config eksikse veya
// istek başarısız olursa arama yine de optimize edilmemiş phrase ile devam eder.
// Çıktı birkaç kelimelik bir anahtar kelime listesi olduğu için num_predict düşük
// tutuluyor — hem daha hızlı yanıt hem modelin gereksiz uzatmasını önler.
try {
const { runpodUrl, aiModel } = getAiConfig();
const aiResponse = await fetch(`${runpodUrl}/v1/chat/completions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: aiModel,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: phrase }
],
think: false,
stream: false,
}),
});
if (aiResponse.ok) {
const data = await aiResponse.json();
const aiContent = data.message?.content || (data.choices && data.choices[0]?.message?.content);
if (aiContent) {
optimizedPhrase = aiContent.trim().replace(/["'\n]/g, '');
console.log(`[AI Search] Orijinal: "${phrase}" -> Optimize: "${optimizedPhrase}"`);
}
} else {
console.error('AI Query Optimization API returned status:', aiResponse.status);
const aiContent = await callOllama([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: phrase },
], { numPredict: 40, timeoutMs: 20_000 });
if (aiContent) {
optimizedPhrase = aiContent.trim().replace(/["'\n]/g, '');
console.log(`[AI Search] Orijinal: "${phrase}" -> Optimize: "${optimizedPhrase}"`);
}
} catch (err) {
console.error('AI Query Optimization Fetch Error:', err);
console.error('AI Query Optimization Error:', err);
}
}
@@ -113,28 +98,10 @@ export const analyzePrecedents = async (req: AuthenticatedRequest, res: Response
const systemPrompt = 'Sen uzman bir Türk avukatısın. Kullanıcının anlattığı hukuki durumu, aşağıda listelenen emsal karar arama sonuçları ışığında kısaca değerlendir. Hangi kararların duruma daha yakın olabileceğini belirt ve olası bir hukuki değerlendirme sun. Emin olmadığın noktalarda bunu açıkça belirt, uydurma bilgi verme. Cevabın yaklaşık 150-250 kelime olsun.';
const userPrompt = `DURUM:\n${String(situation).slice(0, 3000)}\n\nBULUNAN KARARLAR:\n${listText}`;
const { runpodUrl, aiModel } = getAiConfig();
const response = await fetch(`${runpodUrl}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: aiModel,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
think: false,
stream: false,
}),
});
if (!response.ok) {
throw new Error(`AI Model request failed: ${response.statusText}`);
}
const data = await response.json();
const analysis = data.message?.content || 'Analiz üretilemedi.';
const analysis = await callOllama([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
], { numPredict: 500 }) || 'Analiz üretilemedi.';
res.json({ analysis });
} catch (error: any) {
console.error('Analyze Precedents Error:', error);