@lobehub/chat 0.25.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.eslintrc.js +2 -1
  2. package/CHANGELOG.md +113 -6
  3. package/package.json +2 -5
  4. package/src/config/server.ts +22 -0
  5. package/src/const/fetch.ts +2 -2
  6. package/src/const/message.ts +2 -0
  7. package/src/locales/create.ts +3 -14
  8. package/src/locales/default/common.ts +4 -0
  9. package/src/locales/default/error.ts +27 -0
  10. package/src/locales/default/plugin.ts +19 -1
  11. package/src/locales/resources/zh_CN.ts +2 -0
  12. package/src/pages/api/auth.ts +25 -0
  13. package/src/pages/api/error.ts +21 -0
  14. package/src/pages/api/openai.api.ts +11 -5
  15. package/src/pages/api/openai.ts +24 -9
  16. package/src/pages/api/plugins.api.ts +11 -36
  17. package/src/pages/chat/[id]/Conversation/ChatList/Error/ApiKeyForm.tsx +40 -0
  18. package/src/pages/chat/[id]/Conversation/ChatList/Error/ErrorActionContainer.tsx +23 -0
  19. package/src/pages/chat/[id]/Conversation/ChatList/Error/InvalidAccess.tsx +76 -0
  20. package/src/pages/chat/[id]/Conversation/ChatList/Error/OpenAiBizError.tsx +52 -0
  21. package/src/pages/chat/[id]/Conversation/ChatList/Error/style.tsx +44 -0
  22. package/src/pages/chat/[id]/Conversation/{MessageExtra.tsx → ChatList/MessageExtra.tsx} +28 -26
  23. package/src/pages/chat/[id]/Conversation/ChatList/OTPInput.tsx +142 -0
  24. package/src/pages/chat/[id]/Conversation/ChatList/Plugins/FunctionCall.tsx +60 -0
  25. package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginMessage.tsx +45 -0
  26. package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginResultRender.tsx +51 -0
  27. package/src/pages/chat/[id]/Conversation/ChatList/Plugins/style.ts +25 -0
  28. package/src/pages/chat/[id]/Conversation/ChatList/index.tsx +112 -0
  29. package/src/pages/chat/[id]/Conversation/Input/Token.tsx +1 -1
  30. package/src/pages/chat/[id]/edit/AgentPlugin/index.tsx +2 -2
  31. package/src/pages/setting/Header.tsx +2 -2
  32. package/src/pages/setting/index.page.tsx +11 -28
  33. package/src/pages/setting/layout.tsx +35 -0
  34. package/src/plugins/Render.ts +8 -0
  35. package/src/plugins/index.ts +7 -3
  36. package/src/plugins/searchEngine/index.ts +4 -1
  37. package/src/plugins/searchEngine/runner.ts +5 -73
  38. package/src/plugins/searchEngine/type.ts +80 -0
  39. package/src/plugins/type.ts +17 -0
  40. package/src/plugins/weather/Render.tsx +53 -0
  41. package/src/plugins/weather/index.ts +9 -1
  42. package/src/plugins/weather/runner.ts +12 -7
  43. package/src/plugins/weather/type.ts +36 -0
  44. package/src/plugins/webCrawler/index.ts +4 -1
  45. package/src/plugins/webCrawler/runner.ts +3 -27
  46. package/src/plugins/webCrawler/type.ts +32 -0
  47. package/src/services/chatModel.ts +3 -3
  48. package/src/services/plugin.ts +30 -0
  49. package/src/store/session/slices/chat/actions/message.ts +61 -42
  50. package/src/store/session/slices/chat/initialState.ts +2 -4
  51. package/src/store/session/slices/chat/selectors/utils.test.ts +3 -2
  52. package/src/store/session/slices/chat/selectors/utils.ts +4 -3
  53. package/src/types/chatMessage.ts +9 -6
  54. package/src/types/fetch.ts +26 -0
  55. package/src/types/openai.ts +3 -0
  56. package/src/types/plugin.ts +4 -0
  57. package/src/utils/fetch.ts +21 -25
  58. package/src/utils/message.ts +16 -0
  59. package/src/pages/chat/[id]/Conversation/ChatList.tsx +0 -69
  60. package/src/pages/chat/[id]/Conversation/FunctionMessage.tsx +0 -31
@@ -1,39 +1,22 @@
1
- import Head from 'next/head';
2
- import { memo, useEffect } from 'react';
3
- import { useTranslation } from 'react-i18next';
1
+ import { memo } from 'react';
4
2
  import { Flexbox } from 'react-layout-kit';
5
3
 
6
4
  import HeaderSpacing from '@/components/HeaderSpacing';
7
- import { createI18nNext } from '@/locales/create';
8
- import ChatLayout from '@/pages/chat/layout';
9
- import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
10
5
 
11
6
  import Header from './Header';
12
7
  import SettingForm from './SettingForm';
8
+ import SettingLayout from './layout';
13
9
 
14
- const initI18n = createI18nNext('setting');
15
-
16
- const SettingLayout = memo(() => {
17
- const { t } = useTranslation('setting');
18
- const pageTitle = genSiteHeadTitle(t('header.global'));
19
-
20
- useEffect(() => {
21
- initI18n.finally();
22
- }, []);
10
+ const Setting = memo(() => {
23
11
  return (
24
- <>
25
- <Head>
26
- <title>{pageTitle}</title>
27
- </Head>
28
- <ChatLayout>
29
- <Header />
30
- <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
31
- <HeaderSpacing />
32
- <SettingForm />
33
- </Flexbox>
34
- </ChatLayout>
35
- </>
12
+ <SettingLayout>
13
+ <Header />
14
+ <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
15
+ <HeaderSpacing />
16
+ <SettingForm />
17
+ </Flexbox>
18
+ </SettingLayout>
36
19
  );
37
20
  });
38
21
 
39
- export default SettingLayout;
22
+ export default Setting;
@@ -0,0 +1,35 @@
1
+ import Head from 'next/head';
2
+ import { ReactNode, memo, useEffect } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ import SideBar from '@/features/SideBar';
7
+ import { createI18nNext } from '@/locales/create';
8
+ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
9
+
10
+ const initI18n = createI18nNext('setting');
11
+
12
+ const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
13
+ const { t } = useTranslation('setting');
14
+ const pageTitle = genSiteHeadTitle(t('header.global'));
15
+
16
+ useEffect(() => {
17
+ initI18n.finally();
18
+ }, []);
19
+
20
+ return (
21
+ <>
22
+ <Head>
23
+ <title>{pageTitle}</title>
24
+ </Head>
25
+ <Flexbox horizontal width={'100%'}>
26
+ <SideBar />
27
+ <Flexbox flex={1} height={'100vh'} style={{ position: 'relative' }}>
28
+ {children}
29
+ </Flexbox>
30
+ </Flexbox>
31
+ </>
32
+ );
33
+ });
34
+
35
+ export default SettingLayout;
@@ -0,0 +1,8 @@
1
+ import { PluginRender } from '@/plugins/type';
2
+
3
+ import getWeather from './weather';
4
+ import WeatherRender from './weather/Render';
5
+
6
+ export const PluginsRender: Record<string, PluginRender> = {
7
+ [getWeather.name]: WeatherRender,
8
+ };
@@ -1,7 +1,11 @@
1
+ import type { PluginItem } from '@/plugins/type';
2
+
1
3
  import searchEngine from './searchEngine';
2
4
  import getWeather from './weather';
3
5
  import webCrawler from './webCrawler';
4
6
 
5
- const pluginList = [getWeather, searchEngine, webCrawler];
6
-
7
- export default pluginList;
7
+ export const PluginsMap: Record<string, PluginItem> = {
8
+ [getWeather.name]: getWeather,
9
+ [searchEngine.name]: searchEngine,
10
+ [webCrawler.name]: webCrawler,
11
+ };
@@ -1,6 +1,9 @@
1
1
  import { ChatCompletionFunctions } from 'openai-edge/types/api';
2
2
 
3
+ import { PluginItem } from '@/plugins/type';
4
+
3
5
  import runner from './runner';
6
+ import { Result } from './type';
4
7
 
5
8
  const schema: ChatCompletionFunctions = {
6
9
  description: '查询搜索引擎获取信息',
@@ -17,7 +20,7 @@ const schema: ChatCompletionFunctions = {
17
20
  },
18
21
  };
19
22
 
20
- const searchEngine = {
23
+ const searchEngine: PluginItem<Result> = {
21
24
  avatar: '🔍',
22
25
  name: 'searchEngine',
23
26
  runner,
@@ -1,82 +1,14 @@
1
1
  import querystring from 'query-string';
2
2
 
3
- const BASE_URL = 'https://serpapi.com/search';
4
-
5
- const API_KEY = process.env.SERPAI_API_KEY;
6
-
7
- export type OrganicResults = OrganicResult[];
8
-
9
- export interface OrganicResult {
10
- about_page_link: string;
11
- about_page_serpapi_link: string;
12
- about_this_result: AboutThisResult;
13
- cached_page_link?: string;
14
- date?: string;
15
- displayed_link: string;
16
- favicon?: string;
17
- link: string;
18
- position: number;
19
- related_results?: RelatedResult[];
20
- rich_snippet?: RichSnippet;
21
- snippet: string;
22
- snippet_highlighted_words?: string[];
23
- source: string;
24
- thumbnail?: string;
25
- title: string;
26
- }
27
-
28
- export interface AboutThisResult {
29
- languages: string[];
30
- regions: string[];
31
- source: Source;
32
- }
3
+ import { PluginRunner } from '@/plugins/type';
33
4
 
34
- export interface Source {
35
- description: string;
36
- icon: string;
37
- security?: string;
38
- source_info_link?: string;
39
- }
5
+ import { OrganicResults, Result } from './type';
40
6
 
41
- export interface RelatedResult {
42
- about_page_link: string;
43
- about_page_serpapi_link: string;
44
- about_this_result: AboutThisResult2;
45
- cached_page_link: string;
46
- date: string;
47
- displayed_link: string;
48
- link: string;
49
- position: number;
50
- snippet: string;
51
- snippet_highlighted_words: string[];
52
- title: string;
53
- }
54
-
55
- export interface AboutThisResult2 {
56
- languages: string[];
57
- regions: string[];
58
- source: Source2;
59
- }
60
-
61
- export interface Source2 {
62
- description: string;
63
- icon: string;
64
- }
65
-
66
- export interface RichSnippet {
67
- top: Top;
68
- }
69
-
70
- export interface Top {
71
- detected_extensions: DetectedExtensions;
72
- extensions: string[];
73
- }
7
+ const BASE_URL = 'https://serpapi.com/search';
74
8
 
75
- export interface DetectedExtensions {
76
- month_ago: number;
77
- }
9
+ const API_KEY = process.env.SERPAI_API_KEY;
78
10
 
79
- const fetchResult = async ({ keywords }: { keywords: string }) => {
11
+ const fetchResult: PluginRunner<{ keywords: string }, Result> = async ({ keywords }) => {
80
12
  const params = {
81
13
  api_key: API_KEY,
82
14
  engine: 'google',
@@ -0,0 +1,80 @@
1
+ export type OrganicResults = OrganicResult[];
2
+
3
+ export interface SearchItem {
4
+ content?: string;
5
+ date?: string;
6
+ link?: string;
7
+ source?: string;
8
+ title?: string;
9
+ }
10
+ export type Result = SearchItem[];
11
+
12
+ interface OrganicResult {
13
+ about_page_link: string;
14
+ about_page_serpapi_link: string;
15
+ about_this_result: AboutThisResult;
16
+ cached_page_link?: string;
17
+ date?: string;
18
+ displayed_link: string;
19
+ favicon?: string;
20
+ link: string;
21
+ position: number;
22
+ related_results?: RelatedResult[];
23
+ rich_snippet?: RichSnippet;
24
+ snippet: string;
25
+ snippet_highlighted_words?: string[];
26
+ source: string;
27
+ thumbnail?: string;
28
+ title: string;
29
+ }
30
+
31
+ interface AboutThisResult {
32
+ languages: string[];
33
+ regions: string[];
34
+ source: Source;
35
+ }
36
+
37
+ interface Source {
38
+ description: string;
39
+ icon: string;
40
+ security?: string;
41
+ source_info_link?: string;
42
+ }
43
+
44
+ interface RelatedResult {
45
+ about_page_link: string;
46
+ about_page_serpapi_link: string;
47
+ about_this_result: AboutThisResult2;
48
+ cached_page_link: string;
49
+ date: string;
50
+ displayed_link: string;
51
+ link: string;
52
+ position: number;
53
+ snippet: string;
54
+ snippet_highlighted_words: string[];
55
+ title: string;
56
+ }
57
+
58
+ interface AboutThisResult2 {
59
+ languages: string[];
60
+ regions: string[];
61
+ source: Source2;
62
+ }
63
+
64
+ interface Source2 {
65
+ description: string;
66
+ icon: string;
67
+ }
68
+
69
+ interface RichSnippet {
70
+ top: Top;
71
+ }
72
+
73
+ interface Top {
74
+ detected_extensions: DetectedExtensions;
75
+ extensions: string[];
76
+ }
77
+
78
+ interface DetectedExtensions {
79
+ month_ago: number;
80
+ }
@@ -0,0 +1,17 @@
1
+ import { ChatCompletionFunctions } from 'openai-edge/types/api';
2
+ import { ReactNode } from 'react';
3
+
4
+ export interface PluginItem<Result = any, RunnerParams = any> {
5
+ avatar: string;
6
+ name: string;
7
+ runner: PluginRunner<RunnerParams, Result>;
8
+ schema: ChatCompletionFunctions;
9
+ }
10
+ export type PluginRender = (props: PluginRenderProps) => ReactNode;
11
+
12
+ export type PluginRunner<Params = object, Result = any> = (params: Params) => Promise<Result>;
13
+
14
+ export interface PluginRenderProps<Result = any> {
15
+ content: Result;
16
+ name: string;
17
+ }
@@ -0,0 +1,53 @@
1
+ import { Table } from 'antd';
2
+ import { createStyles } from 'antd-style';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Flexbox } from 'react-layout-kit';
6
+
7
+ import { PluginRenderProps } from '@/plugins/type';
8
+
9
+ import { WeatherResult } from './type';
10
+
11
+ const useStyles = createStyles(({ css, token }) => ({
12
+ time: css`
13
+ color: ${token.colorTextQuaternary};
14
+ `,
15
+ title: css`
16
+ font-weight: bold;
17
+ `,
18
+ }));
19
+
20
+ const Render = memo<PluginRenderProps<WeatherResult>>(({ content }) => {
21
+ const { t } = useTranslation('plugin');
22
+
23
+ const { styles } = useStyles();
24
+ return (
25
+ <div>
26
+ {content.map((item, index) => (
27
+ <Flexbox gap={8} key={`${item.city}-${index}`}>
28
+ <Flexbox align={'center'} distribution={'space-between'} horizontal>
29
+ <div className={styles.title}>{t('realtimeWeather.title', { city: item.city })}</div>
30
+ <div className={styles.time}>
31
+ {t('realtimeWeather.updateAt')}: {item.reporttime}
32
+ </div>
33
+ </Flexbox>
34
+ <Table
35
+ bordered
36
+ columns={[
37
+ { dataIndex: 'date', title: t('realtimeWeather.data.date') },
38
+ { dataIndex: 'week', title: t('realtimeWeather.data.week') },
39
+ { dataIndex: 'dayweather', title: t('realtimeWeather.data.dayweather') },
40
+ { dataIndex: 'daytemp_float', title: t('realtimeWeather.data.daytemp_float') },
41
+ { dataIndex: 'daywind', title: t('realtimeWeather.data.daywind') },
42
+ { dataIndex: 'nightweather', title: t('realtimeWeather.data.nightweather') },
43
+ { dataIndex: 'nighttemp_float', title: t('realtimeWeather.data.nighttemp_float') },
44
+ ]}
45
+ dataSource={item.casts}
46
+ pagination={false}
47
+ />
48
+ </Flexbox>
49
+ ))}
50
+ </div>
51
+ );
52
+ });
53
+ export default Render;
@@ -1,3 +1,6 @@
1
+ import { PluginItem } from '@/plugins/type';
2
+ import { WeatherResult } from '@/plugins/weather/type';
3
+
1
4
  import runner from './runner';
2
5
 
3
6
  const schema = {
@@ -15,6 +18,11 @@ const schema = {
15
18
  },
16
19
  };
17
20
 
18
- const getWeather = { avatar: '☂️', name: 'realtimeWeather', runner, schema };
21
+ const getWeather: PluginItem<WeatherResult> = {
22
+ avatar: '☂️',
23
+ name: 'realtimeWeather',
24
+ runner,
25
+ schema,
26
+ };
19
27
 
20
28
  export default getWeather;
@@ -1,30 +1,35 @@
1
+ import { PluginRunner } from '@/plugins/type';
2
+
3
+ import { Response, WeatherParams, WeatherResult } from './type';
4
+
1
5
  const weatherBaseURL = 'https://restapi.amap.com/v3/weather/weatherInfo';
2
6
 
3
7
  const citySearchURL = 'https://restapi.amap.com/v3/config/district';
4
8
 
5
9
  const KEY = process.env.GAODE_WEATHER_KEY;
6
10
 
7
- interface WeatherParams {
8
- city: string;
9
- extensions?: 'base' | 'all';
10
- }
11
-
12
11
  const fetchCityCode = async (keywords: string): Promise<string> => {
13
12
  const URL = `${citySearchURL}?keywords=${keywords}&subdistrict=0&extensions=base&key=${KEY}`;
14
13
  const res = await fetch(URL);
15
14
 
16
15
  const data = await res.json();
16
+ console.log(data);
17
17
 
18
18
  return data.districts[0].adcode;
19
19
  };
20
20
 
21
- const fetchWeather = async ({ city, extensions = 'all' }: WeatherParams) => {
21
+ const fetchWeather: PluginRunner<WeatherParams, WeatherResult> = async ({
22
+ city,
23
+ extensions = 'all',
24
+ }) => {
22
25
  const cityCode = await fetchCityCode(city);
23
26
 
24
27
  const URL = `${weatherBaseURL}?city=${cityCode}&extensions=${extensions}&key=${KEY}`;
25
28
  const res = await fetch(URL);
26
29
 
27
- return await res.json();
30
+ const data: Response = await res.json();
31
+
32
+ return data.forecasts;
28
33
  };
29
34
 
30
35
  export default fetchWeather;
@@ -0,0 +1,36 @@
1
+ export interface WeatherParams {
2
+ city: string;
3
+ extensions?: 'base' | 'all';
4
+ }
5
+ export type WeatherResult = Forecast[];
6
+
7
+ export interface Response {
8
+ count: string;
9
+ forecasts: Forecast[];
10
+ info: string;
11
+ infocode: string;
12
+ status: string;
13
+ }
14
+
15
+ export interface Forecast {
16
+ adcode: string;
17
+ casts: Cast[];
18
+ city: string;
19
+ province: string;
20
+ reporttime: string;
21
+ }
22
+
23
+ export interface Cast {
24
+ date: string;
25
+ daypower: string;
26
+ daytemp: string;
27
+ daytemp_float: string;
28
+ dayweather: string;
29
+ daywind: string;
30
+ nightpower: string;
31
+ nighttemp: string;
32
+ nighttemp_float: string;
33
+ nightweather: string;
34
+ nightwind: string;
35
+ week: string;
36
+ }
@@ -1,4 +1,7 @@
1
+ import { PluginItem } from '@/plugins/type';
2
+
1
3
  import runner from './runner';
4
+ import { Result } from './type';
2
5
 
3
6
  const schema = {
4
7
  description: '提取网页内容并总结',
@@ -15,6 +18,6 @@ const schema = {
15
18
  },
16
19
  };
17
20
 
18
- const getWeather = { avatar: '🕸', name: 'websiteCrawler', runner, schema };
21
+ const getWeather: PluginItem<Result> = { avatar: '🕸', name: 'websiteCrawler', runner, schema };
19
22
 
20
23
  export default getWeather;
@@ -1,36 +1,12 @@
1
- export type DataResults = DataItem[];
1
+ import { PluginRunner } from '@/plugins/type';
2
2
 
3
- export interface DataItem {
4
- crawl: Crawl;
5
- markdown: string;
6
- metadata: Metadata;
7
- screenshotUrl: any;
8
- text: string;
9
- url: string;
10
- }
11
-
12
- export interface Crawl {
13
- depth: number;
14
- httpStatusCode: number;
15
- loadedTime: string;
16
- loadedUrl: string;
17
- referrerUrl: string;
18
- }
19
-
20
- export interface Metadata {
21
- author: any;
22
- canonicalUrl: string;
23
- description: string;
24
- keywords: string;
25
- languageCode: string;
26
- title: string;
27
- }
3
+ import { DataResults, Result } from './type';
28
4
 
29
5
  const BASE_URL =
30
6
  'https://api.apify.com/v2/acts/apify~website-content-crawler/run-sync-get-dataset-items';
31
7
  const token = process.env.APIFY_API_KEY;
32
8
 
33
- const runner = async ({ url }: { url: string }) => {
9
+ const runner: PluginRunner<{ url: string }, Result> = async ({ url }) => {
34
10
  // Prepare Actor input
35
11
  const input = {
36
12
  aggressivePrune: false,
@@ -0,0 +1,32 @@
1
+ export type DataResults = DataItem[];
2
+
3
+ export type Result = {
4
+ content?: string;
5
+ title?: string;
6
+ url?: string;
7
+ };
8
+ export interface DataItem {
9
+ crawl: Crawl;
10
+ markdown: string;
11
+ metadata: Metadata;
12
+ screenshotUrl: any;
13
+ text: string;
14
+ url: string;
15
+ }
16
+
17
+ export interface Crawl {
18
+ depth: number;
19
+ httpStatusCode: number;
20
+ loadedTime: string;
21
+ loadedUrl: string;
22
+ referrerUrl: string;
23
+ }
24
+
25
+ export interface Metadata {
26
+ author: any;
27
+ canonicalUrl: string;
28
+ description: string;
29
+ keywords: string;
30
+ languageCode: string;
31
+ title: string;
32
+ }
@@ -1,6 +1,6 @@
1
1
  import { merge } from 'lodash-es';
2
2
 
3
- import { OPENAI_API_KEY_HEADER_KEY } from '@/const/fetch';
3
+ import { LOBE_CHAT_ACCESS_CODE, OPENAI_API_KEY_HEADER_KEY } from '@/const/fetch';
4
4
  import { initialLobeAgentConfig } from '@/store/session';
5
5
  import { useSettings } from '@/store/settings';
6
6
  import type { OpenAIStreamPayload } from '@/types/openai';
@@ -9,7 +9,6 @@ import { URLS } from './url';
9
9
 
10
10
  interface FetchChatModelOptions {
11
11
  signal?: AbortSignal | undefined;
12
- withPlugin?: boolean;
13
12
  }
14
13
 
15
14
  /**
@@ -28,10 +27,11 @@ export const fetchChatModel = (
28
27
  params,
29
28
  );
30
29
 
31
- return fetch(options?.withPlugin ? URLS.plugins : URLS.openai, {
30
+ return fetch(URLS.openai, {
32
31
  body: JSON.stringify(payload),
33
32
  headers: {
34
33
  'Content-Type': 'application/json',
34
+ [LOBE_CHAT_ACCESS_CODE]: useSettings.getState().settings.password || '',
35
35
  [OPENAI_API_KEY_HEADER_KEY]: useSettings.getState().settings.OPENAI_API_KEY || '',
36
36
  },
37
37
  method: 'POST',
@@ -0,0 +1,30 @@
1
+ import { LOBE_CHAT_ACCESS_CODE } from '@/const/fetch';
2
+ import { useSettings } from '@/store/settings';
3
+ import { OpenAIPluginPayload } from '@/types/plugin';
4
+
5
+ import { URLS } from './url';
6
+
7
+ interface FetchChatModelOptions {
8
+ signal?: AbortSignal | undefined;
9
+ withPlugin?: boolean;
10
+ }
11
+
12
+ /**
13
+ * 专门用于对话的 fetch
14
+ */
15
+ export const fetchPlugin = async (
16
+ params: Partial<OpenAIPluginPayload>,
17
+ options?: FetchChatModelOptions,
18
+ ) => {
19
+ const res = await fetch(URLS.plugins, {
20
+ body: JSON.stringify(params),
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ [LOBE_CHAT_ACCESS_CODE]: useSettings.getState().settings.password || '',
24
+ },
25
+ method: 'POST',
26
+ signal: options?.signal,
27
+ });
28
+
29
+ return await res.text();
30
+ };