作家写作
This commit is contained in:
1 parent
1a122eb7fd
commit
07ad87365f
7 files changed
+380
-228
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { ChevronRight, Sparkles, ListChecks, Zap, Loader2 } from 'lucide-react';
|
||||
import { ChevronRight, Sparkles, ListChecks, Zap, Loader2, CheckCircle2, CircleStop } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { SkillSearchStep } from '../../types/ai-writing';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
@@ -14,12 +14,16 @@ const STEP_ICON: Record<SkillSearchStep['type'], typeof Sparkles> = {
|
||||
list_skills: ListChecks,
|
||||
select_skills: Sparkles,
|
||||
invoke_skill: Zap,
|
||||
skill_result: CheckCircle2,
|
||||
stop_early: CircleStop,
|
||||
};
|
||||
|
||||
const STEP_LABEL: Record<SkillSearchStep['type'], string> = {
|
||||
list_skills: '列出可用技能',
|
||||
select_skills: '筛选相关技能',
|
||||
invoke_skill: '调用技能',
|
||||
skill_result: '检索结果',
|
||||
stop_early: '提前停止',
|
||||
};
|
||||
|
||||
export function SkillStepsCard({ steps, inProgress }: SkillStepsCardProps) {
|
||||
@@ -55,13 +59,33 @@ export function SkillStepsCard({ steps, inProgress }: SkillStepsCardProps) {
|
||||
{steps.map((step, idx) => {
|
||||
const Icon = STEP_ICON[step.type] ?? Sparkles;
|
||||
const label = STEP_LABEL[step.type] ?? step.type;
|
||||
const isStopEarly = step.type === 'stop_early';
|
||||
const isResult = step.type === 'skill_result';
|
||||
return (
|
||||
<li key={idx} className="flex items-start gap-2 text-[11px]">
|
||||
<span className="shrink-0 mt-0.5 inline-flex items-center justify-center size-4 rounded-full text-[10px] font-medium bg-violet-100 dark:bg-violet-900/60 text-violet-600 dark:text-violet-300">
|
||||
<span
|
||||
className={cn(
|
||||
'shrink-0 mt-0.5 inline-flex items-center justify-center size-4 rounded-full text-[10px] font-medium',
|
||||
isStopEarly
|
||||
? 'bg-amber-100 dark:bg-amber-900/60 text-amber-600 dark:text-amber-300'
|
||||
: isResult
|
||||
? 'bg-emerald-100 dark:bg-emerald-900/60 text-emerald-600 dark:text-emerald-300'
|
||||
: 'bg-violet-100 dark:bg-violet-900/60 text-violet-600 dark:text-violet-300',
|
||||
)}
|
||||
>
|
||||
{idx + 1}
|
||||
</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-1 font-medium text-violet-700 dark:text-violet-300">
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-1 font-medium',
|
||||
isStopEarly
|
||||
? 'text-amber-700 dark:text-amber-300'
|
||||
: isResult
|
||||
? 'text-emerald-700 dark:text-emerald-300'
|
||||
: 'text-violet-700 dark:text-violet-300',
|
||||
)}
|
||||
>
|
||||
<Icon className="size-3 shrink-0" />
|
||||
<span>{label}</span>
|
||||
{step.skillName && (
|
||||
|
||||
@@ -767,7 +767,9 @@ export function useAIWriting() {
|
||||
// 乐观更新到下一阶段,跟老 hook 行为对齐
|
||||
let nextStatus: WritingStatus = state.status;
|
||||
if (pausePoint === 'material_confirm') {
|
||||
nextStatus = payload.action === 're_search' ? 'researching' : 'writing_outline';
|
||||
// re_search / enable_skill_search 都回到 researching;confirm 才进大纲
|
||||
nextStatus = (payload.action === 're_search' || payload.action === 'enable_skill_search')
|
||||
? 'researching' : 'writing_outline';
|
||||
} else if (pausePoint === 'outline_confirm') {
|
||||
nextStatus = payload.action === 're_outline' ? 'writing_outline' : 'writing_draft';
|
||||
} else if (pausePoint === 'draft_confirm') {
|
||||
@@ -788,6 +790,7 @@ export function useAIWriting() {
|
||||
};
|
||||
if (payload.approvedMaterialIds !== undefined) resumePayload.approvedMaterialIds = payload.approvedMaterialIds;
|
||||
if (payload.extraKeywords !== undefined) resumePayload.extraKeywords = payload.extraKeywords;
|
||||
if (payload.userQuery !== undefined) resumePayload.userQuery = payload.userQuery;
|
||||
if (payload.editedOutline !== undefined) resumePayload.editedOutline = payload.editedOutline;
|
||||
if (payload.outlineFeedback !== undefined) resumePayload.outlineFeedback = payload.outlineFeedback;
|
||||
if (payload.userRevisionNotes !== undefined) resumePayload.userRevisionNotes = payload.userRevisionNotes;
|
||||
|
||||
@@ -17,9 +17,11 @@ export interface AIMaterial {
|
||||
// 技能检索过程的单步记录(前端时间线展示"使用了 X 技能")
|
||||
// list_skills:列出全部 enabled 技能
|
||||
// select_skills:LLM 按相关度排序的候选
|
||||
// invoke_skill:实际按顺序调用某个技能
|
||||
// invoke_skill:开始调用某个技能去检索
|
||||
// skill_result:某个技能检索返回了 N 条素材
|
||||
// stop_early:累计素材达到上限,停止后续技能
|
||||
export interface SkillSearchStep {
|
||||
type: 'list_skills' | 'select_skills' | 'invoke_skill';
|
||||
type: 'list_skills' | 'select_skills' | 'invoke_skill' | 'skill_result' | 'stop_early';
|
||||
message: string;
|
||||
skillNames?: string[];
|
||||
skillName?: string;
|
||||
|
||||
Reference in new issue
Block a user