修改名称 笔记本改为 空间

This commit is contained in:
xuhd committed 2026-06-11 11:19:26 +08:00
1 parent 06508cfb7c
commit 82d14351fc
12 files changed
+446 -393

No files matched your search

@@ -22,7 +22,7 @@ interface AIWritingFormProps {
disabled?: boolean;
/** workspace 入口:隐藏严格模式、目标读者 */
hideAdvancedFields?: boolean;
/** 预选笔记本 ID(传入时自动切换素材来源为「我的笔记」) */
/** 预选空间 ID(传入时自动切换素材来源为「我的笔记」) */
initialNotebookId?: number;
/** 预选文档 ID 列表 */
initialDocumentIds?: number[];
@@ -45,7 +45,7 @@ const MAX_INTENT_LENGTH = 500;
const MATERIAL_SOURCE_OPTIONS: Array<{ value: MaterialSource; label: string; desc: string }> = [
{ value: 'knowledge_base', label: '知识库', desc: '默认 web/intranet 检索' },
{ value: 'skill', label: '技能检索', desc: '用已启用的技能编排检索' },
{ value: 'notebook', label: '我的笔记', desc: '从笔记本中检索素材' },
{ value: 'notebook', label: '我的笔记', desc: '从空间中检索素材' },
];
const FIELD_LABEL_CLASS = 'text-[16px] font-semibold leading-none text-[#222]';
@@ -139,7 +139,7 @@ export function AIWritingForm({
function handleMaterialSourceChange(val: MaterialSource) {
setMaterialSource(val);
// studioToken 模式下笔记本和文档已锁定,切换素材来源时不清空
// studioToken 模式下空间和文档已锁定,切换素材来源时不清空
if (val !== 'notebook' && !studioToken) {
setSelectedNotebookId(null);
setSelectedDocumentIds([]);
@@ -296,10 +296,10 @@ export function AIWritingForm({
</SelectContent>
</Select>
{/* 选了"我的笔记"才展示笔记本 / 文档选择器 */}
{/* 选了"我的笔记"才展示空间 / 文档选择器 */}
{materialSource === 'notebook' && (
<div className="mt-2 space-y-2">
{/* studioToken 模式:笔记本已锁定,不展示选择器 */}
{/* studioToken 模式:空间已锁定,不展示选择器 */}
{!studioToken && (
<Select
value={selectedNotebookId !== null ? String(selectedNotebookId) : ''}
@@ -307,7 +307,7 @@ export function AIWritingForm({
disabled={disabled || notebooksLoading}
>
<SelectTrigger className={FIELD_TRIGGER_CLASS}>
<SelectValue placeholder={notebooksLoading ? '加载中…' : '选择笔记本'} />
<SelectValue placeholder={notebooksLoading ? '加载中…' : '选择空间'} />
</SelectTrigger>
<SelectContent>
{notebooks.map((nb) => (
@@ -324,7 +324,7 @@ export function AIWritingForm({
<p className="text-xs text-muted-foreground">
{sourcesLoading
? '文档加载中…'
: `选择文档(可多选;不选则搜整个笔记本${selectedDocumentIds.length > 0 ? `,已选 ${selectedDocumentIds.length} 篇` : ''})`}
: `选择文档(可多选;不选则搜整个空间${selectedDocumentIds.length > 0 ? `,已选 ${selectedDocumentIds.length} 篇` : ''})`}
</p>
{!sourcesLoading && (
<div className="max-h-36 overflow-y-auto rounded-lg border border-[#e8dedd] bg-white divide-y divide-[#f0e8e7]">
@@ -7,7 +7,7 @@ export interface AIMaterial {
source: string;
publishedAt: string;
relevanceScore: number;
sourceType: 'internet' | 'intranet' | 'skill' | 'notebook';
sourceType: "internet" | "intranet" | "skill" | "notebook";
url?: string;
recUuid?: string;
// skill 类素材的元信息(skill_name / container_path / category / skill_full_content 等)
@@ -22,7 +22,13 @@ export interface AIMaterial {
// skill_result:某个技能检索返回了 N 条素材
// stop_early:累计素材达到上限,停止后续技能
export interface SkillSearchStep {
type: 'list_skills' | 'match_skills' | 'select_skills' | 'invoke_skill' | 'skill_result' | 'stop_early';
type:
| "list_skills"
| "match_skills"
| "select_skills"
| "invoke_skill"
| "skill_result"
| "stop_early";
message: string;
skillNames?: string[];
skillName?: string;
@@ -41,8 +47,8 @@ export interface SkillSearchStep {
// guard 兼容,防止前端流式接收到旧大纲时崩溃。详见 normalizeKeyPoint() helper。
export interface KeyPoint {
pointTitle: string; // 小节标题(渲染为 ### 三级标题)
subPoints: string[]; // 子要点(可空;非空时在小节正文起始处以 bullet 列表呈现)
pointTitle: string; // 小节标题(渲染为 ### 三级标题)
subPoints: string[]; // 子要点(可空;非空时在小节正文起始处以 bullet 列表呈现)
}
export interface OutlineSection {
@@ -65,23 +71,28 @@ export interface AIOutline {
* - 任何意外形态 → 空 KeyPoint(防止崩溃,不抛异常)
*/
export function normalizeKeyPoint(raw: unknown): KeyPoint {
if (typeof raw === 'string') {
if (typeof raw === "string") {
return { pointTitle: raw, subPoints: [] };
}
if (raw && typeof raw === 'object') {
if (raw && typeof raw === "object") {
const r = raw as Record<string, unknown>;
const title =
typeof r.pointTitle === 'string' ? r.pointTitle :
typeof r.point_title === 'string' ? r.point_title :
typeof r.title === 'string' ? r.title :
'';
typeof r.pointTitle === "string"
? r.pointTitle
: typeof r.point_title === "string"
? r.point_title
: typeof r.title === "string"
? r.title
: "";
const subsRaw = (r.subPoints ?? r.sub_points ?? []) as unknown;
const subPoints: string[] = Array.isArray(subsRaw)
? subsRaw.map((s) => (typeof s === 'string' ? s : String(s ?? ''))).filter(Boolean)
? subsRaw
.map((s) => (typeof s === "string" ? s : String(s ?? "")))
.filter(Boolean)
: [];
return { pointTitle: title, subPoints };
}
return { pointTitle: '', subPoints: [] };
return { pointTitle: "", subPoints: [] };
}
// ── 素材不足求助 ──────────────────────────────────────────────────────────────
@@ -93,7 +104,7 @@ export interface BlockedSection {
}
/** 单个被阻塞章节的处理决策 */
export type SectionDecisionKind = 'supplement' | 'delete' | 'loose';
export type SectionDecisionKind = "supplement" | "delete" | "loose";
export interface SectionDecision {
sectionTitle: string;
@@ -103,15 +114,15 @@ export interface SectionDecision {
// ── 编辑审核 ──────────────────────────────────────────────────────────────────
export interface ReviewIssue {
category: 'fact' | 'logic' | 'language';
severity: 'major' | 'minor';
category: "fact" | "logic" | "language";
severity: "major" | "minor";
location: string;
issue: string;
suggestion: string;
}
export interface ReviewResult {
verdict: 'pass' | 'reject';
verdict: "pass" | "reject";
factScore: number;
logicScore: number;
languageScore: number;
@@ -123,44 +134,44 @@ export interface ReviewResult {
// ── 写作状态 ──────────────────────────────────────────────────────────────────
export type WritingStatus =
| 'idle'
| 'researching'
| 'awaiting_material_confirm'
| 'writing_outline'
| 'awaiting_outline_confirm'
| 'writing_draft'
| 'awaiting_section_help'
| 'awaiting_draft_confirm'
| 'reviewing'
| 'awaiting_review_confirm'
| 'revising'
| 'done'
| 'error';
| "idle"
| "researching"
| "awaiting_material_confirm"
| "writing_outline"
| "awaiting_outline_confirm"
| "writing_draft"
| "awaiting_section_help"
| "awaiting_draft_confirm"
| "reviewing"
| "awaiting_review_confirm"
| "revising"
| "done"
| "error";
// ── SSE 进度事件 ──────────────────────────────────────────────────────────────
export type ProgressEventType =
| 'connected'
| 'step_start'
| 'step_done'
| 'intent_chunk'
| 'intent_ready'
| 'research_progress'
| 'materials_ready'
| 'outline_chunk'
| 'outline_ready'
| 'draft_chunk'
| 'draft_ready'
| 'review_chunk'
| 'review_item_done'
| 'review_ready'
| 'await_user'
| 'resumed'
| 'notice'
| 'skill_search_step'
| 'skill_select_chunk'
| 'done'
| 'error';
| "connected"
| "step_start"
| "step_done"
| "intent_chunk"
| "intent_ready"
| "research_progress"
| "materials_ready"
| "outline_chunk"
| "outline_ready"
| "draft_chunk"
| "draft_ready"
| "review_chunk"
| "review_item_done"
| "review_ready"
| "await_user"
| "resumed"
| "notice"
| "skill_search_step"
| "skill_select_chunk"
| "done"
| "error";
export interface ProgressEvent {
type: ProgressEventType;
@@ -183,13 +194,18 @@ export interface ProgressEvent {
draftTitle?: string;
revisionCount?: number;
// review_item_done (streaming per-category result)
reviewItemCategory?: 'fact' | 'logic' | 'language';
reviewItemCategory?: "fact" | "logic" | "language";
reviewItemScore?: number;
reviewItemIssues?: ReviewIssue[];
// review_ready
reviewResult?: ReviewResult;
// await_user
pausePoint?: 'material_confirm' | 'outline_confirm' | 'draft_confirm' | 'review_confirm' | 'section_help';
pausePoint?:
| "material_confirm"
| "outline_confirm"
| "draft_confirm"
| "review_confirm"
| "section_help";
pauseContext?: Record<string, unknown>;
// section_help:素材不足、待用户决策的章节
blockedSections?: BlockedSection[];
@@ -229,19 +245,19 @@ export interface AIWritingRequest {
/** 素材检索关键词数量(1~10,默认 1) */
keywordCount: number;
/** 写作模式:strict=严格依据素材 / loose=可结合通用知识(默认 loose) */
writingMode: 'strict' | 'loose';
writingMode: "strict" | "loose";
/** 素材来源:knowledge_base=知识库 / skill=技能检索 / notebook=我的笔记 */
materialSource: 'knowledge_base' | 'skill' | 'notebook';
/** 笔记来源(可选):笔记本 search_space_id */
materialSource: "knowledge_base" | "skill" | "notebook";
/** 笔记来源(可选):空间 search_space_id */
noteSearchSpaceId?: number;
/** 笔记来源(可选):笔记本内指定文档的 document_id 列表,空数组表示检索整个笔记本 */
/** 笔记来源(可选):空间内指定文档的 document_id 列表,空数组表示检索整个空间 */
noteSourceIds?: number[];
}
// ── 流式审核条目 ──────────────────────────────────────────────────────────────
export interface StreamingReviewItem {
category: 'fact' | 'logic' | 'language';
category: "fact" | "logic" | "language";
// 是否已生成完毕(true 时展示结构化评分/意见,false 时展示流式打字机文本)
isDone: boolean;
// 流式过程文本(正文 / 思考分开)
@@ -266,7 +282,7 @@ export interface RevisionSummary {
export interface StreamingDraftSection {
sectionIndex: number;
sectionTitle: string;
text: string; // 正文内容(非思考)
text: string; // 正文内容(非思考)
thinkingText: string; // 思考内容(<think>...</think> 内)
isDone: boolean;
}
@@ -274,7 +290,12 @@ export interface StreamingDraftSection {
// ── 已完成干预记录 ────────────────────────────────────────────────────────────
export interface CompletedIntervention {
pausePoint: 'material_confirm' | 'outline_confirm' | 'draft_confirm' | 'review_confirm' | 'section_help';
pausePoint:
| "material_confirm"
| "outline_confirm"
| "draft_confirm"
| "review_confirm"
| "section_help";
action: string;
// material_confirm
materials?: AIMaterial[];