feat(training): Style Studio — upload, rich corpus, lessons, curator portrait, chat
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m7s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m7s
Six-phase upgrade of /training from a read-only dashboard into a full Style Studio for managing Daphna's style corpus. - Upload Sheet on /training: file → proofread preview → commit (no more CLI-only `upload-training` skill). - Rich corpus metadata: GET /api/training/corpus returns summary, outcome, key_principles, page_count, parties (regex), legal_citation, lessons_count. PATCH endpoint for chair edits. CorpusDetailDrawer with 4 tabs (details /content/lessons/patterns) replaces the bare table row. - LLM metadata enrichment: style_metadata_extractor + MCP tools (style_corpus_enrich, style_corpus_pending_enrichment) fill summary /outcome/key_principles via claude_session (free, host-side). - Per-decision lessons: new decision_lessons table + 4 REST endpoints + LessonsTab in drawer; hermes-curator now auto-posts findings as decision_lessons(source=curator). - Curator Portrait tab: prompt rendered with link to Gitea, recent curator findings, style_analyzer training prompts, propose-change form that writes proposals to data/curator-proposals/ for manual chair review (no auto-mutation of the agent file). - Style chat tab: SSE-streamed conversations with the style agent. New host-side pm2 service (legal-chat-service, port 8770) wraps claude CLI with stream-json + --resume continuation; FastAPI proxies via host.docker.internal. Zero API cost — uses chaim's claude.ai subscription. chat_conversations + chat_messages persist history. Architecture: keeps the existing rule that claude_session only runs on the host (not the container). The new legal-chat-service is the canonical bridge between the container and the local CLI for the chat feature; everything else (upload, metadata, lessons) stays within the container's existing capabilities. Audit script (scripts/audit_training_corpus.py) included for verifying which corpus rows still need enrichment. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,30 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { Upload } from "lucide-react";
|
||||
import { AppShell } from "@/components/app-shell";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { StyleReportPanel } from "@/components/training/style-report-panel";
|
||||
import { CorpusPanel } from "@/components/training/corpus-panel";
|
||||
import { ComparePanel } from "@/components/training/compare-panel";
|
||||
import { CuratorPortraitPanel } from "@/components/training/curator-portrait-panel";
|
||||
import { ChatPanel } from "@/components/training/chat-panel";
|
||||
import { TrainingUploadDialog } from "@/components/training/upload-dialog";
|
||||
|
||||
export default function TrainingPage() {
|
||||
const [uploadOpen, setUploadOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<AppShell>
|
||||
<section className="space-y-6">
|
||||
<header>
|
||||
<nav className="text-[0.78rem] text-ink-muted mb-1">
|
||||
<Link href="/" className="hover:text-gold-deep">בית</Link>
|
||||
<span aria-hidden> · </span>
|
||||
<span className="text-navy">אימון סגנון</span>
|
||||
</nav>
|
||||
<h1 className="text-navy mb-0">הפורטרט הסגנוני של דפנה</h1>
|
||||
<p className="text-ink-muted text-sm mt-1 max-w-2xl">
|
||||
לוח בקרה של קורפוס האימון — סטטיסטיקות, אנטומיית החלטה ממוצעת,
|
||||
ביטויי חתימה, וכלי השוואה בין שתי החלטות.
|
||||
</p>
|
||||
<header className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<nav className="text-[0.78rem] text-ink-muted mb-1">
|
||||
<Link href="/" className="hover:text-gold-deep">בית</Link>
|
||||
<span aria-hidden> · </span>
|
||||
<span className="text-navy">אימון סגנון</span>
|
||||
</nav>
|
||||
<h1 className="text-navy mb-0">הפורטרט הסגנוני של דפנה</h1>
|
||||
<p className="text-ink-muted text-sm mt-1 max-w-2xl">
|
||||
לוח בקרה של קורפוס האימון — סטטיסטיקות, אנטומיית החלטה ממוצעת,
|
||||
ביטויי חתימה, וכלי השוואה בין שתי החלטות.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => setUploadOpen(true)}
|
||||
className="bg-navy text-parchment hover:bg-navy-soft shrink-0"
|
||||
>
|
||||
<Upload className="w-4 h-4 me-1" />
|
||||
העלה החלטה
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<TrainingUploadDialog open={uploadOpen} onOpenChange={setUploadOpen} />
|
||||
|
||||
<div className="h-[2px] bg-gradient-to-l from-transparent via-gold to-transparent" />
|
||||
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
@@ -34,6 +53,8 @@ export default function TrainingPage() {
|
||||
<TabsTrigger value="report">פורטרט סגנון</TabsTrigger>
|
||||
<TabsTrigger value="corpus">קורפוס</TabsTrigger>
|
||||
<TabsTrigger value="compare">השוואה</TabsTrigger>
|
||||
<TabsTrigger value="curator">הסוכן</TabsTrigger>
|
||||
<TabsTrigger value="chat">שיחה</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="report" className="mt-5">
|
||||
@@ -47,6 +68,14 @@ export default function TrainingPage() {
|
||||
<TabsContent value="compare" className="mt-5">
|
||||
<ComparePanel />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="curator" className="mt-5">
|
||||
<CuratorPortraitPanel />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="chat" className="mt-5">
|
||||
<ChatPanel />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user