前台页面/conversation修改积分计算逻辑

1、后台页面/credit-ratios,需要选择视频,上边是模型价格,下边增加传入视频价格,也要输入对应的倍率、基础积分、每秒积分
2、前台/conversation获取积分逻辑的接口也要增加对应的传入视频的比例
3、然后前台根据用户上传视频自动获取对应的比例加上对应模型选择的积分计算总积分
4、后台提交也要验证对应的积分是否正确
5、多个视频总时长需限制15s,最低视频时长2s
This commit is contained in:
2026-07-01 19:37:51 +08:00
parent 5e70064751
commit 5302d7f531
18 changed files with 657 additions and 1662 deletions
+55 -4
View File
@@ -63,6 +63,7 @@ interface MediaReference {
name: string;
type: 'image' | 'video';
url: string;
duration?: number;
}
interface Message {
@@ -280,6 +281,9 @@ const AIChatPage: React.FC = () => {
perSecondCredits: 2,
baseCredits: 60,
ratio: 1,
inputVideoRatio: 1,
inputVideoBaseCredits: 0,
inputVideoPerSecondCredits: 0.5,
};
if (videoResolution === '1080p') {
config.ratio = 2;
@@ -304,13 +308,21 @@ const AIChatPage: React.FC = () => {
}
}
// 根据配置计算积分
if (mediaType === 'video') {
// 视频:(秒数 × perSecondCredits + baseCredits) × ratio
return Math.round((videoDuration * config.perSecondCredits + config.baseCredits) * config.ratio);
let total = Math.round((videoDuration * config.perSecondCredits + config.baseCredits) * config.ratio);
// 传入视频积分
const inputVideoDuration = currentMedia
.filter((m) => m.type === 'video')
.reduce((sum, m) => sum + (m.duration || 0), 0);
if (inputVideoDuration > 0) {
const inputVideoCost = Math.round(
((config.inputVideoBaseCredits || 0) + (config.inputVideoPerSecondCredits || 0) * inputVideoDuration) * (config.inputVideoRatio || 1)
);
total += inputVideoCost;
}
return total;
} else {
// 图片:baseCredits × ratio
return config.baseCredits * config.ratio;
@@ -836,6 +848,22 @@ const AIChatPage: React.FC = () => {
}
};
const getVideoDuration = (file: File): Promise<number> => {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.preload = 'metadata';
video.onloadedmetadata = () => {
window.URL.revokeObjectURL(video.src);
resolve(video.duration);
};
video.onerror = () => {
window.URL.revokeObjectURL(video.src);
reject(new Error('无法获取视频时长'));
};
video.src = URL.createObjectURL(file);
});
};
const handleUpload = async (file: File) => {
// 验证文件类型
const isImage = file.type.startsWith('image/');
@@ -879,6 +907,28 @@ const AIChatPage: React.FC = () => {
return false;
}
// 获取视频时长并验证
let videoDuration = 0;
if (isVideo) {
try {
videoDuration = await getVideoDuration(file);
if (videoDuration < 2) {
message.error('视频素材最短不能少于 2 秒');
return false;
}
const existingVideoDuration = currentMedia
.filter((m) => m.type === 'video')
.reduce((sum, m) => sum + (m.duration || 0), 0);
if (existingVideoDuration + videoDuration > 15) {
message.error(`所有视频素材总时长不能超过 15 秒,当前 ${(existingVideoDuration + videoDuration).toFixed(1)}`);
return false;
}
} catch {
message.error('无法获取视频时长');
return false;
}
}
// 设置上传状态
setUploading(true);
@@ -893,6 +943,7 @@ const AIChatPage: React.FC = () => {
type: mediaType,
url: res.url,
label: '',
...(isVideo && { duration: videoDuration }),
}];
const labels = generateMediaLabels(newList);
setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));