返回 oh-my-ppt
image-model-handlers.ts
根目录 / src / main / config / image-model-handlers.ts
1 import { ipcMain } from 'electron'
2 import log from 'electron-log/main.js'
3 import type { ImageModelProvider } from '@shared/image-generation'
4 import type { IpcContext } from '../ipc/context'
5 import { readAppLocale, uiText } from './locale-utils'
6
7 const VALID_IMAGE_PROVIDERS = [
8 'jimeng',
9 'jimeng4',
10 'agnes',
11 'siliconflow',
12 'openaiCompatible',
13 'gemini',
14 'seedream'
15 ] as const
16
17 const resolveProvider = (provider: unknown): ImageModelProvider => {
18 if (VALID_IMAGE_PROVIDERS.includes(provider as ImageModelProvider)) {
19 return provider as ImageModelProvider
20 }
21 throw new Error('Unsupported image provider')
22 }
23
24 const normalizeModelConfig = (value: unknown): string => {
25 const text = typeof value === 'string' ? value.trim() : ''
26 if (!text) return '{}'
27 try {
28 const parsed = JSON.parse(text)
29 if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return '{}'
30 return text
31 } catch {
32 return '{}'
33 }
34 }
35
36 export function registerImageModelHandlers(ctx: IpcContext): void {
37 const { db, encryptApiKey, decryptApiKey } = ctx
38
39 ipcMain.handle('imageModels:list', async () => {
40 return (await db.listImageModelConfigs()).map((config) => ({
41 id: config.id,
42 name: config.name,
43 provider: resolveProvider(config.provider),
44 active: config.active === 1,
45 modelConfig: decryptApiKey(config.modelConfig || '{}'),
46 createdAt: config.createdAt,
47 updatedAt: config.updatedAt
48 }))
49 })
50
51 ipcMain.handle('imageModels:upsert', async (_event, payload) => {
52 const locale = await readAppLocale(ctx)
53 const record = payload && typeof payload === 'object' ? (payload as Record<string, unknown>) : {}
54 const name = typeof record.name === 'string' ? record.name.trim() : ''
55 const provider = resolveProvider(record.provider)
56 const modelConfig = normalizeModelConfig(record.modelConfig)
57 const id =
58 typeof record.id === 'string' && record.id.trim().length > 0 ? record.id.trim() : undefined
59 if (!name) throw new Error(uiText(locale, '请填写生图模型名称。', 'Enter image model name.'))
60 if (modelConfig === '{}') {
61 throw new Error(uiText(locale, '请填写生图模型配置。', 'Enter image model config.'))
62 }
63 const savedId = await db.upsertImageModelConfig({
64 id,
65 name,
66 provider,
67 modelConfig: encryptApiKey(modelConfig),
68 active: record.active === true,
69 })
70 return { success: true, id: savedId }
71 })
72
73 ipcMain.handle('imageModels:setActive', async (_event, id) => {
74 const locale = await readAppLocale(ctx)
75 if (typeof id !== 'string' || id.trim().length === 0) {
76 throw new Error(uiText(locale, '生图模型配置 ID 不能为空。', 'Image model config ID is required.'))
77 }
78 try {
79 await db.setActiveImageModelConfig(id.trim())
80 } catch (error) {
81 if (error instanceof Error && error.message === 'Image model config does not exist') {
82 throw new Error(uiText(locale, '生图模型配置不存在。', 'Image model config does not exist.'))
83 }
84 throw error
85 }
86 return { success: true }
87 })
88
89 ipcMain.handle('imageModels:delete', async (_event, id) => {
90 const locale = await readAppLocale(ctx)
91 if (typeof id !== 'string' || id.trim().length === 0) {
92 throw new Error(uiText(locale, '生图模型配置 ID 不能为空。', 'Image model config ID is required.'))
93 }
94 try {
95 await db.deleteImageModelConfig(id.trim())
96 } catch (error) {
97 if (error instanceof Error && error.message === 'Image model config does not exist') {
98 throw new Error(uiText(locale, '生图模型配置不存在。', 'Image model config does not exist.'))
99 }
100 throw error
101 }
102 return { success: true }
103 })
104
105 ipcMain.handle('imageModels:verify', async (_event, payload) => {
106 const locale = await readAppLocale(ctx)
107 const record = payload && typeof payload === 'object' ? (payload as Record<string, unknown>) : {}
108 const provider = resolveProvider(record.provider)
109 const modelConfig = normalizeModelConfig(record.modelConfig)
110 log.info('[imageModels:verify] received', { provider, hasConfig: modelConfig !== '{}' })
111 if (modelConfig === '{}') {
112 return {
113 valid: false,
114 message: uiText(locale, '请先填写生图模型配置。', 'Enter image model config first.')
115 }
116 }
117 return {
118 valid: true,
119 message: uiText(
120 locale,
121 '基础配置已通过检查。生图接口会在首次生成时验证。',
122 'Basic configuration looks valid. The image endpoint is verified on first generation.'
123 )
124 }
125 })
126 }
127
127 lines TYPESCRIPT