feature/dmxapi_painting_custom_size (#8689)

* 修改生成图片尺寸

* fix:known problem

* fix:Switching but no recovery occurred

* fix:The problem of loading images

* fix:text i18n
This commit is contained in:
Caelan 2025-08-01 20:55:57 +08:00 committed by GitHub
parent 63ae211af1
commit 2ced1b2d71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 189 additions and 119 deletions

View File

@ -1507,6 +1507,7 @@
"image": "New Image" "image": "New Image"
} }
}, },
"custom_size": "Custom Size",
"edit": { "edit": {
"image_file": "Edited Image", "image_file": "Edited Image",
"magic_prompt_option_tip": "Intelligently enhances editing prompts", "magic_prompt_option_tip": "Intelligently enhances editing prompts",
@ -1629,6 +1630,7 @@
}, },
"text_desc_required": "Please enter image description first", "text_desc_required": "Please enter image description first",
"title": "Images", "title": "Images",
"top_up": "Top up ",
"translating": "Translating...", "translating": "Translating...",
"uploaded_input": "Uploaded input", "uploaded_input": "Uploaded input",
"upscale": { "upscale": {

View File

@ -1507,6 +1507,7 @@
"image": "新しい画像" "image": "新しい画像"
} }
}, },
"custom_size": "カスタムサイズ",
"edit": { "edit": {
"image_file": "編集画像", "image_file": "編集画像",
"magic_prompt_option_tip": "編集効果を向上させるための提示詞を最適化します", "magic_prompt_option_tip": "編集効果を向上させるための提示詞を最適化します",
@ -1629,6 +1630,7 @@
}, },
"text_desc_required": "画像の説明を先に入力してください", "text_desc_required": "画像の説明を先に入力してください",
"title": "画像", "title": "画像",
"top_up": "チャージする",
"translating": "翻訳中...", "translating": "翻訳中...",
"uploaded_input": "アップロード済みの入力", "uploaded_input": "アップロード済みの入力",
"upscale": { "upscale": {

View File

@ -1507,6 +1507,7 @@
"image": "Новое изображение" "image": "Новое изображение"
} }
}, },
"custom_size": "Пользовательский размер",
"edit": { "edit": {
"image_file": "Изображение для редактирования", "image_file": "Изображение для редактирования",
"magic_prompt_option_tip": "Интеллектуально оптимизирует подсказки для улучшения эффекта редактирования", "magic_prompt_option_tip": "Интеллектуально оптимизирует подсказки для улучшения эффекта редактирования",
@ -1629,6 +1630,7 @@
}, },
"text_desc_required": "Пожалуйста, сначала введите описание изображения", "text_desc_required": "Пожалуйста, сначала введите описание изображения",
"title": "Изображения", "title": "Изображения",
"top_up": "пополнить счёт",
"translating": "Перевод...", "translating": "Перевод...",
"uploaded_input": "Загруженный ввод", "uploaded_input": "Загруженный ввод",
"upscale": { "upscale": {

View File

@ -1507,6 +1507,7 @@
"image": "新建图片" "image": "新建图片"
} }
}, },
"custom_size": "自定义尺寸",
"edit": { "edit": {
"image_file": "编辑的图像", "image_file": "编辑的图像",
"magic_prompt_option_tip": "智能优化编辑提示词", "magic_prompt_option_tip": "智能优化编辑提示词",
@ -1629,6 +1630,7 @@
}, },
"text_desc_required": "请先输入图片描述", "text_desc_required": "请先输入图片描述",
"title": "图片", "title": "图片",
"top_up": "充值",
"translating": "翻译中...", "translating": "翻译中...",
"uploaded_input": "已上传输入", "uploaded_input": "已上传输入",
"upscale": { "upscale": {

View File

@ -1507,6 +1507,7 @@
"image": "新繪圖" "image": "新繪圖"
} }
}, },
"custom_size": "自訂尺寸",
"edit": { "edit": {
"image_file": "編輯圖像", "image_file": "編輯圖像",
"magic_prompt_option_tip": "智能優化編輯提示詞", "magic_prompt_option_tip": "智能優化編輯提示詞",
@ -1629,6 +1630,7 @@
}, },
"text_desc_required": "請先輸入圖片描述", "text_desc_required": "請先輸入圖片描述",
"title": "繪圖", "title": "繪圖",
"top_up": "儲值",
"translating": "翻譯中...", "translating": "翻譯中...",
"uploaded_input": "已上傳輸入", "uploaded_input": "已上傳輸入",
"upscale": { "upscale": {

View File

@ -1,11 +1,10 @@
import { PlusOutlined, RedoOutlined } from '@ant-design/icons' import { PlusOutlined, RedoOutlined } from '@ant-design/icons'
import DMXAPIToImg from '@renderer/assets/images/providers/DMXAPI-to-img.webp' import DMXAPIToImg from '@renderer/assets/images/providers/DMXAPI-to-img.webp'
import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar'
import { HStack, VStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import { isMac } from '@renderer/config/constant' import { isMac } from '@renderer/config/constant'
import { getProviderLogo } from '@renderer/config/providers' import { getProviderLogo } from '@renderer/config/providers'
import { useTheme } from '@renderer/context/ThemeProvider'
import { usePaintings } from '@renderer/hooks/usePaintings' import { usePaintings } from '@renderer/hooks/usePaintings'
import { useAllProviders } from '@renderer/hooks/useProvider' import { useAllProviders } from '@renderer/hooks/useProvider'
import { useRuntime } from '@renderer/hooks/useRuntime' import { useRuntime } from '@renderer/hooks/useRuntime'
@ -16,7 +15,7 @@ import { setGenerating } from '@renderer/store/runtime'
import type { FileMetadata, PaintingsState } from '@renderer/types' import type { FileMetadata, PaintingsState } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { DmxapiPainting } from '@types' import { DmxapiPainting } from '@types'
import { Avatar, Button, Input, Radio, Segmented, Select, Switch, Tooltip } from 'antd' import { Avatar, Button, Input, InputNumber, Segmented, Select, Switch, Tooltip } from 'antd'
import TextArea from 'antd/es/input/TextArea' import TextArea from 'antd/es/input/TextArea'
import { Info } from 'lucide-react' import { Info } from 'lucide-react'
import React, { FC, useEffect, useRef, useState } from 'react' import React, { FC, useEffect, useRef, useState } from 'react'
@ -34,9 +33,9 @@ import {
COURSE_URL, COURSE_URL,
DEFAULT_PAINTING, DEFAULT_PAINTING,
GetModelGroup, GetModelGroup,
IMAGE_SIZES,
MODEOPTIONS, MODEOPTIONS,
STYLE_TYPE_OPTIONS STYLE_TYPE_OPTIONS,
TOP_UP_URL
} from './config/DmxapiConfig' } from './config/DmxapiConfig'
const generateRandomSeed = () => Math.floor(Math.random() * 1000000).toString() const generateRandomSeed = () => Math.floor(Math.random() * 1000000).toString()
@ -45,7 +44,6 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
const [mode] = useState<keyof PaintingsState>('DMXAPIPaintings') const [mode] = useState<keyof PaintingsState>('DMXAPIPaintings')
const { DMXAPIPaintings, addPainting, removePainting, updatePainting } = usePaintings() const { DMXAPIPaintings, addPainting, removePainting, updatePainting } = usePaintings()
const [painting, setPainting] = useState<DmxapiPainting>(DMXAPIPaintings?.[0] || DEFAULT_PAINTING) const [painting, setPainting] = useState<DmxapiPainting>(DMXAPIPaintings?.[0] || DEFAULT_PAINTING)
const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
const providers = useAllProviders() const providers = useAllProviders()
const providerOptions = Options.map((option) => { const providerOptions = Options.map((option) => {
@ -88,6 +86,11 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
paths: [] paths: []
}) })
// 自定义尺寸相关状态
const [isCustomSize, setIsCustomSize] = useState(false)
const [customWidth, setCustomWidth] = useState<number | undefined>()
const [customHeight, setCustomHeight] = useState<number | undefined>()
const modeOptions = MODEOPTIONS.map((ele) => { const modeOptions = MODEOPTIONS.map((ele) => {
return { return {
label: t(ele.label), label: t(ele.label),
@ -144,25 +147,45 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
updatePainting('DMXAPIPaintings', updatedPainting) updatePainting('DMXAPIPaintings', updatedPainting)
} }
const getNewPainting = (params?: Partial<DmxapiPainting>) => { const getFirstModelInfo = (v: generationModeType) => {
clearImages() const modelGroups = getModelOptions(v)
const generationMode = params?.generationMode || painting?.generationMode || MODEOPTIONS[0].value
const modelGroups = getModelOptions(generationMode as generationModeType) let model = ''
// 获取第一个非空分组的第一个模型 let priceModel = ''
let firstModel = '' let image_size = ''
for (const provider of Object.keys(modelGroups)) { for (const provider of Object.keys(modelGroups)) {
if (modelGroups[provider].length > 0) { if (modelGroups[provider] && modelGroups[provider].length > 0) {
firstModel = modelGroups[provider][0].id model = modelGroups[provider][0].id
priceModel = modelGroups[provider][0].price
image_size = modelGroups[provider][0].image_sizes[0].value
break break
} }
} }
return {
model,
priceModel,
image_size,
modelGroups
}
}
const getNewPainting = (params?: Partial<DmxapiPainting>) => {
clearImages()
const generationMode = params?.generationMode || painting?.generationMode || MODEOPTIONS[0].value
const { model, priceModel, image_size, modelGroups } = getFirstModelInfo(generationMode)
return { return {
...DEFAULT_PAINTING, ...DEFAULT_PAINTING,
id: uuid(), id: uuid(),
seed: generateRandomSeed(), seed: generateRandomSeed(),
generationMode, generationMode,
model: firstModel, model,
modelGroups,
priceModel,
image_size,
...params ...params
} }
} }
@ -180,7 +203,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
const onSelectModel = (modelId: string) => { const onSelectModel = (modelId: string) => {
const model = allModels.find((m) => m.id === modelId) const model = allModels.find((m) => m.id === modelId)
if (model) { if (model) {
updatePaintingState({ model: modelId, priceModel: model.price }) updatePaintingState({ model: modelId, priceModel: model.price, image_size: model.image_sizes[0].value })
} }
} }
@ -189,8 +212,34 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
} }
const onSelectImageSize = (v: string) => { const onSelectImageSize = (v: string) => {
const size = IMAGE_SIZES.find((i) => i.value === v) if (v === 'custom') {
size && updatePaintingState({ image_size: size.value, aspect_ratio: size.label }) setIsCustomSize(true)
// 如果有自定义尺寸值,使用它们
if (customWidth && customHeight) {
updatePaintingState({ image_size: `${customWidth}x${customHeight}`, aspect_ratio: 'custom' })
}
} else {
setIsCustomSize(false)
const currentModel = allModels.find((m) => m.id === painting.model)
const size = currentModel?.image_sizes?.find((i) => i.value === v)
size && updatePaintingState({ image_size: size.value, aspect_ratio: size.label })
}
}
const onCustomSizeChange = (value: number | null, type: string) => {
if (value === null) return
if (type === 'width') {
setCustomWidth(value)
if (customHeight) {
updatePaintingState({ image_size: `${value}x${customHeight}`, aspect_ratio: 'custom' })
}
} else if (type === 'height') {
setCustomHeight(value)
if (customWidth) {
updatePaintingState({ image_size: `${customWidth}x${value}`, aspect_ratio: 'custom' })
}
}
} }
const onSelectStyleType = (v: string) => { const onSelectStyleType = (v: string) => {
@ -251,27 +300,21 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
} }
const onGenerationModeChange = (v: generationModeType) => { const onGenerationModeChange = (v: generationModeType) => {
clearImages() if (isLoading) {
const newModelGroups = getModelOptions(v) return
setModelOptions(newModelGroups)
// 获取第一个非空分组的第一个模型
let firstModel = ''
let priceModel = ''
for (const provider of Object.keys(newModelGroups)) {
if (newModelGroups[provider] && newModelGroups[provider].length > 0) {
firstModel = newModelGroups[provider][0].id
priceModel = newModelGroups[provider][0].price
break
}
} }
clearImages()
const { model, priceModel, image_size, modelGroups } = getFirstModelInfo(v)
setModelOptions(modelGroups)
// 如果有urls创建新的painting // 如果有urls创建新的painting
if (Array.isArray(painting.urls) && painting.urls.length > 0) { if (Array.isArray(painting.urls) && painting.urls.length > 0) {
const newPainting = getNewPainting({ const newPainting = getNewPainting({
generationMode: v, generationMode: v,
model: firstModel, // 使用新模式下的第一个模型 model
priceModel: priceModel
}) })
const addedPainting = addPainting('DMXAPIPaintings', newPainting) const addedPainting = addPainting('DMXAPIPaintings', newPainting)
setPainting(addedPainting) setPainting(addedPainting)
@ -279,12 +322,20 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
// 否则更新当前painting // 否则更新当前painting
updatePaintingState({ updatePaintingState({
generationMode: v, generationMode: v,
model: firstModel, // 使用新模式下的第一个模型 model: model,
image_size: image_size,
priceModel: priceModel priceModel: priceModel
}) })
} }
} }
const createNewPainting = () => {
if (isLoading) {
return
}
setPainting(addPainting('DMXAPIPaintings', getNewPainting()))
}
// 检查提供者状态函数 // 检查提供者状态函数
const checkProviderStatus = () => { const checkProviderStatus = () => {
if (!dmxapiProvider.enabled) { if (!dmxapiProvider.enabled) {
@ -324,10 +375,6 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
if (painting.aspect_ratio) {
params['aspect_ratio'] = painting.aspect_ratio
}
if (painting.image_size) { if (painting.image_size) {
params['size'] = painting.image_size params['size'] = painting.image_size
} }
@ -360,7 +407,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
} }
if (painting.image_size) { if (painting.image_size) {
params['size'] = '1024x1024' params['size'] = painting.image_size
} }
if (painting.style_type) { if (painting.style_type) {
@ -562,6 +609,10 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
const onDeletePainting = async (paintingToDelete: DmxapiPainting) => { const onDeletePainting = async (paintingToDelete: DmxapiPainting) => {
if (paintingToDelete.id === painting.id) { if (paintingToDelete.id === painting.id) {
if (isLoading) {
return
}
const currentIndex = DMXAPIPaintings.findIndex((p) => p.id === paintingToDelete.id) const currentIndex = DMXAPIPaintings.findIndex((p) => p.id === paintingToDelete.id)
if (currentIndex > 0) { if (currentIndex > 0) {
@ -715,17 +766,21 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoadingModels, dynamicModelGroups]) // 依赖模型加载状态 }, [isLoadingModels, dynamicModelGroups]) // 依赖模型加载状态
// 当模型切换时,检查是否支持自定义尺寸
useEffect(() => {
const currentModel = allModels.find((m) => m.id === painting.model)
if (currentModel && !currentModel.is_custom_size && isCustomSize) {
setIsCustomSize(false)
}
}, [painting.model, allModels, isCustomSize])
return ( return (
<Container> <Container>
<Navbar> <Navbar>
<NavbarCenter style={{ borderRight: 'none' }}>{t('paintings.title')}</NavbarCenter> <NavbarCenter style={{ borderRight: 'none' }}>{t('paintings.title')}</NavbarCenter>
{isMac && ( {isMac && (
<NavbarRight style={{ justifyContent: 'flex-end' }}> <NavbarRight style={{ justifyContent: 'flex-end' }}>
<Button <Button size="small" className="nodrag" icon={<PlusOutlined />} onClick={createNewPainting}>
size="small"
className="nodrag"
icon={<PlusOutlined />}
onClick={() => setPainting(addPainting('DMXAPIPaintings', getNewPainting()))}>
{t('paintings.button.new.image')} {t('paintings.button.new.image')}
</Button> </Button>
</NavbarRight> </NavbarRight>
@ -735,15 +790,20 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
<LeftContainer> <LeftContainer>
<ProviderTitleContainer> <ProviderTitleContainer>
<SettingTitle style={{ marginBottom: 5 }}>{t('common.provider')}</SettingTitle> <SettingTitle style={{ marginBottom: 5 }}>{t('common.provider')}</SettingTitle>
<SettingHelpLink target="_blank" href={COURSE_URL}> <div>
{t('paintings.paint_course')} <SettingHelpLink target="_blank" href={COURSE_URL}>
{t('paintings.paint_course')}
</SettingHelpLink>
<SettingHelpLink target="_blank" href={TOP_UP_URL}>
{t('paintings.top_up')}
</SettingHelpLink>
<ProviderLogo <ProviderLogo
shape="square" shape="square"
src={getProviderLogo(dmxapiProvider.id)} src={getProviderLogo(dmxapiProvider.id)}
size={16} size={16}
style={{ marginLeft: 5 }} style={{ marginLeft: 5 }}
/> />
</SettingHelpLink> </div>
</ProviderTitleContainer> </ProviderTitleContainer>
<Select value={providerOptions[2].value} onChange={handleProviderChange} style={{ marginBottom: 15 }}> <Select value={providerOptions[2].value} onChange={handleProviderChange} style={{ marginBottom: 15 }}>
{providerOptions.map((provider) => ( {providerOptions.map((provider) => (
@ -793,23 +853,66 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
})} })}
</Select> </Select>
<SettingTitle style={{ marginBottom: 5, marginTop: 15 }}>{t('paintings.image.size')}</SettingTitle>
<Select
value={isCustomSize ? 'custom' : painting.image_size}
onChange={(value) => onSelectImageSize(value)}
style={{ width: '100%' }}>
{(() => {
const currentModel = allModels.find((m) => m.id === painting.model)
const modelImageSizes = currentModel?.image_sizes || []
// 直接使用模型返回的image_sizes数据包含label和value
return modelImageSizes.map((size) => {
return (
<Select.Option key={size.value} value={size.value}>
<HStack style={{ alignItems: 'center', gap: 8 }}>
<span>{size.label}</span>
</HStack>
</Select.Option>
)
})
})()}
{/* 检查当前模型是否支持自定义尺寸 */}
{allModels.find((m) => m.id === painting.model)?.is_custom_size && (
<Select.Option value="custom" key="custom">
<HStack style={{ alignItems: 'center', gap: 8 }}>
<span>{t('paintings.custom_size')}</span>
</HStack>
</Select.Option>
)}
</Select>
{/* 自定义尺寸输入框 */}
{isCustomSize && allModels.find((m) => m.id === painting.model)?.is_custom_size && (
<div style={{ marginTop: 10 }}>
<HStack style={{ gap: 8, alignItems: 'center' }}>
<InputNumber
placeholder="W"
value={customWidth}
controls={false}
onChange={(value) => onCustomSizeChange(value, 'width')}
min={parseInt(allModels.find((m) => m.id === painting.model)?.min_image_size || '512')}
max={parseInt(allModels.find((m) => m.id === painting.model)?.max_image_size || '2048')}
style={{ width: 80, flex: 1 }}
/>
<span style={{ color: 'var(--color-text-2)', fontSize: '12px' }}>x</span>
<InputNumber
placeholder="H"
value={customHeight}
controls={false}
onChange={(value) => onCustomSizeChange(value, 'height')}
min={parseInt(allModels.find((m) => m.id === painting.model)?.min_image_size || 512)}
max={parseInt(allModels.find((m) => m.id === painting.model)?.max_image_size || 2048)}
style={{ width: 80, flex: 1 }}
/>
<span style={{ color: 'var(--color-text-3)', fontSize: '11px' }}>px</span>
</HStack>
</div>
)}
{painting.generationMode === generationModeType.GENERATION && ( {painting.generationMode === generationModeType.GENERATION && (
<> <>
<SettingTitle style={{ marginBottom: 5, marginTop: 15 }}>{t('paintings.image.size')}</SettingTitle>
<Radio.Group
value={painting.image_size}
onChange={(e) => onSelectImageSize(e.target.value)}
style={{ display: 'flex' }}>
{IMAGE_SIZES.map((size) => (
<RadioButton value={size.value} key={size.value}>
<VStack alignItems="center">
<ImageSizeImage src={size.icon} theme={theme} />
<span>{size.label}</span>
</VStack>
</RadioButton>
))}
</Radio.Group>
<SettingTitle style={{ marginBottom: 5, marginTop: 15 }}> <SettingTitle style={{ marginBottom: 5, marginTop: 15 }}>
{t('paintings.seed')} {t('paintings.seed')}
<Tooltip title={t('paintings.seed_desc_tip')}> <Tooltip title={t('paintings.seed_desc_tip')}>
@ -896,7 +999,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
selectedPainting={painting} selectedPainting={painting}
onSelectPainting={onSelectPainting} onSelectPainting={onSelectPainting}
onDeletePainting={onDeletePainting} onDeletePainting={onDeletePainting}
onNewPainting={() => setPainting(addPainting('DMXAPIPaintings', getNewPainting()))} onNewPainting={createNewPainting}
/> />
</ContentContainer> </ContentContainer>
</Container> </Container>
@ -991,22 +1094,6 @@ const ToolbarMenu = styled.div`
align-items: center; align-items: center;
gap: 6px; gap: 6px;
` `
const ImageSizeImage = styled.img<{ theme: string }>`
filter: ${({ theme }) => (theme === 'dark' ? 'invert(100%)' : 'none')};
margin-top: 8px;
`
const RadioButton = styled(Radio.Button)`
width: 30px;
height: 55px;
display: flex;
flex-direction: column;
flex: 1;
justify-content: center;
align-items: center;
`
const InfoIcon = styled(Info)` const InfoIcon = styled(Info)`
margin-left: 5px; margin-left: 5px;
cursor: help; cursor: help;
@ -1078,8 +1165,11 @@ const EmptyImgBox = styled.div`
const EmptyImg = styled.div<{ bgUrl?: string }>` const EmptyImg = styled.div<{ bgUrl?: string }>`
width: 70vh; width: 70vh;
height: 70vh; height: 70vh;
background-size: cover; background-size: contain;
background-repeat: no-repeat;
background-position: center;
background-image: ${(props) => (props.bgUrl ? `url(${props.bgUrl})` : `url(${DMXAPIToImg})`)}; background-image: ${(props) => (props.bgUrl ? `url(${props.bgUrl})` : `url(${DMXAPIToImg})`)};
background-color: #ffffff;
` `
const LoadTextWrap = styled.div` const LoadTextWrap = styled.div`

View File

@ -1,9 +1,3 @@
import ImageSize1_1 from '@renderer/assets/images/paintings/image-size-1-1.svg'
import ImageSize1_2 from '@renderer/assets/images/paintings/image-size-1-2.svg'
import ImageSize3_2 from '@renderer/assets/images/paintings/image-size-3-2.svg'
import ImageSize3_4 from '@renderer/assets/images/paintings/image-size-3-4.svg'
import ImageSize9_16 from '@renderer/assets/images/paintings/image-size-9-16.svg'
import ImageSize16_9 from '@renderer/assets/images/paintings/image-size-16-9.svg'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { t } from 'i18next' import { t } from 'i18next'
@ -15,6 +9,13 @@ export type DMXApiModelData = {
provider: string provider: string
name: string name: string
price: string price: string
image_sizes: Array<{
label: string
value: string
}>
is_custom_size: boolean
max_image_size?: number
min_image_size?: number
} }
// 模型分组类型 // 模型分组类型
@ -54,41 +55,10 @@ export const STYLE_TYPE_OPTIONS = [
{ label: '巴洛克', value: '巴洛克' } { label: '巴洛克', value: '巴洛克' }
] ]
export const IMAGE_SIZES = [
{
label: '1:1',
value: '1328x1328',
icon: ImageSize1_1
},
{
label: '1:2',
value: '800x1600',
icon: ImageSize1_2
},
{
label: '3:2',
value: '1584x1056',
icon: ImageSize3_2
},
{
label: '3:4',
value: '1104x1472',
icon: ImageSize3_4
},
{
label: '16:9',
value: '1664x936',
icon: ImageSize16_9
},
{
label: '9:16',
value: '936x1664',
icon: ImageSize9_16
}
]
export const COURSE_URL = 'http://seedream.dmxapi.cn/' export const COURSE_URL = 'http://seedream.dmxapi.cn/'
export const TOP_UP_URL = 'https://www.dmxapi.cn/topup'
export const DEFAULT_PAINTING: DmxapiPainting = { export const DEFAULT_PAINTING: DmxapiPainting = {
id: uuid(), id: uuid(),
urls: [], urls: [],