mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 03:30:19 +00:00
♻️ refactor: 优化 plugin 文件夹命名以支持 standalone 类型的插件
This commit is contained in:
@@ -5,22 +5,18 @@ import { useSessionStore } from '@/store/session';
|
||||
import { chatSelectors } from '@/store/session/selectors';
|
||||
import { isFunctionMessageAtStart } from '@/utils/message';
|
||||
|
||||
import FunctionCall from '../Plugins/FunctionCall';
|
||||
import Inspector from '../Plugins/Inspector';
|
||||
import { DefaultMessage } from './Default';
|
||||
|
||||
export const AssistantMessage: RenderMessage = memo(
|
||||
({ id, plugin, function_call, content, ...props }) => {
|
||||
const genFunctionCallProps = useSessionStore(chatSelectors.getFunctionMessageParams);
|
||||
export const AssistantMessage: RenderMessage = memo(({ id, plugin, content, ...props }) => {
|
||||
const fcProps = useSessionStore(chatSelectors.getFunctionMessageProps({ content, id, plugin }));
|
||||
|
||||
if (!isFunctionMessageAtStart(content))
|
||||
return <DefaultMessage content={content} id={id} {...props} />;
|
||||
if (!isFunctionMessageAtStart(content))
|
||||
return <DefaultMessage content={content} id={id} {...props} />;
|
||||
|
||||
const fcProps = genFunctionCallProps({ content, function_call, id, plugin });
|
||||
|
||||
return (
|
||||
<div id={id}>
|
||||
<FunctionCall {...fcProps} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
return (
|
||||
<div id={id}>
|
||||
<Inspector {...fcProps} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import { RenderMessage } from '@lobehub/ui';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { useSessionStore } from '@/store/session';
|
||||
import { chatSelectors } from '@/store/session/selectors';
|
||||
|
||||
import FunctionCall from '../Plugins/FunctionCall';
|
||||
import PluginMessage from '../Plugins/PluginMessage';
|
||||
import Inspector from '../Plugins/Inspector';
|
||||
import PluginRender from '../Plugins/Render';
|
||||
|
||||
export const FunctionMessage: RenderMessage = memo(
|
||||
({ id, content, plugin, function_call, name }) => {
|
||||
const genFunctionCallProps = useSessionStore(chatSelectors.getFunctionMessageParams);
|
||||
const fcProps = genFunctionCallProps({ content, function_call, id, plugin });
|
||||
export const FunctionMessage: RenderMessage = memo(({ id, content, plugin, name }) => {
|
||||
const fcProps = useSessionStore(
|
||||
chatSelectors.getFunctionMessageProps({ content, id, plugin }),
|
||||
isEqual,
|
||||
);
|
||||
|
||||
return (
|
||||
<Flexbox gap={12} id={id}>
|
||||
<FunctionCall {...fcProps} />
|
||||
<PluginMessage content={content} loading={fcProps.loading} name={name} />
|
||||
</Flexbox>
|
||||
);
|
||||
},
|
||||
);
|
||||
return (
|
||||
<Flexbox gap={12} id={id}>
|
||||
<Inspector {...fcProps} />
|
||||
<PluginRender content={content} loading={fcProps.loading} name={name} type={fcProps.type} />
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
+5
-5
@@ -8,10 +8,10 @@ import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
||||
|
||||
import PluginResult from './PluginResultRender';
|
||||
import { useStyles } from './style';
|
||||
import { useStyles } from '../style';
|
||||
import PluginResult from './PluginResultJSON';
|
||||
|
||||
export interface FunctionCallProps {
|
||||
export interface InspectorProps {
|
||||
arguments?: string;
|
||||
command?: any;
|
||||
content: string;
|
||||
@@ -19,7 +19,7 @@ export interface FunctionCallProps {
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const FunctionCall = memo<FunctionCallProps>(
|
||||
const Inspector = memo<InspectorProps>(
|
||||
({ arguments: requestArgs = '{}', command, loading, content, id = 'unknown' }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles } = useStyles();
|
||||
@@ -87,4 +87,4 @@ const FunctionCall = memo<FunctionCallProps>(
|
||||
},
|
||||
);
|
||||
|
||||
export default FunctionCall;
|
||||
export default Inspector;
|
||||
+3
-3
@@ -11,13 +11,13 @@ import IFrameRender from './IFrameRender';
|
||||
|
||||
const SystemJsRender = dynamic(() => import('./SystemJsRender'), { ssr: false });
|
||||
|
||||
export interface FunctionMessageProps {
|
||||
export interface PluginDefaultTypeProps {
|
||||
content: string;
|
||||
loading?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
||||
const PluginDefaultType = memo<PluginDefaultTypeProps>(({ content, name }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const manifest = usePluginStore((s) => s.pluginManifestMap[name || '']);
|
||||
@@ -65,4 +65,4 @@ const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
||||
);
|
||||
});
|
||||
|
||||
export default PluginMessage;
|
||||
export default PluginDefaultType;
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Skeleton } from 'antd';
|
||||
import { memo, useRef, useState } from 'react';
|
||||
|
||||
interface IFrameRenderProps {
|
||||
height?: number;
|
||||
url: string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
const IFrameRender = memo<IFrameRenderProps>(({ url, width = 600, height = 300 }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
{loading && <Skeleton active style={{ width }} />}
|
||||
<iframe
|
||||
// @ts-ignore
|
||||
allowtransparency="true"
|
||||
height={height}
|
||||
hidden={loading}
|
||||
onLoad={() => {
|
||||
setLoading(false);
|
||||
}}
|
||||
ref={iframeRef}
|
||||
src={url}
|
||||
style={{
|
||||
border: 0,
|
||||
// iframe 在 color-scheme:dark 模式下无法透明
|
||||
// refs: https://www.jianshu.com/p/bc5a37bb6a7b
|
||||
colorScheme: 'light',
|
||||
}}
|
||||
width={width}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
export default IFrameRender;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
import { usePluginStore } from '@/store/plugin';
|
||||
|
||||
import IFrameRender from './Iframe';
|
||||
|
||||
export interface PluginStandaloneTypeProps {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const PluginDefaultType = memo<PluginStandaloneTypeProps>(({ name = 'unknown' }) => {
|
||||
const manifest = usePluginStore((s) => s.pluginManifestMap[name]);
|
||||
|
||||
if (!manifest?.ui) return;
|
||||
|
||||
const ui = manifest.ui;
|
||||
|
||||
if (!ui.url) return;
|
||||
|
||||
return <IFrameRender height={ui.height} url={ui.url} width={ui.width} />;
|
||||
});
|
||||
|
||||
export default PluginDefaultType;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { LobePluginType } from '@lobehub/chat-plugin-sdk';
|
||||
import { memo } from 'react';
|
||||
|
||||
import DefaultType from './DefaultType';
|
||||
import Standalone from './StandaloneType';
|
||||
|
||||
export interface PluginRenderProps {
|
||||
content: string;
|
||||
loading?: boolean;
|
||||
name?: string;
|
||||
type?: LobePluginType;
|
||||
}
|
||||
|
||||
const PluginRender = memo<PluginRenderProps>(({ content, name, type }) => {
|
||||
switch (type) {
|
||||
case 'standalone': {
|
||||
return <Standalone name={name} />;
|
||||
}
|
||||
|
||||
default: {
|
||||
return <DefaultType content={content} name={name} />;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default PluginRender;
|
||||
@@ -16,7 +16,8 @@ const t = setNamespace('chat/plugin');
|
||||
* 插件方法
|
||||
*/
|
||||
export interface ChatPluginAction {
|
||||
runPluginAutoMode: (id: string, payload: any) => Promise<void>;
|
||||
runPluginDefaultType: (id: string, payload: any) => Promise<void>;
|
||||
runPluginStandaloneType: (id: string, payload: any) => Promise<void>;
|
||||
triggerFunctionCall: (id: string) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ export const chatPlugin: StateCreator<
|
||||
[],
|
||||
ChatPluginAction
|
||||
> = (set, get) => ({
|
||||
runPluginAutoMode: async (id, payload) => {
|
||||
runPluginDefaultType: async (id, payload) => {
|
||||
const { dispatchMessage, coreProcessMessage, toggleChatLoading } = get();
|
||||
let data: string;
|
||||
try {
|
||||
@@ -44,12 +45,13 @@ export const chatPlugin: StateCreator<
|
||||
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: data });
|
||||
|
||||
const chats = chatSelectors.currentChats(get());
|
||||
|
||||
await coreProcessMessage(chats, id);
|
||||
},
|
||||
|
||||
runPluginStandaloneType: async (id, payload) => {
|
||||
console.log('触发standalone', id, payload);
|
||||
},
|
||||
triggerFunctionCall: async (id) => {
|
||||
const { dispatchMessage, runPluginAutoMode } = get();
|
||||
const { dispatchMessage, runPluginDefaultType, runPluginStandaloneType } = get();
|
||||
const session = sessionSelectors.currentSession(get());
|
||||
|
||||
if (!session) return;
|
||||
@@ -58,6 +60,7 @@ export const chatPlugin: StateCreator<
|
||||
if (!message) return;
|
||||
|
||||
let payload: PluginRequestPayload = { apiName: '', identifier: '' };
|
||||
|
||||
// 识别到内容是 function_call 的情况下
|
||||
// 将 function_call 转换为 plugin request payload
|
||||
if (message.content) {
|
||||
@@ -65,8 +68,14 @@ export const chatPlugin: StateCreator<
|
||||
function_call: OpenAIFunctionCall;
|
||||
};
|
||||
|
||||
const [identifier, apiName] = function_call.name.split(PLUGIN_SCHEMA_SEPARATOR);
|
||||
payload = { apiName, arguments: function_call.arguments, identifier };
|
||||
const [identifier, apiName, type] = function_call.name.split(PLUGIN_SCHEMA_SEPARATOR);
|
||||
|
||||
payload = {
|
||||
apiName,
|
||||
arguments: function_call.arguments,
|
||||
identifier,
|
||||
type: type ?? 'default',
|
||||
};
|
||||
|
||||
dispatchMessage({ id, key: 'plugin', type: 'updateMessage', value: payload });
|
||||
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: '' });
|
||||
@@ -82,6 +91,7 @@ export const chatPlugin: StateCreator<
|
||||
dispatchMessage({ id, key: 'name', type: 'updateMessage', value: payload.identifier });
|
||||
dispatchMessage({ id, key: 'plugin', type: 'updateMessage', value: payload });
|
||||
|
||||
runPluginAutoMode(id, payload);
|
||||
if (payload.type === 'standalone') runPluginStandaloneType(id, payload);
|
||||
else runPluginDefaultType(id, payload);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LobePluginType } from '@lobehub/chat-plugin-sdk';
|
||||
import { t } from 'i18next';
|
||||
|
||||
import { FunctionCallProps } from '@/app/chat/features/Conversation/ChatList/Plugins/FunctionCall';
|
||||
import { DEFAULT_INBOX_AVATAR, DEFAULT_USER_AVATAR } from '@/const/meta';
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
@@ -92,22 +92,13 @@ export const chatsMessageString = (s: SessionStore): string => {
|
||||
return chats.map((m) => m.content).join('');
|
||||
};
|
||||
|
||||
export const getFunctionMessageParams =
|
||||
(
|
||||
s: SessionStore,
|
||||
): ((
|
||||
props: Pick<ChatMessage, 'plugin' | 'function_call' | 'content' | 'id'>,
|
||||
) => FunctionCallProps) =>
|
||||
({ plugin, function_call, content, id }) => {
|
||||
const itemId = plugin?.identifier || function_call?.name;
|
||||
const command = plugin ?? function_call;
|
||||
const args = command?.arguments;
|
||||
|
||||
return {
|
||||
arguments: args,
|
||||
command,
|
||||
content,
|
||||
id: itemId,
|
||||
loading: id === s.chatLoadingId,
|
||||
};
|
||||
};
|
||||
export const getFunctionMessageProps =
|
||||
({ plugin, content, id }: Pick<ChatMessage, 'plugin' | 'content' | 'id'>) =>
|
||||
(s: SessionStore) => ({
|
||||
arguments: plugin?.arguments,
|
||||
command: plugin,
|
||||
content,
|
||||
id: plugin?.identifier,
|
||||
loading: id === s.chatLoadingId,
|
||||
type: plugin?.type as LobePluginType,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
currentChatsWithGuideMessage,
|
||||
currentChatsWithHistoryConfig,
|
||||
getChatsById,
|
||||
getFunctionMessageParams,
|
||||
getFunctionMessageProps,
|
||||
} from './chat';
|
||||
import { currentTopics, getTopicMessages } from './topic';
|
||||
|
||||
@@ -14,7 +14,7 @@ export const chatSelectors = {
|
||||
currentChatsWithGuideMessage,
|
||||
currentChatsWithHistoryConfig,
|
||||
getChatsById,
|
||||
getFunctionMessageParams,
|
||||
getFunctionMessageProps,
|
||||
};
|
||||
|
||||
export const topicSelectors = {
|
||||
|
||||
Reference in New Issue
Block a user