diff --git a/app/client/api.ts b/app/client/api.ts index 98202c4db76..d7fb023a226 100644 --- a/app/client/api.ts +++ b/app/client/api.ts @@ -44,6 +44,8 @@ export interface LLMConfig { presence_penalty?: number; frequency_penalty?: number; size?: DalleRequestPayload["size"]; + quality?: DalleRequestPayload["quality"]; + style?: DalleRequestPayload["style"]; } export interface ChatOptions { diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index 98c6f406afa..d4e262c16b4 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -17,7 +17,7 @@ import { base64Image2Blob, } from "@/app/utils/chat"; import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; -import { DalleSize } from "@/app/typing"; +import { DalleSize, DalleQuality, DalleStyle } from "@/app/typing"; import { ChatOptions, @@ -70,6 +70,8 @@ export interface DalleRequestPayload { response_format: "url" | "b64_json"; n: number; size: DalleSize; + quality: DalleQuality; + style: DalleStyle; } export class ChatGPTApi implements LLMApi { @@ -162,6 +164,8 @@ export class ChatGPTApi implements LLMApi { response_format: "b64_json", // using b64_json, and save image in CacheStorage n: 1, size: options.config?.size ?? "1024x1024", + quality: options.config?.quality ?? "standard", + style: options.config?.style ?? "vivid", }; } else { const visionModel = isVisionModel(options.config.model); diff --git a/app/components/chat.tsx b/app/components/chat.tsx index b18c86708a7..52befde13bb 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -38,6 +38,8 @@ import BottomIcon from "../icons/bottom.svg"; import StopIcon from "../icons/pause.svg"; import RobotIcon from "../icons/robot.svg"; import SizeIcon from "../icons/size.svg"; +import QualityIcon from "../icons/hd.svg"; +import StyleIcon from "../icons/palette.svg"; import PluginIcon from "../icons/plugin.svg"; import { @@ -69,7 +71,7 @@ import { uploadImage as uploadImageRemote } from "@/app/utils/chat"; import dynamic from "next/dynamic"; import { ChatControllerPool } from "../client/controller"; -import { DalleSize } from "../typing"; +import { DalleSize, DalleQuality, DalleStyle } from "../typing"; import { Prompt, usePromptStore } from "../store/prompt"; import Locale from "../locales"; @@ -485,9 +487,17 @@ export function ChatActions(props: { const [showUploadImage, setShowUploadImage] = useState(false); const [showSizeSelector, setShowSizeSelector] = useState(false); + const [showQualitySelector, setShowQualitySelector] = useState(false); + const [showStyleSelector, setShowStyleSelector] = useState(false); const dalle3Sizes: DalleSize[] = ["1024x1024", "1792x1024", "1024x1792"]; + const dalle3Qualitys: DalleQuality[] = ["standard", "hd"]; + const dalle3Styles: DalleStyle[] = ["vivid", "natural"]; const currentSize = chatStore.currentSession().mask.modelConfig?.size ?? "1024x1024"; + const currentQuality = + chatStore.currentSession().mask.modelConfig?.quality ?? "standard"; + const currentStyle = + chatStore.currentSession().mask.modelConfig?.style ?? "vivid"; useEffect(() => { const show = isVisionModel(currentModel); @@ -659,6 +669,60 @@ export function ChatActions(props: { /> )} + {isDalle3(currentModel) && ( + setShowQualitySelector(true)} + text={currentQuality} + icon={} + /> + )} + + {showQualitySelector && ( + ({ + title: m, + value: m, + }))} + onClose={() => setShowQualitySelector(false)} + onSelection={(q) => { + if (q.length === 0) return; + const quality = q[0]; + chatStore.updateCurrentSession((session) => { + session.mask.modelConfig.quality = quality; + }); + showToast(quality); + }} + /> + )} + + {isDalle3(currentModel) && ( + setShowStyleSelector(true)} + text={currentStyle} + icon={} + /> + )} + + {showStyleSelector && ( + ({ + title: m, + value: m, + }))} + onClose={() => setShowStyleSelector(false)} + onSelection={(s) => { + if (s.length === 0) return; + const style = s[0]; + chatStore.updateCurrentSession((session) => { + session.mask.modelConfig.style = style; + }); + showToast(style); + }} + /> + )} + setShowPluginSelector(true)} text={Locale.Plugin.Name} diff --git a/app/icons/hd.svg b/app/icons/hd.svg new file mode 100644 index 00000000000..baae66af0f2 --- /dev/null +++ b/app/icons/hd.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/icons/palette.svg b/app/icons/palette.svg new file mode 100644 index 00000000000..474d0e2177d --- /dev/null +++ b/app/icons/palette.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/store/config.ts b/app/store/config.ts index b478858a978..e8e3c9863ef 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -1,5 +1,5 @@ import { LLMModel } from "../client/api"; -import { DalleSize } from "../typing"; +import { DalleSize, DalleQuality, DalleStyle } from "../typing"; import { getClientConfig } from "../config/client"; import { DEFAULT_INPUT_TEMPLATE, @@ -63,6 +63,8 @@ export const DEFAULT_CONFIG = { enableInjectSystemPrompts: true, template: config?.template ?? DEFAULT_INPUT_TEMPLATE, size: "1024x1024" as DalleSize, + quality: "standard" as DalleQuality, + style: "vivid" as DalleStyle, }, }; diff --git a/app/typing.ts b/app/typing.ts index 86320358157..0336be75d39 100644 --- a/app/typing.ts +++ b/app/typing.ts @@ -9,3 +9,5 @@ export interface RequestMessage { } export type DalleSize = "1024x1024" | "1792x1024" | "1024x1792"; +export type DalleQuality = "standard" | "hd"; +export type DalleStyle = "vivid" | "natural";