revert: restore original image generation config
This commit is contained in:
@@ -101,11 +101,10 @@ function isVideoMode(mode: CreationMode) {
|
||||
}
|
||||
|
||||
const DEFAULT_IMAGE_SIZE_OPTIONS: RuntimeSizeOption[] = [
|
||||
{ id: "1024x1536", label: "竖图 2:3 · 1024×1536", value: "1024x1536" },
|
||||
{ id: "1088x1920", label: "竖屏 9:16 · 1088×1920", value: "1088x1920" },
|
||||
{ id: "1024x1024", label: "方图 1:1 · 1024×1024", value: "1024x1024" },
|
||||
{ id: "1536x1024", label: "横图 3:2 · 1536×1024", value: "1536x1024" },
|
||||
{ id: "auto", label: "自动 · 生成后显示实际像素", value: "auto" },
|
||||
{ id: "1024x1536", label: "竖图 2:3", value: "1024x1536" },
|
||||
{ id: "1024x1024", label: "方图 1:1", value: "1024x1024" },
|
||||
{ id: "1536x1024", label: "横图 3:2", value: "1536x1024" },
|
||||
{ id: "auto", label: "自动", value: "auto" },
|
||||
]
|
||||
|
||||
const DEFAULT_VIDEO_SIZE_OPTIONS: RuntimeSizeOption[] = [
|
||||
|
||||
@@ -61,35 +61,18 @@
|
||||
</div>
|
||||
|
||||
<!-- Size selector | 尺寸选择 -->
|
||||
<div v-if="hasSizeOptions" class="space-y-1.5">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span class="text-xs text-[var(--text-secondary)] flex-shrink-0">尺寸</span>
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<n-dropdown :options="sizeOptions" @select="handleSizeSelect">
|
||||
<button
|
||||
class="flex items-center justify-end gap-1 text-sm text-right text-[var(--text-primary)] hover:text-[var(--accent-color)]">
|
||||
{{ displaySize }}
|
||||
<n-icon :size="12">
|
||||
<ChevronForwardOutline />
|
||||
</n-icon>
|
||||
</button>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="supportsCustomSize" class="flex items-center gap-1.5">
|
||||
<input
|
||||
v-model="customSizeInput"
|
||||
@keydown.enter.prevent="applyCustomSize"
|
||||
class="flex-1 min-w-0 rounded-md border border-[var(--border-color)] bg-[var(--bg-primary)] px-2 py-1 text-xs text-[var(--text-primary)] outline-none focus:border-[var(--accent-color)]"
|
||||
placeholder="自定义 1088x1920"
|
||||
/>
|
||||
<button
|
||||
@click="applyCustomSize"
|
||||
class="flex-shrink-0 rounded-md border border-[var(--border-color)] px-2 py-1 text-xs text-[var(--text-secondary)] hover:border-[var(--accent-color)] hover:text-[var(--accent-color)]"
|
||||
>应用</button>
|
||||
</div>
|
||||
<div v-if="customSizeError" class="text-[10px] leading-tight text-red-500">
|
||||
{{ customSizeError }}
|
||||
<div v-if="hasSizeOptions" class="flex items-center justify-between">
|
||||
<span class="text-xs text-[var(--text-secondary)]">尺寸</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<n-dropdown :options="sizeOptions" @select="handleSizeSelect">
|
||||
<button
|
||||
class="flex items-center gap-1 text-sm text-[var(--text-primary)] hover:text-[var(--accent-color)]">
|
||||
{{ displaySize }}
|
||||
<n-icon :size="12">
|
||||
<ChevronForwardOutline />
|
||||
</n-icon>
|
||||
</button>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -183,7 +166,7 @@ import { useImageGeneration } from '../../hooks'
|
||||
import { updateNode, addNode, addEdge, nodes, edges, duplicateNode, removeNode } from '../../stores/canvas'
|
||||
import NodeHandleMenu from './NodeHandleMenu.vue'
|
||||
import { useModelStore } from '../../stores/pinia'
|
||||
import { getModelSizeOptions, getModelQualityOptions, getModelConfig, DEFAULT_IMAGE_MODEL, DEFAULT_IMAGE_SIZE, DEFAULT_IMAGE_QUALITY } from '../../stores/models'
|
||||
import { getModelSizeOptions, getModelQualityOptions, getModelConfig, DEFAULT_IMAGE_MODEL, DEFAULT_IMAGE_SIZE } from '../../stores/models'
|
||||
import { parseMentions } from '../../hooks/useNodeRef'
|
||||
|
||||
// 使用 Pinia store 获取模型选项(根据渠道过滤)
|
||||
@@ -204,16 +187,10 @@ const isConfigured = computed(() => !!modelStore.currentApiKey)
|
||||
const { loading, error, images: generatedImages, generate } = useImageGeneration()
|
||||
|
||||
// Local state | 本地状态
|
||||
const normalizeQualityKey = (quality) => {
|
||||
if (quality === 'standard' || quality === 'hd') return 'high'
|
||||
return quality || DEFAULT_IMAGE_QUALITY
|
||||
}
|
||||
const showHandleMenu = ref(false)
|
||||
const localModel = ref(props.data?.model || DEFAULT_IMAGE_MODEL)
|
||||
const localSize = ref(props.data?.size || DEFAULT_IMAGE_SIZE)
|
||||
const localQuality = ref(normalizeQualityKey(props.data?.quality))
|
||||
const customSizeInput = ref(localSize.value)
|
||||
const customSizeError = ref('')
|
||||
const localQuality = ref(props.data?.quality || 'standard')
|
||||
|
||||
// Label editing state | Label 编辑状态
|
||||
const isEditingLabel = ref(false)
|
||||
@@ -283,7 +260,7 @@ const hasQualityOptions = computed(() => {
|
||||
// Display quality | 显示画质
|
||||
const displayQuality = computed(() => {
|
||||
const option = qualityOptions.value.find(o => o.key === localQuality.value)
|
||||
return option?.label || '高 · 最终稿'
|
||||
return option?.label || '标准画质'
|
||||
})
|
||||
|
||||
// Size options based on model and quality | 基于模型和画质的尺寸选项
|
||||
@@ -297,44 +274,12 @@ const hasSizeOptions = computed(() => {
|
||||
return config?.sizes && config.sizes.length > 0
|
||||
})
|
||||
|
||||
const supportsCustomSize = computed(() => {
|
||||
const config = getModelConfig(localModel.value)
|
||||
return config?.supportsCustomSize !== false
|
||||
})
|
||||
|
||||
// Display size with label | 显示尺寸(带标签)
|
||||
const displaySize = computed(() => {
|
||||
const option = sizeOptions.value.find(o => o.key === localSize.value)
|
||||
return option?.label || formatSizeLabel(localSize.value)
|
||||
return option?.label || localSize.value
|
||||
})
|
||||
|
||||
const parseImageSize = (value) => {
|
||||
const normalized = String(value || '').trim().toLowerCase().replace('×', 'x')
|
||||
const match = normalized.match(/^(\d{3,4})\s*x\s*(\d{3,4})$/)
|
||||
if (!match) return null
|
||||
return { width: Number(match[1]), height: Number(match[2]), key: `${Number(match[1])}x${Number(match[2])}` }
|
||||
}
|
||||
|
||||
const formatSizeLabel = (value) => {
|
||||
if (value === 'auto') return '自动 · 生成后显示实际像素'
|
||||
const parsed = parseImageSize(value)
|
||||
return parsed ? `自定义 · ${parsed.width}×${parsed.height}` : value
|
||||
}
|
||||
|
||||
const validateImageSize = (value) => {
|
||||
const parsed = parseImageSize(value)
|
||||
if (!parsed) return { ok: false, message: '格式用 1088x1920' }
|
||||
const { width, height } = parsed
|
||||
const pixels = width * height
|
||||
const longEdge = Math.max(width, height)
|
||||
const shortEdge = Math.min(width, height)
|
||||
if (width % 16 !== 0 || height % 16 !== 0) return { ok: false, message: '宽高需为 16 的倍数' }
|
||||
if (longEdge > 3840) return { ok: false, message: '最长边不能超过 3840px' }
|
||||
if (longEdge / shortEdge > 3) return { ok: false, message: '比例不能超过 3:1' }
|
||||
if (pixels < 655360 || pixels > 8294400) return { ok: false, message: '总像素超出模型范围' }
|
||||
return { ok: true, key: parsed.key }
|
||||
}
|
||||
|
||||
// Initialize on mount | 挂载时初始化
|
||||
onMounted(() => {
|
||||
// 检查当前模型是否在可用模型列表中
|
||||
@@ -347,19 +292,6 @@ onMounted(() => {
|
||||
localModel.value = selected || availableModels[0]?.key || DEFAULT_IMAGE_MODEL
|
||||
updateNode(props.id, { model: localModel.value })
|
||||
}
|
||||
if (props.data?.quality !== localQuality.value) {
|
||||
updateNode(props.id, { quality: localQuality.value })
|
||||
}
|
||||
const mountedSizeOptions = getModelSizeOptions(localModel.value, localQuality.value)
|
||||
if (mountedSizeOptions.length > 0 && !mountedSizeOptions.some(o => o.key === localSize.value)) {
|
||||
const defaultSize = currentModelConfig.value?.defaultParams?.size
|
||||
|| mountedSizeOptions.find(o => o.key === DEFAULT_IMAGE_SIZE)?.key
|
||||
|| mountedSizeOptions[0].key
|
||||
localSize.value = defaultSize
|
||||
customSizeInput.value = defaultSize === 'auto' ? '' : defaultSize
|
||||
customSizeError.value = ''
|
||||
updateNode(props.id, { size: defaultSize })
|
||||
}
|
||||
})
|
||||
|
||||
// 解析 textNode 内容中的 @ 引用,转换为简短引用(如 图 1)并收集图片
|
||||
@@ -561,8 +493,6 @@ const handleModelSelect = (key) => {
|
||||
}
|
||||
|
||||
localSize.value = defaultSize
|
||||
customSizeInput.value = defaultSize === 'auto' ? '' : defaultSize
|
||||
customSizeError.value = ''
|
||||
|
||||
// 更新节点数据
|
||||
updateNode(props.id, {
|
||||
@@ -575,14 +505,20 @@ const handleModelSelect = (key) => {
|
||||
// Handle quality selection | 处理画质选择
|
||||
const handleQualitySelect = (quality) => {
|
||||
localQuality.value = quality
|
||||
updateNode(props.id, { quality })
|
||||
// Update size to first option of new quality | 更新尺寸为新画质的第一个选项
|
||||
const newSizeOptions = getModelSizeOptions(localModel.value, quality)
|
||||
if (newSizeOptions.length > 0) {
|
||||
const defaultSize = newSizeOptions.find(o => o.key === DEFAULT_IMAGE_SIZE)?.key
|
||||
localSize.value = defaultSize || newSizeOptions[0].key
|
||||
updateNode(props.id, { quality, size: localSize.value })
|
||||
} else {
|
||||
updateNode(props.id, { quality })
|
||||
}
|
||||
}
|
||||
|
||||
// Handle size selection | 处理尺寸选择
|
||||
const handleSizeSelect = (size) => {
|
||||
localSize.value = size
|
||||
customSizeInput.value = size === 'auto' ? '' : size
|
||||
customSizeError.value = ''
|
||||
updateNode(props.id, { size })
|
||||
}
|
||||
|
||||
@@ -591,19 +527,6 @@ const updateSize = () => {
|
||||
updateNode(props.id, { size: localSize.value })
|
||||
}
|
||||
|
||||
const applyCustomSize = () => {
|
||||
if (!supportsCustomSize.value) return
|
||||
const result = validateImageSize(customSizeInput.value)
|
||||
if (!result.ok) {
|
||||
customSizeError.value = result.message
|
||||
return
|
||||
}
|
||||
customSizeError.value = ''
|
||||
localSize.value = result.key
|
||||
customSizeInput.value = result.key
|
||||
updateNode(props.id, { size: result.key })
|
||||
}
|
||||
|
||||
// Created image node ID | 创建的图片节点 ID
|
||||
const createdImageNodeId = ref(null)
|
||||
|
||||
@@ -673,16 +596,7 @@ const handleGenerate = async (mode = 'auto') => {
|
||||
// Replace mode: find any connected image node | 替换模式:查找任意连接的图片节点
|
||||
imageNodeId = findConnectedOutputImageNode(false)
|
||||
if (imageNodeId) {
|
||||
updateNode(imageNodeId, {
|
||||
loading: true,
|
||||
url: '',
|
||||
error: '',
|
||||
model: localModel.value,
|
||||
size: localSize.value,
|
||||
quality: localQuality.value,
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
updateNode(imageNodeId, { loading: true, url: '' })
|
||||
}
|
||||
} else if (mode === 'new') {
|
||||
// New mode: always create new node | 新建模式:始终创建新节点
|
||||
@@ -691,15 +605,7 @@ const handleGenerate = async (mode = 'auto') => {
|
||||
// Auto mode: check for empty connected node first | 自动模式:先检查空白连接节点
|
||||
imageNodeId = findConnectedOutputImageNode(true)
|
||||
if (imageNodeId) {
|
||||
updateNode(imageNodeId, {
|
||||
loading: true,
|
||||
error: '',
|
||||
model: localModel.value,
|
||||
size: localSize.value,
|
||||
quality: localQuality.value,
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
updateNode(imageNodeId, { loading: true })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,10 +626,7 @@ const handleGenerate = async (mode = 'auto') => {
|
||||
imageNodeId = addNode('image', { x: nodeX + 400, y: nodeY + yOffset }, {
|
||||
url: '',
|
||||
loading: true,
|
||||
label: '图像生成结果',
|
||||
model: localModel.value,
|
||||
size: localSize.value,
|
||||
quality: localQuality.value
|
||||
label: '图像生成结果'
|
||||
})
|
||||
|
||||
// Auto-connect imageConfig → image | 自动连接 生图配置 → 图片
|
||||
@@ -765,11 +668,7 @@ const handleGenerate = async (mode = 'auto') => {
|
||||
url: result[0].url,
|
||||
loading: false,
|
||||
label: '文生图',
|
||||
model: result[0].model || localModel.value,
|
||||
size: result[0].size || localSize.value,
|
||||
quality: result[0].quality || localQuality.value,
|
||||
width: result[0].width || 0,
|
||||
height: result[0].height || 0,
|
||||
model: localModel.value,
|
||||
updatedAt: Date.now()
|
||||
})
|
||||
|
||||
@@ -843,25 +742,10 @@ watch(() => props.data?.model, (newModel) => {
|
||||
// 同步 Size
|
||||
if (config?.defaultParams?.size) {
|
||||
localSize.value = config.defaultParams.size
|
||||
customSizeInput.value = localSize.value === 'auto' ? '' : localSize.value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.data?.size, (newSize) => {
|
||||
if (newSize && newSize !== localSize.value) {
|
||||
localSize.value = newSize
|
||||
customSizeInput.value = newSize === 'auto' ? '' : newSize
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.data?.quality, (newQuality) => {
|
||||
const normalized = normalizeQualityKey(newQuality)
|
||||
if (normalized !== localQuality.value) {
|
||||
localQuality.value = normalized
|
||||
}
|
||||
})
|
||||
|
||||
// 修复 Vue Flow visibility: hidden 问题
|
||||
watch(() => props.data, () => {
|
||||
nextTick(() => {
|
||||
|
||||
@@ -95,9 +95,9 @@
|
||||
</n-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Model and output metadata | 模型与输出规格 -->
|
||||
<div v-if="imageMetaText" class="mt-1 text-xs text-[var(--text-secondary)] truncate">
|
||||
{{ imageMetaText }}
|
||||
<!-- Model name | 模型名称 -->
|
||||
<div v-if="data.model" class="mt-1 text-xs text-[var(--text-secondary)] truncate">
|
||||
{{ data.model }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -371,21 +371,6 @@ const isPublic = computed(() => {
|
||||
return props.data?.publicProps?.name != null && props.data?.publicProps?.name !== ''
|
||||
})
|
||||
|
||||
const imageMetaText = computed(() => {
|
||||
const parts = []
|
||||
if (props.data?.model) parts.push(props.data.model)
|
||||
if (props.data?.quality) {
|
||||
const qualityMap = { low: '低', medium: '中', high: '高', standard: '高', hd: '高' }
|
||||
parts.push(`${qualityMap[props.data.quality] || props.data.quality}画质`)
|
||||
}
|
||||
if (props.data?.width && props.data?.height) {
|
||||
parts.push(`${props.data.width}×${props.data.height}`)
|
||||
} else if (props.data?.size) {
|
||||
parts.push(String(props.data.size).replace('x', '×'))
|
||||
}
|
||||
return parts.join(' · ')
|
||||
})
|
||||
|
||||
// Handle toggle public | 处理切换公开状态
|
||||
const handleTogglePublic = (value) => {
|
||||
if (value) {
|
||||
@@ -434,7 +419,6 @@ const handleSelect = (item) => {
|
||||
const configNodeId = addNode('imageConfig', { x: nodeX + 900, y: nodeY }, {
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
label: '生图配置'
|
||||
})
|
||||
|
||||
@@ -644,7 +628,6 @@ const createInpaintWorkflow = () => {
|
||||
const configNodeId = addNode('imageConfig', { x: nodeX + 600, y: nodeY }, {
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
label: '局部重绘',
|
||||
inpaintMode: true
|
||||
})
|
||||
@@ -867,7 +850,6 @@ const handleImageGen = () => {
|
||||
const configNodeId = addNode('imageConfig', { x: nodeX + 900, y: nodeY }, {
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
label: '生图配置'
|
||||
})
|
||||
|
||||
|
||||
@@ -417,7 +417,7 @@ const handleSelect = (item) => {
|
||||
const nodeY = currentNode?.position?.y || 0
|
||||
|
||||
const defaultData = {
|
||||
imageConfig: { model: 'auto', size: '1024x1536', quality: 'high', label: '文生图' },
|
||||
imageConfig: { model: 'auto', size: '1024x1536', label: '文生图' },
|
||||
videoConfig: { label: '视频生成' },
|
||||
text: { content: '', label: '文本输入' }
|
||||
}
|
||||
@@ -1008,8 +1008,7 @@ const handleSplitToTextWithImage = () => {
|
||||
data: {
|
||||
label: `图片 ${i + 1}`,
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high'
|
||||
size: '1024x1536'
|
||||
}
|
||||
}
|
||||
nodeSpecs.push(imageConfigSpec)
|
||||
|
||||
@@ -442,7 +442,7 @@ const handleSelect = (item) => {
|
||||
const nodeY = currentNode?.position?.y || 0
|
||||
|
||||
const defaultData = {
|
||||
imageConfig: { model: 'auto', size: '1024x1536', quality: 'high', label: '文生图' },
|
||||
imageConfig: { model: 'auto', size: '1024x1536', label: '文生图' },
|
||||
videoConfig: { label: '视频生成' },
|
||||
llmConfig: { label: 'LLM文本生成' }
|
||||
}
|
||||
@@ -699,7 +699,6 @@ const handleImageGen = () => {
|
||||
const configNodeId = addNode('imageConfig', { x: nodeX + 400, y: nodeY }, {
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
label: '文生图'
|
||||
})
|
||||
|
||||
|
||||
@@ -5,53 +5,18 @@
|
||||
|
||||
// SKG backend image size options | SKG 后端图片尺寸选项
|
||||
export const SEEDREAM_SIZE_OPTIONS = [
|
||||
{ label: '自动 · 生成后显示实际像素', key: 'auto', ratio: 'auto' },
|
||||
{ label: '竖图 2:3 · 1024×1536', key: '1024x1536', ratio: '2:3', width: 1024, height: 1536 },
|
||||
{ label: '竖图 2:3 · 1536×2304', key: '1536x2304', ratio: '2:3', width: 1536, height: 2304 },
|
||||
{ label: '竖屏 9:16 · 1088×1920', key: '1088x1920', ratio: '9:16', width: 1088, height: 1920 },
|
||||
{ label: '竖屏 9:16 · 1440×2560', key: '1440x2560', ratio: '9:16', width: 1440, height: 2560 },
|
||||
{ label: '竖图 3:4 · 960×1280', key: '960x1280', ratio: '3:4', width: 960, height: 1280 },
|
||||
{ label: '竖图 4:5 · 1536×1920', key: '1536x1920', ratio: '4:5', width: 1536, height: 1920 },
|
||||
{ label: '方图 1:1 · 1024×1024', key: '1024x1024', ratio: '1:1', width: 1024, height: 1024 },
|
||||
{ label: '方图 1:1 · 2048×2048', key: '2048x2048', ratio: '1:1', width: 2048, height: 2048 },
|
||||
{ label: '横图 3:2 · 1536×1024', key: '1536x1024', ratio: '3:2', width: 1536, height: 1024 },
|
||||
{ label: '横图 3:2 · 2304×1536', key: '2304x1536', ratio: '3:2', width: 2304, height: 1536 },
|
||||
{ label: '横屏 16:9 · 1280×720', key: '1280x720', ratio: '16:9', width: 1280, height: 720 },
|
||||
{ label: '横屏 16:9 · 2048×1152', key: '2048x1152', ratio: '16:9', width: 2048, height: 1152 }
|
||||
]
|
||||
|
||||
// Gemini 3 Pro Image official aspect ratio + imageSize presets.
|
||||
// Gemini does not support arbitrary custom pixel dimensions.
|
||||
export const GEMINI_SIZE_OPTIONS = [
|
||||
{ label: '自动 · 生成后显示实际像素', key: 'auto', ratio: 'auto' },
|
||||
{ label: '方图 1:1 · 1K · 1024×1024', key: '1024x1024', ratio: '1:1', imageSize: '1K', width: 1024, height: 1024 },
|
||||
{ label: '竖图 2:3 · 1K · 848×1264', key: '848x1264', ratio: '2:3', imageSize: '1K', width: 848, height: 1264 },
|
||||
{ label: '横图 3:2 · 1K · 1264×848', key: '1264x848', ratio: '3:2', imageSize: '1K', width: 1264, height: 848 },
|
||||
{ label: '竖图 3:4 · 1K · 896×1200', key: '896x1200', ratio: '3:4', imageSize: '1K', width: 896, height: 1200 },
|
||||
{ label: '竖图 4:5 · 1K · 928×1152', key: '928x1152', ratio: '4:5', imageSize: '1K', width: 928, height: 1152 },
|
||||
{ label: '竖屏 9:16 · 1K · 768×1376', key: '768x1376', ratio: '9:16', imageSize: '1K', width: 768, height: 1376 },
|
||||
{ label: '横屏 16:9 · 1K · 1376×768', key: '1376x768', ratio: '16:9', imageSize: '1K', width: 1376, height: 768 },
|
||||
{ label: '方图 1:1 · 2K · 2048×2048', key: '2048x2048', ratio: '1:1', imageSize: '2K', width: 2048, height: 2048 },
|
||||
{ label: '竖图 2:3 · 2K · 1696×2528', key: '1696x2528', ratio: '2:3', imageSize: '2K', width: 1696, height: 2528 },
|
||||
{ label: '横图 3:2 · 2K · 2528×1696', key: '2528x1696', ratio: '3:2', imageSize: '2K', width: 2528, height: 1696 },
|
||||
{ label: '竖图 3:4 · 2K · 1792×2400', key: '1792x2400', ratio: '3:4', imageSize: '2K', width: 1792, height: 2400 },
|
||||
{ label: '竖图 4:5 · 2K · 1856×2304', key: '1856x2304', ratio: '4:5', imageSize: '2K', width: 1856, height: 2304 },
|
||||
{ label: '竖屏 9:16 · 2K · 1536×2752', key: '1536x2752', ratio: '9:16', imageSize: '2K', width: 1536, height: 2752 },
|
||||
{ label: '横屏 16:9 · 2K · 2752×1536', key: '2752x1536', ratio: '16:9', imageSize: '2K', width: 2752, height: 1536 },
|
||||
{ label: '方图 1:1 · 4K · 4096×4096', key: '4096x4096', ratio: '1:1', imageSize: '4K', width: 4096, height: 4096 },
|
||||
{ label: '竖图 2:3 · 4K · 3392×5056', key: '3392x5056', ratio: '2:3', imageSize: '4K', width: 3392, height: 5056 },
|
||||
{ label: '横图 3:2 · 4K · 5056×3392', key: '5056x3392', ratio: '3:2', imageSize: '4K', width: 5056, height: 3392 },
|
||||
{ label: '竖屏 9:16 · 4K · 3072×5504', key: '3072x5504', ratio: '9:16', imageSize: '4K', width: 3072, height: 5504 },
|
||||
{ label: '横屏 16:9 · 4K · 5504×3072', key: '5504x3072', ratio: '16:9', imageSize: '4K', width: 5504, height: 3072 }
|
||||
{ label: '自动', key: 'auto' },
|
||||
{ label: '竖图 2:3', key: '1024x1536' },
|
||||
{ label: '方图 1:1', key: '1024x1024' },
|
||||
{ label: '横图 3:2', key: '1536x1024' }
|
||||
]
|
||||
|
||||
// Kept for compatibility with upstream model helpers.
|
||||
export const SEEDREAM_4K_SIZE_OPTIONS = SEEDREAM_SIZE_OPTIONS
|
||||
|
||||
// SKG backend currently exposes model choice and size; quality is retained as a no-op UI field.
|
||||
export const SEEDREAM_QUALITY_OPTIONS = [
|
||||
{ label: '低 · 快速草稿', key: 'low' },
|
||||
{ label: '中 · 常规出图', key: 'medium' },
|
||||
{ label: '高 · 最终稿', key: 'high' }
|
||||
{ label: '标准', key: 'standard' }
|
||||
]
|
||||
|
||||
export const BANANA_SIZE_OPTIONS = [
|
||||
@@ -71,12 +36,10 @@ export const IMAGE_MODELS = [
|
||||
key: 'auto',
|
||||
provider: ['chatfire'],
|
||||
sizes: SEEDREAM_SIZE_OPTIONS.map(s => s.key),
|
||||
sizeOptions: SEEDREAM_SIZE_OPTIONS,
|
||||
qualities: SEEDREAM_QUALITY_OPTIONS,
|
||||
supportsCustomSize: true,
|
||||
defaultParams: {
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
quality: 'standard',
|
||||
style: 'vivid'
|
||||
}
|
||||
},
|
||||
@@ -85,12 +48,10 @@ export const IMAGE_MODELS = [
|
||||
key: 'gpt-image-2',
|
||||
provider: ['chatfire'],
|
||||
sizes: SEEDREAM_SIZE_OPTIONS.map(s => s.key),
|
||||
sizeOptions: SEEDREAM_SIZE_OPTIONS,
|
||||
qualities: SEEDREAM_QUALITY_OPTIONS,
|
||||
supportsCustomSize: true,
|
||||
defaultParams: {
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
quality: 'standard',
|
||||
style: 'vivid'
|
||||
}
|
||||
},
|
||||
@@ -98,13 +59,11 @@ export const IMAGE_MODELS = [
|
||||
label: 'Gemini 图片',
|
||||
key: 'gemini-3-pro-image-preview',
|
||||
provider: ['chatfire'],
|
||||
sizes: GEMINI_SIZE_OPTIONS.map(s => s.key),
|
||||
sizeOptions: GEMINI_SIZE_OPTIONS,
|
||||
qualities: [],
|
||||
supportsCustomSize: false,
|
||||
sizes: SEEDREAM_SIZE_OPTIONS.map(s => s.key),
|
||||
qualities: SEEDREAM_QUALITY_OPTIONS,
|
||||
defaultParams: {
|
||||
size: '1024x1024',
|
||||
quality: 'high',
|
||||
size: '1024x1536',
|
||||
quality: 'standard',
|
||||
style: 'vivid'
|
||||
}
|
||||
},
|
||||
@@ -159,12 +118,16 @@ export const CHAT_MODELS = [
|
||||
|
||||
// Image size options | 图片尺寸选项
|
||||
export const IMAGE_SIZE_OPTIONS = [
|
||||
...SEEDREAM_SIZE_OPTIONS
|
||||
{ label: '自动', key: 'auto' },
|
||||
{ label: '竖图 2:3', key: '1024x1536' },
|
||||
{ label: '方图 1:1', key: '1024x1024' },
|
||||
{ label: '横图 3:2', key: '1536x1024' }
|
||||
]
|
||||
|
||||
// Image quality options | 图片质量选项
|
||||
export const IMAGE_QUALITY_OPTIONS = [
|
||||
...SEEDREAM_QUALITY_OPTIONS
|
||||
{ label: '标准', key: 'standard' },
|
||||
{ label: '高清', key: 'hd' }
|
||||
]
|
||||
|
||||
// Image style options | 图片风格选项
|
||||
@@ -190,7 +153,6 @@ export const DEFAULT_IMAGE_MODEL = 'auto'
|
||||
export const DEFAULT_VIDEO_MODEL = 'seedance'
|
||||
export const DEFAULT_CHAT_MODEL = 'gpt-4o-mini'
|
||||
export const DEFAULT_IMAGE_SIZE = '1024x1536'
|
||||
export const DEFAULT_IMAGE_QUALITY = 'high'
|
||||
export const DEFAULT_VIDEO_RATIO = '720x1280'
|
||||
export const DEFAULT_VIDEO_DURATION = 10
|
||||
|
||||
|
||||
@@ -192,7 +192,6 @@ export const useImageGeneration = () => {
|
||||
prompt: params.prompt || '',
|
||||
model: params.model || 'auto',
|
||||
size: params.size || '1024x1536',
|
||||
quality: params.quality || 'high',
|
||||
mode: firstRef ? 'edit' : 'text'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -244,7 +244,7 @@ const getDefaultNodeData = (type) => {
|
||||
prompt: '',
|
||||
model: DEFAULT_IMAGE_MODEL,
|
||||
size: imageModel?.defaultParams?.size || '1x1',
|
||||
quality: imageModel?.defaultParams?.quality || 'high',
|
||||
quality: imageModel?.defaultParams?.quality || 'standard',
|
||||
label: '文生图'
|
||||
}
|
||||
}
|
||||
@@ -402,8 +402,7 @@ export const initSampleData = () => {
|
||||
addNode('imageConfig', { x: 450, y: 150 }, {
|
||||
prompt: '',
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
ratio: '16:9 | 4张 | 高清',
|
||||
label: '文生图'
|
||||
})
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
DEFAULT_VIDEO_MODEL,
|
||||
DEFAULT_CHAT_MODEL,
|
||||
DEFAULT_IMAGE_SIZE,
|
||||
DEFAULT_IMAGE_QUALITY,
|
||||
DEFAULT_VIDEO_RATIO,
|
||||
DEFAULT_VIDEO_DURATION
|
||||
} from '@/config/models'
|
||||
@@ -67,7 +66,7 @@ export const getModelConfig = (modelKey) => {
|
||||
* Get size options for image model | 获取图片模型尺寸选项
|
||||
* Returns options based on model's sizes array and quality
|
||||
*/
|
||||
export const getModelSizeOptions = (modelKey, quality = 'high') => {
|
||||
export const getModelSizeOptions = (modelKey, quality = 'standard') => {
|
||||
const model = IMAGE_MODELS.find(m => m.key === modelKey)
|
||||
|
||||
// If model has getSizesByQuality function, use it | 如果模型有 getSizesByQuality 函数,使用它
|
||||
@@ -78,7 +77,7 @@ export const getModelSizeOptions = (modelKey, quality = 'high') => {
|
||||
if (!model?.sizes) return SEEDREAM_SIZE_OPTIONS
|
||||
|
||||
// Convert sizes array to dropdown options | 转换 sizes 数组为下拉选项
|
||||
const sizeOptions = model.sizeOptions || (quality === '4k' ? SEEDREAM_4K_SIZE_OPTIONS : SEEDREAM_SIZE_OPTIONS)
|
||||
const sizeOptions = quality === '4k' ? SEEDREAM_4K_SIZE_OPTIONS : SEEDREAM_SIZE_OPTIONS
|
||||
return model.sizes.map(size => {
|
||||
const option = sizeOptions.find(o => o.key === size)
|
||||
return option || { label: size, key: size }
|
||||
@@ -203,7 +202,6 @@ export {
|
||||
DEFAULT_VIDEO_MODEL,
|
||||
DEFAULT_CHAT_MODEL,
|
||||
DEFAULT_IMAGE_SIZE,
|
||||
DEFAULT_IMAGE_QUALITY,
|
||||
DEFAULT_VIDEO_RATIO,
|
||||
DEFAULT_VIDEO_DURATION
|
||||
}
|
||||
|
||||
@@ -891,9 +891,6 @@ const sendMessage = async () => {
|
||||
})
|
||||
|
||||
const imageConfigNodeId = addNode('imageConfig', { x: baseX + 400, y: baseY }, {
|
||||
model: 'auto',
|
||||
size: '1024x1536',
|
||||
quality: 'high',
|
||||
label: '文生图'
|
||||
})
|
||||
|
||||
|
||||
@@ -42,10 +42,6 @@ export interface GeneratedImage {
|
||||
model: string
|
||||
mode: string
|
||||
url: string
|
||||
size?: string
|
||||
quality?: string
|
||||
width?: number
|
||||
height?: number
|
||||
selected: boolean
|
||||
created_at: number
|
||||
}
|
||||
@@ -273,16 +269,6 @@ export interface RuntimeModelOption {
|
||||
}
|
||||
|
||||
export interface RuntimeSizeOption {
|
||||
id: string
|
||||
label: string
|
||||
value: string
|
||||
ratio?: string
|
||||
width?: number
|
||||
height?: number
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface RuntimeQualityOption {
|
||||
id: string
|
||||
label: string
|
||||
value: string
|
||||
@@ -308,7 +294,6 @@ export interface RuntimeModels {
|
||||
image_base_url?: string
|
||||
image_options?: RuntimeModelOption[]
|
||||
image_size_options?: RuntimeSizeOption[]
|
||||
image_quality_options?: RuntimeQualityOption[]
|
||||
image_fallbacks?: string[]
|
||||
image_circuit?: {
|
||||
primary?: string
|
||||
@@ -1272,7 +1257,7 @@ export async function translateText(text: string, target: "en" | "zh" = "en"): P
|
||||
export async function generateImage(
|
||||
jobId: string,
|
||||
frameIdx: number,
|
||||
body: { prompt: string; extra_prompt?: string; negative_prompt?: string; model?: string; size?: string; quality?: string; mode?: "edit" | "text"; from_selected?: boolean },
|
||||
body: { prompt: string; extra_prompt?: string; negative_prompt?: string; model?: string; size?: string; mode?: "edit" | "text"; from_selected?: boolean },
|
||||
): Promise<Job> {
|
||||
const res = await fetch(`${API_BASE}/jobs/${jobId}/frames/${frameIdx}/generate`, {
|
||||
method: "POST",
|
||||
|
||||
Reference in New Issue
Block a user