style: markdown render

main
jialin 12 months ago
parent 4498f069f0
commit 8ae031dbbd

@ -70,7 +70,6 @@ const MarkdownViewer: React.FC<MarkdownViewerProps> = ({
const renderItem = useCallback(
(token: any, render: any) => {
console.log('token====', token);
if (!reDefineTypes.includes(token.type)) {
return (
<span

@ -138,5 +138,6 @@ export default {
'playground.image.download': 'Download Image',
'playground.image.generate': 'Generate',
'playground.image.edit': 'Edit',
'playground.image.fitview': 'Fit View'
'playground.image.fitview': 'Fit View',
'playground.chat.aithought': 'CoT'
};

@ -133,5 +133,6 @@ export default {
'playground.image.download': '下载图片',
'playground.image.generate': '生成图片',
'playground.image.edit': '编辑图片',
'playground.image.fitview': '适应视图'
'playground.image.fitview': '适应视图',
'playground.chat.aithought': '思考过程'
};

@ -90,7 +90,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
reasoningContent: string;
}) => {
if (data.reasoningContent && !data.content) {
return `<think>${data.reasoningContent}${data.content}`;
return `<think>${data.reasoningContent}`;
}
if (data.reasoningContent && data.content) {
return `<think>${data.reasoningContent}</think>${data.content}`;
@ -127,15 +127,18 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
_.get(chunk, 'choices.0.delta.reasoning_content', '');
contentRef.current =
contentRef.current + _.get(chunk, 'choices.0.delta.content', '');
const content = formatContent({
content: contentRef.current,
reasoningContent: reasonContentRef.current
});
setMessageList([
...messageList,
...currentMessageRef.current,
{
role: Roles.Assistant,
content: formatContent({
content: contentRef.current,
reasoningContent: reasonContentRef.current
}),
content: content,
uid: messageId.current
}
]);

@ -3,7 +3,11 @@ import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import CompareContext from '../../config/compare-context';
import { MessageItem, ModelSelectionItem } from '../../config/types';
import {
MessageItem,
MessageItemAction,
ModelSelectionItem
} from '../../config/types';
import '../../style/multiple-chat.less';
import EmptyModels from '../empty-models';
import MessageInput from '../message-input';
@ -42,6 +46,11 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList, loaded }) => {
const modelRefs = useRef<any>({});
const chatListScrollRef = useRef<any>(null);
const boxHeight = 'calc(100vh - 72px)';
const [actions, setActions] = useState<MessageItemAction[]>([
'upload',
'delete',
'copy'
]);
const isLoading = useMemo(() => {
const modelRefList = Object.getOwnPropertySymbols(loadingStatus);
@ -228,6 +237,15 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList, loaded }) => {
handleUpdateModelList(value);
};
const handleOnCheck = (e: any) => {
const checked = e.target.checked;
if (checked) {
setActions(['upload', 'delete', 'copy', 'markdown']);
} else {
setActions(['upload', 'delete', 'copy']);
}
};
useEffect(() => {
modelRefs.current = {};
let list = _.take(modelList, spans.count);
@ -268,6 +286,7 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList, loaded }) => {
globalParams,
loadingStatus,
modelFullList: modelList,
actions,
handleApplySystemChangeToAll,
setGlobalParams,
setLoadingStatus: handleSetLoadingStatus,
@ -302,6 +321,18 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList, loaded }) => {
updateLayout={updateLayout}
setModelSelections={handleUpdateModelSelections}
presetPrompt={handlePresetPrompt}
actions={[
'clear',
'layout',
'role',
'upload',
'add',
'paste',
'check'
]}
defaultChecked={false}
checkLabel="Markdown"
onCheck={handleOnCheck}
defaultSize={{
minRows: 5,
maxRows: 5

@ -50,7 +50,8 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
handleDeleteModel,
handleApplySystemChangeToAll,
modelFullList,
loadingStatus
loadingStatus,
actions
} = useContext(CompareContext);
const intl = useIntl();
const isApplyToAllModels = useRef(false);
@ -93,7 +94,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
reasoningContent: string;
}) => {
if (data.reasoningContent && !data.content) {
return `<think>${data.reasoningContent}${data.content}`;
return `<think>${data.reasoningContent}`;
}
if (data.reasoningContent && data.content) {
return `<think>${data.reasoningContent}</think>${data.content}`;
@ -117,15 +118,16 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
contentRef.current =
contentRef.current + _.get(chunk, 'choices.0.delta.content', '');
const content = formatContent({
content: contentRef.current,
reasoningContent: reasonContentRef.current
});
setMessageList([
...messageList,
...currentMessageRef.current,
{
role: Roles.Assistant,
content: formatContent({
content: contentRef.current,
reasoningContent: reasonContentRef.current
}),
content,
uid: messageId.current
}
]);
@ -476,6 +478,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
<MessageContent
messageList={messageList}
setMessageList={setMessageList}
actions={actions}
editable={true}
/>
<Spin

@ -1,6 +1,8 @@
import IconFont from '@/components/icon-font';
import { DownOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button } from 'antd';
import React from 'react';
import React, { useState } from 'react';
import '../../style/think-content.less';
interface ThinkContentProps {
@ -8,15 +10,29 @@ interface ThinkContentProps {
}
const ThinkContent: React.FC<ThinkContentProps> = ({ content }) => {
const intl = useIntl();
const [collapsed, setCollapsed] = useState(false);
return (
<>
{content ? (
<div className="think-wrapper">
<IconFont type="icon-AIzhineng" className="m-l-4" />
<Button size="small" type="text">
AI Thought...
</Button>
<div className="think-content">{content}</div>
<div className="btn-collapse">
<Button
size="small"
type="text"
className="flex-center"
variant={collapsed ? 'filled' : undefined}
color="default"
onClick={() => setCollapsed(!collapsed)}
>
<IconFont type="icon-AIzhineng" />
<span>
{intl.formatMessage({ id: 'playground.chat.aithought' })}
</span>
<DownOutlined rotate={collapsed ? 0 : 180} className="m-l-10" />
</Button>
</div>
{!collapsed && <div className="think-content">{content}</div>}
</div>
) : null}
</>

@ -1,8 +1,8 @@
class ThinkParser {
private lastCheckedIndex: number;
private collecting: boolean;
thought: string;
result: string;
collecting: boolean;
lastCheckedIndex: number;
constructor() {
this.thought = '';
@ -12,40 +12,33 @@ class ThinkParser {
}
parse(chunk: string) {
if (this.lastCheckedIndex < chunk.length) {
const currentChunk = chunk.substring(this.lastCheckedIndex);
while (this.lastCheckedIndex < chunk.length) {
if (!this.collecting) {
// find <think> tag
let startIndex = currentChunk.indexOf('<think>');
let startIndex = chunk.indexOf('<think>', this.lastCheckedIndex);
if (startIndex !== -1) {
// handle text before <think> tag
this.result += currentChunk.substring(0, startIndex);
// handle thought part
this.thought += currentChunk.substring(startIndex + 7);
this.result += chunk.substring(this.lastCheckedIndex, startIndex);
this.collecting = true;
this.lastCheckedIndex = startIndex + 7;
} else {
// if no <think> tag found, just append the whole chunk to result
this.result += currentChunk;
this.result += chunk.substring(this.lastCheckedIndex);
this.lastCheckedIndex = chunk.length;
break;
}
} else {
// find </think> tag
let endIndex = currentChunk.indexOf('</think>');
let endIndex = chunk.indexOf('</think>', this.lastCheckedIndex);
if (endIndex !== -1) {
// handle text before </think> tag
this.thought += currentChunk.substring(0, endIndex);
// handle result part
this.result += currentChunk.substring(endIndex + 8);
this.thought += chunk.substring(this.lastCheckedIndex, endIndex);
this.collecting = false;
this.lastCheckedIndex = endIndex + 8;
} else {
this.thought += currentChunk;
this.thought += chunk.substring(this.lastCheckedIndex);
this.lastCheckedIndex = chunk.length;
break;
}
this.lastCheckedIndex = chunk.length;
}
}
return { thought: this.thought.trim(), result: this.result };
return { thought: this.thought.trimStart(), result: this.result };
}
reset() {

@ -1,10 +1,12 @@
import React from 'react';
import { MessageItemAction } from './types';
interface CompareContextProps {
spans: {
span: number;
count: number;
};
actions?: MessageItemAction[];
systemMessage?: string;
globalParams: Record<string, any>;
loadingStatus: Record<symbol, boolean>;

@ -1,6 +1,14 @@
.content-item {
margin-bottom: 12px;
.markdown-viewer {
h4 {
margin-top: 10px;
margin-bottom: 10px;
font-size: var(--font-size-middle);
}
}
&-role {
display: flex;
align-items: center;

@ -1,13 +1,19 @@
.think-wrapper {
margin-bottom: 16px;
color: var(--ant-color-text-tertiary);
border-left: 2px solid var(--ant-color-fill-secondary);
.btn-collapse {
margin-bottom: 8px;
border-radius: var(--border-radius-base);
width: max-content;
overflow: hidden;
}
.think-content {
white-space: pre-wrap;
padding: 6px 4px;
padding: 12px;
border-left: 2px solid var(--ant-color-fill-secondary);
background-color: var(--ant-color-fill-tertiary);
color: var(--ant-color-text-tertiary);
border-radius: var(--border-radius-base);
}
}

Loading…
Cancel
Save