Skip to content

Commit

Permalink
chore: replace text patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Jan 24, 2025
1 parent 7635fd3 commit 181b9a0
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 106 deletions.
26 changes: 13 additions & 13 deletions src/const/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,46 @@ import { describe, expect, it } from 'vitest';
import { ARTIFACT_TAG_REGEX } from './plugin';

describe('ARTIFACT_TAG_REGEX', () => {
it('should match a simple lobeArtifact tag', () => {
const input = '<lobeArtifact>Simple content</lobeArtifact>';
it('should match a simple artifact tag', () => {
const input = '<artifact>Simple content</artifact>';
const matches = input.match(ARTIFACT_TAG_REGEX);
expect(matches).toHaveLength(2);
expect(matches?.[1]).toBe('Simple content');
});

it('should match a lobeArtifact tag with attributes', () => {
const input = '<lobeArtifact type="image">Content with attributes</lobeArtifact>';
it('should match a artifact tag with attributes', () => {
const input = '<artifact type="image">Content with attributes</artifact>';
const matches = input.match(ARTIFACT_TAG_REGEX);
expect(matches).toHaveLength(2);
expect(matches?.[1]).toBe('Content with attributes');
});

it('should match lobeArtifact tag with multiline content', () => {
const input = '<lobeArtifact>\nMultiline\ncontent\n</lobeArtifact>';
it('should match artifact tag with multiline content', () => {
const input = '<artifact>\nMultiline\ncontent\n</artifact>';
const matches = input.match(ARTIFACT_TAG_REGEX);
expect(matches).toHaveLength(2);
expect(matches?.[1]).toBe('\nMultiline\ncontent\n');
});

it('should match an unclosed lobeArtifact tag', () => {
const input = '<lobeArtifact>Unclosed tag';
it('should match an unclosed artifact tag', () => {
const input = '<artifact>Unclosed tag';
const matches = input.match(ARTIFACT_TAG_REGEX);
expect(matches).toHaveLength(2);
expect(matches?.[1]).toBe('Unclosed tag');
});

it('should not match when there is no lobeArtifact tag', () => {
const input = 'This is a text without any lobeArtifact tag';
it('should not match when there is no artifact tag', () => {
const input = 'This is a text without any artifact tag';
const matches = input.match(ARTIFACT_TAG_REGEX);
expect(matches).toBeNull();
});

it('should match', () => {
const input = `好的,让我来为您解释"OpenAI"这个词。
<lobeThinking>这个词涉及人工智能领域的一家知名公司,我需要用批判性和幽默的视角来解读它的本质。我会结合当前AI发展的现状,用隐喻的方式来表达。</lobeThinking>
<thinking>这个词涉及人工智能领域的一家知名公司,我需要用批判性和幽默的视角来解读它的本质。我会结合当前AI发展的现状,用隐喻的方式来表达。</thinking>
<lobeArtifact identifier="openai-new-interpretation" type="image/svg+xml" title="OpenAI 汉语新解">
<artifact identifier="openai-new-interpretation" type="image/svg+xml" title="OpenAI 汉语新解">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600">
<rect width="400" height="600" fill="#f0f0f0"/>
<g font-family="Arial, sans-serif">
Expand All @@ -62,7 +62,7 @@ describe('ARTIFACT_TAG_REGEX', () => {
<text x="200" y="450" font-size="14" text-anchor="middle" fill="#555">开放的盒子里装着封闭的秘密</text>
</g>
</svg>
</lobeArtifact>
</artifact>
OpenAI,这个名字听起来多么崇高啊!就像是一位身披白袍、头戴光环的科技天使,降临凡间来拯救我们这些被信息海洋淹没的可怜虫。
Expand Down
10 changes: 5 additions & 5 deletions src/const/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
export const PLUGIN_SCHEMA_SEPARATOR = '____';
export const PLUGIN_SCHEMA_API_MD5_PREFIX = 'MD5HASH_';

export const ARTIFACT_TAG = 'lobeArtifact';
export const ARTIFACT_THINKING_TAG = 'lobeThinking';
export const ARTIFACT_TAG = 'artifact';
export const ARTIFACT_THINKING_TAG = 'thinking';

// https://regex101.com/r/TwzTkf/2
export const ARTIFACT_TAG_REGEX = /<lobeArtifact\b[^>]*>(?<content>[\S\s]*?)(?:<\/lobeArtifact>|$)/;
export const ARTIFACT_TAG_REGEX = /<artifact\b[^>]*>(?<content>[\S\s]*?)(?:<\/artifact>|$)/;

// https://regex101.com/r/r9gqGg/1
export const ARTIFACT_TAG_CLOSED_REGEX = /<lobeArtifact\b[^>]*>([\S\s]*?)<\/lobeArtifact>/;
export const ARTIFACT_TAG_CLOSED_REGEX = /<artifact\b[^>]*>([\S\s]*?)<\/artifact>/;

// https://regex101.com/r/AvPA2g/1
export const ARTIFACT_THINKING_TAG_REGEX = /<lobeThinking\b[^>]*>([\S\s]*?)(?:<\/lobeThinking>|$)/;
export const ARTIFACT_THINKING_TAG_REGEX = /<thinking\b[^>]*>([\S\s]*?)(?:<\/thinking>|$)/;
64 changes: 32 additions & 32 deletions src/features/Conversation/components/ChatItem/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('processWithArtifact', () => {
it('should removeLineBreaks with closed tag', () => {
const input = `好的
<lobeArtifact identifier="sleep-interpretation-card" type="image/svg+xml" title="睡觉的新解释">
<artifact identifier="sleep-interpretation-card" type="image/svg+xml" title="睡觉的新解释">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600">
<defs>
<style>
Expand All @@ -18,19 +18,19 @@ describe('processWithArtifact', () => {
<!-- 总结 -->
<text x="200" y="500" font-family="'Noto Serif SC', serif" font-size="20" text-anchor="middle" fill="#8B4513">睡觉:生产力的假死,创造力的重生。</text>
</svg>
</lobeArtifact>`;
</artifact>`;

const output = processWithArtifact(input);

expect(output).toEqual(`好的
<lobeArtifact identifier="sleep-interpretation-card" type="image/svg+xml" title="睡觉的新解释"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"><defs><style>@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap');</style></defs><!-- 背景 --><rect width="400" height="600" fill="#F0EAD6"/><!-- 总结 --><text x="200" y="500" font-family="'Noto Serif SC', serif" font-size="20" text-anchor="middle" fill="#8B4513">睡觉:生产力的假死,创造力的重生。</text></svg></lobeArtifact>`);
<artifact identifier="sleep-interpretation-card" type="image/svg+xml" title="睡觉的新解释"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"><defs><style>@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap');</style></defs><!-- 背景 --><rect width="400" height="600" fill="#F0EAD6"/><!-- 总结 --><text x="200" y="500" font-family="'Noto Serif SC', serif" font-size="20" text-anchor="middle" fill="#8B4513">睡觉:生产力的假死,创造力的重生。</text></svg></artifact>`);
});

it('should removeLineBreaks with open tag', () => {
const input = `好的
<lobeArtifact identifier="ai-interpretation-card" type="image/svg+xml" title="人工智能新解卡片">
<artifact identifier="ai-interpretation-card" type="image/svg+xml" title="人工智能新解卡片">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600">
<defs>
<style>
Expand All @@ -43,7 +43,7 @@ describe('processWithArtifact', () => {

expect(output).toEqual(`好的
<lobeArtifact identifier="ai-interpretation-card" type="image/svg+xml" title="人工智能新解卡片"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"> <defs> <style> @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap'); </style> </defs>`);
<artifact identifier="ai-interpretation-card" type="image/svg+xml" title="人工智能新解卡片"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"> <defs> <style> @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap'); </style> </defs>`);
});
it('should not throw error with empty', () => {
const input = '';
Expand All @@ -53,64 +53,64 @@ describe('processWithArtifact', () => {
expect(output).toEqual('');
});

describe('close the <lobeArtifact tag', () => {
it('close tag for <lobeArtifact', () => {
const input = '<lobeArtifact';
describe('close the <artifact tag', () => {
it('close tag for <artifact', () => {
const input = '<artifact';

const output = processWithArtifact(input);

expect(output).toEqual('<lobeArtifact>');
expect(output).toEqual('<artifact>');
});

it('close tag for <lobeArtifact identifier="something"', () => {
const input = '<lobeArtifact identifier="something"';
it('close tag for <artifact identifier="something"', () => {
const input = '<artifact identifier="something"';

const output = processWithArtifact(input);

expect(output).toEqual('<lobeArtifact>');
expect(output).toEqual('<artifact>');
});

it('close tag for <lobeArtifact identifier="ai-interpretation" type="image/svg+xml" titl', () => {
const input = '<lobeArtifact identifier="ai-interpretation" type="image/svg+xml" titl';
it('close tag for <artifact identifier="ai-interpretation" type="image/svg+xml" titl', () => {
const input = '<artifact identifier="ai-interpretation" type="image/svg+xml" titl';

const output = processWithArtifact(input);

expect(output).toEqual('<lobeArtifact>');
expect(output).toEqual('<artifact>');
});

it('only change the <lobeArtifact> part', () => {
it('only change the <artifact> part', () => {
const input = `好的,让我来用新的视角解释"人工智能"这个词汇。
<lobeThinking>这个词汇涉及了当代科技和社会热点,需要用批判性和幽默感来解读其本质。我会用隐喻和讽刺来表达,同时保持简洁有力。</lobeThinking>
<thinking>这个词汇涉及了当代科技和社会热点,需要用批判性和幽默感来解读其本质。我会用隐喻和讽刺来表达,同时保持简洁有力。</thinking>
<lobeArtifact identifier="ai-new-interpretation" type="image/svg+xml" t`;
<artifact identifier="ai-new-interpretation" type="image/svg+xml" t`;

const output = processWithArtifact(input);

expect(output).toEqual(`好的,让我来用新的视角解释"人工智能"这个词汇。
<lobeThinking>这个词汇涉及了当代科技和社会热点,需要用批判性和幽默感来解读其本质。我会用隐喻和讽刺来表达,同时保持简洁有力。</lobeThinking>
<thinking>这个词汇涉及了当代科技和社会热点,需要用批判性和幽默感来解读其本质。我会用隐喻和讽刺来表达,同时保持简洁有力。</thinking>
<lobeArtifact>`);
<artifact>`);
});

it('not change for <lobeArtifact />', () => {
const input = '<lobeArtifact/>';
it('not change for <artifact />', () => {
const input = '<artifact/>';

const output = processWithArtifact(input);

expect(output).toEqual(input);
});
});

it('should removeLinkBreaks for lobeThinking', () => {
it('should removeLinkBreaks for thinking', () => {
const input = `好的,让我以一个特别的视角来解释"人工智能"这个词汇。
<lobeThinking>
<thinking>
这个词汇涉及了当代科技和社会热点,需要用批判性、幽默而深刻的视角来解读。我会运用隐喻和讽刺,抓住其本质,并以精练的方式表达出来。这符合一个好的artifact的标准,因为它是一个独立的、可能被用户修改或重用的内容。我将创建一个新的SVG artifact来呈现这个解释。
</lobeThinking>
</thinking>
<lobeArtifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能的新解释">
<artifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能的新解释">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600">
<defs>
<style>
Expand All @@ -123,28 +123,28 @@ describe('processWithArtifact', () => {
</style>
</defs>
</svg>
</lobeArtifact>
</artifact>
我为"人工智能"这个词创建了一个新的解释,并将其呈现在一个SVG卡片中。这个解释采用了批判性和幽默的视角,试图揭示这个概念背后的一些潜在问题。`;

const output = processWithArtifact(input);

expect(output).toEqual(`好的,让我以一个特别的视角来解释"人工智能"这个词汇。
<lobeThinking>这个词汇涉及了当代科技和社会热点,需要用批判性、幽默而深刻的视角来解读。我会运用隐喻和讽刺,抓住其本质,并以精练的方式表达出来。这符合一个好的artifact的标准,因为它是一个独立的、可能被用户修改或重用的内容。我将创建一个新的SVG artifact来呈现这个解释。</lobeThinking>
<thinking>这个词汇涉及了当代科技和社会热点,需要用批判性、幽默而深刻的视角来解读。我会运用隐喻和讽刺,抓住其本质,并以精练的方式表达出来。这符合一个好的artifact的标准,因为它是一个独立的、可能被用户修改或重用的内容。我将创建一个新的SVG artifact来呈现这个解释。</thinking>
<lobeArtifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能的新解释"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"> <defs> <style> @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap'); .background { fill: #f0f0f0; } .title { font-family: 'Noto Serif SC', serif; font-size: 28px; font-weight: 700; fill: #333; } .content { font-family: 'Noto Serif SC', serif; font-size: 18px; fill: #555; } .divider { stroke: #999; stroke-width: 1; } .decoration { fill: none; stroke: #999; stroke-width: 1; } </style> </defs></svg></lobeArtifact>
<artifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能的新解释"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 600"> <defs> <style> @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&amp;display=swap'); .background { fill: #f0f0f0; } .title { font-family: 'Noto Serif SC', serif; font-size: 28px; font-weight: 700; fill: #333; } .content { font-family: 'Noto Serif SC', serif; font-size: 18px; fill: #555; } .divider { stroke: #999; stroke-width: 1; } .decoration { fill: none; stroke: #999; stroke-width: 1; } </style> </defs></svg></artifact>
我为"人工智能"这个词创建了一个新的解释,并将其呈现在一个SVG卡片中。这个解释采用了批判性和幽默的视角,试图揭示这个概念背后的一些潜在问题。`);
});

it('should removeLinkBreaks for lobeThinking', () => {
const input = `<lobeThinking>
it('should removeLinkBreaks for thinking', () => {
const input = `<thinking>
这个词汇涉及了
`;

const output = processWithArtifact(input);

expect(output).toEqual(`<lobeThinking>这个词汇涉及了`);
expect(output).toEqual(`<thinking>这个词汇涉及了`);
});
});
12 changes: 6 additions & 6 deletions src/features/Conversation/components/ChatItem/utils.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { ARTIFACT_TAG_REGEX, ARTIFACT_THINKING_TAG_REGEX } from '@/const/plugin';

/**
* Replace all line breaks in the matched `lobeArtifact` tag with an empty string
* Replace all line breaks in the matched `artifact` tag with an empty string
*/
export const processWithArtifact = (input: string = '') => {
let output = input;
const thinkMatch = ARTIFACT_THINKING_TAG_REGEX.exec(input);

// If the input contains the `lobeThinking` tag, replace all line breaks with an empty string
// If the input contains the `thinking` tag, replace all line breaks with an empty string
if (thinkMatch)
output = input.replace(ARTIFACT_THINKING_TAG_REGEX, (match) =>
match.replaceAll(/\r?\n|\r/g, ''),
);

const match = ARTIFACT_TAG_REGEX.exec(input);
// If the input contains the `lobeArtifact` tag, replace all line breaks with an empty string
// If the input contains the `artifact` tag, replace all line breaks with an empty string
if (match)
return output.replace(ARTIFACT_TAG_REGEX, (match) => match.replaceAll(/\r?\n|\r/g, ''));

// if not match, check if it's start with <lobeArtifact but not closed
const regex = /<lobeArtifact\b(?:(?!\/?>)[\S\s])*$/;
// if not match, check if it's start with <artifact but not closed
const regex = /<artifact\b(?:(?!\/?>)[\S\s])*$/;
if (regex.test(output)) {
return output.replace(regex, '<lobeArtifact>');
return output.replace(regex, '<artifact>');
}

return output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import rehypePlugin from './rehypePlugin';
const AntArtifactElement = {
Component,
rehypePlugin,
tag: 'lobeArtifact',
tag: 'artifact',
};

export default AntArtifactElement;
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ function rehypeAntArtifact() {
if (node.type === 'element' && node.tagName === 'p' && node.children.length > 0) {
const firstChild = node.children[0];
if (firstChild.type === 'raw' && firstChild.value.startsWith(`<${ARTIFACT_TAG}`)) {
// 提取 lobeArtifact 的属性
// 提取 artifact 的属性
const attributes: Record<string, string> = {};
const attributeRegex = /(\w+)="([^"]*)"/g;
let match;
while ((match = attributeRegex.exec(firstChild.value)) !== null) {
attributes[match[1]] = match[2];
}

// 创建新的 lobeArtifact 节点
// 创建新的 artifact 节点
const newNode = {
children: [
{
Expand Down Expand Up @@ -47,15 +47,15 @@ function rehypeAntArtifact() {
return [SKIP, index];
}
}
// 如果字符串是 <lobeArtifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能新解释">
// 如果字符串是 <artifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能新解释">
// 得到的节点就是:
// {
// type: 'raw',
// value:
// '<lobeArtifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能新解释">',
// '<artifact identifier="ai-new-interpretation" type="image/svg+xml" title="人工智能新解释">',
// }
else if (node.type === 'raw' && node.value.startsWith(`<${ARTIFACT_TAG}`)) {
// 创建新的 lobeArtifact 节点
// 创建新的 artifact 节点
const newNode = {
children: [],
properties: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { dotLoading } from '@/styles/loading';
import { MarkdownElementProps } from '../type';

/**
* Replace all line breaks in the matched `lobeArtifact` tag with an empty string
* Replace all line breaks in the matched `artifact` tag with an empty string
*/
export const isLobeThinkingClosed = (input: string = '') => {
const openTag = `<${ARTIFACT_THINKING_TAG}>`;
Expand Down
Loading

0 comments on commit 181b9a0

Please sign in to comment.