v4.3.39: 법률 앱 사건 자동 이름짓기
메모를 처음 작성하고 포커스를 벗어나면(blur), 제목이 아직 기본값 "새 사건"인 경우에 한해 AI가 메모 내용을 보고 8자 이내 사건명을 지어 채워줌. 채팅창에는 안 보이는 조용한 호출(quietChatCall)로 처리 — 이미 만든 generateChecklist용 callChatRaw(화면에 타이핑 표시)와 달리 UI에 아무 흔적을 안 남김. 사용자가 이미 직접 이름을 바꿨거나 다른 사건으로 넘어간 경우는 덮어쓰지 않음. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -475,7 +475,7 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
- 의뢰인: 홍길동 (임차인)
|
||||
- 쟁점: 전세보증금 반환 지연
|
||||
- 관련 법령: 주택임대차보호법
|
||||
- 상담 내용: 계약 만료일 경과 후 2개월째 미반환" oninput="onNotesChange()" onblur="saveCases()" onkeydown="handleNotesTab(event)"></textarea>
|
||||
- 상담 내용: 계약 만료일 경과 후 2개월째 미반환" oninput="onNotesChange()" onblur="saveCases();autoNameCaseIfNeeded()" onkeydown="handleNotesTab(event)"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -865,6 +865,62 @@ function handleNotesTab(e){
|
||||
onNotesChange();
|
||||
}
|
||||
|
||||
// A no-UI chat call (no typing indicator/bubble in the visible panel) for
|
||||
// small background AI tasks like auto-naming — callChatRaw is the visible-
|
||||
// bubble version used by generateChecklist, this is the silent counterpart.
|
||||
async function quietChatCall(message){
|
||||
try{
|
||||
const body={message,sessionId:'lw_tmp_'+Math.random().toString(36).slice(2,8),useTools:false,
|
||||
...(selectedModel?{model:selectedModel}:{}),
|
||||
...(skillContext?{skillContext}:{})};
|
||||
const r=await fetch('/api/chat',{method:'POST',headers:authH({'Content-Type':'application/json'}),body:JSON.stringify(body)});
|
||||
if(!r.ok)return null;
|
||||
const reader=r.body.getReader();const dec=new TextDecoder();let buf='',textBuf='';
|
||||
while(true){
|
||||
const{done,value}=await reader.read();if(done)break;
|
||||
buf+=dec.decode(value,{stream:true});
|
||||
const parts=buf.split('\n\n');buf=parts.pop()||'';
|
||||
for(const part of parts){
|
||||
if(!part.startsWith('data: '))continue;
|
||||
let ev;try{ev=JSON.parse(part.slice(6));}catch{continue;}
|
||||
if(ev.type==='token'||ev.type==='text_delta')textBuf+=(ev.text||'');
|
||||
}
|
||||
}
|
||||
return textBuf.trim();
|
||||
}catch{return null;}
|
||||
}
|
||||
|
||||
// Auto-names a new case from its notes the first time they're written, so
|
||||
// "새 사건" doesn't have to be manually retitled — only fires while the title
|
||||
// is still the untouched default, and never overrides a name the user typed
|
||||
// in themselves (checked again after the AI call returns, in case they
|
||||
// switched case or renamed it while waiting).
|
||||
let lwAutoNaming=false;
|
||||
async function autoNameCaseIfNeeded(){
|
||||
const c=currentCase();
|
||||
if(!c||lwAutoNaming)return;
|
||||
const title=(document.getElementById('case-name-input').value||'').trim();
|
||||
const notes=document.getElementById('case-notes').value||'';
|
||||
if(title!=='새 사건'||notes.trim().length<15)return;
|
||||
lwAutoNaming=true;
|
||||
const targetId=c.id;
|
||||
try{
|
||||
const prompt=`다음은 법률 상담 메모입니다. 8자 이내의 간결한 사건명을 지어주세요. 사건명만 출력하고 다른 설명·따옴표·마침표는 넣지 마세요.\n\n${notes.slice(0,500)}`;
|
||||
const result=await quietChatCall(prompt);
|
||||
if(!result||currentCaseId!==targetId)return; // case switched away while waiting
|
||||
const cur=cases.find(x=>x.id===targetId);
|
||||
if(!cur||(document.getElementById('case-name-input').value||'').trim()!=='새 사건')return; // user already renamed it
|
||||
const name=result.split('\n')[0].replace(/^["'“”]+|["'“”]+$/g,'').trim().slice(0,30);
|
||||
if(!name)return;
|
||||
cur.title=name;
|
||||
document.getElementById('case-name-input').value=name;
|
||||
renderCaseList();
|
||||
const label=document.getElementById('lw-chat-ctx-label');
|
||||
if(label)label.textContent=name;
|
||||
saveCases();
|
||||
}finally{lwAutoNaming=false;}
|
||||
}
|
||||
|
||||
function switchCaseTab(tab){
|
||||
activeCaseTab=tab;
|
||||
['notes','checklist','timeline','files','docs'].forEach(t=>{
|
||||
|
||||
Reference in New Issue
Block a user