chore: create, edit image handler

This commit is contained in:
jialin
2025-11-12 20:47:34 +08:00
parent a34c375e2d
commit 03963b736a
5 changed files with 86 additions and 102 deletions
+15 -11
View File
@@ -1,5 +1,5 @@
import { CloseCircleOutlined } from '@ant-design/icons';
import { Progress, ProgressProps } from 'antd';
import { CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons';
import { Progress, ProgressProps, Spin } from 'antd';
import classNames from 'classnames';
import { round } from 'lodash';
import ResizeObserver from 'rc-resize-observer';
@@ -94,6 +94,17 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
const handleOnLoad = React.useCallback(async () => {}, []);
const renderProgress = () => {
<Progress
percent={round(progress, 0)}
type="dashboard"
size={loadingSize}
steps={{ count: 50, gap: 2 }}
format={() => <span className="font-size-20">{round(progress, 0)}%</span>}
trailColor="var(--ant-color-fill-secondary)"
/>;
};
return (
<ResizeObserver onResize={handleResize}>
<div
@@ -135,15 +146,8 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
overflow: 'hidden'
}}
>
<Progress
percent={round(progress, 0)}
type="dashboard"
size={loadingSize}
steps={{ count: 50, gap: 2 }}
format={() => (
<span className="font-size-20">{round(progress, 0)}%</span>
)}
trailColor="var(--ant-color-fill-secondary)"
<Spin
indicator={<LoadingOutlined style={{ fontSize: 32 }} spin />}
/>
</span>
) : (
+36
View File
@@ -1,4 +1,5 @@
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
import { createFormData, errorHandler } from '@/utils/fetch-chunk-data';
import { request } from '@umijs/max';
export const OPENAI_COMPATIBLE = 'v1-openai';
@@ -94,6 +95,41 @@ export const createImages = async (
return res.json();
};
// =========== edit image ============
export const editImage = async (params: {
data?: any;
signal?: AbortSignal;
}) => {
const response = await fetch(EDIT_IMAGE_API, {
method: 'POST',
body: createFormData(params.data),
signal: params.signal
});
if (!response.ok) {
return await errorHandler(response);
}
return response.json();
};
export const createImage = async (params: {
data?: any;
signal?: AbortSignal;
}) => {
const response = await fetch(CREAT_IMAGE_API, {
method: 'POST',
body: JSON.stringify(params.data),
signal: params.signal,
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
return await errorHandler(response);
}
return response.json();
};
// ============ audio ============
export const textToSpeech = async (params: any, options?: any) => {
const res = await fetch(AUDIO_TEXT_TO_SPEECH_API, {
@@ -213,4 +213,4 @@ const ThumbImg: React.FC<{
);
};
export default React.memo(ThumbImg);
export default ThumbImg;
+24 -87
View File
@@ -1,13 +1,14 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { extractErrorMessage, promptList } from '@/pages/playground/config';
import {
fetchChunkedData,
fetchChunkedDataPostFormData
} from '@/utils/fetch-chunk-data';
import { useIntl } from '@umijs/max';
import _ from 'lodash';
import { useEffect, useRef, useState } from 'react';
import { CREAT_IMAGE_API, EDIT_IMAGE_API } from '../apis';
import {
CREAT_IMAGE_API,
EDIT_IMAGE_API,
createImage,
editImage
} from '../apis';
const ODD_STRING = 'AAAABJRU5ErkJgg===';
@@ -126,21 +127,21 @@ export default function useTextImage(props: any) {
let result: any = {};
if (API === CREAT_IMAGE_API) {
result = await fetchChunkedData({
result = await createImage({
data: parameters,
url: `${API}?t=${Date.now()}`,
signal: requestToken.current.signal
});
}
if (API === EDIT_IMAGE_API) {
result = await fetchChunkedDataPostFormData({
result = await editImage({
data: parameters,
url: `${API}?t=${Date.now()}`,
signal: requestToken.current.signal
});
}
console.log('result:', result);
if (result.error) {
setTokenResult({
error: true,
@@ -149,18 +150,19 @@ export default function useTextImage(props: any) {
setImageList([]);
return;
}
console.log('result:', result);
// If the request ID has changed, ignore this chunk
if (requestIdRef.current !== currentRequestId) {
// If the request ID has changed, ignore this chunk
// return;
return;
}
// if (result?.error) {
// setTokenResult({
// error: true,
// errorMessage: extractErrorMessage(result)
// });
// return;
// }
if (result?.error) {
setTokenResult({
error: true,
errorMessage: extractErrorMessage(result)
});
return;
}
result?.data?.forEach((item: any, index: number) => {
const imgItem = newImageList[index];
@@ -168,8 +170,6 @@ export default function useTextImage(props: any) {
imgItem.dataUrl = `data:image/png;base64,${item.b64_json}`;
}
const progress = 100;
newImageList[index] = {
dataUrl: imgItem.dataUrl,
height: imgSize[1],
@@ -178,76 +178,13 @@ export default function useTextImage(props: any) {
maxWidth: `${imgSize[0]}px`,
uid: imgItem.uid,
span: imgItem.span,
loading: _.get(parameters, chunkFields) ? progress < 100 : false,
preview: API === CREAT_IMAGE_API ? progress >= 100 : false,
progress: progress
loading: false,
preview: true,
progress: 100
};
});
console.log('newImageList:', newImageList);
// if (
// done &&
// !chunk?.error &&
// newImageList.some((item) => item.progress < 100)
// ) {
// setTokenResult({
// error: true,
// errorMessage: intl.formatMessage({
// id: 'playground.image.generate.error'
// })
// });
// }
setImageList([...newImageList]);
// const { reader, decoder } = result;
// streamReaderRef.current = reader;
// await readStreamData(reader, decoder, (chunk: any, done?: boolean) => {
// console.log('chunk done:', chunk, done);
// if (requestIdRef.current !== currentRequestId) {
// // If the request ID has changed, ignore this chunk
// return;
// }
// if (chunk?.error) {
// setTokenResult({
// error: true,
// errorMessage: extractErrorMessage(chunk)
// });
// return;
// }
// chunk?.data?.forEach((item: any) => {
// const imgItem = newImageList[item.index];
// if (item.b64_json && _.get(parameters, chunkFields)) {
// imgItem.dataUrl += removeBase64Suffix(item.b64_json, ODD_STRING);
// } else if (item.b64_json) {
// imgItem.dataUrl = `data:image/png;base64,${removeBase64Suffix(item.b64_json, ODD_STRING)}`;
// }
// const progress = item.progress;
// newImageList[item.index] = {
// dataUrl: imgItem.dataUrl,
// height: imgSize[1],
// width: imgSize[0],
// maxHeight: `${imgSize[1]}px`,
// maxWidth: `${imgSize[0]}px`,
// uid: imgItem.uid,
// span: imgItem.span,
// loading: _.get(parameters, chunkFields) ? progress < 100 : false,
// preview: API === CREAT_IMAGE_API ? progress >= 100 : false,
// progress: progress
// };
// });
// if (
// done &&
// !chunk?.error &&
// newImageList.some((item) => item.progress < 100)
// ) {
// setTokenResult({
// error: true,
// errorMessage: intl.formatMessage({
// id: 'playground.image.generate.error'
// })
// });
// }
// setImageList([...newImageList]);
// });
} catch (error) {
console.log('error:', error);
updateRequestId();
+10 -3
View File
@@ -32,7 +32,7 @@ const extractJSON = (
return { results, remaining };
};
const errorHandler = async (res: any) => {
export const errorHandler = async (res: any) => {
try {
const data = await res.json();
return {
@@ -78,10 +78,17 @@ export const fetchChunkedData = async (params: {
if (!response.ok) {
return await errorHandler(response);
}
return response.json();
const reader = response?.body?.getReader();
const decoder = new TextDecoder('utf-8', {
fatal: true
});
return {
reader,
decoder
};
};
const createFormData = (data: any): FormData => {
export const createFormData = (data: any): FormData => {
const formData = new FormData();
const appendToFormData = (key: string, value: any) => {