diff --git a/src/components/auto-image/index.tsx b/src/components/auto-image/index.tsx index a40d91a0..06750c87 100644 --- a/src/components/auto-image/index.tsx +++ b/src/components/auto-image/index.tsx @@ -45,6 +45,7 @@ const AutoImage: React.FC< return; } const { ratio } = await getImgRatio(props.src || ''); + console.log('ratio', ratio); if (typeof height === 'number') { setWidth(height * ratio); } else { @@ -66,6 +67,7 @@ const AutoImage: React.FC< const handleImgLoad = useCallback(() => { props.onLoad?.(); + setIsError(false); }, [props.onLoad]); const handleOnError = () => { diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index c7b71af8..5a1cdf51 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; // import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_hdf3t88r4j.js' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_bslq45omhet.js' }); export default IconFont; diff --git a/src/components/image-editor/index.tsx b/src/components/image-editor/index.tsx index afb0cf33..eb988c57 100644 --- a/src/components/image-editor/index.tsx +++ b/src/components/image-editor/index.tsx @@ -16,7 +16,7 @@ type Stroke = Point[]; type CanvasImageEditorProps = { imageSrc: string; disabled?: boolean; - onSave: (imageData: string) => void; + onSave: (imageData: { mask: string; img: string }) => void; uploadButton: React.ReactNode; imageStatus: { isOriginal: boolean; @@ -131,20 +131,44 @@ const CanvasImageEditor: React.FC = ({ const maskCanvas = document.createElement('canvas'); maskCanvas.width = overlayCanvas.width; maskCanvas.height = overlayCanvas.height; - const maskCtx = maskCanvas.getContext('2d'); + const maskCtx = maskCanvas.getContext('2d')!; + const overlayCtx = overlayCanvas.getContext('2d')!; + + const imageData = overlayCtx.getImageData( + 0, + 0, + overlayCanvas.width, + overlayCanvas.height + ); + const data = imageData.data; + + for (let i = 0; i < data.length; i += 4) { + const alpha = data[i + 3]; + if (alpha > 0) { + data[i] = 255; // Red + data[i + 1] = 255; // Green + data[i + 2] = 255; // Blue + data[i + 3] = 255; // Alpha + } + } + maskCtx.putImageData(imageData, 0, 0); - // Create the transparent overlay - maskCtx!.fillStyle = 'black'; - maskCtx!.fillRect(0, 0, maskCanvas.width, maskCanvas.height); - maskCtx!.globalCompositeOperation = 'destination-out'; - maskCtx!.drawImage(overlayCanvas, 0, 0); + maskCtx.globalCompositeOperation = 'destination-over'; + maskCtx.fillStyle = 'black'; + maskCtx.fillRect(0, 0, maskCanvas.width, maskCanvas.height); return maskCanvas.toDataURL('image/png'); }, []); - const saveMask = useCallback(() => { + const generateImage = useCallback(() => { + const canvas = canvasRef.current!; + return canvas.toDataURL('image/png'); + }, []); + + const saveImage = useCallback(() => { const mask = generateMask(); - onSave(mask); + const img = generateImage(); + onSave({ mask, img }); }, [onSave, generateMask]); const downloadMask = useCallback(() => { @@ -273,7 +297,7 @@ const CanvasImageEditor: React.FC = ({ currentStroke.current = []; - saveMask(); + saveImage(); }; const clearOverlayCanvas = useCallback(() => { @@ -560,7 +584,7 @@ const CanvasImageEditor: React.FC = ({
diff --git a/src/components/status-tag/index.tsx b/src/components/status-tag/index.tsx index e4aade7a..056a01b5 100644 --- a/src/components/status-tag/index.tsx +++ b/src/components/status-tag/index.tsx @@ -82,7 +82,7 @@ const StatusTag: React.FC = ({ > {actions?.map((item) => { return ( - <> +
= ({ {item.icon} - +
); })}
diff --git a/src/pages/playground/components/ground-images.tsx b/src/pages/playground/components/ground-images.tsx index d02fe8a7..713b7749 100644 --- a/src/pages/playground/components/ground-images.tsx +++ b/src/pages/playground/components/ground-images.tsx @@ -52,6 +52,7 @@ const advancedFieldsDefaultValus = { seed: null, sample_method: 'euler_a', cfg_scale: 4.5, + guidance: 3.5, sampling_steps: 10, negative_prompt: null, schedule_method: 'discrete', @@ -404,6 +405,9 @@ const GroundImages: React.FC = forwardRef((props, ref) => { } const formValues = form.current?.form?.getFieldsValue(); return ImageAdvancedParamsConfig.map((item: ParamsSchema) => { + if (item.name === 'strength') { + return null; + } return ( = forwardRef((props, ref) => { ? item.disabledConfig?.when?.(formValues) : item.disabled } + description={ + item.description?.isLocalized + ? intl.formatMessage({ id: item.description.text }) + : item.description?.text + } onChange={item.name === 'random_seed' ? handleFieldChange : null} {..._.omit(item, ['name', 'rules', 'disabledConfig'])} > diff --git a/src/pages/playground/components/image-edit.tsx b/src/pages/playground/components/image-edit.tsx index eb6c2985..06f070bd 100644 --- a/src/pages/playground/components/image-edit.tsx +++ b/src/pages/playground/components/image-edit.tsx @@ -53,6 +53,8 @@ const advancedFieldsDefaultValus = { seed: 1, sample_method: 'euler_a', cfg_scale: 4.5, + guidance: 3.5, + strength: 0.75, sampling_steps: 10, negative_prompt: null, preview: null, @@ -152,10 +154,12 @@ const GroundImages: React.FC = forwardRef((props, ref) => { }, [parameters.n]); const imageFile = useMemo(() => { + console.log('image:', image); return base64ToFile(image, 'image'); }, [image]); const maskFile = useMemo(() => { + console.log('mask:', mask); return base64ToFile(mask, 'mask'); }, [mask]); @@ -222,7 +226,9 @@ const GroundImages: React.FC = forwardRef((props, ref) => { setCurrentPrompt(current?.content || ''); setRouteCache(routeCachekey.playgroundTextToImage, true); - const imgSize = _.split(finalParameters.size, 'x'); + const imgSize = _.split(finalParameters.size, 'x').map((item: string) => + _.toNumber(item) + ); // preview let stream_options: Record = { @@ -278,9 +284,12 @@ const GroundImages: React.FC = forwardRef((props, ref) => { const result: any = await fetchChunkedData({ data: params, + // url: `http://192.168.50.174:40935/v1/images/edits?t=${Date.now()}`, url: `${EDIT_IMAGE_API}?t=${Date.now()}`, signal: requestToken.current.signal }); + + console.log('result:', result); if (result.error) { setTokenResult({ error: true, @@ -432,6 +441,11 @@ const GroundImages: React.FC = forwardRef((props, ref) => { ? item.disabledConfig?.when?.(formValues) : item.disabled } + description={ + item.description?.isLocalized + ? intl.formatMessage({ id: item.description.text }) + : item.description?.text || '' + } onChange={item.name === 'random_seed' ? handleFieldChange : null} {..._.omit(item, ['name', 'rules', 'disabledConfig'])} > @@ -494,16 +508,16 @@ const GroundImages: React.FC = forwardRef((props, ref) => { setImageList([]); }, []); - const handleOnSave = useCallback((url: string) => { + const handleOnSave = useCallback((data: { img: string; mask: string }) => { setImageStatus({ isOriginal: true, isResetNeeded: false }); - setMask(url); + setMask(data.mask); + setImage(data.img); }, []); const renderImageEditor = useMemo(() => { - console.log('image:', image); if (image) { return ( = forwardRef((props, ref) => { disabled={loading} handleUpdateImgList={handleUpdateImageList} size="middle" + accept="image/png" > } @@ -525,6 +540,7 @@ const GroundImages: React.FC = forwardRef((props, ref) => { } return ( = forwardRef((props, ref) => {
void; @@ -24,6 +25,7 @@ const UploadImg: React.FC = ({ drag = false, disabled = false, children, + accept = 'image/*', size = 'small' }) => { const intl = useIntl(); @@ -81,7 +83,7 @@ const UploadImg: React.FC = ({ {drag ? ( = ({ ) : ( { {intl.formatMessage({ id: 'menu.playground.text2images' })} - {/* { + { setActiveKey(key)} > - } */} + }
), breadcrumb: {} diff --git a/src/utils/fetch-chunk-data.ts b/src/utils/fetch-chunk-data.ts index 0b3dcacb..8b55869b 100644 --- a/src/utils/fetch-chunk-data.ts +++ b/src/utils/fetch-chunk-data.ts @@ -72,13 +72,10 @@ const createFormData = (data: any): FormData => { const appendToFormData = (key: string, value: any) => { if (value instanceof File) { - // 处理文件类型 formData.append(key, value); } else if (typeof value === 'object' && value !== null) { - // 如果是对象或数组,序列化为 JSON 字符串 formData.append(key, JSON.stringify(value)); } else { - // 处理基本数据类型 formData.append(key, String(value)); } }; @@ -106,7 +103,6 @@ export const fetchChunkedDataPostFormData = async (params: { body: createFormData(params.data), signal: params.signal }); - console.log('response====', response); if (!response.ok) { return { error: true, @@ -170,6 +166,7 @@ export const readLargeStreamData = async ( while (true) { const { done, value } = await reader?.read?.(); + if (done) { // Process remaining buffered data if (buffer.trim()) { @@ -198,6 +195,12 @@ export const readLargeStreamData = async ( console.error('Failed to parse JSON:', jsonStr, e); } } + + if (line.startsWith('error:')) { + const errorStr = line.slice(7).trim(); + const jsonData = JSON.parse(errorStr); + callback({ error: jsonData }); + } } } };