fix: row-textarea upload img
This commit is contained in:
@@ -81,9 +81,6 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||
onChange?.(e);
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
onChange?.({ target: { value: '' } });
|
||||
};
|
||||
const handleOnPaste = (e: any) => {
|
||||
props.onPaste?.(e);
|
||||
};
|
||||
@@ -119,20 +116,41 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||
updateUidCount: () => `img-${Date.now()}`
|
||||
});
|
||||
|
||||
const handleClear = () => {
|
||||
onChange?.({ target: { value: '' } });
|
||||
onDeleteImage?.([]);
|
||||
};
|
||||
|
||||
const handleDeleteImage = (uid: number) => {
|
||||
const updatedImgs = (data.imgs || []).filter((img) => img.uid !== uid);
|
||||
onDeleteImage?.(updatedImgs);
|
||||
};
|
||||
|
||||
const expanded = autoSize.focus || !!data.imgs?.length || isFromUrl;
|
||||
const renderTextContent = () => {
|
||||
if (data.imgs?.length || isFromUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('expanded===========', expanded);
|
||||
return (
|
||||
<>
|
||||
{label && <span className="title">{label}</span>}
|
||||
{data.content || (
|
||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
||||
{placeholder}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const expanded = autoSize.focus && !isFromUrl && !data.imgs?.length;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('row-textarea-wrapper', {
|
||||
dropDownOpen: dropDownOpen,
|
||||
expanded: expanded
|
||||
expanded: expanded,
|
||||
'from-url': isFromUrl
|
||||
})}
|
||||
>
|
||||
<div
|
||||
@@ -141,51 +159,45 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||
})}
|
||||
style={{ ...style }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: expanded ? 'block' : 'none'
|
||||
}}
|
||||
className="textarea-wrapper"
|
||||
>
|
||||
{label && <span className="textarea-label">{label}</span>}
|
||||
{!!data.imgs?.length && (
|
||||
<div style={{ padding: 8 }}>
|
||||
<ThumbImg
|
||||
editable
|
||||
dataList={data.imgs}
|
||||
onDelete={handleDeleteImage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Input.TextArea
|
||||
className="custome-scrollbar"
|
||||
allowClear
|
||||
ref={rowTextAreaRef}
|
||||
placeholder={placeholder}
|
||||
{!data.imgs?.length && (
|
||||
<div
|
||||
style={{
|
||||
borderRadius: '0',
|
||||
border: 'none',
|
||||
width: '100%',
|
||||
boxShadow: 'none'
|
||||
display: expanded ? 'block' : 'none'
|
||||
}}
|
||||
value={data.content}
|
||||
autoSize={
|
||||
expanded
|
||||
? {
|
||||
minRows: 5,
|
||||
maxRows: 5
|
||||
}
|
||||
: { minRows: autoSize.minRows, maxRows: autoSize.maxRows }
|
||||
className="textarea-wrapper"
|
||||
>
|
||||
{label && <span className="textarea-label">{label}</span>}
|
||||
{
|
||||
<Input.TextArea
|
||||
className="custome-scrollbar"
|
||||
allowClear
|
||||
ref={rowTextAreaRef}
|
||||
placeholder={placeholder}
|
||||
style={{
|
||||
borderRadius: '0',
|
||||
border: 'none',
|
||||
width: '100%',
|
||||
boxShadow: 'none'
|
||||
}}
|
||||
value={data.content}
|
||||
autoSize={
|
||||
expanded
|
||||
? {
|
||||
minRows: 5,
|
||||
maxRows: 5
|
||||
}
|
||||
: { minRows: autoSize.minRows, maxRows: autoSize.maxRows }
|
||||
}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onChange={handleOnChange}
|
||||
onSelect={handleOnSelect}
|
||||
onPaste={handleOnPaste}
|
||||
onClear={handleClear}
|
||||
></Input.TextArea>
|
||||
}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onChange={handleOnChange}
|
||||
onSelect={handleOnSelect}
|
||||
onPaste={handleOnPaste}
|
||||
onClear={handleClear}
|
||||
></Input.TextArea>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!expanded && (
|
||||
<div
|
||||
@@ -194,16 +206,19 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||
})}
|
||||
onClick={handleFocus}
|
||||
>
|
||||
{
|
||||
<div className="content" style={{ height: height }}>
|
||||
{label && <span className="title">{label}</span>}
|
||||
{data.content || (
|
||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
||||
{placeholder}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
<div className="content" style={{ height: height }}>
|
||||
{renderTextContent()}
|
||||
{!!data.imgs?.length && (
|
||||
<div className="flex-center">
|
||||
{label && <span className="title">{label}</span>}
|
||||
<ThumbImg
|
||||
editable
|
||||
dataList={data.imgs}
|
||||
onDelete={handleDeleteImage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
@@ -213,7 +228,7 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||
>
|
||||
{ImageURLInput}
|
||||
<div className={'actions'}>
|
||||
{!expanded && data.content && (
|
||||
{!expanded && (data.content || !!data.imgs?.length) && (
|
||||
<SmallCloseButton onClick={handleClear}></SmallCloseButton>
|
||||
)}
|
||||
{UploadImageButton}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
border-radius: var(--ant-border-radius);
|
||||
@@ -37,6 +38,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.from-url {
|
||||
.actions-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
.actions-wrapper {
|
||||
display: flex;
|
||||
|
||||
@@ -41,7 +41,7 @@ export const rerankerQuery = async (
|
||||
model: string;
|
||||
query: string;
|
||||
top_n: number;
|
||||
documents: string[];
|
||||
documents: any[];
|
||||
},
|
||||
options?: any
|
||||
) => {
|
||||
@@ -57,7 +57,7 @@ export const handleEmbedding = async (
|
||||
model: string;
|
||||
encoding_format?: string;
|
||||
dimensions?: number;
|
||||
input: string[];
|
||||
input?: any[];
|
||||
messages?: {
|
||||
role: string;
|
||||
content: Array<{
|
||||
|
||||
@@ -308,7 +308,13 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
newList[index] = {
|
||||
...current,
|
||||
content: '',
|
||||
imgs: list
|
||||
imgs: list.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
width: 32,
|
||||
height: 32
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
return newList;
|
||||
|
||||
@@ -19,6 +19,7 @@ const ImgInputWrapper = styled.div`
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-radius: var(--ant-border-radius);
|
||||
background: var(--ant-color-bg-container);
|
||||
}
|
||||
&:hover {
|
||||
@@ -85,7 +86,8 @@ const useAddImage = (options: {
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
const handleClose = (e?: any) => {
|
||||
e?.stopPropagation();
|
||||
setIsFromUrl(false);
|
||||
setOpenImgTips(false);
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ import InputList from '../components/input-list';
|
||||
import RightContainer from '../components/right-container';
|
||||
import TokenUsage from '../components/token-usage';
|
||||
import ViewCommonCode from '../components/view-common-code';
|
||||
import { extractErrorMessage } from '../config';
|
||||
import { extractErrorMessage, generateMessagesByListContent } from '../config';
|
||||
import { rerankerSamples } from '../config/samples';
|
||||
import { LLM_METAKEYS } from '../hooks/config';
|
||||
import { useInitLLmMeta } from '../hooks/use-init-llm';
|
||||
@@ -72,42 +72,32 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const requestToken = useRef<any>(null);
|
||||
const multiplePasteEnable = useRef<boolean>(true);
|
||||
const [isEmptyText, setIsEmptyText] = useState<boolean>(false);
|
||||
const [fileList, setFileList] = useState<
|
||||
{
|
||||
text: string;
|
||||
name: string;
|
||||
uid: number | string;
|
||||
score?: number;
|
||||
showExtra?: boolean;
|
||||
percent?: number;
|
||||
rank?: number;
|
||||
}[]
|
||||
>([]);
|
||||
const [isEmptyQuery, setIsEmptyQuery] = useState<boolean>(false);
|
||||
|
||||
const [textList, setTextList] = useState<
|
||||
{
|
||||
text: string;
|
||||
content: string;
|
||||
uid: number | string;
|
||||
name: string;
|
||||
score?: number;
|
||||
showExtra?: boolean;
|
||||
dataUrl?: string;
|
||||
imgs?: { uid: number | string; dataUrl: string }[];
|
||||
percent?: number;
|
||||
rank?: number;
|
||||
role: string;
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
text: '',
|
||||
content: '',
|
||||
uid: -1,
|
||||
name: '',
|
||||
dataUrl: ''
|
||||
role: 'user'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
content: '',
|
||||
uid: -2,
|
||||
name: '',
|
||||
dataUrl: ''
|
||||
role: 'user'
|
||||
}
|
||||
]);
|
||||
const [queryValue, setQueryValue] = useState<string>('');
|
||||
@@ -152,9 +142,10 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
if (sample) {
|
||||
setTextList(
|
||||
sample.documents.map((item: string, index: number) => ({
|
||||
text: item,
|
||||
content: item,
|
||||
uid: setMessageId(),
|
||||
name: `Document ${index + 1}`,
|
||||
role: 'user',
|
||||
percent: undefined,
|
||||
score: undefined,
|
||||
rank: undefined
|
||||
@@ -165,18 +156,40 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const formatDocuments = (
|
||||
list: {
|
||||
content: string;
|
||||
imgs?: { uid: number | string; dataUrl: string }[];
|
||||
uid: number | string;
|
||||
name: string;
|
||||
role?: string;
|
||||
}[]
|
||||
) => {
|
||||
const validTextList = list.filter(
|
||||
(item) => item.content || item.imgs?.length
|
||||
);
|
||||
|
||||
const hasImages = validTextList.some((item) => item.imgs?.length);
|
||||
|
||||
if (hasImages) {
|
||||
return generateMessagesByListContent(validTextList, true).map(
|
||||
(msg: any) => ({ content: msg.content })
|
||||
);
|
||||
}
|
||||
|
||||
return validTextList.map((item) => item.content || '');
|
||||
};
|
||||
|
||||
const viewCodeContent = useMemo(() => {
|
||||
return generateRerankCode({
|
||||
api: RERANKER_API,
|
||||
parameters: {
|
||||
...parameters,
|
||||
query: queryValue,
|
||||
documents: [...textList, ...fileList]
|
||||
.map((item) => item.text)
|
||||
.filter((text) => text)
|
||||
documents: formatDocuments(textList as any)
|
||||
}
|
||||
});
|
||||
}, [parameters, queryValue, textList, fileList]);
|
||||
}, [parameters, queryValue, textList]);
|
||||
|
||||
// [0.1, 1.0]
|
||||
const normalizValue = (data: { min: number; max: number; value: number }) => {
|
||||
@@ -232,9 +245,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
await formRef.current?.form.validateFields();
|
||||
|
||||
if (!parameters.model || !queryValue) return;
|
||||
const documentList: any[] = [...textList, ...fileList];
|
||||
const documentList: any[] = [...textList];
|
||||
|
||||
const validDocus = documentList.filter((item) => item.text);
|
||||
const validDocus = documentList.filter(
|
||||
(item) => item.content || item.imgs?.length
|
||||
);
|
||||
|
||||
if (!validDocus.length) {
|
||||
setIsEmptyText(true);
|
||||
@@ -247,7 +262,9 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
requestToken.current?.cancel?.();
|
||||
requestToken.current = requestSource();
|
||||
|
||||
const filledList = textList.filter((item) => item.text);
|
||||
const filledList = textList.filter(
|
||||
(item) => item.content || item.imgs?.length
|
||||
);
|
||||
|
||||
setTextList(filledList);
|
||||
|
||||
@@ -256,7 +273,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
model: parameters.model,
|
||||
top_n: parameters.top_n,
|
||||
query: query,
|
||||
documents: filledList.map((item) => item.text)
|
||||
documents: formatDocuments(filledList)
|
||||
},
|
||||
{
|
||||
token: requestToken.current.token
|
||||
@@ -332,7 +349,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
};
|
||||
|
||||
const handleTextListChange = (
|
||||
list: { text: string; uid: number | string; name: string }[]
|
||||
list: { content: string; uid: number | string; name: string }[]
|
||||
) => {
|
||||
const newList = list?.map((item: any) => {
|
||||
item.percent = undefined;
|
||||
@@ -357,35 +374,33 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
list: { uid: number | string; dataUrl: string }[],
|
||||
index: number
|
||||
) => {
|
||||
// replace the text with dataUrl in the textList
|
||||
setTextList((preList) => {
|
||||
const newList = [...preList];
|
||||
const current = newList[index];
|
||||
if (current) {
|
||||
newList[index] = {
|
||||
...current,
|
||||
text: '',
|
||||
uid: list[0].uid,
|
||||
dataUrl: list[0].dataUrl
|
||||
content: '',
|
||||
imgs: list.map((item) => ({
|
||||
...item,
|
||||
width: 32,
|
||||
height: 32
|
||||
}))
|
||||
};
|
||||
}
|
||||
return newList;
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnDeleteImage = (item: {
|
||||
text: string;
|
||||
uid: number | string;
|
||||
name: string;
|
||||
dataUrl?: string;
|
||||
}) => {
|
||||
// replace the dataUrl with empty text in the textList
|
||||
const handleOnDeleteImage = (
|
||||
itemUid: number | string,
|
||||
updatedImgs: { uid: number | string; dataUrl: string }[]
|
||||
) => {
|
||||
setTextList((preList) => {
|
||||
const newList = [...preList];
|
||||
const current = newList.find((i) => i.uid === item.uid);
|
||||
const current = newList.find((i) => i.uid === itemUid);
|
||||
if (current) {
|
||||
current.text = '';
|
||||
current.dataUrl = '';
|
||||
current.imgs = updatedImgs;
|
||||
}
|
||||
return newList;
|
||||
});
|
||||
@@ -397,20 +412,21 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
if (text) {
|
||||
const dataLlist = text.split('\n').map((item: string) => {
|
||||
return {
|
||||
text: item?.trim(),
|
||||
content: item?.trim(),
|
||||
name: '',
|
||||
uid: setMessageId(),
|
||||
role: 'user',
|
||||
percent: undefined,
|
||||
score: undefined,
|
||||
rank: undefined
|
||||
};
|
||||
});
|
||||
dataLlist[0].text = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].text}${selectionTextRef.current?.afterText || ''}`;
|
||||
dataLlist[0].content = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].content}${selectionTextRef.current?.afterText || ''}`;
|
||||
const result = [
|
||||
...textList.slice(0, index),
|
||||
...dataLlist,
|
||||
...textList.slice(index + 1)
|
||||
].filter((item) => item.text);
|
||||
].filter((item) => item.content || item.imgs?.length);
|
||||
|
||||
setTextList(result);
|
||||
}
|
||||
@@ -419,17 +435,18 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const handleClearDocuments = () => {
|
||||
setTextList([
|
||||
{
|
||||
text: '',
|
||||
content: '',
|
||||
uid: setMessageId(),
|
||||
name: ''
|
||||
name: '',
|
||||
role: 'user'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
content: '',
|
||||
uid: setMessageId(),
|
||||
name: ''
|
||||
name: '',
|
||||
role: 'user'
|
||||
}
|
||||
]);
|
||||
setFileList([]);
|
||||
setTokenResult(null);
|
||||
setIsEmptyText(false);
|
||||
};
|
||||
@@ -448,11 +465,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
}, [initialize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (textList.length + fileList.length > messageListLengthCache.current) {
|
||||
if (textList.length > messageListLengthCache.current) {
|
||||
updateDocumentScrollerPosition();
|
||||
}
|
||||
messageListLengthCache.current = textList.length + fileList.length;
|
||||
}, [textList.length, fileList.length]);
|
||||
messageListLengthCache.current = textList.length;
|
||||
}, [textList.length]);
|
||||
|
||||
return (
|
||||
<div className="ground-left-wrapper rerank">
|
||||
|
||||
Reference in New Issue
Block a user