mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	Merge pull request #7 from ConnectAI-E/feature/plugin-artifact
Feature/plugin artifact
This commit is contained in:
		@@ -91,8 +91,7 @@ For enterprise inquiries, please contact: **business@nextchat.dev**
 | 
			
		||||
- [x] Desktop App with tauri
 | 
			
		||||
- [x] Self-host Model: Fully compatible with [RWKV-Runner](https://github.com/josStorer/RWKV-Runner), as well as server deployment of [LocalAI](https://github.com/go-skynet/LocalAI): llama/gpt4all/rwkv/vicuna/koala/gpt4all-j/cerebras/falcon/dolly etc.
 | 
			
		||||
- [x] Artifacts: Easily preview, copy and share generated content/webpages through a separate window [#5092](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/pull/5092)
 | 
			
		||||
- [x] Plugins: support artifacts, network search, calculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
  - [x] artifacts
 | 
			
		||||
- [x] Plugins: support network search, calculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
  - [x] network search, calculator, any other apis etc. [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
- [ ] local knowledge base
 | 
			
		||||
 | 
			
		||||
@@ -129,8 +128,7 @@ For enterprise inquiries, please contact: **business@nextchat.dev**
 | 
			
		||||
- [x] 使用 tauri 打包桌面应用
 | 
			
		||||
- [x] 支持自部署的大语言模型:开箱即用 [RWKV-Runner](https://github.com/josStorer/RWKV-Runner) ,服务端部署 [LocalAI 项目](https://github.com/go-skynet/LocalAI) llama / gpt4all / rwkv / vicuna / koala / gpt4all-j / cerebras / falcon / dolly 等等,或者使用 [api-for-open-llm](https://github.com/xusenlinzy/api-for-open-llm)
 | 
			
		||||
- [x] Artifacts: 通过独立窗口,轻松预览、复制和分享生成的内容/可交互网页 [#5092](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/pull/5092)
 | 
			
		||||
- [x] 插件机制,支持 artifacts,联网搜索、计算器、调用其他平台 api [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
   - [x] artifacts
 | 
			
		||||
- [x] 插件机制,支持`联网搜索`、`计算器`、调用其他平台 api [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
   - [x] 支持联网搜索、计算器、调用其他平台 api [#165](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/165) [#5353](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/issues/5353)
 | 
			
		||||
 - [ ] 本地知识库
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,6 @@ import {
 | 
			
		||||
  REQUEST_TIMEOUT_MS,
 | 
			
		||||
  UNFINISHED_INPUT,
 | 
			
		||||
  ServiceProvider,
 | 
			
		||||
  ArtifactsPlugin,
 | 
			
		||||
} from "../constant";
 | 
			
		||||
import { Avatar } from "./emoji";
 | 
			
		||||
import { ContextPrompts, MaskAvatar, MaskConfig } from "./mask";
 | 
			
		||||
@@ -727,38 +726,26 @@ export function ChatActions(props: {
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      <ChatAction
 | 
			
		||||
        onClick={() => setShowPluginSelector(true)}
 | 
			
		||||
        text={Locale.Plugin.Name}
 | 
			
		||||
        icon={<PluginIcon />}
 | 
			
		||||
      />
 | 
			
		||||
      {showPluginSelector && (
 | 
			
		||||
      {showPlugins(currentProviderName, currentModel) && (
 | 
			
		||||
        <ChatAction
 | 
			
		||||
          onClick={() => setShowPluginSelector(true)}
 | 
			
		||||
          text={Locale.Plugin.Name}
 | 
			
		||||
          icon={<PluginIcon />}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {showPluginSelector && showPlugins(currentProviderName, currentModel) && (
 | 
			
		||||
        <Selector
 | 
			
		||||
          multiple
 | 
			
		||||
          defaultSelectedValue={chatStore.currentSession().mask?.plugin}
 | 
			
		||||
          items={[
 | 
			
		||||
            {
 | 
			
		||||
              title: Locale.Plugin.Artifacts,
 | 
			
		||||
              value: ArtifactsPlugin.Artifacts as string,
 | 
			
		||||
            },
 | 
			
		||||
          ].concat(
 | 
			
		||||
            showPlugins(currentProviderName, currentModel)
 | 
			
		||||
              ? pluginStore.getAll().map((item) => ({
 | 
			
		||||
                  // @ts-ignore
 | 
			
		||||
                  title: `${item?.title}@${item?.version}`,
 | 
			
		||||
                  // @ts-ignore
 | 
			
		||||
                  value: item?.id,
 | 
			
		||||
                }))
 | 
			
		||||
              : [],
 | 
			
		||||
          )}
 | 
			
		||||
          items={pluginStore.getAll().map((item) => ({
 | 
			
		||||
            title: `${item?.title}@${item?.version}`,
 | 
			
		||||
            value: item?.id,
 | 
			
		||||
          }))}
 | 
			
		||||
          onClose={() => setShowPluginSelector(false)}
 | 
			
		||||
          onSelection={(s) => {
 | 
			
		||||
            chatStore.updateCurrentSession((session) => {
 | 
			
		||||
              session.mask.plugin = s as string[];
 | 
			
		||||
            });
 | 
			
		||||
            if (s.includes(ArtifactsPlugin.Artifacts)) {
 | 
			
		||||
              showToast(ArtifactsPlugin.Artifacts);
 | 
			
		||||
            }
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@ import {
 | 
			
		||||
  HTMLPreview,
 | 
			
		||||
  HTMLPreviewHander,
 | 
			
		||||
} from "./artifacts";
 | 
			
		||||
import { ArtifactsPlugin } from "../constant";
 | 
			
		||||
import { useChatStore } from "../store";
 | 
			
		||||
import { IconButton } from "./button";
 | 
			
		||||
 | 
			
		||||
@@ -77,7 +76,6 @@ export function PreCode(props: { children: any }) {
 | 
			
		||||
  const { height } = useWindowSize();
 | 
			
		||||
  const chatStore = useChatStore();
 | 
			
		||||
  const session = chatStore.currentSession();
 | 
			
		||||
  const plugins = session.mask?.plugin;
 | 
			
		||||
 | 
			
		||||
  const renderArtifacts = useDebouncedCallback(() => {
 | 
			
		||||
    if (!ref.current) return;
 | 
			
		||||
@@ -94,10 +92,7 @@ export function PreCode(props: { children: any }) {
 | 
			
		||||
    }
 | 
			
		||||
  }, 600);
 | 
			
		||||
 | 
			
		||||
  const enableArtifacts = useMemo(
 | 
			
		||||
    () => plugins?.includes(ArtifactsPlugin.Artifacts),
 | 
			
		||||
    [plugins],
 | 
			
		||||
  );
 | 
			
		||||
  const enableArtifacts = session.mask?.enableArtifacts !== false;
 | 
			
		||||
 | 
			
		||||
  //Wrap the paragraph for plain-text
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -167,6 +167,22 @@ export function MaskConfig(props: {
 | 
			
		||||
          ></input>
 | 
			
		||||
        </ListItem>
 | 
			
		||||
 | 
			
		||||
        <ListItem
 | 
			
		||||
          title={Locale.Mask.Config.Artifacts.Title}
 | 
			
		||||
          subTitle={Locale.Mask.Config.Artifacts.SubTitle}
 | 
			
		||||
        >
 | 
			
		||||
          <input
 | 
			
		||||
            aria-label={Locale.Mask.Config.Artifacts.Title}
 | 
			
		||||
            type="checkbox"
 | 
			
		||||
            checked={props.mask.enableArtifacts}
 | 
			
		||||
            onChange={(e) => {
 | 
			
		||||
              props.updateMask((mask) => {
 | 
			
		||||
                mask.enableArtifacts = e.currentTarget.checked;
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          ></input>
 | 
			
		||||
        </ListItem>
 | 
			
		||||
 | 
			
		||||
        {!props.shouldSyncFromGlobal ? (
 | 
			
		||||
          <ListItem
 | 
			
		||||
            title={Locale.Mask.Config.Share.Title}
 | 
			
		||||
 
 | 
			
		||||
@@ -73,10 +73,6 @@ export enum FileName {
 | 
			
		||||
  Prompts = "prompts.json",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ArtifactsPlugin {
 | 
			
		||||
  Artifacts = "artifacts",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum StoreKey {
 | 
			
		||||
  Chat = "chat-next-web-store",
 | 
			
		||||
  Plugin = "chat-next-web-plugin",
 | 
			
		||||
 
 | 
			
		||||
@@ -532,7 +532,6 @@ const cn = {
 | 
			
		||||
  },
 | 
			
		||||
  Plugin: {
 | 
			
		||||
    Name: "插件",
 | 
			
		||||
    Artifacts: "Artifacts",
 | 
			
		||||
    Page: {
 | 
			
		||||
      Title: "插件",
 | 
			
		||||
      SubTitle: (count: number) => `${count} 个插件`,
 | 
			
		||||
@@ -604,6 +603,10 @@ const cn = {
 | 
			
		||||
        Title: "隐藏预设对话",
 | 
			
		||||
        SubTitle: "隐藏后预设对话不会出现在聊天界面",
 | 
			
		||||
      },
 | 
			
		||||
      Artifacts: {
 | 
			
		||||
        Title: "启用Artifacts",
 | 
			
		||||
        SubTitle: "启用之后可以直接渲染HTML页面",
 | 
			
		||||
      },
 | 
			
		||||
      Share: {
 | 
			
		||||
        Title: "分享此面具",
 | 
			
		||||
        SubTitle: "生成此面具的直达链接",
 | 
			
		||||
 
 | 
			
		||||
@@ -540,7 +540,6 @@ const en: LocaleType = {
 | 
			
		||||
  },
 | 
			
		||||
  Plugin: {
 | 
			
		||||
    Name: "Plugin",
 | 
			
		||||
    Artifacts: "Artifacts",
 | 
			
		||||
    Page: {
 | 
			
		||||
      Title: "Plugins",
 | 
			
		||||
      SubTitle: (count: number) => `${count} plugins`,
 | 
			
		||||
@@ -613,6 +612,10 @@ const en: LocaleType = {
 | 
			
		||||
        Title: "Hide Context Prompts",
 | 
			
		||||
        SubTitle: "Do not show in-context prompts in chat",
 | 
			
		||||
      },
 | 
			
		||||
      Artifacts: {
 | 
			
		||||
        Title: "Enable Artifacts",
 | 
			
		||||
        SubTitle: "Can render HTML page when enable artifacts.",
 | 
			
		||||
      },
 | 
			
		||||
      Share: {
 | 
			
		||||
        Title: "Share This Mask",
 | 
			
		||||
        SubTitle: "Generate a link to this mask",
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import { BUILTIN_MASKS } from "../masks";
 | 
			
		||||
import { getLang, Lang } from "../locales";
 | 
			
		||||
import { DEFAULT_TOPIC, ChatMessage } from "./chat";
 | 
			
		||||
import { ModelConfig, useAppConfig } from "./config";
 | 
			
		||||
import { StoreKey, ArtifactsPlugin } from "../constant";
 | 
			
		||||
import { StoreKey } from "../constant";
 | 
			
		||||
import { nanoid } from "nanoid";
 | 
			
		||||
import { createPersistStore } from "../utils/store";
 | 
			
		||||
 | 
			
		||||
@@ -18,6 +18,7 @@ export type Mask = {
 | 
			
		||||
  lang: Lang;
 | 
			
		||||
  builtin: boolean;
 | 
			
		||||
  plugin?: string[];
 | 
			
		||||
  enableArtifacts?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const DEFAULT_MASK_STATE = {
 | 
			
		||||
@@ -38,7 +39,7 @@ export const createEmptyMask = () =>
 | 
			
		||||
    lang: getLang(),
 | 
			
		||||
    builtin: false,
 | 
			
		||||
    createdAt: Date.now(),
 | 
			
		||||
    plugin: [ArtifactsPlugin.Artifacts as string],
 | 
			
		||||
    plugin: [],
 | 
			
		||||
  }) as Mask;
 | 
			
		||||
 | 
			
		||||
export const useMaskStore = createPersistStore(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user