4.8.8 test fix (#2149)

* perf: code comment

* feat: system plugin input guide

* perf: variable avatar

* feat: feishu webhook

* perf: select tool config tip

* perf: rename variable

* fix: per inherit error

* perf: docker-compose oneapi version and i18n

* perf: ui tip bug

* fix: ts

* perf: pg log

* perf: editor color

* perf: update init
This commit is contained in:
Archer
2024-07-26 10:23:44 +08:00
committed by GitHub
parent 2d016b7462
commit cd554f573e
59 changed files with 1648 additions and 506 deletions

View File

@@ -36,4 +36,4 @@ const MdImage = ({ src }: { src?: string }) => {
);
};
export default React.memo(MdImage);
export default MdImage;

View File

@@ -1,10 +1,11 @@
import React, { useMemo } from 'react';
import ReactMarkdown from 'react-markdown';
import 'katex/dist/katex.min.css';
import RemarkMath from 'remark-math';
import RemarkBreaks from 'remark-breaks';
import RehypeKatex from 'rehype-katex';
import RemarkGfm from 'remark-gfm';
import RemarkMath from 'remark-math'; // Math syntax
import RemarkBreaks from 'remark-breaks'; // Line break
import RehypeKatex from 'rehype-katex'; // Math render
import RemarkGfm from 'remark-gfm'; // Special markdown syntax
import RehypeExternalLinks from 'rehype-external-links';
import styles from './index.module.scss';
import dynamic from 'next/dynamic';
@@ -15,6 +16,7 @@ import { useTranslation } from 'next-i18next';
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants';
import { CodeClassNameEnum } from './utils';
const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false });
const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false });
@@ -24,15 +26,6 @@ const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr:
const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false });
const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false });
export enum CodeClassName {
guide = 'guide',
questionGuide = 'questionGuide',
mermaid = 'mermaid',
echarts = 'echarts',
quote = 'quote',
files = 'files'
}
const Markdown = ({
source = '',
showAnimation = false
@@ -51,10 +44,13 @@ const Markdown = ({
[]
);
const formatSource = source
// .replace(/\\n/g, '\n')
.replace(/(http[s]?:\/\/[^\s。]+)([。,])/g, '$1 $2')
.replace(/\n*(\[QUOTE SIGN\]\(.*\))/g, '$1');
const formatSource = useMemo(() => {
const formatSource = source
.replace(/(http[s]?:\/\/[^\s。]+)([。,])/g, '$1 $2') // Follow the link with a space
.replace(/\n*(\[QUOTE SIGN\]\(.*\))/g, '$1');
return formatSource;
}, [source]);
return (
<ReactMarkdown
@@ -62,9 +58,8 @@ const Markdown = ({
${showAnimation ? `${formatSource ? styles.waitingAnimation : styles.animation}` : ''}
`}
remarkPlugins={[RemarkMath, [RemarkGfm, { singleTilde: false }], RemarkBreaks]}
rehypePlugins={[RehypeKatex]}
rehypePlugins={[RehypeKatex, [RehypeExternalLinks, { target: '_blank' }]]}
components={components}
linkTarget={'_blank'}
>
{formatSource}
</ReactMarkdown>
@@ -73,6 +68,7 @@ const Markdown = ({
export default React.memo(Markdown);
/* Custom dom */
const Code = React.memo(function Code(e: any) {
const { inline, className, children } = e;
@@ -82,17 +78,16 @@ const Code = React.memo(function Code(e: any) {
const strChildren = String(children);
const Component = useMemo(() => {
if (codeType === CodeClassName.mermaid) {
if (codeType === CodeClassNameEnum.mermaid) {
return <MermaidCodeBlock code={strChildren} />;
}
if (codeType === CodeClassName.guide) {
if (codeType === CodeClassNameEnum.guide) {
return <ChatGuide text={strChildren} />;
}
if (codeType === CodeClassName.questionGuide) {
if (codeType === CodeClassNameEnum.questionGuide) {
return <QuestionGuide text={strChildren} />;
}
if (codeType === CodeClassName.echarts) {
if (codeType === CodeClassNameEnum.echarts) {
return <EChartsCodeBlock code={strChildren} />;
}
@@ -105,7 +100,6 @@ const Code = React.memo(function Code(e: any) {
return Component;
});
const Image = React.memo(function Image({ src }: { src?: string }) {
return <MdImage src={src} />;
});

View File

@@ -0,0 +1,77 @@
export enum CodeClassNameEnum {
guide = 'guide',
questionGuide = 'questionGuide',
mermaid = 'mermaid',
echarts = 'echarts',
quote = 'quote',
files = 'files',
latex = 'latex'
}
function htmlTableToLatex(html: string) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const table = doc.querySelector('table');
if (!table) return '';
let latex = '\\begin{tabular}{';
// 获取列数
const columns = table.querySelectorAll('tr:first-child th, tr:first-child td').length;
latex += '|' + 'c|'.repeat(columns) + '}\n\\hline\n';
// 创建一个二维数组来跟踪单元格合并情况
const cellTracker = Array.from({ length: table.rows.length }, () => Array(columns).fill(false));
// 遍历行
table.querySelectorAll('tr').forEach((row, rowIndex) => {
const cells = row.querySelectorAll('th, td');
let cellTexts: string[] = [];
let colIndex = 0;
cells.forEach((cell) => {
// 跳过已经被合并的单元格
while (cellTracker[rowIndex][colIndex]) {
colIndex++;
}
// @ts-ignore
const rowspan = parseInt(cell.getAttribute('rowspan') || 1, 10);
// @ts-ignore
const colspan = parseInt(cell.getAttribute('colspan') || 1, 10);
// 添加单元格内容
let cellText = cell.textContent?.trim() || '';
if (colspan > 1) {
cellText = `\\multicolumn{${colspan}}{|c|}{${cellText}}`;
}
if (rowspan > 1) {
cellText = `\\multirow{${rowspan}}{*}{${cellText}}`;
}
cellTexts.push(cellText);
// 标记合并的单元格
for (let i = 0; i < rowspan; i++) {
for (let j = 0; j < colspan; j++) {
cellTracker[rowIndex + i][colIndex + j] = true;
}
}
colIndex += colspan;
});
latex += cellTexts.join(' & ') + ' \\\\\n\\hline\n';
});
latex += '\\end{tabular}';
return `\`\`\`${CodeClassNameEnum.latex}
${latex}
\`\`\``;
}
export function convertHtmlTablesToLatex(input: string) {
const tableRegex = /<table[\s\S]*?<\/table>/gi;
return input.replace(tableRegex, (match) => htmlTableToLatex(match));
}

View File

@@ -16,6 +16,7 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
type Props = TextareaProps & {
title?: string;
iconSrc?: string;
// variables: string[];
};
@@ -24,7 +25,11 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
const TextareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();
const { title = t('common:core.app.edit.Prompt Editor'), ...childProps } = props;
const {
title = t('common:core.app.edit.Prompt Editor'),
iconSrc = 'modal/edit',
...childProps
} = props;
const { isOpen, onOpen, onClose } = useDisclosure();
@@ -32,7 +37,7 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
<>
<Editor textareaRef={TextareaRef} {...childProps} onOpenModal={onOpen} />
{isOpen && (
<MyModal iconSrc="/imgs/modal/edit.svg" title={title} isOpen onClose={onClose}>
<MyModal iconSrc={iconSrc} title={title} isOpen onClose={onClose}>
<ModalBody>
<Editor
textareaRef={ModalTextareaRef}

View File

@@ -96,9 +96,7 @@ const VariableEdit = ({
<Box>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/variable'} w={'20px'} />
<FormLabel ml={2} fontWeight={'medium'}>
{t('common:core.module.Variable')}
</FormLabel>
<FormLabel ml={2}>{t('common:core.module.Variable')}</FormLabel>
<ChatFunctionTip type={'variable'} />
<Box flex={1} />
<Button

View File

@@ -17,6 +17,8 @@ const WelcomeTextConfig = (props: TextareaProps) => {
<ChatFunctionTip type={'welcome'} />
</Flex>
<MyTextarea
iconSrc={'core/app/simpleMode/chat'}
title={t('common:core.app.Welcome Text')}
mt={2}
rows={6}
fontSize={'sm'}

View File

@@ -1,4 +1,5 @@
import Markdown, { CodeClassName } from '@/components/Markdown';
import Markdown from '@/components/Markdown';
import { CodeClassNameEnum } from '@/components/Markdown/utils';
import {
Accordion,
AccordionButton,
@@ -41,7 +42,7 @@ const AIResponseBox = ({ value, index, chat, isLastChild, isChatting, questionGu
index === chat.value.length - 1
) {
source = `${source}
\`\`\`${CodeClassName.questionGuide}
\`\`\`${CodeClassNameEnum.questionGuide}
${JSON.stringify(questionGuides)}`;
}

View File

@@ -14,6 +14,7 @@ const SearchParamsTip = ({
limit = 1500,
responseEmptyText,
usingReRank = false,
datasetSearchUsingExtensionQuery,
queryExtensionModel
}: {
searchMode: `${DatasetSearchModeEnum}`;
@@ -21,6 +22,7 @@ const SearchParamsTip = ({
limit?: number;
responseEmptyText?: string;
usingReRank?: boolean;
datasetSearchUsingExtensionQuery?: boolean;
queryExtensionModel?: string;
}) => {
const { t } = useTranslation();
@@ -32,11 +34,11 @@ const SearchParamsTip = ({
const extensionModelName = useMemo(
() =>
queryExtensionModel
datasetSearchUsingExtensionQuery
? llmModelList.find((item) => item.model === queryExtensionModel)?.name ??
llmModelList[0]?.name
: undefined,
[llmModelList, queryExtensionModel]
[datasetSearchUsingExtensionQuery, llmModelList, queryExtensionModel]
);
return (

View File

@@ -52,7 +52,7 @@ const ConfigPerModal = ({
>
<ModalBody>
<HStack>
<Avatar src={avatar} w={'1.75rem'} />
<Avatar src={avatar} w={'1.75rem'} borderRadius={'md'} />
<Box>{name}</Box>
</HStack>
{!isInheritPermission && (