feat(aihubmix): support nano banana (#11476)

support nano banana
This commit is contained in:
chenxue
2025-11-26 20:51:52 +08:00
committed by GitHub
parent cbf1d461f0
commit 97519d96d7
3 changed files with 88 additions and 4 deletions

View File

@@ -93,7 +93,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => {
const getNewPainting = useCallback(() => {
return {
...DEFAULT_PAINTING,
model: mode === 'aihubmix_image_generate' ? 'gpt-image-1' : 'V_3',
model: mode === 'aihubmix_image_generate' ? 'gemini-3-pro-image-preview' : 'V_3',
id: uuid()
}
}, [mode])
@@ -201,6 +201,74 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => {
updatePaintingState({ files: validFiles, urls: validFiles.map((file) => file.name) })
}
return
} else if (painting.model === 'gemini-3-pro-image-preview') {
const geminiUrl = `${aihubmixProvider.apiHost}/gemini/v1beta/models/gemini-3-pro-image-preview:streamGenerateContent`
const geminiHeaders = {
'Content-Type': 'application/json',
'x-goog-api-key': aihubmixProvider.apiKey
}
const requestBody = {
contents: [
{
parts: [
{
text: prompt
}
],
role: 'user'
}
],
generationConfig: {
responseModalities: ['TEXT', 'IMAGE'],
imageConfig: {
aspectRatio: painting.aspectRatio?.replace('ASPECT_', '').replace('_', ':') || '1:1',
imageSize: painting.imageSize || '1k'
}
}
}
logger.silly(`Gemini Request: ${JSON.stringify(requestBody)}`)
const response = await fetch(geminiUrl, {
method: 'POST',
headers: geminiHeaders,
body: JSON.stringify(requestBody)
})
if (!response.ok) {
const errorData = await response.json()
logger.error('Gemini API Error:', errorData)
throw new Error(errorData.error?.message || '生成图像失败')
}
const data = await response.json()
logger.silly(`Gemini API Response: ${JSON.stringify(data)}`)
// Handle array response (stream) or single object
const responseItems = Array.isArray(data) ? data : [data]
const base64s: string[] = []
responseItems.forEach((item) => {
item.candidates?.forEach((candidate: any) => {
candidate.content?.parts?.forEach((part: any) => {
if (part.inlineData?.data) {
base64s.push(part.inlineData.data)
}
})
})
})
if (base64s.length > 0) {
const validFiles = await Promise.all(
base64s.map(async (base64: string) => {
return await window.api.file.saveBase64Image(base64)
})
)
await FileManager.addFiles(validFiles)
updatePaintingState({ files: validFiles, urls: validFiles.map((file) => file.name) })
}
return
} else if (painting.model === 'V_3') {
// V3 API uses different endpoint and parameters format
const formData = new FormData()

View File

@@ -72,6 +72,7 @@ export const createModeConfigs = (): Record<AihubmixMode, ConfigItem[]> => {
label: 'Gemini',
title: 'Gemini',
options: [
{ label: 'Nano Banana Pro', value: 'gemini-3-pro-image-preview' },
{ label: 'imagen-4.0-preview', value: 'imagen-4.0-generate-preview-06-06' },
{ label: 'imagen-4.0-ultra', value: 'imagen-4.0-ultra-generate-preview-06-06' }
]
@@ -224,7 +225,20 @@ export const createModeConfigs = (): Record<AihubmixMode, ConfigItem[]> => {
{ label: '16:9', value: 'ASPECT_16_9' }
],
initialValue: 'ASPECT_1_1',
condition: (painting) => Boolean(painting.model?.startsWith('imagen-'))
condition: (painting) =>
Boolean(painting.model?.startsWith('imagen-') || painting.model === 'gemini-3-pro-image-preview')
},
{
type: 'select',
key: 'imageSize',
title: 'paintings.image.size',
options: [
{ label: '1K', value: '1K' },
{ label: '2K', value: '2K' },
{ label: '4K', value: '4K' }
],
initialValue: '1K',
condition: (painting) => painting.model === 'gemini-3-pro-image-preview'
},
{
type: 'select',
@@ -398,7 +412,7 @@ export const createModeConfigs = (): Record<AihubmixMode, ConfigItem[]> => {
// 几种默认的绘画配置
export const DEFAULT_PAINTING: PaintingAction = {
id: 'aihubmix_1',
model: 'gpt-image-1',
model: 'gemini-3-pro-image-preview',
aspectRatio: 'ASPECT_1_1',
numImages: 1,
styleType: 'AUTO',
@@ -420,5 +434,6 @@ export const DEFAULT_PAINTING: PaintingAction = {
moderation: 'auto',
n: 1,
numberOfImages: 4,
safetyTolerance: 6
safetyTolerance: 6,
imageSize: '1K'
}

View File

@@ -320,6 +320,7 @@ export interface GeneratePainting extends PaintingParams {
safetyTolerance?: number
width?: number
height?: number
imageSize?: string
}
export interface EditPainting extends PaintingParams {