292 lines
9.2 KiB
JavaScript
292 lines
9.2 KiB
JavaScript
|
|
'use client';
|
|||
|
|
|
|||
|
|
import { useState } from 'react';
|
|||
|
|
import { useTranslation } from 'react-i18next';
|
|||
|
|
import { toast } from 'sonner';
|
|||
|
|
import axios from 'axios';
|
|||
|
|
import i18n from '@/lib/i18n';
|
|||
|
|
import request from '@/lib/util/request';
|
|||
|
|
import { processInParallel } from '@/lib/util/processInParallel';
|
|||
|
|
|
|||
|
|
export function useQuestionGeneration(projectId, model, taskSettings, getQuestionList) {
|
|||
|
|
const { t } = useTranslation();
|
|||
|
|
|
|||
|
|
// 处理状态
|
|||
|
|
const [processing, setProcessing] = useState(false);
|
|||
|
|
|
|||
|
|
// 进度状态
|
|||
|
|
const [progress, setProgress] = useState({
|
|||
|
|
total: 0, // 总共选择的问题数量
|
|||
|
|
completed: 0, // 已处理完成的数量
|
|||
|
|
percentage: 0, // 进度百分比
|
|||
|
|
datasetCount: 0 // 已生成的数据集数量
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 批量生成答案
|
|||
|
|
const handleBatchGenerateAnswers = async selectedQuestions => {
|
|||
|
|
if (selectedQuestions.length === 0) {
|
|||
|
|
toast.warning(t('questions.noQuestionsSelected'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!model) {
|
|||
|
|
toast.warning(t('models.configNotFound'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
setProgress({
|
|||
|
|
total: selectedQuestions.length,
|
|||
|
|
completed: 0,
|
|||
|
|
percentage: 0,
|
|||
|
|
datasetCount: 0
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 然后设置处理状态为真,确保进度条显示
|
|||
|
|
setProcessing(true);
|
|||
|
|
|
|||
|
|
toast.info(t('questions.batchGenerateStart', { count: selectedQuestions.length }));
|
|||
|
|
|
|||
|
|
// 单个问题处理函数
|
|||
|
|
const processQuestion = async questionId => {
|
|||
|
|
try {
|
|||
|
|
console.log('开始生成数据集:', { questionId });
|
|||
|
|
const language = i18n.language === 'zh-CN' ? '中文' : 'en';
|
|||
|
|
// 调用API生成数据集
|
|||
|
|
const response = await request(`/api/projects/${projectId}/datasets`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify({
|
|||
|
|
questionId,
|
|||
|
|
model,
|
|||
|
|
language
|
|||
|
|
})
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
const errorData = await response.json();
|
|||
|
|
console.error(t('datasets.generateError'), errorData.error || t('datasets.generateFailed'));
|
|||
|
|
|
|||
|
|
// 更新进度状态(即使失败也计入已处理)
|
|||
|
|
setProgress(prev => {
|
|||
|
|
const completed = prev.completed + 1;
|
|||
|
|
const percentage = Math.round((completed / prev.total) * 100);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
...prev,
|
|||
|
|
completed,
|
|||
|
|
percentage
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return { success: false, questionId, error: errorData.error || t('datasets.generateFailed') };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const data = await response.json();
|
|||
|
|
|
|||
|
|
// 更新进度状态
|
|||
|
|
setProgress(prev => {
|
|||
|
|
const completed = prev.completed + 1;
|
|||
|
|
const percentage = Math.round((completed / prev.total) * 100);
|
|||
|
|
const datasetCount = prev.datasetCount + 1;
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
...prev,
|
|||
|
|
completed,
|
|||
|
|
percentage,
|
|||
|
|
datasetCount
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log(`数据集生成成功: ${questionId}`);
|
|||
|
|
return { success: true, questionId, data: data.dataset };
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('生成数据集失败:', error);
|
|||
|
|
|
|||
|
|
// 更新进度状态(即使失败也计入已处理)
|
|||
|
|
setProgress(prev => {
|
|||
|
|
const completed = prev.completed + 1;
|
|||
|
|
const percentage = Math.round((completed / prev.total) * 100);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
...prev,
|
|||
|
|
completed,
|
|||
|
|
percentage
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return { success: false, questionId, error: error.message };
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 并行处理所有问题,最多同时处理2个
|
|||
|
|
const results = await processInParallel(selectedQuestions, processQuestion, taskSettings.concurrencyLimit);
|
|||
|
|
|
|||
|
|
// 刷新数据
|
|||
|
|
getQuestionList();
|
|||
|
|
|
|||
|
|
// 处理完成后设置结果消息
|
|||
|
|
const successCount = results.filter(r => r.success).length;
|
|||
|
|
const failCount = results.filter(r => !r.success).length;
|
|||
|
|
|
|||
|
|
if (failCount > 0) {
|
|||
|
|
toast.warning(
|
|||
|
|
t('datasets.partialSuccess', {
|
|||
|
|
successCount,
|
|||
|
|
total: selectedQuestions.length,
|
|||
|
|
failCount
|
|||
|
|
})
|
|||
|
|
);
|
|||
|
|
} else {
|
|||
|
|
toast.success(t('common.success', { successCount }));
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('生成数据集出错:', error);
|
|||
|
|
toast.error(error.message || '生成数据集失败');
|
|||
|
|
} finally {
|
|||
|
|
// 延迟关闭处理状态,确保用户可以看到完成的进度
|
|||
|
|
setTimeout(() => {
|
|||
|
|
setProcessing(false);
|
|||
|
|
// 再次延迟重置进度状态
|
|||
|
|
setTimeout(() => {
|
|||
|
|
setProgress({
|
|||
|
|
total: 0,
|
|||
|
|
completed: 0,
|
|||
|
|
percentage: 0,
|
|||
|
|
datasetCount: 0
|
|||
|
|
});
|
|||
|
|
}, 500);
|
|||
|
|
}, 2000); // 延迟关闭处理状态,让用户看到完成的进度
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 自动生成数据集
|
|||
|
|
const handleAutoGenerateDatasets = async () => {
|
|||
|
|
try {
|
|||
|
|
if (!model) {
|
|||
|
|
toast.error(t('questions.selectModelFirst', { defaultValue: '请先选择模型' }));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用创建任务接口
|
|||
|
|
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
|||
|
|
taskType: 'answer-generation',
|
|||
|
|
modelInfo: model,
|
|||
|
|
language: i18n.language
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (response.data?.code === 0) {
|
|||
|
|
toast.success(t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理未生成答案的问题' }));
|
|||
|
|
} else {
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建后台任务失败' }));
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('创建任务失败:', error);
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 自动生成图像问答数据集
|
|||
|
|
const handleAutoGenerateImageDatasets = async () => {
|
|||
|
|
try {
|
|||
|
|
if (!model) {
|
|||
|
|
toast.error(t('questions.selectModelFirst', { defaultValue: '请先选择模型' }));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (model.type !== 'vision') {
|
|||
|
|
toast.error(t('images.visionModelRequired', { defaultValue: '请选择支持视觉的模型' }));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用创建任务接口
|
|||
|
|
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
|||
|
|
taskType: 'image-dataset-generation',
|
|||
|
|
modelInfo: model,
|
|||
|
|
language: i18n.language
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (response.data?.code === 0) {
|
|||
|
|
toast.success(t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理未生成答案的图片问题' }));
|
|||
|
|
} else {
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建后台任务失败' }));
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('创建图片数据集任务失败:', error);
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 自动生成多轮对话数据集
|
|||
|
|
const handleAutoGenerateMultiTurnDatasets = async () => {
|
|||
|
|
try {
|
|||
|
|
if (!model) {
|
|||
|
|
toast.error(t('questions.selectModelFirst', { defaultValue: '请先选择模型' }));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 首先检查项目是否配置了多轮对话设置
|
|||
|
|
const configResponse = await axios.get(`/api/projects/${projectId}/tasks`);
|
|||
|
|
if (configResponse.status !== 200) {
|
|||
|
|
throw new Error('获取项目配置失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const config = configResponse.data;
|
|||
|
|
const multiTurnConfig = {
|
|||
|
|
systemPrompt: config.multiTurnSystemPrompt,
|
|||
|
|
scenario: config.multiTurnScenario,
|
|||
|
|
rounds: config.multiTurnRounds,
|
|||
|
|
roleA: config.multiTurnRoleA,
|
|||
|
|
roleB: config.multiTurnRoleB
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 检查是否已配置必要的多轮对话设置
|
|||
|
|
if (
|
|||
|
|
!multiTurnConfig.scenario ||
|
|||
|
|
!multiTurnConfig.roleA ||
|
|||
|
|
!multiTurnConfig.roleB ||
|
|||
|
|
!multiTurnConfig.rounds ||
|
|||
|
|
multiTurnConfig.rounds < 1
|
|||
|
|
) {
|
|||
|
|
toast.error(t('questions.multiTurnNotConfigured', '请先在项目设置中配置多轮对话相关参数'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用创建任务接口
|
|||
|
|
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
|||
|
|
taskType: 'multi-turn-generation',
|
|||
|
|
modelInfo: model,
|
|||
|
|
language: i18n.language,
|
|||
|
|
config: JSON.stringify(multiTurnConfig)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (response.data?.code === 0) {
|
|||
|
|
toast.success(
|
|||
|
|
t('tasks.multiTurnCreateSuccess', {
|
|||
|
|
defaultValue: '多轮对话生成任务已创建,系统将自动处理未生成多轮对话的问题'
|
|||
|
|
})
|
|||
|
|
);
|
|||
|
|
} else {
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建后台任务失败' }));
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('创建多轮对话任务失败:', error);
|
|||
|
|
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
// 状态
|
|||
|
|
processing,
|
|||
|
|
progress,
|
|||
|
|
|
|||
|
|
// 方法
|
|||
|
|
handleBatchGenerateAnswers,
|
|||
|
|
handleAutoGenerateDatasets,
|
|||
|
|
handleAutoGenerateMultiTurnDatasets,
|
|||
|
|
handleAutoGenerateImageDatasets
|
|||
|
|
};
|
|||
|
|
}
|