feat(ui): study/topics 학습 진단(study_diagnosis) 패널 — 이드 코치 표면 UI
eid study_diagnosis 백엔드(/api/study-topics/diagnosis/generate)에 프론트 진입점 추가. 학습 주제 페이지 상단 '학습 진단' 카드: [진단 생성] → POST → 코치 응답(약점 Top-N·근거· 복습세트 초안) 마크다운 렌더. data 없으면 status=none 안내(토픽 focus 유도). LLM 호출이라 버튼 트리거. 디자인 토큰·no-emoji. 백엔드 무변(frontend-only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { api } from '$lib/api';
|
||||
import { addToast } from '$lib/stores/toast';
|
||||
import { Plus, ArrowLeft, FolderKanban, Trash2, Pencil } from 'lucide-svelte';
|
||||
import { Plus, ArrowLeft, FolderKanban, Trash2, Pencil, Activity } from 'lucide-svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Card from '$lib/components/ui/Card.svelte';
|
||||
import EmptyState from '$lib/components/ui/EmptyState.svelte';
|
||||
@@ -21,6 +21,7 @@
|
||||
import TextInput from '$lib/components/ui/TextInput.svelte';
|
||||
import Select from '$lib/components/ui/Select.svelte';
|
||||
import Textarea from '$lib/components/ui/Textarea.svelte';
|
||||
import { renderMathMarkdown } from '$lib/utils/mathMarkdown';
|
||||
|
||||
const STUDY_TYPE_OPTIONS = [
|
||||
{ value: '', label: '미지정' },
|
||||
@@ -35,6 +36,29 @@
|
||||
let total = $state(0);
|
||||
let loading = $state(true);
|
||||
|
||||
// ─── 이드 학습 진단 (study_diagnosis surface) ───
|
||||
// 워커(study_weakness)가 산출한 최신 약점 스냅샷을 코치 언어로 번역. 데이터 없으면 status='none'.
|
||||
// LLM 호출이라 버튼 트리거(자동 호출 X).
|
||||
let diag = $state(null); // StudyDiagnosisResponse | null
|
||||
let diagLoading = $state(false);
|
||||
async function generateDiagnosis() {
|
||||
if (diagLoading) return;
|
||||
diagLoading = true;
|
||||
try {
|
||||
diag = await api('/study-topics/diagnosis/generate', { method: 'POST' });
|
||||
} catch {
|
||||
addToast('error', '진단 생성 실패');
|
||||
} finally {
|
||||
diagLoading = false;
|
||||
}
|
||||
}
|
||||
function fmtDiagTime(s) {
|
||||
if (!s) return '';
|
||||
const d = new Date(s);
|
||||
if (isNaN(d.getTime())) return '';
|
||||
return d.toLocaleString('ko-KR', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
// 생성 폼
|
||||
let formOpen = $state(false);
|
||||
let f_name = $state('');
|
||||
@@ -205,6 +229,48 @@
|
||||
<p class="text-xs text-dim mt-1">한 주제 아래에 필기 세션과 자료를 묶어 보고 진도 관리. 향후 단어장·오디오·문제세트도 같은 묶음으로 연결됩니다.</p>
|
||||
</header>
|
||||
|
||||
<!-- 이드 학습 진단 -->
|
||||
<Card class="mb-4">
|
||||
{#snippet children()}
|
||||
<div class="p-3">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<Activity size={16} class="text-accent shrink-0" />
|
||||
<span class="text-sm font-semibold text-text">학습 진단</span>
|
||||
<span class="text-[11px] text-faint truncate hidden sm:inline">누적 풀이 약점·학습 태도 코치</span>
|
||||
</div>
|
||||
<Button onclick={generateDiagnosis} size="sm" variant={diag ? 'ghost' : 'primary'} loading={diagLoading}>
|
||||
{diag ? '새로고침' : '진단 생성'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{#if diagLoading}
|
||||
<div class="mt-3 space-y-2">
|
||||
<Skeleton w="w-full" h="h-4" /><Skeleton w="w-5/6" h="h-4" /><Skeleton w="w-2/3" h="h-4" />
|
||||
</div>
|
||||
{:else if diag && diag.status === 'ready'}
|
||||
<div class="markdown-body math-area mt-3 text-sm leading-relaxed text-text">{@html renderMathMarkdown(diag.content)}</div>
|
||||
{#if diag.review_set_draft_id}
|
||||
<div class="mt-2.5 inline-block text-xs text-accent-hover bg-accent/10 rounded-md px-2.5 py-1.5">
|
||||
권장 복습세트 초안 #{diag.review_set_draft_id} — 복습함에서 1클릭 확인 후 편성
|
||||
</div>
|
||||
{/if}
|
||||
<div class="mt-2 text-[11px] text-faint">
|
||||
{#if diag.snapshot_at}스냅샷 {fmtDiagTime(diag.snapshot_at)}{/if}{#if diag.generated_at} · 생성 {fmtDiagTime(diag.generated_at)}{/if}{#if diag.model} · {diag.model}{/if}
|
||||
</div>
|
||||
{:else if diag && diag.status === 'none'}
|
||||
<p class="mt-3 text-xs text-dim leading-relaxed">
|
||||
아직 진단할 약점 데이터가 없습니다. 학습 주제를 <b class="text-text">공부중</b>으로 표시하면 매일 새벽 누적 풀이에서 약점·태도 스냅샷이 만들어지고, 여기서 진단 코치를 받을 수 있습니다.
|
||||
</p>
|
||||
{:else}
|
||||
<p class="mt-3 text-xs text-dim leading-relaxed">
|
||||
누적 학습 이력을 근거로 약점 토픽과 학습 태도를 진단합니다. <span class="text-text font-medium">진단 생성</span>을 눌러보세요.
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</Card>
|
||||
|
||||
<!-- 새 주제 -->
|
||||
<Card class="mb-4">
|
||||
{#snippet children()}
|
||||
|
||||
Reference in New Issue
Block a user