fix: sync canvas angle availability
This commit is contained in:
parent
1f8e19598c
commit
2f52589469
@ -159,6 +159,7 @@ type RealtimeCanvasModeIconConfig = {
|
||||
|
||||
const DEFAULT_REALTIME_CANVAS_MODE_LABEL = "实时画布模式";
|
||||
const DEFAULT_ENHANCE_CANVAS_MODE_LABEL = "图像增强模式";
|
||||
const ANGLE_EDIT_CONFIG_KEY = "angle_edit_config";
|
||||
|
||||
const defaultRealtimeCanvasModeIconConfig: RealtimeCanvasModeIconConfig = {
|
||||
realtimeIconUrl: "",
|
||||
@ -182,6 +183,9 @@ async function readCanvasFeatureAvailability(valueByKey: Map<string, unknown>) {
|
||||
]);
|
||||
|
||||
return {
|
||||
angleEditEnabled: normalizeAngleEditEnabled(
|
||||
valueByKey.get(ANGLE_EDIT_CONFIG_KEY),
|
||||
),
|
||||
enhanceProEnabled: normalizeEnhanceProKreaConfig(
|
||||
valueByKey.get(ENHANCE_PRO_KREA_SETTING_KEY),
|
||||
).enabled,
|
||||
@ -441,6 +445,13 @@ function normalizeLayerSplitEnabled(value: unknown): boolean {
|
||||
return (value as { enabled?: unknown }).enabled === true;
|
||||
}
|
||||
|
||||
function normalizeAngleEditEnabled(value: unknown): boolean {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return false;
|
||||
}
|
||||
return (value as { enabled?: unknown }).enabled === true;
|
||||
}
|
||||
|
||||
function normalizeAgentCategoryTreeConfig(value: unknown): AgentCategoryTreeConfig {
|
||||
const raw =
|
||||
value && typeof value === "object" && !Array.isArray(value)
|
||||
@ -596,6 +607,7 @@ async function getScopedPublicSiteSettings(scope: PublicSiteSettingsScope) {
|
||||
REALTIME_CANVAS_MODE_ICON_CONFIG_KEY,
|
||||
CANVAS_TOOLBAR_CONFIG_SETTING_KEY,
|
||||
LAYER_SPLIT_CONFIG_KEY,
|
||||
ANGLE_EDIT_CONFIG_KEY,
|
||||
CANVAS_AGENT_MODE_ENABLED_KEY,
|
||||
VIDEO_CANVAS_ENABLED_KEY,
|
||||
VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
|
||||
@ -644,6 +656,7 @@ async function getScopedPublicSiteSettings(scope: PublicSiteSettingsScope) {
|
||||
layerSplitEnabled: normalizeLayerSplitEnabled(
|
||||
valueByKey.get(LAYER_SPLIT_CONFIG_KEY)
|
||||
),
|
||||
angleEditEnabled: canvasFeatureAvailability.angleEditEnabled,
|
||||
enhanceProEnabled: canvasFeatureAvailability.enhanceProEnabled,
|
||||
tripo3dEnabled: canvasFeatureAvailability.tripo3dEnabled,
|
||||
worldlabs3dEnabled: canvasFeatureAvailability.worldlabs3dEnabled,
|
||||
@ -691,6 +704,7 @@ async function getScopedPublicSiteSettings(scope: PublicSiteSettingsScope) {
|
||||
REALTIME_CANVAS_MODE_ICON_CONFIG_KEY,
|
||||
CANVAS_TOOLBAR_CONFIG_SETTING_KEY,
|
||||
LAYER_SPLIT_CONFIG_KEY,
|
||||
ANGLE_EDIT_CONFIG_KEY,
|
||||
CANVAS_AGENT_MODE_ENABLED_KEY,
|
||||
VIDEO_CANVAS_ENABLED_KEY,
|
||||
VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
|
||||
@ -727,6 +741,7 @@ async function getScopedPublicSiteSettings(scope: PublicSiteSettingsScope) {
|
||||
layerSplitEnabled: normalizeLayerSplitEnabled(
|
||||
valueByKey.get(LAYER_SPLIT_CONFIG_KEY)
|
||||
),
|
||||
angleEditEnabled: canvasFeatureAvailability.angleEditEnabled,
|
||||
enhanceProEnabled: canvasFeatureAvailability.enhanceProEnabled,
|
||||
tripo3dEnabled: canvasFeatureAvailability.tripo3dEnabled,
|
||||
worldlabs3dEnabled: canvasFeatureAvailability.worldlabs3dEnabled,
|
||||
|
||||
@ -1784,6 +1784,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
||||
canvasAgentModeEnabled?: boolean;
|
||||
videoCanvasSidebarEnabled?: boolean;
|
||||
layerSplitEnabled?: boolean;
|
||||
angleEditEnabled?: boolean;
|
||||
realtimeCanvasEnabled?: boolean;
|
||||
realtimeCanvasServiceEnabled?: boolean;
|
||||
enhanceProEnabled?: boolean;
|
||||
@ -1831,6 +1832,8 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
||||
}, [canvasSiteSettingsKey]);
|
||||
const isLayerSplitEnabled =
|
||||
hasResolvedCanvasSiteSettings && siteSettingsData?.layerSplitEnabled === true;
|
||||
const isAngleEditEnabled =
|
||||
hasResolvedCanvasSiteSettings && siteSettingsData?.angleEditEnabled === true;
|
||||
const isTripo3dEnabled =
|
||||
hasResolvedCanvasSiteSettings && siteSettingsData?.tripo3dEnabled === true;
|
||||
const isWorldlabs3dEnabled =
|
||||
@ -8976,6 +8979,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
|
||||
workspaceLabel={workspaceLabel}
|
||||
workspaceVariant={isVideoMode ? "video" : "canvas"}
|
||||
layerSplitEnabled={isLayerSplitEnabled}
|
||||
angleEditEnabled={isAngleEditEnabled}
|
||||
tripo3dEnabled={isTripo3dEnabled}
|
||||
worldlabs3dEnabled={isWorldlabs3dEnabled}
|
||||
/>
|
||||
|
||||
@ -191,6 +191,7 @@ interface CanvasWorkspaceProps {
|
||||
workspaceVariant?: "canvas" | "video";
|
||||
canvasToolbarConfig?: CanvasToolbarConfig;
|
||||
layerSplitEnabled?: boolean;
|
||||
angleEditEnabled?: boolean;
|
||||
tripo3dEnabled?: boolean;
|
||||
worldlabs3dEnabled?: boolean;
|
||||
batchProcessingEnabled?: boolean;
|
||||
@ -209,6 +210,7 @@ export function CanvasWorkspace({
|
||||
workspaceVariant = "canvas",
|
||||
canvasToolbarConfig: rawCanvasToolbarConfig,
|
||||
layerSplitEnabled = false,
|
||||
angleEditEnabled = false,
|
||||
tripo3dEnabled = false,
|
||||
worldlabs3dEnabled = false,
|
||||
batchProcessingEnabled = true,
|
||||
@ -1517,6 +1519,7 @@ export function CanvasWorkspace({
|
||||
<ImageNode
|
||||
batchProcessingEnabled={batchProcessingEnabled}
|
||||
canvasToolbarConfig={canvasToolbarConfig}
|
||||
angleEditEnabled={angleEditEnabled}
|
||||
isLayerSplitEnabled={layerSplitEnabled}
|
||||
isSelected={isSelected}
|
||||
node={node}
|
||||
|
||||
@ -1304,6 +1304,7 @@ interface ImageNodeProps {
|
||||
isLayerSplitEnabled?: boolean;
|
||||
batchProcessingEnabled?: boolean;
|
||||
canvasToolbarConfig?: CanvasToolbarConfig;
|
||||
angleEditEnabled?: boolean;
|
||||
tripo3dEnabled?: boolean;
|
||||
worldlabs3dEnabled?: boolean;
|
||||
}
|
||||
@ -1314,6 +1315,7 @@ export function ImageNode({
|
||||
isLayerSplitEnabled = false,
|
||||
batchProcessingEnabled = true,
|
||||
canvasToolbarConfig,
|
||||
angleEditEnabled = false,
|
||||
tripo3dEnabled = false,
|
||||
worldlabs3dEnabled = false,
|
||||
}: ImageNodeProps) {
|
||||
@ -1395,7 +1397,7 @@ export function ImageNode({
|
||||
const imageMultiAngleEnabled = isCanvasToolbarItemEnabled(
|
||||
canvasToolbarConfig,
|
||||
"imageMultiAngle"
|
||||
);
|
||||
) && angleEditEnabled;
|
||||
const imagePromptRegenerateEnabled = isCanvasToolbarItemEnabled(
|
||||
canvasToolbarConfig,
|
||||
"imagePromptRegenerate"
|
||||
@ -4489,6 +4491,12 @@ export function ImageNode({
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!angleEditEnabled && anglePanelOpen) {
|
||||
setAnglePanelOpen(false);
|
||||
}
|
||||
}, [angleEditEnabled, anglePanelOpen]);
|
||||
|
||||
async function handleConfirmThreedGeneration() {
|
||||
if (threedGenerationDialogMode === "model") {
|
||||
const targetModelVersion = selectedTripoModelEntry?.id || "";
|
||||
@ -4544,6 +4552,10 @@ export function ImageNode({
|
||||
return;
|
||||
}
|
||||
if (action === "angle") {
|
||||
if (!angleEditEnabled) {
|
||||
toast.info("多视角功能未开启");
|
||||
return;
|
||||
}
|
||||
setCropPanelOpen(false);
|
||||
setCropInteraction(null);
|
||||
setImageAdjustPanelOpen(false);
|
||||
|
||||
@ -26,6 +26,8 @@ interface UploadedImage {
|
||||
const DEFAULT_IMAGE_SIZE = "2K";
|
||||
const DEFAULT_TIMEOUT_MS = 300000;
|
||||
const OPENAI_IMAGE_MIN_TOTAL_PIXELS = 3_686_400;
|
||||
const BLTCY_HOST_REGEX = /(^|\.)bltcy\.ai$/i;
|
||||
const KONTEXT_MODEL_REGEX = /kontext/i;
|
||||
const SUPPORTED_ASPECT_RATIOS = [
|
||||
"1:1",
|
||||
"1:4",
|
||||
@ -55,6 +57,19 @@ function joinEndpoint(baseURL: string, path: string) {
|
||||
return `${normalizeBaseURL(baseURL)}${normalizedPath}`;
|
||||
}
|
||||
|
||||
function isBltcyBaseURL(baseURL: string) {
|
||||
try {
|
||||
const parsed = new URL(normalizeBaseURL(baseURL));
|
||||
return BLTCY_HOST_REGEX.test(parsed.hostname);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldUseBltcyFluxCompatParams(baseURL: string, model: string) {
|
||||
return isBltcyBaseURL(baseURL) && KONTEXT_MODEL_REGEX.test(String(model || "").trim());
|
||||
}
|
||||
|
||||
function normalizeImageSizeLabel(imageSize?: string): "1K" | "2K" | "4K" {
|
||||
const normalized = String(imageSize || "").trim().toUpperCase();
|
||||
if (normalized === "1K" || normalized === "2K" || normalized === "4K") return normalized;
|
||||
@ -375,12 +390,31 @@ async function requestOpenAIImageGeneration(params: {
|
||||
model: string;
|
||||
prompt: string;
|
||||
size?: string;
|
||||
aspectRatio?: string;
|
||||
imageSizeLabel?: "1K" | "2K" | "4K";
|
||||
imageUrls: string[];
|
||||
quality?: string;
|
||||
background?: string;
|
||||
outputFormat?: string;
|
||||
}) {
|
||||
const { baseURL, apiKey, model, prompt, size, imageUrls, quality, background, outputFormat } = params;
|
||||
const {
|
||||
baseURL,
|
||||
apiKey,
|
||||
model,
|
||||
prompt,
|
||||
size,
|
||||
aspectRatio,
|
||||
imageSizeLabel,
|
||||
imageUrls,
|
||||
quality,
|
||||
background,
|
||||
outputFormat,
|
||||
} = params;
|
||||
const useBltcyFluxCompatParams = shouldUseBltcyFluxCompatParams(baseURL, model);
|
||||
const explicitAspectRatio =
|
||||
typeof aspectRatio === "string" && aspectRatio.trim() && aspectRatio !== "auto"
|
||||
? aspectRatio.trim()
|
||||
: undefined;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
||||
@ -392,6 +426,10 @@ async function requestOpenAIImageGeneration(params: {
|
||||
formData.append("model", model);
|
||||
formData.append("prompt", prompt);
|
||||
if (size) formData.append("size", size);
|
||||
if (useBltcyFluxCompatParams) {
|
||||
if (explicitAspectRatio) formData.append("aspect_ratio", explicitAspectRatio);
|
||||
if (imageSizeLabel) formData.append("image_size", imageSizeLabel);
|
||||
}
|
||||
formData.append("response_format", "url");
|
||||
|
||||
if (quality) formData.append("quality", quality);
|
||||
@ -434,6 +472,10 @@ async function requestOpenAIImageGeneration(params: {
|
||||
model,
|
||||
prompt,
|
||||
...(size ? { size } : {}),
|
||||
...(useBltcyFluxCompatParams && explicitAspectRatio
|
||||
? { aspect_ratio: explicitAspectRatio }
|
||||
: {}),
|
||||
...(useBltcyFluxCompatParams && imageSizeLabel ? { image_size: imageSizeLabel } : {}),
|
||||
response_format: "url",
|
||||
...(quality ? { quality } : {}),
|
||||
...(background ? { background } : {}),
|
||||
@ -504,6 +546,8 @@ export function createOpenAIImage({ apiKey, baseURL }: OpenAIImageConfig) {
|
||||
model: activeModelId,
|
||||
size,
|
||||
aspectRatio: aspectRatio || "auto",
|
||||
imageSize,
|
||||
useBltcyFluxCompatParams: shouldUseBltcyFluxCompatParams(baseURL, activeModelId),
|
||||
imageCount: imageUrls.length,
|
||||
baseURL: normalizeBaseURL(baseURL),
|
||||
});
|
||||
@ -514,6 +558,8 @@ export function createOpenAIImage({ apiKey, baseURL }: OpenAIImageConfig) {
|
||||
model: activeModelId,
|
||||
prompt,
|
||||
size,
|
||||
aspectRatio: aspectRatio || undefined,
|
||||
imageSizeLabel: imageSize,
|
||||
imageUrls,
|
||||
quality,
|
||||
background,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user