suisuyy commited on
Commit
90f5e5b
·
1 Parent(s): dbeee1d

Add generated image URL handling in AiEditModal and update useAiFeatures hook; improve prompt change logic

Browse files
App.tsx CHANGED
@@ -82,12 +82,13 @@ const App: React.FC = () => {
82
  aiEditError,
83
  isAskingAi,
84
  askUrl,
 
85
  handleMagicUpload,
86
  handleGenerateAiImage,
87
  handleAskAi,
88
  handleCancelAiEdit,
89
  setAiPrompt,
90
- clearAskUrl,
91
  } = useAiFeatures({
92
  currentDataURL,
93
  showToast,
@@ -104,8 +105,8 @@ const App: React.FC = () => {
104
  const handlePromptChange = (newPrompt: string) => {
105
  setAiPrompt(newPrompt);
106
  // Clear the previous "Ask" response when the user types a new prompt
107
- if (askUrl !== null) {
108
- clearAskUrl();
109
  }
110
  };
111
 
@@ -198,6 +199,7 @@ const App: React.FC = () => {
198
  isAsking={isAskingAi}
199
  error={aiEditError}
200
  askUrl={askUrl}
 
201
  t={t}
202
  />
203
  )}
@@ -264,4 +266,4 @@ const App: React.FC = () => {
264
  );
265
  };
266
 
267
- export default App;
 
82
  aiEditError,
83
  isAskingAi,
84
  askUrl,
85
+ generatedImageUrl,
86
  handleMagicUpload,
87
  handleGenerateAiImage,
88
  handleAskAi,
89
  handleCancelAiEdit,
90
  setAiPrompt,
91
+ clearAiOutputs,
92
  } = useAiFeatures({
93
  currentDataURL,
94
  showToast,
 
105
  const handlePromptChange = (newPrompt: string) => {
106
  setAiPrompt(newPrompt);
107
  // Clear the previous "Ask" response when the user types a new prompt
108
+ if (askUrl !== null || generatedImageUrl !== null) {
109
+ clearAiOutputs();
110
  }
111
  };
112
 
 
199
  isAsking={isAskingAi}
200
  error={aiEditError}
201
  askUrl={askUrl}
202
+ generatedImageUrl={generatedImageUrl}
203
  t={t}
204
  />
205
  )}
 
266
  );
267
  };
268
 
269
+ export default App;
components/AiEditModal.tsx CHANGED
@@ -14,6 +14,7 @@ interface AiEditModalProps {
14
  isAsking: boolean;
15
  error: string | null;
16
  askUrl: string | null;
 
17
  t: TFunction;
18
  }
19
 
@@ -29,6 +30,7 @@ const AiEditModal: React.FC<AiEditModalProps> = ({
29
  isAsking,
30
  error,
31
  askUrl,
 
32
  t,
33
  }) => {
34
  const iframeContainerRef = useRef<HTMLDivElement>(null);
@@ -87,7 +89,7 @@ const AiEditModal: React.FC<AiEditModalProps> = ({
87
  </div>
88
 
89
  {error && (
90
- <div id="ai-edit-error" className="mb-4 p-3 bg-red-100 border border-red-300 text-red-700 rounded-md text-sm" role="alert">
91
  <p className="font-semibold">{t('errorPrefix')}</p>
92
  <p>{error}</p>
93
  </div>
@@ -136,6 +138,20 @@ const AiEditModal: React.FC<AiEditModalProps> = ({
136
  </button>
137
  </div>
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  {askUrl && (
140
  <div ref={iframeContainerRef} className="mt-4 pt-2">
141
  <iframe
@@ -150,4 +166,4 @@ const AiEditModal: React.FC<AiEditModalProps> = ({
150
  );
151
  };
152
 
153
- export default AiEditModal;
 
14
  isAsking: boolean;
15
  error: string | null;
16
  askUrl: string | null;
17
+ generatedImageUrl: string | null;
18
  t: TFunction;
19
  }
20
 
 
30
  isAsking,
31
  error,
32
  askUrl,
33
+ generatedImageUrl,
34
  t,
35
  }) => {
36
  const iframeContainerRef = useRef<HTMLDivElement>(null);
 
89
  </div>
90
 
91
  {error && (
92
+ <div id="ai-edit-error" className="mb-4 p-3 bg-red-100 border border-red-300 text-red-700 rounded-md text-sm overflow-y-auto max-h-32" role="alert">
93
  <p className="font-semibold">{t('errorPrefix')}</p>
94
  <p>{error}</p>
95
  </div>
 
138
  </button>
139
  </div>
140
 
141
+ {generatedImageUrl && (
142
+ <div className="mt-4 p-3 bg-slate-50 border border-slate-200 rounded-md text-sm">
143
+ <p className="text-slate-600 font-medium">{t('aiGeneratedImageURLMessage')}</p>
144
+ <a
145
+ href={generatedImageUrl}
146
+ target="_blank"
147
+ rel="noopener noreferrer"
148
+ className="text-blue-600 hover:text-blue-800 break-all underline"
149
+ >
150
+ {generatedImageUrl}
151
+ </a>
152
+ </div>
153
+ )}
154
+
155
  {askUrl && (
156
  <div ref={iframeContainerRef} className="mt-4 pt-2">
157
  <iframe
 
166
  );
167
  };
168
 
169
+ export default AiEditModal;
components/CanvasComponent.tsx CHANGED
@@ -202,4 +202,4 @@ const CanvasComponent: React.FC<CanvasComponentProps> = ({
202
  );
203
  };
204
 
205
- export default CanvasComponent;
 
202
  );
203
  };
204
 
205
+ export default CanvasComponent;
hooks/useAiFeatures.ts CHANGED
@@ -20,12 +20,13 @@ interface AiFeaturesHook {
20
  aiEditError: string | null;
21
  isAskingAi: boolean;
22
  askUrl: string | null;
 
23
  handleMagicUpload: () => Promise<void>;
24
  handleGenerateAiImage: () => Promise<void>;
25
  handleAskAi: () => Promise<void>;
26
  handleCancelAiEdit: () => void;
27
  setAiPrompt: React.Dispatch<React.SetStateAction<string>>;
28
- clearAskUrl: () => void;
29
  }
30
 
31
  interface UseAiFeaturesProps {
@@ -61,9 +62,11 @@ export const useAiFeatures = ({
61
  const [aiEditError, setAiEditError] = useState<string | null>(null);
62
  const [isAskingAi, setIsAskingAi] = useState<boolean>(false);
63
  const [askUrl, setAskUrl] = useState<string | null>(null);
 
64
 
65
- const clearAskUrl = useCallback(() => {
66
  setAskUrl(null);
 
67
  }, []);
68
 
69
  const loadAiImageOntoCanvas = useCallback((aiImageDataUrl: string) => {
@@ -168,7 +171,7 @@ export const useAiFeatures = ({
168
  setShowAiEditModal(true);
169
  setAiPrompt('');
170
  setAiEditError(null);
171
- clearAskUrl();
172
 
173
  } catch (error: any) {
174
  console.error('Magic upload error:', error);
@@ -176,7 +179,7 @@ export const useAiFeatures = ({
176
  } finally {
177
  setIsMagicUploading(false);
178
  }
179
- }, [isMagicUploading, currentDataURL, showToast, clearAskUrl, t]);
180
 
181
  const handleGenerateAiImage = useCallback(async () => {
182
  if (!aiPrompt.trim() || !sharedImageUrlForAi) {
@@ -185,7 +188,7 @@ export const useAiFeatures = ({
185
  }
186
  setIsGeneratingAiImage(true);
187
  setAiEditError(null);
188
- clearAskUrl();
189
  showToast(t('generatingAiImage'), 'info');
190
 
191
  const encodedPrompt = encodeURIComponent(aiPrompt);
@@ -208,6 +211,8 @@ export const useAiFeatures = ({
208
  }
209
  finalApiUrl = finalApiUrl.replace('{size_params}', sizeParamsString);
210
  }
 
 
211
 
212
  try {
213
  const response = await fetch(finalApiUrl);
@@ -247,7 +252,7 @@ export const useAiFeatures = ({
247
  setAiEditError(error.message || t('unknownAiError'));
248
  setIsGeneratingAiImage(false);
249
  }
250
- }, [aiPrompt, sharedImageUrlForAi, showToast, loadAiImageOntoCanvas, aiImageQuality, aiApiEndpoint, aiDimensionsMode, currentCanvasWidth, currentCanvasHeight, clearAskUrl, t]);
251
 
252
  const handleAskAi = useCallback(async () => {
253
  if (!aiPrompt.trim() || !sharedImageUrlForAi) {
@@ -256,7 +261,7 @@ export const useAiFeatures = ({
256
  }
257
  setIsAskingAi(true);
258
  setAiEditError(null);
259
- setAskUrl(null); // Clear previous URL first
260
 
261
  try {
262
  const encodedPrompt = encodeURIComponent(aiPrompt);
@@ -270,7 +275,7 @@ export const useAiFeatures = ({
270
  } finally {
271
  setIsAskingAi(false);
272
  }
273
- }, [aiPrompt, sharedImageUrlForAi, t]);
274
 
275
 
276
  const handleCancelAiEdit = () => {
@@ -285,7 +290,7 @@ export const useAiFeatures = ({
285
  setAiPrompt('');
286
  setAiEditError(null);
287
  setSharedImageUrlForAi(null);
288
- clearAskUrl();
289
  };
290
 
291
  return {
@@ -297,11 +302,12 @@ export const useAiFeatures = ({
297
  aiEditError,
298
  isAskingAi,
299
  askUrl,
 
300
  handleMagicUpload,
301
  handleGenerateAiImage,
302
  handleAskAi,
303
  handleCancelAiEdit,
304
  setAiPrompt,
305
- clearAskUrl,
306
  };
307
  };
 
20
  aiEditError: string | null;
21
  isAskingAi: boolean;
22
  askUrl: string | null;
23
+ generatedImageUrl: string | null;
24
  handleMagicUpload: () => Promise<void>;
25
  handleGenerateAiImage: () => Promise<void>;
26
  handleAskAi: () => Promise<void>;
27
  handleCancelAiEdit: () => void;
28
  setAiPrompt: React.Dispatch<React.SetStateAction<string>>;
29
+ clearAiOutputs: () => void;
30
  }
31
 
32
  interface UseAiFeaturesProps {
 
62
  const [aiEditError, setAiEditError] = useState<string | null>(null);
63
  const [isAskingAi, setIsAskingAi] = useState<boolean>(false);
64
  const [askUrl, setAskUrl] = useState<string | null>(null);
65
+ const [generatedImageUrl, setGeneratedImageUrl] = useState<string | null>(null);
66
 
67
+ const clearAiOutputs = useCallback(() => {
68
  setAskUrl(null);
69
+ setGeneratedImageUrl(null);
70
  }, []);
71
 
72
  const loadAiImageOntoCanvas = useCallback((aiImageDataUrl: string) => {
 
171
  setShowAiEditModal(true);
172
  setAiPrompt('');
173
  setAiEditError(null);
174
+ clearAiOutputs();
175
 
176
  } catch (error: any) {
177
  console.error('Magic upload error:', error);
 
179
  } finally {
180
  setIsMagicUploading(false);
181
  }
182
+ }, [isMagicUploading, currentDataURL, showToast, clearAiOutputs, t]);
183
 
184
  const handleGenerateAiImage = useCallback(async () => {
185
  if (!aiPrompt.trim() || !sharedImageUrlForAi) {
 
188
  }
189
  setIsGeneratingAiImage(true);
190
  setAiEditError(null);
191
+ clearAiOutputs();
192
  showToast(t('generatingAiImage'), 'info');
193
 
194
  const encodedPrompt = encodeURIComponent(aiPrompt);
 
211
  }
212
  finalApiUrl = finalApiUrl.replace('{size_params}', sizeParamsString);
213
  }
214
+
215
+ setGeneratedImageUrl(finalApiUrl);
216
 
217
  try {
218
  const response = await fetch(finalApiUrl);
 
252
  setAiEditError(error.message || t('unknownAiError'));
253
  setIsGeneratingAiImage(false);
254
  }
255
+ }, [aiPrompt, sharedImageUrlForAi, showToast, loadAiImageOntoCanvas, aiImageQuality, aiApiEndpoint, aiDimensionsMode, currentCanvasWidth, currentCanvasHeight, clearAiOutputs, t]);
256
 
257
  const handleAskAi = useCallback(async () => {
258
  if (!aiPrompt.trim() || !sharedImageUrlForAi) {
 
261
  }
262
  setIsAskingAi(true);
263
  setAiEditError(null);
264
+ clearAiOutputs();
265
 
266
  try {
267
  const encodedPrompt = encodeURIComponent(aiPrompt);
 
275
  } finally {
276
  setIsAskingAi(false);
277
  }
278
+ }, [aiPrompt, sharedImageUrlForAi, t, clearAiOutputs]);
279
 
280
 
281
  const handleCancelAiEdit = () => {
 
290
  setAiPrompt('');
291
  setAiEditError(null);
292
  setSharedImageUrlForAi(null);
293
+ clearAiOutputs();
294
  };
295
 
296
  return {
 
302
  aiEditError,
303
  isAskingAi,
304
  askUrl,
305
+ generatedImageUrl,
306
  handleMagicUpload,
307
  handleGenerateAiImage,
308
  handleAskAi,
309
  handleCancelAiEdit,
310
  setAiPrompt,
311
+ clearAiOutputs,
312
  };
313
  };
translations.ts CHANGED
@@ -34,6 +34,7 @@ const translations = {
34
  aiAsking: 'Asking...',
35
  aiGenerateImage: 'Generate Image',
36
  aiGenerating: 'Generating...',
 
37
 
38
  // Settings Panel
39
  settingsTitle: 'Application Settings',
@@ -148,6 +149,7 @@ const translations = {
148
  aiAsking: '提问中...',
149
  aiGenerateImage: '生成图片',
150
  aiGenerating: '生成中...',
 
151
 
152
  // Settings Panel
153
  settingsTitle: '应用设置',
@@ -257,4 +259,4 @@ export const getTranslator = () => {
257
  }
258
  return text;
259
  };
260
- };
 
34
  aiAsking: 'Asking...',
35
  aiGenerateImage: 'Generate Image',
36
  aiGenerating: 'Generating...',
37
+ aiGeneratedImageURLMessage: 'You can get the image via link:',
38
 
39
  // Settings Panel
40
  settingsTitle: 'Application Settings',
 
149
  aiAsking: '提问中...',
150
  aiGenerateImage: '生成图片',
151
  aiGenerating: '生成中...',
152
+ aiGeneratedImageURLMessage: '您可以通过以下链接获取图片:',
153
 
154
  // Settings Panel
155
  settingsTitle: '应用设置',
 
259
  }
260
  return text;
261
  };
262
+ };