update:1.增加AI批量创作章节内容时,支持加载模型列表,使用不同模型批量生成内容 2.支持AI生成/续写大纲时,选择自定义模型进行生成
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|||||||
+18
-10
@@ -1973,12 +1973,13 @@ async def batch_generate_chapters_in_order(
|
|||||||
|
|
||||||
logger.info(f"📦 创建批量生成任务: {batch_id}, 章节: 第{start_number}-{end_number}章, 预估耗时: {estimated_time}分钟")
|
logger.info(f"📦 创建批量生成任务: {batch_id}, 章节: 第{start_number}-{end_number}章, 预估耗时: {estimated_time}分钟")
|
||||||
|
|
||||||
# 启动后台批量生成任务
|
# 启动后台批量生成任务,传递model参数
|
||||||
background_tasks.add_task(
|
background_tasks.add_task(
|
||||||
execute_batch_generation_in_order,
|
execute_batch_generation_in_order,
|
||||||
batch_id=batch_id,
|
batch_id=batch_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
ai_service=user_ai_service
|
ai_service=user_ai_service,
|
||||||
|
custom_model=batch_request.model
|
||||||
)
|
)
|
||||||
|
|
||||||
return BatchGenerateResponse(
|
return BatchGenerateResponse(
|
||||||
@@ -2105,7 +2106,8 @@ async def cancel_batch_generation(
|
|||||||
async def execute_batch_generation_in_order(
|
async def execute_batch_generation_in_order(
|
||||||
batch_id: str,
|
batch_id: str,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
ai_service: AIService
|
ai_service: AIService,
|
||||||
|
custom_model: Optional[str] = None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
按顺序执行批量生成任务(后台任务)
|
按顺序执行批量生成任务(后台任务)
|
||||||
@@ -2194,7 +2196,7 @@ async def execute_batch_generation_in_order(
|
|||||||
if not can_generate:
|
if not can_generate:
|
||||||
raise Exception(f"前置条件不满足: {error_msg}")
|
raise Exception(f"前置条件不满足: {error_msg}")
|
||||||
|
|
||||||
# 生成章节内容(复用现有流式生成逻辑的核心部分)
|
# 生成章节内容(复用现有流式生成逻辑的核心部分),传递model参数
|
||||||
await generate_single_chapter_for_batch(
|
await generate_single_chapter_for_batch(
|
||||||
db_session=db_session,
|
db_session=db_session,
|
||||||
chapter=chapter,
|
chapter=chapter,
|
||||||
@@ -2202,7 +2204,8 @@ async def execute_batch_generation_in_order(
|
|||||||
style_id=task.style_id,
|
style_id=task.style_id,
|
||||||
target_word_count=task.target_word_count,
|
target_word_count=task.target_word_count,
|
||||||
ai_service=ai_service,
|
ai_service=ai_service,
|
||||||
write_lock=write_lock
|
write_lock=write_lock,
|
||||||
|
custom_model=custom_model
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"✅ 章节生成完成: 第{chapter.chapter_number}章")
|
logger.info(f"✅ 章节生成完成: 第{chapter.chapter_number}章")
|
||||||
@@ -2316,7 +2319,8 @@ async def generate_single_chapter_for_batch(
|
|||||||
style_id: Optional[int],
|
style_id: Optional[int],
|
||||||
target_word_count: int,
|
target_word_count: int,
|
||||||
ai_service: AIService,
|
ai_service: AIService,
|
||||||
write_lock: Lock
|
write_lock: Lock,
|
||||||
|
custom_model: Optional[str] = None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
为批量生成执行单个章节的生成(非流式)
|
为批量生成执行单个章节的生成(非流式)
|
||||||
@@ -2503,10 +2507,14 @@ async def generate_single_chapter_for_batch(
|
|||||||
|
|
||||||
# 非流式生成内容
|
# 非流式生成内容
|
||||||
full_content = ""
|
full_content = ""
|
||||||
async for chunk in ai_service.generate_text_stream(
|
# 准备生成参数
|
||||||
prompt=prompt,
|
generate_kwargs = {"prompt": prompt}
|
||||||
model=None # 批量生成时使用用户默认模型,后续可扩展
|
# 如果传入了自定义模型,使用指定的模型
|
||||||
):
|
if custom_model:
|
||||||
|
generate_kwargs["model"] = custom_model
|
||||||
|
logger.info(f" 批量生成使用自定义模型: {custom_model}")
|
||||||
|
|
||||||
|
async for chunk in ai_service.generate_text_stream(**generate_kwargs):
|
||||||
full_content += chunk
|
full_content += chunk
|
||||||
|
|
||||||
# 更新章节内容到数据库(使用锁保护)
|
# 更新章节内容到数据库(使用锁保护)
|
||||||
|
|||||||
@@ -1111,10 +1111,19 @@ async def new_outline_generator(
|
|||||||
|
|
||||||
# 调用AI
|
# 调用AI
|
||||||
yield await SSEResponse.send_progress("🤖 正在调用AI生成...", 30)
|
yield await SSEResponse.send_progress("🤖 正在调用AI生成...", 30)
|
||||||
|
|
||||||
|
# 添加调试日志
|
||||||
|
model_param = data.get("model")
|
||||||
|
provider_param = data.get("provider")
|
||||||
|
logger.info(f"=== 大纲生成AI调用参数 ===")
|
||||||
|
logger.info(f" provider参数: {provider_param}")
|
||||||
|
logger.info(f" model参数: {model_param}")
|
||||||
|
logger.info(f" 完整data: {data}")
|
||||||
|
|
||||||
ai_response = await user_ai_service.generate_text(
|
ai_response = await user_ai_service.generate_text(
|
||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
provider=data.get("provider"),
|
provider=provider_param,
|
||||||
model=data.get("model")
|
model=model_param
|
||||||
)
|
)
|
||||||
|
|
||||||
yield await SSEResponse.send_progress("✅ AI生成完成,正在解析...", 70)
|
yield await SSEResponse.send_progress("✅ AI生成完成,正在解析...", 70)
|
||||||
@@ -1446,10 +1455,16 @@ async def continue_outline_generator(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 调用AI生成当前批次
|
# 调用AI生成当前批次
|
||||||
|
model_param = data.get("model")
|
||||||
|
provider_param = data.get("provider")
|
||||||
|
logger.info(f"=== 续写批次{batch_num + 1} AI调用参数 ===")
|
||||||
|
logger.info(f" provider参数: {provider_param}")
|
||||||
|
logger.info(f" model参数: {model_param}")
|
||||||
|
|
||||||
ai_response = await user_ai_service.generate_text(
|
ai_response = await user_ai_service.generate_text(
|
||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
provider=data.get("provider"),
|
provider=provider_param,
|
||||||
model=data.get("model")
|
model=model_param
|
||||||
)
|
)
|
||||||
|
|
||||||
yield await SSEResponse.send_progress(
|
yield await SSEResponse.send_progress(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export default function Chapters() {
|
|||||||
const [targetWordCount, setTargetWordCount] = useState<number>(3000);
|
const [targetWordCount, setTargetWordCount] = useState<number>(3000);
|
||||||
const [availableModels, setAvailableModels] = useState<Array<{value: string, label: string}>>([]);
|
const [availableModels, setAvailableModels] = useState<Array<{value: string, label: string}>>([]);
|
||||||
const [selectedModel, setSelectedModel] = useState<string | undefined>();
|
const [selectedModel, setSelectedModel] = useState<string | undefined>();
|
||||||
|
const [batchSelectedModel, setBatchSelectedModel] = useState<string | undefined>(); // 批量生成的模型选择
|
||||||
const [analysisVisible, setAnalysisVisible] = useState(false);
|
const [analysisVisible, setAnalysisVisible] = useState(false);
|
||||||
const [analysisChapterId, setAnalysisChapterId] = useState<string | null>(null);
|
const [analysisChapterId, setAnalysisChapterId] = useState<string | null>(null);
|
||||||
// 分析任务状态管理
|
// 分析任务状态管理
|
||||||
@@ -48,6 +49,7 @@ export default function Chapters() {
|
|||||||
const [batchGenerateVisible, setBatchGenerateVisible] = useState(false);
|
const [batchGenerateVisible, setBatchGenerateVisible] = useState(false);
|
||||||
const [batchGenerating, setBatchGenerating] = useState(false);
|
const [batchGenerating, setBatchGenerating] = useState(false);
|
||||||
const [batchTaskId, setBatchTaskId] = useState<string | null>(null);
|
const [batchTaskId, setBatchTaskId] = useState<string | null>(null);
|
||||||
|
const [batchForm] = Form.useForm();
|
||||||
const [batchProgress, setBatchProgress] = useState<{
|
const [batchProgress, setBatchProgress] = useState<{
|
||||||
status: string;
|
status: string;
|
||||||
total: number;
|
total: number;
|
||||||
@@ -208,6 +210,7 @@ export default function Chapters() {
|
|||||||
setAvailableModels(data.models);
|
setAvailableModels(data.models);
|
||||||
// 设置默认模型为当前配置的模型
|
// 设置默认模型为当前配置的模型
|
||||||
setSelectedModel(settings.llm_model);
|
setSelectedModel(settings.llm_model);
|
||||||
|
return settings.llm_model; // 返回模型名称
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -218,6 +221,7 @@ export default function Chapters() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载可用模型失败:', error);
|
console.error('加载可用模型失败:', error);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查并恢复批量生成任务
|
// 检查并恢复批量生成任务
|
||||||
@@ -590,13 +594,23 @@ export default function Chapters() {
|
|||||||
enableAnalysis: boolean;
|
enableAnalysis: boolean;
|
||||||
styleId?: number;
|
styleId?: number;
|
||||||
targetWordCount?: number;
|
targetWordCount?: number;
|
||||||
|
model?: string;
|
||||||
}) => {
|
}) => {
|
||||||
if (!currentProject?.id) return;
|
if (!currentProject?.id) return;
|
||||||
|
|
||||||
|
// 调试日志
|
||||||
|
console.log('[批量生成] 表单values:', values);
|
||||||
|
console.log('[批量生成] batchSelectedModel状态:', batchSelectedModel);
|
||||||
|
|
||||||
// 使用批量生成对话框中选择的风格和字数,如果没有选择则使用默认值
|
// 使用批量生成对话框中选择的风格和字数,如果没有选择则使用默认值
|
||||||
const styleId = values.styleId || selectedStyleId;
|
const styleId = values.styleId || selectedStyleId;
|
||||||
const wordCount = values.targetWordCount || targetWordCount;
|
const wordCount = values.targetWordCount || targetWordCount;
|
||||||
|
|
||||||
|
// 使用批量生成专用的模型状态
|
||||||
|
const model = batchSelectedModel;
|
||||||
|
|
||||||
|
console.log('[批量生成] 最终使用的model:', model);
|
||||||
|
|
||||||
if (!styleId) {
|
if (!styleId) {
|
||||||
message.error('请选择写作风格');
|
message.error('请选择写作风格');
|
||||||
return;
|
return;
|
||||||
@@ -606,18 +620,30 @@ export default function Chapters() {
|
|||||||
setBatchGenerating(true);
|
setBatchGenerating(true);
|
||||||
setBatchGenerateVisible(false); // 关闭配置对话框,避免遮挡进度弹窗
|
setBatchGenerateVisible(false); // 关闭配置对话框,避免遮挡进度弹窗
|
||||||
|
|
||||||
|
const requestBody: any = {
|
||||||
|
start_chapter_number: values.startChapterNumber,
|
||||||
|
count: values.count,
|
||||||
|
enable_analysis: values.enableAnalysis,
|
||||||
|
style_id: styleId,
|
||||||
|
target_word_count: wordCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果有模型参数,添加到请求体中
|
||||||
|
if (model) {
|
||||||
|
requestBody.model = model;
|
||||||
|
console.log('[批量生成] 请求体包含model:', model);
|
||||||
|
} else {
|
||||||
|
console.log('[批量生成] 请求体不包含model,使用后端默认模型');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[批量生成] 完整请求体:', JSON.stringify(requestBody, null, 2));
|
||||||
|
|
||||||
const response = await fetch(`/api/chapters/project/${currentProject.id}/batch-generate`, {
|
const response = await fetch(`/api/chapters/project/${currentProject.id}/batch-generate`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(requestBody),
|
||||||
start_chapter_number: values.startChapterNumber,
|
|
||||||
count: values.count,
|
|
||||||
enable_analysis: values.enableAnalysis,
|
|
||||||
style_id: styleId,
|
|
||||||
target_word_count: wordCount,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -725,7 +751,7 @@ export default function Chapters() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 打开批量生成对话框
|
// 打开批量生成对话框
|
||||||
const handleOpenBatchGenerate = () => {
|
const handleOpenBatchGenerate = async () => {
|
||||||
// 找到第一个未生成的章节
|
// 找到第一个未生成的章节
|
||||||
const firstIncompleteChapter = sortedChapters.find(
|
const firstIncompleteChapter = sortedChapters.find(
|
||||||
ch => !ch.content || ch.content.trim() === ''
|
ch => !ch.content || ch.content.trim() === ''
|
||||||
@@ -743,6 +769,24 @@ export default function Chapters() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开对话框时加载模型列表,等待完成
|
||||||
|
const defaultModel = await loadAvailableModels();
|
||||||
|
|
||||||
|
console.log('[打开批量生成] defaultModel:', defaultModel);
|
||||||
|
console.log('[打开批量生成] selectedStyleId:', selectedStyleId);
|
||||||
|
|
||||||
|
// 设置批量生成的模型选择状态
|
||||||
|
setBatchSelectedModel(defaultModel || undefined);
|
||||||
|
|
||||||
|
// 重置表单并设置初始值
|
||||||
|
batchForm.setFieldsValue({
|
||||||
|
startChapterNumber: firstIncompleteChapter.chapter_number,
|
||||||
|
count: 5,
|
||||||
|
enableAnalysis: false,
|
||||||
|
styleId: selectedStyleId,
|
||||||
|
targetWordCount: 3000,
|
||||||
|
});
|
||||||
|
|
||||||
setBatchGenerateVisible(true);
|
setBatchGenerateVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1723,7 +1767,7 @@ export default function Chapters() {
|
|||||||
tooltip="选择用于生成章节内容的AI模型,不选择则使用默认模型"
|
tooltip="选择用于生成章节内容的AI模型,不选择则使用默认模型"
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="使用默认模型"
|
placeholder={selectedModel ? `默认: ${availableModels.find(m => m.value === selectedModel)?.label || selectedModel}` : "使用默认模型"}
|
||||||
value={selectedModel}
|
value={selectedModel}
|
||||||
onChange={setSelectedModel}
|
onChange={setSelectedModel}
|
||||||
size="large"
|
size="large"
|
||||||
@@ -1736,11 +1780,12 @@ export default function Chapters() {
|
|||||||
{availableModels.map(model => (
|
{availableModels.map(model => (
|
||||||
<Select.Option key={model.value} value={model.value} label={model.label}>
|
<Select.Option key={model.value} value={model.value} label={model.label}>
|
||||||
{model.label}
|
{model.label}
|
||||||
|
{model.value === selectedModel && ' (默认)'}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<div style={{ color: '#666', fontSize: 12, marginTop: 4 }}>
|
<div style={{ color: '#666', fontSize: 12, marginTop: 4 }}>
|
||||||
不同模型有不同的特点和定价,请根据需要选择
|
{selectedModel ? `当前默认模型: ${availableModels.find(m => m.value === selectedModel)?.label || selectedModel}` : '加载模型列表中...'}
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@@ -1889,6 +1934,7 @@ export default function Chapters() {
|
|||||||
>
|
>
|
||||||
{!batchGenerating ? (
|
{!batchGenerating ? (
|
||||||
<Form
|
<Form
|
||||||
|
form={batchForm}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
onFinish={handleBatchGenerate}
|
onFinish={handleBatchGenerate}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
@@ -1897,6 +1943,7 @@ export default function Chapters() {
|
|||||||
enableAnalysis: false,
|
enableAnalysis: false,
|
||||||
styleId: selectedStyleId,
|
styleId: selectedStyleId,
|
||||||
targetWordCount: 3000,
|
targetWordCount: 3000,
|
||||||
|
model: selectedModel,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Alert
|
<Alert
|
||||||
@@ -1989,6 +2036,31 @@ export default function Chapters() {
|
|||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="AI模型"
|
||||||
|
tooltip="批量生成时所有章节使用相同模型,不选择则使用默认模型"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder={batchSelectedModel ? `默认: ${availableModels.find(m => m.value === batchSelectedModel)?.label || batchSelectedModel}` : "使用默认模型"}
|
||||||
|
value={batchSelectedModel}
|
||||||
|
onChange={setBatchSelectedModel}
|
||||||
|
size="large"
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
>
|
||||||
|
{availableModels.map(model => (
|
||||||
|
<Select.Option key={model.value} value={model.value} label={model.label}>
|
||||||
|
{model.label}
|
||||||
|
{model.value === batchSelectedModel && ' (默认)'}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<div style={{ color: '#666', fontSize: 12, marginTop: 4 }}>
|
||||||
|
{batchSelectedModel ? `当前默认模型: ${availableModels.find(m => m.value === batchSelectedModel)?.label || batchSelectedModel}` : '加载模型列表中...'}
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="同步分析"
|
label="同步分析"
|
||||||
name="enableAnalysis"
|
name="enableAnalysis"
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ export default function Outline() {
|
|||||||
try {
|
try {
|
||||||
setIsGenerating(true);
|
setIsGenerating(true);
|
||||||
|
|
||||||
|
// 添加详细的调试日志
|
||||||
|
console.log('=== 大纲生成调试信息 ===');
|
||||||
|
console.log('1. Form values 原始数据:', values);
|
||||||
|
console.log('2. values.model:', values.model);
|
||||||
|
console.log('3. values.provider:', values.provider);
|
||||||
|
|
||||||
// 关闭生成表单Modal
|
// 关闭生成表单Modal
|
||||||
Modal.destroyAll();
|
Modal.destroyAll();
|
||||||
|
|
||||||
@@ -174,7 +180,7 @@ export default function Outline() {
|
|||||||
setSSEModalVisible(true);
|
setSSEModalVisible(true);
|
||||||
|
|
||||||
// 准备请求数据
|
// 准备请求数据
|
||||||
const requestData = {
|
const requestData: any = {
|
||||||
project_id: currentProject.id,
|
project_id: currentProject.id,
|
||||||
genre: currentProject.genre || '通用',
|
genre: currentProject.genre || '通用',
|
||||||
theme: values.theme || currentProject.theme || '',
|
theme: values.theme || currentProject.theme || '',
|
||||||
@@ -184,11 +190,26 @@ export default function Outline() {
|
|||||||
requirements: values.requirements,
|
requirements: values.requirements,
|
||||||
mode: values.mode || 'auto',
|
mode: values.mode || 'auto',
|
||||||
story_direction: values.story_direction,
|
story_direction: values.story_direction,
|
||||||
plot_stage: values.plot_stage || 'development',
|
plot_stage: values.plot_stage || 'development'
|
||||||
provider: values.provider,
|
|
||||||
model: values.model
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 只有在用户选择了模型时才添加model参数
|
||||||
|
if (values.model) {
|
||||||
|
requestData.model = values.model;
|
||||||
|
console.log('4. 添加model到请求:', values.model);
|
||||||
|
} else {
|
||||||
|
console.log('4. values.model为空,不添加到请求');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加provider参数(如果有)
|
||||||
|
if (values.provider) {
|
||||||
|
requestData.provider = values.provider;
|
||||||
|
console.log('5. 添加provider到请求:', values.provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('6. 最终请求数据:', JSON.stringify(requestData, null, 2));
|
||||||
|
console.log('=========================');
|
||||||
|
|
||||||
// 使用SSE客户端
|
// 使用SSE客户端
|
||||||
const apiUrl = `/api/outlines/generate-stream`;
|
const apiUrl = `/api/outlines/generate-stream`;
|
||||||
const client = new SSEPostClient(apiUrl, requestData, {
|
const client = new SSEPostClient(apiUrl, requestData, {
|
||||||
@@ -224,10 +245,35 @@ export default function Outline() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showGenerateModal = () => {
|
const showGenerateModal = async () => {
|
||||||
const hasOutlines = outlines.length > 0;
|
const hasOutlines = outlines.length > 0;
|
||||||
const initialMode = hasOutlines ? 'continue' : 'new';
|
const initialMode = hasOutlines ? 'continue' : 'new';
|
||||||
|
|
||||||
|
// 直接加载可用模型列表
|
||||||
|
const settingsResponse = await fetch('/api/settings');
|
||||||
|
const settings = await settingsResponse.json();
|
||||||
|
const { api_key, api_base_url, api_provider } = settings;
|
||||||
|
|
||||||
|
let loadedModels: Array<{value: string, label: string}> = [];
|
||||||
|
let defaultModel: string | undefined = undefined;
|
||||||
|
|
||||||
|
if (api_key && api_base_url) {
|
||||||
|
try {
|
||||||
|
const modelsResponse = await fetch(
|
||||||
|
`/api/settings/models?api_key=${encodeURIComponent(api_key)}&api_base_url=${encodeURIComponent(api_base_url)}&provider=${api_provider}`
|
||||||
|
);
|
||||||
|
if (modelsResponse.ok) {
|
||||||
|
const data = await modelsResponse.json();
|
||||||
|
if (data.models && data.models.length > 0) {
|
||||||
|
loadedModels = data.models;
|
||||||
|
defaultModel = settings.llm_model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('获取模型列表失败,将使用默认模型');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: hasOutlines ? (
|
title: hasOutlines ? (
|
||||||
<Space>
|
<Space>
|
||||||
@@ -249,6 +295,7 @@ export default function Outline() {
|
|||||||
plot_stage: 'development',
|
plot_stage: 'development',
|
||||||
keep_existing: true,
|
keep_existing: true,
|
||||||
theme: currentProject.theme || '',
|
theme: currentProject.theme || '',
|
||||||
|
model: defaultModel, // 添加默认模型
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{hasOutlines && (
|
{hasOutlines && (
|
||||||
@@ -360,6 +407,32 @@ export default function Outline() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* 自定义模型选择 - 移到外层,所有模式都显示 */}
|
||||||
|
{loadedModels.length > 0 && (
|
||||||
|
<Form.Item
|
||||||
|
label="AI模型"
|
||||||
|
name="model"
|
||||||
|
tooltip="选择用于生成的AI模型,不选则使用系统默认模型"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder={defaultModel ? `默认: ${loadedModels.find(m => m.value === defaultModel)?.label || defaultModel}` : "使用默认模型"}
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
options={loadedModels}
|
||||||
|
onChange={(value) => {
|
||||||
|
console.log('用户在下拉框中选择了模型:', value);
|
||||||
|
// 手动同步到Form
|
||||||
|
generateForm.setFieldsValue({ model: value });
|
||||||
|
console.log('已同步到Form,当前Form值:', generateForm.getFieldsValue());
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div style={{ color: '#666', fontSize: 12, marginTop: 4 }}>
|
||||||
|
{defaultModel ? `当前默认模型: ${loadedModels.find(m => m.value === defaultModel)?.label || defaultModel}` : '未配置默认模型'}
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
),
|
),
|
||||||
okText: hasOutlines ? '开始续写' : '开始生成',
|
okText: hasOutlines ? '开始续写' : '开始生成',
|
||||||
|
|||||||
Reference in New Issue
Block a user