@lobehub/chat 0.54.2 → 0.54.3

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.54.3](https://github.com/lobehub/lobe-chat/compare/v0.54.2...v0.54.3)
6
+
7
+ <sup>Released on **2023-08-21**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor plugin request.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor plugin request, closes [#89](https://github.com/lobehub/lobe-chat/issues/89) ([23efee3](https://github.com/lobehub/lobe-chat/commit/23efee3))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 0.54.2](https://github.com/lobehub/lobe-chat/compare/v0.54.1...v0.54.2)
6
31
 
7
32
  <sup>Released on **2023-08-16**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.54.2",
3
+ "version": "0.54.3",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -63,10 +63,10 @@
63
63
  "dependencies": {
64
64
  "@ant-design/colors": "^7",
65
65
  "@ant-design/icons": "^5",
66
- "@commitlint/cli": "^17",
67
66
  "@emoji-mart/data": "^1",
68
67
  "@emoji-mart/react": "^1",
69
68
  "@icons-pack/react-simple-icons": "^8",
69
+ "@lobehub/chat-plugin-sdk": "latest",
70
70
  "@lobehub/ui": "latest",
71
71
  "@vercel/analytics": "^1",
72
72
  "ahooks": "^3",
@@ -86,7 +86,6 @@
86
86
  "next": "13.4.7",
87
87
  "openai-edge": "^1",
88
88
  "polished": "^4",
89
- "query-string": "^8",
90
89
  "react": "^18",
91
90
  "react-dom": "^18",
92
91
  "react-hotkeys-hook": "^4",
@@ -1,22 +1,10 @@
1
- import { OpenAIPluginPayload } from '@/types/plugin';
2
-
3
- import { PluginsMap } from '../../plugins';
4
-
5
1
  export const runtime = 'edge';
6
2
 
7
- export default async function handler(req: Request) {
8
- const { name, arguments: args } = (await req.json()) as OpenAIPluginPayload;
9
-
10
- console.log(`检测到 functionCall: ${name}`);
3
+ // chat plugin gateway
4
+ // refs to: https://github.com/lobehub/chat-plugins-gateway
5
+ const PLUGIN_GATEWAY_URL = process.env.PLUGIN_GATEWAY_URL || 'https://chat-plugins.lobehub.com';
11
6
 
12
- const func = PluginsMap[name];
13
-
14
- if (func) {
15
- const data = JSON.parse(args);
16
- const result = await func.runner(data);
17
-
18
- console.log(`[${name}]`, args, `result:`, JSON.stringify(result, null, 2).slice(0, 3600));
19
-
20
- return new Response(JSON.stringify(result));
21
- }
7
+ export default async function handler(req: Request) {
8
+ const payload = await req.text();
9
+ return fetch(`${PLUGIN_GATEWAY_URL}/api/v1/runner`, { body: payload, method: 'POST' });
22
10
  }
@@ -2,9 +2,6 @@ import { ChatCompletionFunctions } from 'openai-edge/types/api';
2
2
 
3
3
  import { PluginItem } from '@/plugins/type';
4
4
 
5
- import runner from './runner';
6
- import { Result } from './type';
7
-
8
5
  const schema: ChatCompletionFunctions = {
9
6
  description: '查询搜索引擎获取信息',
10
7
  name: 'searchEngine',
@@ -20,10 +17,9 @@ const schema: ChatCompletionFunctions = {
20
17
  },
21
18
  };
22
19
 
23
- const searchEngine: PluginItem<Result> = {
20
+ const searchEngine: PluginItem = {
24
21
  avatar: '🔍',
25
22
  name: 'searchEngine',
26
- runner,
27
23
  schema,
28
24
  };
29
25
 
@@ -6,7 +6,7 @@ import { ReactNode } from 'react';
6
6
  * @template Result - 结果类型,默认为 any
7
7
  * @template RunnerParams - 运行参数类型,默认为 any
8
8
  */
9
- export interface PluginItem<Result = any, RunnerParams = any> {
9
+ export interface PluginItem {
10
10
  /**
11
11
  * 头像
12
12
  */
@@ -15,12 +15,7 @@ export interface PluginItem<Result = any, RunnerParams = any> {
15
15
  * 名称
16
16
  */
17
17
  name: string;
18
- /**
19
- * 运行器
20
- * @param params - 运行参数
21
- * @returns 运行结果的 Promise
22
- */
23
- runner: PluginRunner<RunnerParams, Result>;
18
+ render?: PluginRender;
24
19
  /**
25
20
  * 聊天完成函数的模式
26
21
  */
@@ -34,15 +29,6 @@ export interface PluginItem<Result = any, RunnerParams = any> {
34
29
  */
35
30
  export type PluginRender = (props: PluginRenderProps) => ReactNode;
36
31
 
37
- /**
38
- * 插件运行器
39
- * @template Params - 参数类型,默认为 object
40
- * @template Result - 结果类型,默认为 any
41
- * @param params - 运行参数
42
- * @returns 运行结果的 Promise
43
- */
44
- export type PluginRunner<Params = object, Result = any> = (params: Params) => Promise<Result>;
45
-
46
32
  /**
47
33
  * 插件渲染属性
48
34
  * @template Result - 结果类型,默认为 any
@@ -1,7 +1,4 @@
1
1
  import { PluginItem } from '@/plugins/type';
2
- import { WeatherResult } from '@/plugins/weather/type';
3
-
4
- import runner from './runner';
5
2
 
6
3
  const schema = {
7
4
  description: '获取当前天气情况',
@@ -18,10 +15,9 @@ const schema = {
18
15
  },
19
16
  };
20
17
 
21
- const getWeather: PluginItem<WeatherResult> = {
18
+ const getWeather: PluginItem = {
22
19
  avatar: '☂️',
23
20
  name: 'realtimeWeather',
24
- runner,
25
21
  schema,
26
22
  };
27
23
 
@@ -1,8 +1,5 @@
1
1
  import { PluginItem } from '@/plugins/type';
2
2
 
3
- import runner from './runner';
4
- import { Result } from './type';
5
-
6
3
  const schema = {
7
4
  description: '提取网页内容并总结',
8
5
  name: 'websiteCrawler',
@@ -18,6 +15,6 @@ const schema = {
18
15
  },
19
16
  };
20
17
 
21
- const getWeather: PluginItem<Result> = { avatar: '🕸', name: 'websiteCrawler', runner, schema };
18
+ const getWeather: PluginItem = { avatar: '🕸', name: 'websiteCrawler', schema };
22
19
 
23
20
  export default getWeather;
@@ -1,6 +1,7 @@
1
+ import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
2
+
1
3
  import { LOBE_CHAT_ACCESS_CODE } from '@/const/fetch';
2
4
  import { useGlobalStore } from '@/store/global';
3
- import { OpenAIPluginPayload } from '@/types/plugin';
4
5
 
5
6
  import { URLS } from './url';
6
7
 
@@ -13,7 +14,7 @@ interface FetchChatModelOptions {
13
14
  * 专门用于对话的 fetch
14
15
  */
15
16
  export const fetchPlugin = async (
16
- params: Partial<OpenAIPluginPayload>,
17
+ params: PluginRequestPayload,
17
18
  options?: FetchChatModelOptions,
18
19
  ) => {
19
20
  const res = await fetch(URLS.plugins, {
@@ -1,41 +0,0 @@
1
- import querystring from 'query-string';
2
-
3
- import { PluginRunner } from '@/plugins/type';
4
-
5
- import { OrganicResults, Result } from './type';
6
-
7
- const BASE_URL = 'https://serpapi.com/search';
8
-
9
- const API_KEY = process.env.SERPAI_API_KEY;
10
-
11
- const fetchResult: PluginRunner<{ keywords: string }, Result> = async ({ keywords }) => {
12
- const params = {
13
- api_key: API_KEY,
14
- engine: 'google',
15
- gl: 'cn',
16
- google_domain: 'google.com',
17
- hl: 'zh-cn',
18
- location: 'China',
19
- q: keywords,
20
- };
21
-
22
- const query = querystring.stringify(params);
23
-
24
- const res = await fetch(`${BASE_URL}?${query}`);
25
-
26
- const data = await res.json();
27
-
28
- const results = data.organic_results as OrganicResults;
29
-
30
- return results.map((r) => ({
31
- content: r.snippet,
32
- date: r.date,
33
- displayed_link: r.displayed_link,
34
- favicon: r.favicon,
35
- link: r.link,
36
- source: r.source,
37
- title: r.title,
38
- }));
39
- };
40
-
41
- export default fetchResult;
@@ -1,35 +0,0 @@
1
- import { PluginRunner } from '@/plugins/type';
2
-
3
- import { Response, WeatherParams, WeatherResult } from './type';
4
-
5
- const weatherBaseURL = 'https://restapi.amap.com/v3/weather/weatherInfo';
6
-
7
- const citySearchURL = 'https://restapi.amap.com/v3/config/district';
8
-
9
- const KEY = process.env.GAODE_WEATHER_KEY;
10
-
11
- const fetchCityCode = async (keywords: string): Promise<string> => {
12
- const URL = `${citySearchURL}?keywords=${keywords}&subdistrict=0&extensions=base&key=${KEY}`;
13
- const res = await fetch(URL);
14
-
15
- const data = await res.json();
16
- console.log(data);
17
-
18
- return data.districts[0].adcode;
19
- };
20
-
21
- const fetchWeather: PluginRunner<WeatherParams, WeatherResult> = async ({
22
- city,
23
- extensions = 'all',
24
- }) => {
25
- const cityCode = await fetchCityCode(city);
26
-
27
- const URL = `${weatherBaseURL}?city=${cityCode}&extensions=${extensions}&key=${KEY}`;
28
- const res = await fetch(URL);
29
-
30
- const data: Response = await res.json();
31
-
32
- return data.forecasts;
33
- };
34
-
35
- export default fetchWeather;
@@ -1,46 +0,0 @@
1
- import { PluginRunner } from '@/plugins/type';
2
-
3
- import { ParserResponse, Result } from './type';
4
-
5
- const BASE_URL = process.env.BROWSERLESS_URL ?? 'https://chrome.browserless.io';
6
- const BROWSERLESS_TOKEN = process.env.BROWSERLESS_TOKEN;
7
-
8
- // service from: https://github.com/lobehub/html-parser/tree/master
9
- const HTML_PARSER_URL = process.env.HTML_PARSER_URL;
10
-
11
- const runner: PluginRunner<{ url: string }, Result> = async ({ url }) => {
12
- const input = {
13
- gotoOptions: { waitUntil: 'networkidle2' },
14
- url,
15
- };
16
-
17
- try {
18
- const res = await fetch(`${BASE_URL}/content?token=${BROWSERLESS_TOKEN}`, {
19
- body: JSON.stringify(input),
20
- headers: {
21
- 'Content-Type': 'application/json',
22
- },
23
- method: 'POST',
24
- });
25
- const html = await res.text();
26
-
27
- const parserBody = { html, url };
28
-
29
- const parseRes = await fetch(`${HTML_PARSER_URL}`, {
30
- body: JSON.stringify(parserBody),
31
- headers: {
32
- 'Content-Type': 'application/json',
33
- },
34
- method: 'POST',
35
- });
36
-
37
- const { title, textContent, siteName } = (await parseRes.json()) as ParserResponse;
38
-
39
- return { content: textContent, title, url, website: siteName };
40
- } catch (error) {
41
- console.error(error);
42
- return { content: '抓取失败', errorMessage: (error as any).message, url };
43
- }
44
- };
45
-
46
- export default runner;