- Yeni POST /api/documents/extract-text: dosyayı hiçbir yere
kaydetmeden sadece metnini çıkarıp döner (chat ataç özelliği için)
- chatMessage ve sendThreadMessage artık body'de attachments
({filename,text}[]) kabul ediyor; AI bağlamına ekleniyor, kayıtlı
mesaja da "[Ek dosya(lar): ...]" notu düşülüyor
- chatMessage ayrıca document_ids kabul ediyor — dosya sohbetinde
kullanıcının bu mesajda özellikle işaret ettiği mevcut belge(ler)
AI'ye vurgulanıyor
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
800 token sınırı çok düşüktü — çok bölümlü hukuki cevaplar (kira feshi,
tazminat hesabı gibi) bu sınıra çarpıp cümlenin ortasında kesiliyordu.
Varsayılan ve chatMessage/sendThreadMessage'ın kullandığı num_predict
2048'e çıkarıldı. Ayrıca Ollama done_reason:"length" döndürdüğünde
(yanıt sınıra çarpıp kesildiğinde) sunucu loglarına uyarı yazılıyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Özet-önce yaklaşımı, kullanıcı uzun bir mesaj/belge verdiğinde sohbet
ekranında soruna yol açtığı için geri alındı — chatMessage yine her
zaman belgelerin tam extracted_text'ini sistem promptuna gömüyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Sohbet/Asistan sayfasındaki genel sohbetler artık kalıcı: yeni
chat_threads/thread_messages tabloları (cases ile ilişkisiz) ile
sendThreadMessage endpoint'i eklendi. Eski caseId==='general'
(kalıcı olmayan) dalı kaldırıldı, AI çağrısı ortak callAiChat
yardımcısına taşındı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
generateDraft now inserts into a new drafts table (case_id, content,
petition_type, template_id) so drafts survive navigating away, and
show up in both the "Dilekçelerim" list and the originating case's own
"Dilekçeler" section. Read/update/delete go straight through Supabase
from the frontend (same pattern as events/clients).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
chatMessage() was auto-generating and overwriting cases.title from the
first chat message for ANY case_id, including real UYAP-imported dava
dosyaları (kind='case') — not just the chat-only "Yeni Sohbet" threads
(kind='chat') this was built for. Asking a real case a single question
in Sohbet silently destroyed its court-derived title. Now gated on
kind === 'chat'.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Belge Şablonları uploads now also get extracted_text (same OCR/office
pipeline as documents), and a new POST /api/drafting/generate builds
a real AI draft from the case's actual data (title, UYAP parties,
latest Dosya Özeti) — if the lawyer picks one of their own templates,
its extracted text is passed as a style/format reference only (the
prompt explicitly forbids copying the template's old case facts).
Dilekçe Hazırlama no longer fakes a draft with setTimeout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
summarizeCase now produces a full Markdown narrative report (Olayın
Özeti, Yargılama Süreci ve Kararlar, Taraf İddia/Savunmaları, Önemli
Bulgular ve Belgeler, Sonuç) instead of short structured fields - the
iddianame pre-analysis (when found) still runs first and is fed in as
context. The raw AI text is stored as {ozet: string} rather than
JSON-parsed, since asking the model to escape a multi-paragraph report
inside JSON was fragile.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- summarizeCase: if an iddianame is among the case's documents, run a
narrow first-pass analysis on it alone (isnatEdilenSuc, iddiaOzeti,
onemliTarihler), then feed that as context into the general
case-wide evaluation instead of treating every document equally.
- ANALYSIS_SYSTEM_PROMPT no longer asks the AI to guess "taraflar" -
that now comes from real UYAP data (cases.parties) instead.
- Removed the hardcoded RunPod proxy URL fallback from every call
site (document/chat/precedent controllers + lib/openai.ts) - it was
a real infra endpoint checked into source. New lib/aiConfig.ts
throws if RUNPOD_API_BASE_URL isn't set rather than silently
falling back to it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Belge Şablonları now stores real files: POST /api/templates/upload
(multer -> Supabase Storage under templates/<user>/, then a templates
row), GET /api/templates/:id/download-url (short-lived signed URL),
and DELETE /api/templates/:id. Mounted at /api/templates.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The UYAP extension now captures the davaci/davali/sanik + vekil data
from the "Taraf Bilgileri" tab and sends it once per case. This
endpoint finds/creates the matching case by title (same lookup used
by registerLocalDocument, now shared via lib/caseLookup.ts) and stores
it in a new cases.parties column - a much more reliable source for
the case detail screen's "Taraflar" info than the AI's own guess from
OCR'd document text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
POST /api/cases/:caseId/summarize combines extracted text from all of
a case's documents and runs the existing AI analysis prompt, storing
the result as a case-level analysis (document_id: null). Powers the
"Özet Hazırla" button on the case detail screen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New chat threads created from the Sohbet screen were creating rows in
the same cases table that Dava Dosyaları lists, so every new chat
showed up there too. createCase now accepts an optional kind
('case'|'chat', default 'case') so chat-only threads can be excluded.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Accepts pre-extracted text (no raw file) from the AyrisLegal Electron
app's local OCR pipeline, matches/creates a case by title, and runs
the existing AI analysis flow. Also fixes a bug in uploadDocument:
officeparser@7.x's parseOffice() now returns a result object with
.toText() instead of a plain string, which was breaking PDF/DOCX
manual uploads.
Takes the user's described situation plus the top search results and
asks the AI model for a short legal assessment. Auth-protected since
it's a paid AI call.
POST /api/cases lets the frontend actually create a new dava dosyası
(no working "Yeni Dosya" flow existed before). chatMessage now
generates a short title from a case's first message (like Claude/
ChatGPT auto-titling) and renames the case, returned as `newTitle`.
Chat panel's trash icon should remove the whole case (not just clear
its chat history) — documents/analyses/chat_messages cascade-delete
via the existing ON DELETE CASCADE foreign keys.
Frontend's chat history trash icon was calling this endpoint but it
didn't exist yet, causing a JSON-parse error on the default 404 page.
Also renames the LegalOS health-check message to AyrisLegal.
requireAuth treated every chat caseId as a real cases row and rejected
"general" (the no-file chat sentinel) with 403. general chat now skips
the ownership check and is answered without touching chat_messages,
since that table's case_id is a NOT NULL FK to cases.