Show billing estimate and clarify session replacement
This commit is contained in:
@@ -79,7 +79,7 @@ import {
|
||||
import { isViduModel } from "../../utils/viduRouting";
|
||||
import { isPixverseModel } from "../../utils/pixverseRouting";
|
||||
import { resolveVideoRequestModel } from "../../utils/resolveVideoModel";
|
||||
import { ENTERPRISE_DEFAULT_VIDEO_MODEL } from "../../utils/enterpriseVideoPolicy";
|
||||
import { calculateEnterpriseVideoCredits, ENTERPRISE_DEFAULT_VIDEO_MODEL } from "../../utils/enterpriseVideoPolicy";
|
||||
import {
|
||||
getImageQualityOptions,
|
||||
getDefaultImageQuality,
|
||||
@@ -220,6 +220,12 @@ const MODE_ICONS: Record<WorkbenchMode, ReactNode> = {
|
||||
video: <VideoCameraOutlined />,
|
||||
};
|
||||
|
||||
function formatCreditValue(value: number): string {
|
||||
if (!Number.isFinite(value)) return "-";
|
||||
if (value >= 100) return Math.round(value).toLocaleString("zh-CN");
|
||||
return Number(value.toFixed(2)).toString();
|
||||
}
|
||||
|
||||
function WorkbenchPage({
|
||||
isAuthenticated,
|
||||
session,
|
||||
@@ -464,6 +470,48 @@ function WorkbenchPage({
|
||||
const videoQualityLabel = getVideoQualityLabel(videoModel, videoQuality);
|
||||
|
||||
const imageSettingsSummary = `${imageRatio} / ${imageQuality}`;
|
||||
const billingEstimate = useMemo(() => {
|
||||
if (activeMode === "image") {
|
||||
return {
|
||||
label: "预计 20 积分",
|
||||
title: `图片生成按任务计费:${activeModel},${imageSettingsSummary},预计 20 积分`,
|
||||
};
|
||||
}
|
||||
if (activeMode === "video") {
|
||||
try {
|
||||
const durationSeconds = Math.max(1, Math.ceil(Number(videoDuration) || 1));
|
||||
const credits = calculateEnterpriseVideoCredits({
|
||||
model: activeModelValue,
|
||||
resolution: videoQuality,
|
||||
durationSeconds,
|
||||
muted: false,
|
||||
hasReferenceVideo: referenceItems.some((item) => item.kind === "video"),
|
||||
});
|
||||
return {
|
||||
label: `预计 ${formatCreditValue(credits)} 积分`,
|
||||
title: `${activeModel},${videoQualityLabel},${durationSeconds} 秒,预计 ${formatCreditValue(credits)} 积分`,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
label: "计费以提交后为准",
|
||||
title: "当前模型的预估计费暂不可用,实际扣费以服务端结算为准",
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: "按 Token 结算",
|
||||
title: "文本对话按输入、输出 Token 实际用量结算,完成后显示本次积分",
|
||||
};
|
||||
}, [
|
||||
activeMode,
|
||||
activeModel,
|
||||
activeModelValue,
|
||||
imageSettingsSummary,
|
||||
referenceItems,
|
||||
videoDuration,
|
||||
videoQuality,
|
||||
videoQualityLabel,
|
||||
]);
|
||||
const composerPlaceholder =
|
||||
referenceItems.length > 0 ? `${toolTheme.placeholder},可输入 @ 引用参考内容` : toolTheme.placeholder;
|
||||
const dropdownDirection = hasActivatedWorkspace ? "up" : "down";
|
||||
@@ -2545,7 +2593,15 @@ function WorkbenchPage({
|
||||
}
|
||||
};
|
||||
|
||||
const sendDisabled = !inputValue.trim() || (activeMode !== "chat" && getActiveGenerationTaskCount(getGenerationUserKey(session?.user.id)) >= 3);
|
||||
const activeGenerationCount = getActiveGenerationTaskCount(getGenerationUserKey(session?.user.id));
|
||||
const generationLimitReached = activeMode !== "chat" && activeGenerationCount >= 3;
|
||||
const promptIsEmpty = !inputValue.trim();
|
||||
const sendDisabled = promptIsEmpty || generationLimitReached;
|
||||
const sendButtonTitle = promptIsEmpty
|
||||
? "输入内容后可发送"
|
||||
: generationLimitReached
|
||||
? `当前已有 ${activeGenerationCount} 个任务进行中,请等待任一任务完成`
|
||||
: billingEstimate.title;
|
||||
|
||||
const suggestedPrompts = [
|
||||
{ text: "画一个赛博朋克风格的城市夜景", mode: "image" as WorkbenchMode },
|
||||
@@ -2882,10 +2938,15 @@ function WorkbenchPage({
|
||||
)}
|
||||
</div>
|
||||
<div className="wb-composer__toolbar-right">
|
||||
<span className="wb-composer__billing-estimate" title={billingEstimate.title}>
|
||||
{billingEstimate.label}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className={`wb-composer__send-primary${isGenerating ? " is-loading" : ""}`}
|
||||
disabled={sendDisabled || isGenerating}
|
||||
title={isGenerating ? "任务处理中" : sendButtonTitle}
|
||||
aria-label={isGenerating ? "任务处理中" : sendButtonTitle}
|
||||
onClick={() => {
|
||||
if (getCachedRole() === "admin") console.log("[ai/workbench-send-click]", {
|
||||
mode: activeMode,
|
||||
|
||||
Reference in New Issue
Block a user