update:1.优化世界观生成提示词 2.修复章节分析页面内容重复问题 3.限制mcp调用最大并发数

This commit is contained in:
xiamuceer
2025-11-24 20:42:09 +08:00
parent 187d62f315
commit 4354e74fff
7 changed files with 251 additions and 274 deletions
-156
View File
@@ -1,156 +0,0 @@
# 安装和测试指南
## 1. 安装前端依赖
在完成所有代码更改后,需要安装新添加的npm包:
```bash
cd frontend
npm install
```
这将安装以下新依赖:
- `react-diff-viewer-continued`: 用于版本对比的diff查看器
## 2. 重启后端服务
由于修改了数据模型,需要重启后端服务以加载新的模型定义:
```bash
# 在项目根目录
cd backend
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
## 3. 启动前端开发服务器
```bash
cd frontend
npm run dev
```
## 4. 测试功能流程
### 4.1 基本流程测试
1. **打开章节列表**
- 进入任意项目
- 查看章节列表
2. **分析章节**
- 点击某个章节的"分析"按钮
- 等待AI分析完成
- 查看分析结果和改进建议
3. **重新生成章节**
- 在分析结果页面,点击"根据建议重新生成"
- 选择要应用的建议
- 可以添加自定义修改要求
- 配置生成参数(字数、保留元素等)
- 勾选"保存为版本历史"(不勾选自动应用)
- 点击"开始重新生成"
- 观察流式生成过程
4. **查看版本对比**
- 生成完成后,点击"查看版本对比"按钮
- 进入版本管理器界面
5. **版本管理操作**
- **版本列表**: 查看所有历史版本
- **预览版本**: 点击"预览"查看某个版本的完整内容
- **对比版本**:
- 点击第一个版本的"对比"按钮
- 再点击第二个版本的"对比"按钮
- 自动切换到"对比"标签页
- 查看并排diff对比
- **恢复版本**: 点击"恢复"将章节内容还原到该版本
- **删除版本**: 删除不需要的历史版本(当前激活版本不能删除)
### 4.2 测试场景
#### 场景1:优化情感描写
1. 分析一个章节
2. 查看建议中关于情感的建议
3. 重新生成时选择情感相关建议
4. 设置重点优化方向为"情感渲染"
5. 生成后对比新旧版本的差异
#### 场景2:调整节奏
1. 选择节奏问题的建议
2. 添加自定义指令:"加快前半部分节奏,增强紧张感"
3. 设置目标字数适当减少(如从3000减到2500)
4. 生成后查看结构变化
#### 场景3:版本管理
1. 对同一章节重新生成多次(使用不同建议)
2. 在版本管理器中浏览所有版本
3. 对比不同版本的差异
4. 选择最满意的版本恢复
## 5. 验证清单
- [ ] 依赖安装无错误
- [ ] 前后端服务正常启动
- [ ] 章节分析功能正常
- [ ] 重新生成功能正常
- [ ] 流式生成显示正常
- [ ] 版本保存成功
- [ ] 版本列表显示正确
- [ ] 版本预览功能正常
- [ ] 版本对比diff显示正确
- [ ] 版本恢复功能正常
- [ ] 版本删除功能正常
- [ ] 移动端适配正常
## 6. 常见问题
### Q1: 依赖安装失败
```bash
# 清除缓存重试
npm cache clean --force
npm install
```
### Q2: 后端启动报错
- 检查是否运行了数据库迁移脚本
- 确认模型定义与数据库表结构一致
### Q3: 版本对比不显示
- 检查浏览器控制台是否有JavaScript错误
- 确认react-diff-viewer-continued正确安装
### Q4: 重新生成后看不到新内容
- 检查是否勾选了"自动应用"
- 查看版本管理器中是否有新版本记录
## 7. 性能优化建议
1. **首次加载优化**
- react-diff-viewer-continued是较大的依赖
- 可以考虑代码分割(lazy loading
2. **版本列表优化**
- 如果版本过多,考虑分页加载
- 添加版本数量限制提示
3. **diff计算优化**
- 对于超长文本,可以限制diff行数
- 添加加载提示
## 8. 下一步优化方向
1. **AI质量评分对比**
- 在版本对比时显示质量分数变化
- 自动标注改进/退步的指标
2. **批量操作**
- 支持批量删除历史版本
- 支持版本导出/导入
3. **协作功能**
- 版本评论和讨论
- 多人协作编辑
4. **智能推荐**
- 基于历史生成结果推荐最佳配置
- 学习用户偏好自动调整参数
+135 -44
View File
@@ -24,6 +24,7 @@ interface TextSegment {
type: 'text' | 'annotated';
content: string;
annotation?: MemoryAnnotation;
annotations?: MemoryAnnotation[]; // 🔧 支持多个标注
}
interface AnnotatedTextProps {
@@ -108,30 +109,89 @@ const AnnotatedText: React.FC<AnnotatedTextProps> = ({
const result: TextSegment[] = [];
let lastPos = 0;
// 🔧 智能分组:检测重叠和相邻的标注
const annotationRanges: Array<{
start: number;
end: number;
annotations: MemoryAnnotation[];
}> = [];
for (const annotation of processedAnnotations) {
const { position, length } = annotation;
// 添加普通文本片段
if (position > lastPos) {
const actualLength = length > 0 ? length : 30;
const start = position;
const end = position + actualLength;
// 查找是否有重叠或紧邻的范围
const overlappingRange = annotationRanges.find(
(range) =>
(start >= range.start && start <= range.end) || // 起始点在范围内
(end >= range.start && end <= range.end) || // 结束点在范围内
(start <= range.start && end >= range.end) || // 完全包含
Math.abs(start - range.end) <= 5 || // 紧邻(容差5字符)
Math.abs(end - range.start) <= 5
);
if (overlappingRange) {
// 合并到现有范围
overlappingRange.start = Math.min(overlappingRange.start, start);
overlappingRange.end = Math.max(overlappingRange.end, end);
overlappingRange.annotations.push(annotation);
} else {
// 创建新范围
annotationRanges.push({
start,
end,
annotations: [annotation],
});
}
}
// 按起始位置排序
annotationRanges.sort((a, b) => a.start - b.start);
// 🔧 智能分片:将重叠区域分成多个小片段
for (const range of annotationRanges) {
// 添加前面的普通文本
if (range.start > lastPos) {
result.push({
type: 'text',
content: content.slice(lastPos, position),
content: content.slice(lastPos, range.start),
});
}
// 添加标注片段
const annotatedContent = content.slice(
position,
position + (length > 0 ? length : 30) // 如果没有长度,默认30字符
);
result.push({
type: 'annotated',
content: annotatedContent,
annotation,
});
if (range.annotations.length === 1) {
// 单个标注,直接添加
result.push({
type: 'annotated',
content: content.slice(range.start, range.end),
annotation: range.annotations[0],
annotations: range.annotations,
});
} else {
// 🔧 多个标注:将文本分成多个小片段
const totalLength = range.end - range.start;
const segmentLength = Math.max(1, Math.floor(totalLength / range.annotations.length));
lastPos = position + (length > 0 ? length : 30);
// 按重要性排序标注
const sortedAnnotations = [...range.annotations].sort((a, b) => b.importance - a.importance);
for (let i = 0; i < sortedAnnotations.length; i++) {
const segmentStart = range.start + i * segmentLength;
const segmentEnd = i === sortedAnnotations.length - 1
? range.end
: range.start + (i + 1) * segmentLength;
result.push({
type: 'annotated',
content: content.slice(segmentStart, segmentEnd),
annotation: sortedAnnotations[i],
annotations: sortedAnnotations, // 保留所有标注信息
});
}
}
lastPos = range.end;
}
// 添加剩余文本
@@ -142,6 +202,7 @@ const AnnotatedText: React.FC<AnnotatedTextProps> = ({
});
}
console.log(`AnnotatedText: 处理${processedAnnotations.length}个标注,生成${result.length}个片段`);
return result;
}, [content, processedAnnotations]);
@@ -151,43 +212,73 @@ const AnnotatedText: React.FC<AnnotatedTextProps> = ({
return <span key={index}>{segment.content}</span>;
}
const { annotation } = segment;
const { annotation, annotations } = segment;
if (!annotation) return null;
const color = TYPE_COLORS[annotation.type];
const icon = TYPE_ICONS[annotation.type];
const isActive = activeAnnotationId === annotation.id;
// 工具提示内容
// 🔧 工具提示内容:如果有多个标注,显示所有标注信息
const tooltipContent = (
<div style={{ maxWidth: 300 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>
{icon} {annotation.title}
</div>
<div style={{ fontSize: 12, opacity: 0.9 }}>
{annotation.content.slice(0, 100)}
{annotation.content.length > 100 ? '...' : ''}
</div>
<div style={{ marginTop: 8, fontSize: 11, opacity: 0.7 }}>
: {(annotation.importance * 10).toFixed(1)}/10
</div>
{annotation.tags && annotation.tags.length > 0 && (
<div style={{ marginTop: 4, fontSize: 11 }}>
{annotation.tags.map((tag, i) => (
<span
key={i}
style={{
display: 'inline-block',
background: 'rgba(255,255,255,0.2)',
padding: '2px 6px',
borderRadius: 3,
marginRight: 4,
}}
>
{tag}
</span>
<div style={{ maxWidth: 350 }}>
{annotations && annotations.length > 1 ? (
// 多个标注
<div>
<div style={{ fontWeight: 'bold', marginBottom: 8, borderBottom: '1px solid rgba(255,255,255,0.3)', paddingBottom: 4 }}>
📍 {annotations.length}
</div>
{annotations.map((ann, idx) => (
<div key={ann.id} style={{
marginBottom: idx < annotations.length - 1 ? 8 : 0,
paddingBottom: idx < annotations.length - 1 ? 8 : 0,
borderBottom: idx < annotations.length - 1 ? '1px solid rgba(255,255,255,0.1)' : 'none'
}}>
<div style={{ fontWeight: 'bold', marginBottom: 4, fontSize: 13 }}>
{TYPE_ICONS[ann.type]} {ann.title}
</div>
<div style={{ fontSize: 11, opacity: 0.9 }}>
{ann.content.slice(0, 80)}
{ann.content.length > 80 ? '...' : ''}
</div>
<div style={{ marginTop: 4, fontSize: 10, opacity: 0.7 }}>
: {(ann.importance * 10).toFixed(1)}/10
</div>
</div>
))}
</div>
) : (
// 单个标注
<div>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>
{icon} {annotation.title}
</div>
<div style={{ fontSize: 12, opacity: 0.9 }}>
{annotation.content.slice(0, 100)}
{annotation.content.length > 100 ? '...' : ''}
</div>
<div style={{ marginTop: 8, fontSize: 11, opacity: 0.7 }}>
: {(annotation.importance * 10).toFixed(1)}/10
</div>
{annotation.tags && annotation.tags.length > 0 && (
<div style={{ marginTop: 4, fontSize: 11 }}>
{annotation.tags.map((tag, i) => (
<span
key={i}
style={{
display: 'inline-block',
background: 'rgba(255,255,255,0.2)',
padding: '2px 6px',
borderRadius: 3,
marginRight: 4,
}}
>
{tag}
</span>
))}
</div>
)}
</div>
)}
</div>
);
+20 -5
View File
@@ -57,12 +57,9 @@ export default function ChapterAnalysis({ chapterId, visible, onClose }: Chapter
};
}, [visible, chapterId]);
const fetchAnalysisStatus = async () => {
// 🔧 新增:独立的章节信息加载函数
const loadChapterInfo = async () => {
try {
setLoading(true);
setError(null);
// 同时获取章节信息
const chapterResponse = await fetch(`/api/chapters/${chapterId}`);
if (chapterResponse.ok) {
const chapterData = await chapterResponse.json();
@@ -71,7 +68,20 @@ export default function ChapterAnalysis({ chapterId, visible, onClose }: Chapter
chapter_number: chapterData.chapter_number,
content: chapterData.content || ''
});
console.log('✅ 已刷新章节内容,字数:', chapterData.content?.length || 0);
}
} catch (error) {
console.error('❌ 加载章节信息失败:', error);
}
};
const fetchAnalysisStatus = async () => {
try {
setLoading(true);
setError(null);
// 🔧 使用独立的章节加载函数
await loadChapterInfo();
const response = await fetch(`/api/chapters/${chapterId}/analysis/status`);
@@ -134,6 +144,8 @@ export default function ChapterAnalysis({ chapterId, visible, onClose }: Chapter
if (taskData.status === 'completed') {
clearInterval(pollInterval);
await fetchAnalysisResult();
// 🔧 分析完成后刷新章节内容,确保显示最新内容
await loadChapterInfo();
} else if (taskData.status === 'failed') {
clearInterval(pollInterval);
setError(taskData.error_message || '分析失败');
@@ -152,6 +164,9 @@ export default function ChapterAnalysis({ chapterId, visible, onClose }: Chapter
setLoading(true);
setError(null);
// 🔧 触发分析前先刷新章节内容,确保分析的是最新内容
await loadChapterInfo();
const response = await fetch(`/api/chapters/${chapterId}/analyze`, {
method: 'POST'
});