update:1.优化向导生成逻辑,最后一步不再展开大纲,避免等待时间过久 2.新增章节跳转功能,搜索功能
This commit is contained in:
@@ -21,11 +21,11 @@ TZ=Asia/Shanghai
|
|||||||
# PostgreSQL 连接信息
|
# PostgreSQL 连接信息
|
||||||
POSTGRES_DB=mumuai_novel
|
POSTGRES_DB=mumuai_novel
|
||||||
POSTGRES_USER=mumuai
|
POSTGRES_USER=mumuai
|
||||||
POSTGRES_PASSWORD=your_secure_password_here
|
POSTGRES_PASSWORD=123456
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
# 数据库连接 URL(Docker 部署时自动生成)
|
# 数据库连接 URL(Docker 部署时自动生成)
|
||||||
DATABASE_URL=postgresql+asyncpg://mumuai:your_secure_password_here@localhost:5432/mumuai_novel
|
DATABASE_URL=postgresql+asyncpg://mumuai:123456@localhost:5432/mumuai_novel
|
||||||
|
|
||||||
# PostgreSQL 连接池配置(优化后,支持80-150并发用户)
|
# PostgreSQL 连接池配置(优化后,支持80-150并发用户)
|
||||||
DATABASE_POOL_SIZE=30 # 核心连接数(默认30,小团队可用20)
|
DATABASE_POOL_SIZE=30 # 核心连接数(默认30,小团队可用20)
|
||||||
@@ -101,7 +101,7 @@ FRONTEND_URL=http://localhost:8000
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
LOCAL_AUTH_ENABLED=true
|
LOCAL_AUTH_ENABLED=true
|
||||||
LOCAL_AUTH_USERNAME=admin
|
LOCAL_AUTH_USERNAME=admin
|
||||||
LOCAL_AUTH_PASSWORD=your_secure_password_here
|
LOCAL_AUTH_PASSWORD=admin123
|
||||||
LOCAL_AUTH_DISPLAY_NAME=本地管理员
|
LOCAL_AUTH_DISPLAY_NAME=本地管理员
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|||||||
@@ -876,16 +876,14 @@ async def outline_generator(
|
|||||||
db: AsyncSession,
|
db: AsyncSession,
|
||||||
user_ai_service: AIService
|
user_ai_service: AIService
|
||||||
) -> AsyncGenerator[str, None]:
|
) -> AsyncGenerator[str, None]:
|
||||||
"""大纲生成流式生成器 - 向导生成3个大纲节点,每个展开为3章,共9章"""
|
"""大纲生成流式生成器 - 向导仅生成大纲节点,不展开章节(避免等待过久)"""
|
||||||
db_committed = False
|
db_committed = False
|
||||||
try:
|
try:
|
||||||
yield await SSEResponse.send_progress("开始生成大纲...", 5)
|
yield await SSEResponse.send_progress("开始生成大纲...", 5)
|
||||||
|
|
||||||
project_id = data.get("project_id")
|
project_id = data.get("project_id")
|
||||||
# 向导固定生成3个大纲节点
|
# 向导固定生成3个大纲节点(不展开)
|
||||||
outline_count = 3
|
outline_count = data.get("chapter_count", 3)
|
||||||
# 每个大纲展开为3章
|
|
||||||
chapters_per_outline = 3
|
|
||||||
narrative_perspective = data.get("narrative_perspective")
|
narrative_perspective = data.get("narrative_perspective")
|
||||||
target_words = data.get("target_words", 100000)
|
target_words = data.get("target_words", 100000)
|
||||||
requirements = data.get("requirements", "")
|
requirements = data.get("requirements", "")
|
||||||
@@ -989,59 +987,12 @@ async def outline_generator(
|
|||||||
|
|
||||||
logger.info(f"✅ 成功创建{len(created_outlines)}个大纲节点")
|
logger.info(f"✅ 成功创建{len(created_outlines)}个大纲节点")
|
||||||
|
|
||||||
# 第二阶段:使用PlotExpansionService将每个大纲展开为详细章节
|
# 向导流程中不展开大纲,避免等待时间过长
|
||||||
yield await SSEResponse.send_progress(f"开始将大纲展开为详细章节...", 50)
|
# 用户可以在大纲页面手动展开需要的大纲节点
|
||||||
|
yield await SSEResponse.send_progress("跳过大纲展开,加快创建速度...", 85)
|
||||||
expansion_service = PlotExpansionService(user_ai_service)
|
|
||||||
total_chapters_created = 0
|
|
||||||
start_chapter_number = 1
|
|
||||||
|
|
||||||
for outline_idx, outline in enumerate(created_outlines, 1):
|
|
||||||
yield await SSEResponse.send_progress(
|
|
||||||
f"展开第{outline_idx}/{len(created_outlines)}个大纲节点...",
|
|
||||||
50 + (outline_idx - 1) * 35 // len(created_outlines)
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 分析大纲并生成章节规划
|
|
||||||
chapter_plans = await expansion_service.analyze_outline_for_chapters(
|
|
||||||
outline=outline,
|
|
||||||
project=project,
|
|
||||||
db=db,
|
|
||||||
target_chapter_count=chapters_per_outline,
|
|
||||||
expansion_strategy="balanced",
|
|
||||||
enable_scene_analysis=False,
|
|
||||||
provider=provider,
|
|
||||||
model=model
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"大纲 {outline.title} 生成了 {len(chapter_plans)} 个章节规划")
|
|
||||||
|
|
||||||
# 创建章节记录
|
|
||||||
chapters = await expansion_service.create_chapters_from_plans(
|
|
||||||
outline_id=outline.id,
|
|
||||||
chapter_plans=chapter_plans,
|
|
||||||
project_id=project_id,
|
|
||||||
db=db,
|
|
||||||
start_chapter_number=start_chapter_number
|
|
||||||
)
|
|
||||||
|
|
||||||
total_chapters_created += len(chapters)
|
|
||||||
start_chapter_number += len(chapters)
|
|
||||||
|
|
||||||
logger.info(f"✅ 大纲 {outline.title} 创建了 {len(chapters)} 个章节记录")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ 展开大纲 {outline.title} 失败: {e}")
|
|
||||||
yield await SSEResponse.send_progress(
|
|
||||||
f"⚠️ 展开大纲{outline_idx}失败,跳过",
|
|
||||||
50 + outline_idx * 35 // len(created_outlines),
|
|
||||||
"warning"
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 更新项目信息
|
# 更新项目信息
|
||||||
project.chapter_count = total_chapters_created
|
project.chapter_count = 0 # 向导阶段不创建章节
|
||||||
project.narrative_perspective = narrative_perspective
|
project.narrative_perspective = narrative_perspective
|
||||||
project.target_words = target_words
|
project.target_words = target_words
|
||||||
project.status = "writing"
|
project.status = "writing"
|
||||||
@@ -1053,20 +1004,20 @@ async def outline_generator(
|
|||||||
|
|
||||||
logger.info(f"📊 向导大纲生成完成:")
|
logger.info(f"📊 向导大纲生成完成:")
|
||||||
logger.info(f" - 创建大纲节点:{len(created_outlines)} 个")
|
logger.info(f" - 创建大纲节点:{len(created_outlines)} 个")
|
||||||
logger.info(f" - 创建详细章节:{total_chapters_created} 个")
|
logger.info(f" - 提示:可在大纲页面手动展开为章节")
|
||||||
logger.info(f" - 平均每个大纲:{total_chapters_created / len(created_outlines):.1f} 章")
|
|
||||||
|
|
||||||
# 发送结果
|
# 发送结果
|
||||||
yield await SSEResponse.send_result({
|
yield await SSEResponse.send_result({
|
||||||
"message": f"成功生成{len(created_outlines)}个大纲节点,展开为{total_chapters_created}个详细章节",
|
"message": f"成功生成{len(created_outlines)}个大纲节点(未展开章节,可在大纲页面手动展开)",
|
||||||
"outline_count": len(created_outlines),
|
"outline_count": len(created_outlines),
|
||||||
"chapter_count": total_chapters_created,
|
"chapter_count": 0,
|
||||||
"outlines": [
|
"outlines": [
|
||||||
{
|
{
|
||||||
"id": outline.id,
|
"id": outline.id,
|
||||||
"order_index": outline.order_index,
|
"order_index": outline.order_index,
|
||||||
"title": outline.title,
|
"title": outline.title,
|
||||||
"content": outline.content[:100] + "..." if len(outline.content) > 100 else outline.content
|
"content": outline.content[:100] + "..." if len(outline.content) > 100 else outline.content,
|
||||||
|
"note": "可在大纲页面展开为章节"
|
||||||
} for outline in created_outlines
|
} for outline in created_outlines
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-mumuai_novel}
|
POSTGRES_DB: ${POSTGRES_DB:-mumuai_novel}
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-mumuai}
|
POSTGRES_USER: ${POSTGRES_USER:-mumuai}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mumuai_password_2024}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-123456}
|
||||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
|
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
TZ: ${TZ:-Asia/Shanghai}
|
||||||
volumes:
|
volumes:
|
||||||
@@ -72,7 +72,7 @@ services:
|
|||||||
- DEBUG=${DEBUG:-false}
|
- DEBUG=${DEBUG:-false}
|
||||||
|
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
- DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-mumuai}:${POSTGRES_PASSWORD:-mumuai_password_2024}@postgres:5432/${POSTGRES_DB:-mumuai_novel}
|
- DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-mumuai}:${POSTGRES_PASSWORD:-123456}@postgres:5432/${POSTGRES_DB:-mumuai_novel}
|
||||||
|
|
||||||
# PostgreSQL 连接池配置
|
# PostgreSQL 连接池配置
|
||||||
- DATABASE_POOL_SIZE=${DATABASE_POOL_SIZE:-30}
|
- DATABASE_POOL_SIZE=${DATABASE_POOL_SIZE:-30}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import { useState, useMemo } from 'react';
|
||||||
|
import { Drawer, Input, List, Typography, Empty, Tag } from 'antd';
|
||||||
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
|
import type { Chapter } from '../types';
|
||||||
|
|
||||||
|
const { Link } = Typography;
|
||||||
|
|
||||||
|
interface GroupedChapters {
|
||||||
|
outlineId: string | null;
|
||||||
|
outlineTitle: string;
|
||||||
|
chapters: Chapter[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FloatingIndexPanelProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
groupedChapters: GroupedChapters[];
|
||||||
|
onChapterSelect: (chapterId: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FloatingIndexPanel({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
groupedChapters,
|
||||||
|
onChapterSelect,
|
||||||
|
}: FloatingIndexPanelProps) {
|
||||||
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
|
||||||
|
const filteredGroups = useMemo(() => {
|
||||||
|
if (!searchTerm) {
|
||||||
|
return groupedChapters;
|
||||||
|
}
|
||||||
|
return groupedChapters
|
||||||
|
.map(group => {
|
||||||
|
const filteredChapters = group.chapters.filter(chapter =>
|
||||||
|
chapter.title.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
return { ...group, chapters: filteredChapters };
|
||||||
|
})
|
||||||
|
.filter(group => group.chapters.length > 0);
|
||||||
|
}, [searchTerm, groupedChapters]);
|
||||||
|
|
||||||
|
const handleChapterClick = (chapterId: string) => {
|
||||||
|
onChapterSelect(chapterId);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
title="章节目录"
|
||||||
|
placement="right"
|
||||||
|
onClose={onClose}
|
||||||
|
open={visible}
|
||||||
|
width={320}
|
||||||
|
styles={{
|
||||||
|
body: { padding: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ padding: '16px', borderBottom: '1px solid #f0f0f0' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="搜索章节标题"
|
||||||
|
prefix={<SearchOutlined />}
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{filteredGroups.length > 0 ? (
|
||||||
|
<List
|
||||||
|
dataSource={filteredGroups}
|
||||||
|
renderItem={group => (
|
||||||
|
<List.Item style={{ padding: '0 16px', flexDirection: 'column', alignItems: 'flex-start' }}>
|
||||||
|
<div style={{ padding: '12px 0', fontWeight: 'bold' }}>
|
||||||
|
<Tag color={group.outlineId ? 'blue' : 'default'}>
|
||||||
|
{group.outlineTitle}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
<List
|
||||||
|
size="small"
|
||||||
|
dataSource={group.chapters}
|
||||||
|
renderItem={chapter => (
|
||||||
|
<List.Item style={{ paddingLeft: 16, borderBlockStart: 'none' }}>
|
||||||
|
<Link onClick={() => handleChapterClick(chapter.id)}>
|
||||||
|
{`第${chapter.chapter_number}章: ${chapter.title}`}
|
||||||
|
</Link>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
split={false}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
style={{ height: 'calc(100vh - 120px)', overflowY: 'auto' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Empty description="没有找到匹配的章节" style={{ marginTop: 48 }} />
|
||||||
|
)}
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import { useState, useEffect, useRef, useMemo } from 'react';
|
import { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
import { List, Button, Modal, Form, Input, Select, message, Empty, Space, Badge, Tag, Card, Tooltip, InputNumber, Progress, Alert, Radio, Descriptions, Collapse, Popconfirm } from 'antd';
|
import { List, Button, Modal, Form, Input, Select, message, Empty, Space, Badge, Tag, Card, Tooltip, InputNumber, Progress, Alert, Radio, Descriptions, Collapse, Popconfirm, FloatButton } from 'antd';
|
||||||
import { EditOutlined, FileTextOutlined, ThunderboltOutlined, LockOutlined, DownloadOutlined, SettingOutlined, FundOutlined, SyncOutlined, CheckCircleOutlined, CloseCircleOutlined, RocketOutlined, StopOutlined, InfoCircleOutlined, CaretRightOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { EditOutlined, FileTextOutlined, ThunderboltOutlined, LockOutlined, DownloadOutlined, SettingOutlined, FundOutlined, SyncOutlined, CheckCircleOutlined, CloseCircleOutlined, RocketOutlined, StopOutlined, InfoCircleOutlined, CaretRightOutlined, DeleteOutlined, BookOutlined } from '@ant-design/icons';
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../store';
|
||||||
import { useChapterSync } from '../store/hooks';
|
import { useChapterSync } from '../store/hooks';
|
||||||
import { projectApi, writingStyleApi } from '../services/api';
|
import { projectApi, writingStyleApi } from '../services/api';
|
||||||
import type { Chapter, ChapterUpdate, ApiError, WritingStyle, AnalysisTask, ExpansionPlanData } from '../types';
|
import type { Chapter, ChapterUpdate, ApiError, WritingStyle, AnalysisTask, ExpansionPlanData } from '../types';
|
||||||
import ChapterAnalysis from '../components/ChapterAnalysis';
|
import ChapterAnalysis from '../components/ChapterAnalysis';
|
||||||
import { SSELoadingOverlay } from '../components/SSELoadingOverlay';
|
import { SSELoadingOverlay } from '../components/SSELoadingOverlay';
|
||||||
|
import FloatingIndexPanel from '../components/FloatingIndexPanel';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ export default function Chapters() {
|
|||||||
// 分析任务状态管理
|
// 分析任务状态管理
|
||||||
const [analysisTasksMap, setAnalysisTasksMap] = useState<Record<string, AnalysisTask>>({});
|
const [analysisTasksMap, setAnalysisTasksMap] = useState<Record<string, AnalysisTask>>({});
|
||||||
const pollingIntervalsRef = useRef<Record<string, number>>({});
|
const pollingIntervalsRef = useRef<Record<string, number>>({});
|
||||||
|
const [isIndexPanelVisible, setIsIndexPanelVisible] = useState(false);
|
||||||
|
|
||||||
// 单章节生成进度状态
|
// 单章节生成进度状态
|
||||||
const [singleChapterProgress, setSingleChapterProgress] = useState(0);
|
const [singleChapterProgress, setSingleChapterProgress] = useState(0);
|
||||||
@@ -848,6 +850,19 @@ export default function Chapters() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleChapterSelect = (chapterId: string) => {
|
||||||
|
const element = document.getElementById(`chapter-item-${chapterId}`);
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
// Optional: add a visual highlight effect
|
||||||
|
element.style.transition = 'background-color 0.5s ease';
|
||||||
|
element.style.backgroundColor = '#e6f7ff';
|
||||||
|
setTimeout(() => {
|
||||||
|
element.style.backgroundColor = '';
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -891,7 +906,7 @@ export default function Chapters() {
|
|||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ flex: 1, overflowY: 'auto' }}>
|
<div style={{ flex: 1, overflowY: 'auto', minHeight: 0 }}>
|
||||||
{chapters.length === 0 ? (
|
{chapters.length === 0 ? (
|
||||||
<Empty description="还没有章节,开始创作吧!" />
|
<Empty description="还没有章节,开始创作吧!" />
|
||||||
) : (
|
) : (
|
||||||
@@ -933,6 +948,7 @@ export default function Chapters() {
|
|||||||
dataSource={group.chapters}
|
dataSource={group.chapters}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item
|
<List.Item
|
||||||
|
id={`chapter-item-${item.id}`}
|
||||||
style={{
|
style={{
|
||||||
padding: '16px 0',
|
padding: '16px 0',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
@@ -1000,10 +1016,17 @@ export default function Chapters() {
|
|||||||
<List.Item.Meta
|
<List.Item.Meta
|
||||||
avatar={!isMobile && <FileTextOutlined style={{ fontSize: 32, color: '#1890ff' }} />}
|
avatar={!isMobile && <FileTextOutlined style={{ fontSize: 32, color: '#1890ff' }} />}
|
||||||
title={
|
title={
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: isMobile ? 4 : 8, flexWrap: 'wrap', fontSize: isMobile ? 14 : 16 }}>
|
<div style={{
|
||||||
<span>
|
display: 'flex',
|
||||||
|
flexDirection: isMobile ? 'column' : 'row',
|
||||||
|
alignItems: isMobile ? 'flex-start' : 'center',
|
||||||
|
gap: isMobile ? 6 : 12,
|
||||||
|
width: '100%'
|
||||||
|
}}>
|
||||||
|
<span style={{ fontSize: isMobile ? 14 : 16, fontWeight: 500, flexShrink: 0 }}>
|
||||||
第{item.chapter_number}章:{item.title}
|
第{item.chapter_number}章:{item.title}
|
||||||
</span>
|
</span>
|
||||||
|
<Space wrap size={isMobile ? 4 : 8}>
|
||||||
<Tag color={getStatusColor(item.status)}>{getStatusText(item.status)}</Tag>
|
<Tag color={getStatusColor(item.status)}>{getStatusText(item.status)}</Tag>
|
||||||
<Badge count={`${item.word_count || 0}字`} style={{ backgroundColor: '#52c41a' }} />
|
<Badge count={`${item.word_count || 0}字`} style={{ backgroundColor: '#52c41a' }} />
|
||||||
{renderAnalysisStatus(item.id)}
|
{renderAnalysisStatus(item.id)}
|
||||||
@@ -1032,6 +1055,7 @@ export default function Chapters() {
|
|||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
description={
|
description={
|
||||||
@@ -1630,6 +1654,21 @@ export default function Chapters() {
|
|||||||
progress={singleChapterProgress}
|
progress={singleChapterProgress}
|
||||||
message={singleChapterProgressMessage}
|
message={singleChapterProgressMessage}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FloatButton
|
||||||
|
icon={<BookOutlined />}
|
||||||
|
type="primary"
|
||||||
|
tooltip="章节目录"
|
||||||
|
onClick={() => setIsIndexPanelVisible(true)}
|
||||||
|
style={{ right: isMobile ? 24 : 48, bottom: isMobile ? 80 : 48 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FloatingIndexPanel
|
||||||
|
visible={isIndexPanelVisible}
|
||||||
|
onClose={() => setIsIndexPanelVisible(false)}
|
||||||
|
groupedChapters={groupedChapters}
|
||||||
|
onChapterSelect={handleChapterSelect}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ export default function ProjectWizardNew() {
|
|||||||
await wizardStreamApi.generateCompleteOutlineStream(
|
await wizardStreamApi.generateCompleteOutlineStream(
|
||||||
{
|
{
|
||||||
project_id: createdProjectId,
|
project_id: createdProjectId,
|
||||||
chapter_count: 5, // 开局5章
|
chapter_count: 3, // 生成3个大纲节点(不展开)
|
||||||
narrative_perspective: values.narrative_perspective,
|
narrative_perspective: values.narrative_perspective,
|
||||||
target_words: values.target_words,
|
target_words: values.target_words,
|
||||||
},
|
},
|
||||||
@@ -190,7 +190,7 @@ export default function ProjectWizardNew() {
|
|||||||
创建新项目
|
创建新项目
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph type="secondary" style={{ marginBottom: 32 }}>
|
<Paragraph type="secondary" style={{ marginBottom: 32 }}>
|
||||||
填写基本信息后,AI将自动为您生成世界观、角色和开局大纲
|
填写基本信息后,AI将自动为您生成世界观、角色和大纲节点(大纲可在项目内手动展开为章节)
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
|
|
||||||
<Form
|
<Form
|
||||||
@@ -432,7 +432,13 @@ export default function ProjectWizardNew() {
|
|||||||
marginTop: isMobile ? 16 : 24,
|
marginTop: isMobile ? 16 : 24,
|
||||||
marginBottom: isMobile ? 32 : 48,
|
marginBottom: isMobile ? 32 : 48,
|
||||||
}}>
|
}}>
|
||||||
《{projectTitle}》已成功创建,包含完整的世界观、角色和开局大纲
|
《{projectTitle}》已成功创建,包含完整的世界观、角色和大纲节点
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph type="secondary" style={{
|
||||||
|
fontSize: isMobile ? 12 : 14,
|
||||||
|
marginTop: 8,
|
||||||
|
}}>
|
||||||
|
💡 提示:进入项目后,可在"大纲"页面将大纲节点展开为详细章节
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
|
|||||||
Reference in New Issue
Block a user