fix: image chunk data broken
This commit is contained in:
@@ -28,6 +28,18 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
|||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDownload = () => {
|
||||||
|
const url = props.audioUrl || '';
|
||||||
|
const filename = Date.now() + '';
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="speech-item">
|
<div className="speech-item">
|
||||||
@@ -60,6 +72,7 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Download">
|
<Tooltip title="Download">
|
||||||
<Button
|
<Button
|
||||||
|
onClick={onDownload}
|
||||||
icon={<DownloadOutlined />}
|
icon={<DownloadOutlined />}
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
.split('\n')
|
.split('\n')
|
||||||
.map((item: string) => {
|
.map((item: string) => {
|
||||||
return {
|
return {
|
||||||
text: item,
|
text: item?.trim(),
|
||||||
uid: inputListRef.current?.setMessageId(),
|
uid: inputListRef.current?.setMessageId(),
|
||||||
name: ''
|
name: ''
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import SealInput from '@/components/seal-form/seal-input';
|
|||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import ThumbImg from '@/pages/playground/components/thumb-img';
|
import ThumbImg from '@/pages/playground/components/thumb-img';
|
||||||
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
|
import {
|
||||||
|
fetchChunkedData,
|
||||||
|
readLargeStreamData as readStreamData
|
||||||
|
} from '@/utils/fetch-chunk-data';
|
||||||
import { FileImageOutlined, SwapOutlined } from '@ant-design/icons';
|
import { FileImageOutlined, SwapOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import { Button, Form, Tooltip } from 'antd';
|
import { Button, Form, Tooltip } from 'antd';
|
||||||
@@ -138,18 +141,28 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const setImageSize = useCallback(() => {
|
const setImageSize = useCallback(() => {
|
||||||
let size: Record<string, string | number> = {
|
let size: Record<string, string | number> = {
|
||||||
|
with: 256,
|
||||||
|
height: 256,
|
||||||
span: 12
|
span: 12
|
||||||
};
|
};
|
||||||
if (parameters.n === 1) {
|
if (parameters.n === 1) {
|
||||||
|
size.width = '100%';
|
||||||
|
size.height = '100%';
|
||||||
size.span = 24;
|
size.span = 24;
|
||||||
}
|
}
|
||||||
if (parameters.n === 2) {
|
if (parameters.n === 2) {
|
||||||
|
size.width = '50%';
|
||||||
|
size.height = 256;
|
||||||
size.span = 12;
|
size.span = 12;
|
||||||
}
|
}
|
||||||
if (parameters.n === 3) {
|
if (parameters.n === 3) {
|
||||||
|
size.width = '33%';
|
||||||
|
size.height = 256;
|
||||||
size.span = 12;
|
size.span = 12;
|
||||||
}
|
}
|
||||||
if (parameters.n === 4) {
|
if (parameters.n === 4) {
|
||||||
|
size.width = '25%';
|
||||||
|
size.height = 256;
|
||||||
size.span = 12;
|
size.span = 12;
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
@@ -210,8 +223,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const params = {
|
const params = {
|
||||||
stream: true,
|
stream: true,
|
||||||
stream_options: {
|
stream_options: {
|
||||||
chunk_result: true,
|
chunk_result: true
|
||||||
chunk_size: 16 * 1024
|
|
||||||
},
|
},
|
||||||
prompt: current?.content || currentPrompt || '',
|
prompt: current?.content || currentPrompt || '',
|
||||||
..._.omitBy(finalParameters, (value: string) => !value)
|
..._.omitBy(finalParameters, (value: string) => !value)
|
||||||
@@ -220,7 +232,6 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const result: any = await fetchChunkedData({
|
const result: any = await fetchChunkedData({
|
||||||
data: params,
|
data: params,
|
||||||
url: CREAT_IMAGE_API,
|
url: CREAT_IMAGE_API,
|
||||||
// url: 'http://192.168.50.27:9090/v1/images/generations',
|
|
||||||
signal: requestToken.current.signal
|
signal: requestToken.current.signal
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,12 +246,13 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log('imgItem.dataUrl:', chunk.data);
|
||||||
chunk?.data?.forEach((item: any) => {
|
chunk?.data?.forEach((item: any) => {
|
||||||
const imgItem = newImageList[item.index];
|
const imgItem = newImageList[item.index];
|
||||||
if (item.b64_json) {
|
if (item.b64_json) {
|
||||||
imgItem.dataUrl += item.b64_json;
|
imgItem.dataUrl += item.b64_json;
|
||||||
// imgItem.cache.push(item.b64_json);
|
// imgItem.cache.push(item.b64_json);
|
||||||
|
console.log('imgItem.dataUrl:', imgItem.dataUrl);
|
||||||
}
|
}
|
||||||
const progress = _.round(item.progress, 0);
|
const progress = _.round(item.progress, 0);
|
||||||
newImageList[item.index] = {
|
newImageList[item.index] = {
|
||||||
@@ -295,7 +307,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
setParams((pre: object) => {
|
setParams((pre: object) => {
|
||||||
return {
|
return {
|
||||||
...pre,
|
..._.omit(pre, ['quality', 'style']),
|
||||||
seed: null,
|
seed: null,
|
||||||
sampler: 'euler_a',
|
sampler: 'euler_a',
|
||||||
cfg_scale: 1,
|
cfg_scale: 1,
|
||||||
@@ -306,6 +318,8 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
} else {
|
} else {
|
||||||
setParams((pre: object) => {
|
setParams((pre: object) => {
|
||||||
return {
|
return {
|
||||||
|
quality: 'standard',
|
||||||
|
style: null,
|
||||||
..._.omit(pre, [
|
..._.omit(pre, [
|
||||||
'seed',
|
'seed',
|
||||||
'sampler',
|
'sampler',
|
||||||
@@ -320,6 +334,9 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderExtra = useMemo(() => {
|
const renderExtra = useMemo(() => {
|
||||||
|
if (!isOpenaiCompatible) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
return ImageconstExtraConfig.map((item: ParamsSchema) => {
|
return ImageconstExtraConfig.map((item: ParamsSchema) => {
|
||||||
return (
|
return (
|
||||||
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
@@ -335,7 +352,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, [ImageconstExtraConfig, intl]);
|
}, [ImageconstExtraConfig, isOpenaiCompatible, intl]);
|
||||||
|
|
||||||
const renderAdvanced = useMemo(() => {
|
const renderAdvanced = useMemo(() => {
|
||||||
if (isOpenaiCompatible) {
|
if (isOpenaiCompatible) {
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
.split('\n')
|
.split('\n')
|
||||||
.map((item: string) => {
|
.map((item: string) => {
|
||||||
return {
|
return {
|
||||||
text: item,
|
text: item?.trim(),
|
||||||
uid: inputListRef.current?.setMessageId(),
|
uid: inputListRef.current?.setMessageId(),
|
||||||
name: ''
|
name: ''
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -112,12 +112,12 @@ export const ImageParamsConfig: ParamsSchema[] = [
|
|||||||
type: 'Select',
|
type: 'Select',
|
||||||
name: 'size',
|
name: 'size',
|
||||||
options: [
|
options: [
|
||||||
|
{ label: 'playground.params.custom', value: 'custom', locale: true },
|
||||||
{ label: '256x256', value: '256x256' },
|
{ label: '256x256', value: '256x256' },
|
||||||
{ label: '512x512', value: '512x512' },
|
{ label: '512x512', value: '512x512' },
|
||||||
{ label: '1024x1024', value: '1024x1024' },
|
{ label: '1024x1024', value: '1024x1024' },
|
||||||
{ label: '1792x1024', value: '1792x1024' },
|
{ label: '1792x1024', value: '1792x1024' },
|
||||||
{ label: '1024x1792', value: '1024x1792' },
|
{ label: '1024x1792', value: '1024x1792' }
|
||||||
{ label: 'playground.params.custom', value: 'custom', locale: true }
|
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'playground.params.size',
|
text: 'playground.params.size',
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ export const fetchChunkedData = async (params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const reader = response?.body?.getReader();
|
const reader = response?.body?.getReader();
|
||||||
const decoder = new TextDecoder('utf-8');
|
const decoder = new TextDecoder('utf-8', {
|
||||||
|
fatal: true
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
reader,
|
reader,
|
||||||
decoder
|
decoder
|
||||||
@@ -77,12 +79,54 @@ export const readStreamData = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
let chunk = decoder.decode(value, { stream: true });
|
let chunk = decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
extractJSON(chunk).forEach((data) => {
|
extractJSON(chunk).forEach((data) => {
|
||||||
callback?.(data);
|
callback?.(data);
|
||||||
});
|
});
|
||||||
await readStreamData(reader, decoder, callback);
|
await readStreamData(reader, decoder, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const readLargeStreamData = async (
|
||||||
|
reader: any,
|
||||||
|
decoder: TextDecoder,
|
||||||
|
callback: (data: any) => void
|
||||||
|
) => {
|
||||||
|
let buffer = '';
|
||||||
|
|
||||||
|
const processStream = async () => {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
if (buffer) {
|
||||||
|
try {
|
||||||
|
extractJSON(buffer).forEach((data) => {
|
||||||
|
callback?.(data);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('parse buffer failed:', buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache each chunk
|
||||||
|
buffer += decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
|
const extractedData = extractJSON(buffer);
|
||||||
|
|
||||||
|
extractedData.forEach((data) => {
|
||||||
|
callback?.(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastIndex = buffer.lastIndexOf('}');
|
||||||
|
buffer = lastIndex !== -1 ? buffer.slice(lastIndex + 1) : buffer;
|
||||||
|
|
||||||
|
// next chunk
|
||||||
|
await processStream();
|
||||||
|
};
|
||||||
|
|
||||||
|
await processStream();
|
||||||
|
};
|
||||||
|
|
||||||
export const readTextEventStreamData = async (
|
export const readTextEventStreamData = async (
|
||||||
reader: any,
|
reader: any,
|
||||||
decoder: TextDecoder,
|
decoder: TextDecoder,
|
||||||
|
|||||||
Reference in New Issue
Block a user