diff --git a/src/renderer/src/config/models.ts b/src/renderer/src/config/models.ts
index b48e6ece..c9e6174c 100644
--- a/src/renderer/src/config/models.ts
+++ b/src/renderer/src/config/models.ts
@@ -961,6 +961,11 @@ export const TEXT_TO_IMAGES_MODELS = [
}
]
+export const TEXT_TO_IMAGES_MODELS_SUPPORT_IMAGE_ENHANCEMENT = [
+ 'stabilityai/stable-diffusion-2-1',
+ 'stabilityai/stable-diffusion-xl-base-1.0'
+]
+
export function isTextToImageModel(model: Model): boolean {
return TEXT_TO_IMAGE_REGEX.test(model.id)
}
diff --git a/src/renderer/src/hooks/usePaintings.ts b/src/renderer/src/hooks/usePaintings.ts
index b01c0acc..8a8ed550 100644
--- a/src/renderer/src/hooks/usePaintings.ts
+++ b/src/renderer/src/hooks/usePaintings.ts
@@ -14,6 +14,7 @@ export function usePaintings() {
paintings,
addPainting: () => {
const newPainting: Painting = {
+ model: TEXT_TO_IMAGES_MODELS[0].id,
id: uuid(),
urls: [],
files: [],
@@ -24,7 +25,7 @@ export function usePaintings() {
seed: generateRandomSeed(),
steps: 25,
guidanceScale: 4.5,
- model: TEXT_TO_IMAGES_MODELS[0].id
+ promptEnhancement: true
}
dispatch(addPainting(newPainting))
return newPainting
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index b8cdec96..232b5d06 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -279,7 +279,9 @@
"regenerate.confirm": "This will replace your existing generated images. Do you want to continue?",
"seed": "Seed",
"seed_tip": "The same seed and prompt can produce similar images",
- "title": "Images"
+ "title": "Images",
+ "prompt_enhancement": "Prompt Enhancement",
+ "prompt_enhancement_tip": "Rewrite prompts into detailed, model-friendly versions when switched on"
},
"provider": {
"aihubmix": "AiHubMix",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index 1f146aaf..5570313f 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -277,7 +277,9 @@
"regenerate.confirm": "これにより、既存の生成画像が置き換えられます。続行しますか?",
"seed": "シード",
"seed_tip": "同じシードとプロンプトで似た画像を生成できます",
- "title": "画像"
+ "title": "画像",
+ "prompt_enhancement": "プロンプト強化",
+ "prompt_enhancement_tip": "オンにすると、プロンプトを詳細でモデルに適したバージョンに書き直します"
},
"provider": {
"aihubmix": "AiHubMix",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index c1088ab5..3f758652 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -279,7 +279,9 @@
"regenerate.confirm": "Это заменит ваши существующие сгенерированные изображения. Хотите продолжить?",
"seed": "Ключ генерации",
"seed_tip": "Одинаковый ключ генерации и промпт могут производить похожие изображения",
- "title": "Изображения"
+ "title": "Изображения",
+ "prompt_enhancement": "Улучшение промпта",
+ "prompt_enhancement_tip": "При включении переписывает промпт в более детальную, модель-ориентированную версию"
},
"provider": {
"aihubmix": "AiHubMix",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index a2fb898f..4073cc95 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -280,7 +280,9 @@
"regenerate.confirm": "这将覆盖已生成的图片,是否继续?",
"seed": "随机种子",
"seed_tip": "相同的种子和提示词可以生成相似的图片",
- "title": "图片"
+ "title": "图片",
+ "prompt_enhancement": "提示词增强",
+ "prompt_enhancement_tip": "开启后将提示重写为详细的、适合模型的版本"
},
"provider": {
"aihubmix": "AiHubMix",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index 105d78ef..87b51b32 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -279,7 +279,9 @@
"regenerate.confirm": "這將覆蓋已生成的圖片,是否繼續?",
"seed": "隨機種子",
"seed_tip": "相同的種子和提示詞可以生成相似的圖片",
- "title": "繪圖"
+ "title": "繪圖",
+ "prompt_enhancement": "提示詞增強",
+ "prompt_enhancement_tip": "開啟後將提示重寫為詳細的、適合模型的版本"
},
"provider": {
"aihubmix": "AiHubMix",
diff --git a/src/renderer/src/pages/paintings/PaintingsPage.tsx b/src/renderer/src/pages/paintings/PaintingsPage.tsx
index a6ee6366..7c924486 100644
--- a/src/renderer/src/pages/paintings/PaintingsPage.tsx
+++ b/src/renderer/src/pages/paintings/PaintingsPage.tsx
@@ -6,7 +6,7 @@ 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 { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar'
-import { VStack } from '@renderer/components/Layout'
+import { HStack, VStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar'
import TranslateButton from '@renderer/components/TranslateButton'
import { isMac } from '@renderer/config/constant'
@@ -25,7 +25,7 @@ import { DEFAULT_PAINTING } from '@renderer/store/paintings'
import { setGenerating } from '@renderer/store/runtime'
import { FileType, Painting } from '@renderer/types'
import { getErrorMessage } from '@renderer/utils'
-import { Button, Input, InputNumber, Radio, Select, Slider, Tooltip } from 'antd'
+import { Button, Input, InputNumber, Radio, Select, Slider, Switch, Tooltip } from 'antd'
import TextArea from 'antd/es/input/TextArea'
import { FC, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -149,8 +149,13 @@ const PaintingsPage: FC = () => {
dispatch(setGenerating(true))
const AI = new AiProvider(provider)
+ if (!painting.model) {
+ return
+ }
+
try {
const urls = await AI.generateImage({
+ model: painting.model,
prompt,
negativePrompt: painting.negativePrompt || '',
imageSize: painting.imageSize || '1024x1024',
@@ -158,7 +163,8 @@ const PaintingsPage: FC = () => {
seed: painting.seed || undefined,
numInferenceSteps: painting.steps || 25,
guidanceScale: painting.guidanceScale || 4.5,
- signal: controller.signal
+ signal: controller.signal,
+ promptEnhancement: painting.promptEnhancement || false
})
if (urls.length > 0) {
@@ -360,13 +366,15 @@ const PaintingsPage: FC = () => {
- updatePaintingState({ steps: v })} />
- updatePaintingState({ steps: v || 25 })}
- />
+
+ updatePaintingState({ steps: v })} />
+ updatePaintingState({ steps: (v as number) || 25 })}
+ />
+
{t('paintings.guidance_scale')}
@@ -374,21 +382,22 @@ const PaintingsPage: FC = () => {
- updatePaintingState({ guidanceScale: v })}
- />
- updatePaintingState({ guidanceScale: v || 4.5 })}
- />
-
+
+ updatePaintingState({ guidanceScale: v })}
+ />
+ updatePaintingState({ guidanceScale: (v as number) || 4.5 })}
+ />
+
{t('paintings.negative_prompt')}
@@ -400,6 +409,18 @@ const PaintingsPage: FC = () => {
onChange={(e) => updatePaintingState({ negativePrompt: e.target.value })}
rows={4}
/>
+
+ {t('paintings.prompt_enhancement')}
+
+
+
+
+
+ updatePaintingState({ promptEnhancement: checked })}
+ />
+
{
+ public async generateImage(params: GenerateImageParams): Promise {
return this.sdk.generateImage(params)
}
diff --git a/src/renderer/src/providers/BaseProvider.ts b/src/renderer/src/providers/BaseProvider.ts
index 968bb283..303b9181 100644
--- a/src/renderer/src/providers/BaseProvider.ts
+++ b/src/renderer/src/providers/BaseProvider.ts
@@ -2,7 +2,7 @@ import { REFERENCE_PROMPT } from '@renderer/config/prompts'
import { getOllamaKeepAliveTime } from '@renderer/hooks/useOllama'
import { getKnowledgeReferences } from '@renderer/services/KnowledgeService'
import store from '@renderer/store'
-import { Assistant, Message, Model, Provider, Suggestion } from '@renderer/types'
+import { Assistant, GenerateImageParams, Message, Model, Provider, Suggestion } from '@renderer/types'
import { delay, isJSON } from '@renderer/utils'
import OpenAI from 'openai'
@@ -26,16 +26,7 @@ export default abstract class BaseProvider {
abstract generateText({ prompt, content }: { prompt: string; content: string }): Promise
abstract check(): Promise<{ valid: boolean; error: Error | null }>
abstract models(): Promise
- abstract generateImage(_params: {
- prompt: string
- negativePrompt: string
- imageSize: string
- batchSize: number
- seed?: string
- numInferenceSteps: number
- guidanceScale: number
- signal?: AbortSignal
- }): Promise
+ abstract generateImage(params: GenerateImageParams): Promise
abstract getEmbeddingDimensions(model: Model): Promise
public getBaseURL(): string {
diff --git a/src/renderer/src/providers/OpenAIProvider.ts b/src/renderer/src/providers/OpenAIProvider.ts
index 285b377f..3c19be48 100644
--- a/src/renderer/src/providers/OpenAIProvider.ts
+++ b/src/renderer/src/providers/OpenAIProvider.ts
@@ -4,7 +4,7 @@ import i18n from '@renderer/i18n'
import { getAssistantSettings, getDefaultModel, getTopNamingModel } from '@renderer/services/AssistantService'
import { EVENT_NAMES } from '@renderer/services/EventService'
import { filterContextMessages } from '@renderer/services/MessagesService'
-import { Assistant, FileTypes, Message, Model, Provider, Suggestion } from '@renderer/types'
+import { Assistant, FileTypes, GenerateImageParams, Message, Model, Provider, Suggestion } from '@renderer/types'
import { removeQuotes } from '@renderer/utils'
import { last, takeRight } from 'lodash'
import OpenAI, { AzureOpenAI } from 'openai'
@@ -345,6 +345,7 @@ export default class OpenAIProvider extends BaseProvider {
}
public async generateImage({
+ model,
prompt,
negativePrompt,
imageSize,
@@ -352,30 +353,23 @@ export default class OpenAIProvider extends BaseProvider {
seed,
numInferenceSteps,
guidanceScale,
- signal
- }: {
- prompt: string
- negativePrompt?: string
- imageSize: string
- batchSize: number
- seed?: string
- numInferenceSteps: number
- guidanceScale: number
- signal?: AbortSignal
- }): Promise {
+ signal,
+ promptEnhancement
+ }: GenerateImageParams): Promise {
const response = (await this.sdk.request({
method: 'post',
path: '/images/generations',
signal,
body: {
- model: 'stabilityai/stable-diffusion-3-5-large',
+ model,
prompt,
negative_prompt: negativePrompt,
image_size: imageSize,
batch_size: batchSize,
seed: seed ? parseInt(seed) : undefined,
num_inference_steps: numInferenceSteps,
- guidance_scale: guidanceScale
+ guidance_scale: guidanceScale,
+ prompt_enhancement: promptEnhancement
}
})) as { data: Array<{ url: string }> }
diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts
index 8badfc9c..75bc0125 100644
--- a/src/renderer/src/types/index.ts
+++ b/src/renderer/src/types/index.ts
@@ -112,6 +112,7 @@ export type Suggestion = {
export interface Painting {
id: string
+ model?: string
urls: string[]
files: FileType[]
prompt?: string
@@ -121,7 +122,7 @@ export interface Painting {
seed?: string
steps?: number
guidanceScale?: number
- model?: string
+ promptEnhancement?: boolean
}
export type MinAppType = {
@@ -224,3 +225,16 @@ export type KnowledgeBaseParams = {
apiVersion?: string
baseURL: string
}
+
+export type GenerateImageParams = {
+ model: string
+ prompt: string
+ negativePrompt?: string
+ imageSize: string
+ batchSize: number
+ seed?: string
+ numInferenceSteps: number
+ guidanceScale: number
+ signal?: AbortSignal
+ promptEnhancement?: boolean
+}