diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3eee790..dec6ddd 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -13,6 +13,10 @@ export default function App() { const [historicalActivities, setHistoricalActivities] = useState< Record >({}); + const [imageConfig, setImageConfig] = useState({ + aspectRatio: "16:9", + imageSize: "1K", + }); const scrollAreaRef = useRef(null); const hasFinalizeEventOccurredRef = useRef(false); const [error, setError] = useState(null); @@ -105,7 +109,9 @@ export default function App() { submittedInputValue: string, effort: string, model: string, - language: string + language: string, + aspectRatio: string, + imageSize: string ) => { if (!submittedInputValue.trim()) return; setProcessedEventsTimeline([]); @@ -140,12 +146,15 @@ export default function App() { id: Date.now().toString(), }, ]; + setImageConfig({ aspectRatio, imageSize }); thread.submit({ messages: newMessages, initial_search_query_count: initial_search_query_count, max_research_loops: max_research_loops, reasoning_model: model, language, + aspect_ratio: aspectRatio, + image_size: imageSize, }); }, [thread] @@ -188,6 +197,8 @@ export default function App() { onCancel={handleCancel} liveActivityEvents={processedEventsTimeline} historicalActivities={historicalActivities} + aspectRatio={imageConfig.aspectRatio} + imageSize={imageConfig.imageSize} /> )} diff --git a/frontend/src/components/ChatMessagesView.tsx b/frontend/src/components/ChatMessagesView.tsx index 3edce91..9a00c5a 100644 --- a/frontend/src/components/ChatMessagesView.tsx +++ b/frontend/src/components/ChatMessagesView.tsx @@ -168,6 +168,8 @@ interface AiMessageBubbleProps { mdComponents: typeof mdComponents; handleCopy: (text: string, messageId: string) => void; copiedMessageId: string | null; + aspectRatio?: string; + imageSize?: string; } // AiMessageBubble Component @@ -180,6 +182,8 @@ const AiMessageBubble: React.FC = ({ mdComponents, handleCopy, copiedMessageId, + aspectRatio, + imageSize, }) => { const [pageImages, setPageImages] = useState< Record< @@ -238,7 +242,12 @@ const AiMessageBubble: React.FC = ({ fetch(`${backendBase}/generate_image`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ prompt: page.detail, number_of_images: 1 }), + body: JSON.stringify({ + prompt: page.detail, + number_of_images: 1, + aspect_ratio: aspectRatio || "16:9", + image_size: imageSize || "1K", + }), }) .then(async (res) => { if (!res.ok) throw new Error(await res.text()); @@ -352,10 +361,19 @@ interface ChatMessagesViewProps { messages: Message[]; isLoading: boolean; scrollAreaRef: React.RefObject; - onSubmit: (inputValue: string, effort: string, model: string, language: string) => void; + onSubmit: ( + inputValue: string, + effort: string, + model: string, + language: string, + aspectRatio: string, + imageSize: string + ) => void; onCancel: () => void; liveActivityEvents: ProcessedEvent[]; historicalActivities: Record; + aspectRatio?: string; + imageSize?: string; } export function ChatMessagesView({ @@ -366,6 +384,8 @@ export function ChatMessagesView({ onCancel, liveActivityEvents, historicalActivities, + aspectRatio, + imageSize, }: ChatMessagesViewProps) { const [copiedMessageId, setCopiedMessageId] = useState(null); @@ -406,6 +426,8 @@ export function ChatMessagesView({ mdComponents={mdComponents} handleCopy={handleCopy} copiedMessageId={copiedMessageId} + aspectRatio={aspectRatio} + imageSize={imageSize} /> )} diff --git a/frontend/src/components/InputForm.tsx b/frontend/src/components/InputForm.tsx index ba7b1f2..e08a2b3 100644 --- a/frontend/src/components/InputForm.tsx +++ b/frontend/src/components/InputForm.tsx @@ -24,7 +24,9 @@ interface InputFormProps { inputValue: string, effort: string, model: string, - language: string + language: string, + aspectRatio: string, + imageSize: string ) => void; onCancel: () => void; isLoading: boolean; @@ -38,15 +40,17 @@ export const InputForm: React.FC = ({ hasHistory, }) => { const [internalInputValue, setInternalInputValue] = useState(""); - const [effort, setEffort] = useState("medium"); + const [effort, setEffort] = useState("low"); // Default to a current, broadly capable model const [model, setModel] = useState("gemini-2.5-flash"); const [language, setLanguage] = useState("简体中文"); + const [aspectRatio, setAspectRatio] = useState("16:9"); + const [imageSize, setImageSize] = useState("1K"); const handleInternalSubmit = (e?: React.FormEvent) => { if (e) e.preventDefault(); if (!internalInputValue.trim()) return; - onSubmit(internalInputValue, effort, model, language); + onSubmit(internalInputValue, effort, model, language, aspectRatio, imageSize); setInternalInputValue(""); }; @@ -74,7 +78,7 @@ export const InputForm: React.FC = ({ value={internalInputValue} onChange={(e) => setInternalInputValue(e.target.value)} onKeyDown={handleKeyDown} - placeholder="Who won the Euro 2024 and scored the most goals?" + placeholder="白雪公主大战奥特曼" className={`w-full text-neutral-100 placeholder-neutral-500 resize-none border-0 focus:outline-none focus:ring-0 outline-none focus-visible:ring-0 shadow-none md:text-base min-h-[56px] max-h-[200px]`} rows={1} @@ -107,9 +111,10 @@ export const InputForm: React.FC = ({ )} -
-
-
+
+
+
+
Effort @@ -140,7 +145,7 @@ export const InputForm: React.FC = ({
-
+
Model @@ -173,11 +178,11 @@ export const InputForm: React.FC = ({
3 Pro Preview
- +
-
+
Language @@ -207,7 +212,42 @@ export const InputForm: React.FC = ({ +
+
+
+
+ + Aspect +
+ +
+
+
+ + Size +
+ +
+
{hasHistory && (