@lobehub/chat 0.68.1 → 0.69.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.
@@ -0,0 +1,262 @@
1
+ # LobeChat Plugin Development
2
+
3
+ #### TOC
4
+
5
+ - [Plugin Composition](#plugin-composition)
6
+
7
+ - [Custom Plugin Workflow](#custom-plugin-workflow)
8
+
9
+ - [1. Create and Start a Plugin Project](#1-create-and-start-a-plugin-project)
10
+ - [2. Add the Local Plugin in LobeChat Role Settings](#2-add-the-local-plugin-in-lobechat-role-settings)
11
+ - [3. Test the Plugin Functionality in a Session](#3-test-the-plugin-functionality-in-a-session)
12
+
13
+ - [Local Plugin Development](#local-plugin-development)
14
+
15
+ - [Manifest](#manifest)
16
+ - [Project Structure](#project-structure)
17
+ - [Server-side](#server-side)
18
+ - [Plugin UI Interface](#plugin-ui-interface)
19
+
20
+ - [Plugin Deployment and Publication](#plugin-deployment-and-publication)
21
+
22
+ ## Plugin Composition
23
+
24
+ A LobeChat plugin consists of the following components:
25
+
26
+ 1. **Plugin Index**: Used to display basic information about the plugin, including the plugin name, description, author, version, and a link to the plugin manifest. The official plugin index can be found at [lobe-chat-plugins](https://github.com/lobehub/lobe-chat-plugins). To submit a plugin to the official plugin marketplace, you need to submit a PR to this repository.
27
+ 2. **Plugin Manifest**: Used to describe the functionality of the plugin, including the server-side description, frontend display information, and version number. For more details about the manifest, please refer to the [manifest][manifest-docs-url].
28
+ 3. **Plugin Services**: Used to implement the server-side and frontend modules described in the manifest:
29
+
30
+ - **Server-side**: Implement the API capabilities described in the manifest.
31
+ - **Frontend UI** (optional): Implement the interface described in the manifest, which will be displayed in plugin messages to provide richer information display than plain text.
32
+
33
+ ## Custom Plugin Workflow
34
+
35
+ To integrate a plugin into LobeChat, you need to add and use a custom plugin in LobeChat. This section will guide you through the process.
36
+
37
+ ### 1. Create and Start a Plugin Project
38
+
39
+ First, you need to create a plugin project locally. You can use the [lobe-chat-plugin-template][lobe-chat-plugin-template-url] template we have prepared:
40
+
41
+ ```bash
42
+ $ git clone https://github.com/lobehub/chat-plugin-template.git
43
+ $ cd chat-plugin-template
44
+ $ npm i
45
+ $ npm run dev
46
+ ```
47
+
48
+ When you see `ready started server on 0.0.0.0:3400, url: http://localhost:3400`, it means that the plugin service has been successfully started locally.
49
+
50
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259526-9ef25272-4312-429b-93bc-a95515727ed3.png)
51
+
52
+ ### 2. Add the Local Plugin in LobeChat Role Settings
53
+
54
+ Next, go to LobeChat, create a new assistant, and go to its session settings page:
55
+
56
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259643-1a9cc34a-76f3-4ccf-928b-129654670efd.png)
57
+
58
+ Click the "Add" button on the right side of "Plugin List" to open the custom plugin add dialog:
59
+
60
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259748-2ef6a244-39bb-483c-b359-f156ffcbe1a4.png)
61
+
62
+ Enter `http://localhost:3400/manifest-dev.json` in the "Plugin Manifest URL" field, which is the URL of the locally started plugin manifest.
63
+
64
+ At this point, you should see that the identifier of the plugin has been automatically recognized as `chat-plugin-template`. Then fill in the remaining form fields (only the title is required) and click the "Save" button to complete the custom plugin addition.
65
+
66
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259964-59f4906d-ae2e-4ec0-8b43-db36871d0869.png)
67
+
68
+ After adding the plugin, you can see the newly added plugin in the plugin list. If you need to modify the plugin's configuration, you can click the "Settings" button to make changes.
69
+
70
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260093-a0363c74-0b5b-48dd-b103-2db6b4a8262e.png)
71
+
72
+ ### 3. Test the Plugin Functionality in a Session
73
+
74
+ Next, we need to test the functionality of the custom plugin.
75
+
76
+ Click the "Back" button to go back to the session area, and then send a message to the assistant: "What should I wear?" The assistant will try to ask you about your gender and current mood.
77
+
78
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260291-f0aa0e7c-0ffb-486c-a834-08e73d49896f.png)
79
+
80
+ After answering, the assistant will make a plugin call to retrieve recommended clothing data based on your gender and mood from the server and push it to you. Finally, it will summarize the information in a text response.
81
+
82
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260461-c22ae797-2809-464b-96fc-d0c020f4807b.png)
83
+
84
+ After completing these steps, you have learned the basic process of adding and using a custom plugin in LobeChat.
85
+
86
+ ## Local Plugin Development
87
+
88
+ In the previous workflow, we have learned how to add and use a plugin. Now let's focus on the development process of custom plugins.
89
+
90
+ ### Manifest
91
+
92
+ The manifest aggregates information about how the plugin's functionality is implemented. The core fields are `api` and `ui`, which describe the server-side API capabilities and the frontend rendering interface address of the plugin, respectively.
93
+
94
+ Taking the manifest in our template as an example:
95
+
96
+ ```json
97
+ {
98
+ "api": [
99
+ {
100
+ "url": "http://localhost:3400/api/clothes",
101
+ "name": "recommendClothes",
102
+ "description": "Recommend clothes based on the user's mood",
103
+ "parameters": {
104
+ "properties": {
105
+ "mood": {
106
+ "description": "The user's current mood, with optional values: happy, sad, anger, fear, surprise, disgust",
107
+ "enums": ["happy", "sad", "anger", "fear", "surprise", "disgust"],
108
+ "type": "string"
109
+ },
110
+ "gender": {
111
+ "type": "string",
112
+ "enum": ["man", "woman"],
113
+ "description": "The gender of the user, which needs to be asked before knowing this information"
114
+ }
115
+ },
116
+ "required": ["mood", "gender"],
117
+ "type": "object"
118
+ }
119
+ }
120
+ ],
121
+ "gateway": "http://localhost:3400/api/gateway",
122
+ "identifier": "chat-plugin-template",
123
+ "ui": {
124
+ "url": "http://localhost:3400",
125
+ "height": 200
126
+ },
127
+ "version": "1"
128
+ }
129
+ ```
130
+
131
+ In this manifest, the following parts are included:
132
+
133
+ 1. `identifier`: This is the unique identifier of the plugin, used to distinguish different plugins. This field needs to be globally unique.
134
+ 2. `api`: This is an array that contains all the API interface information provided by the plugin. Each interface includes the `url`, `name`, `description`, and `parameters` fields, all of which are required. The `description` and `parameters` fields will be sent to GPT as the `functions` parameter of the [Function Call](https://sspai.com/post/81986). The parameters need to comply with the [JSON Schema](https://json-schema.org/) specification. In this example, the API interface is named `recommendClothes`, which recommends clothes based on the user's mood and gender. The parameters of the interface include the user's mood and gender, both of which are required.
135
+ 3. `ui`: This field contains information about the plugin's user interface, indicating where LobeChat loads the frontend interface of the plugin from. Since the plugin interface loading in LobeChat is implemented based on `iframe`, you can specify the height and width of the plugin interface as needed.
136
+ 4. `gateway`: This field specifies the gateway for LobeChat to query API interfaces. The default plugin gateway in LobeChat is a cloud service, but for custom plugins, the requests need to be sent to the local service. Therefore, by specifying the gateway in the manifest, LobeChat will directly request this address and access the local plugin service. The gateway field does not need to be specified for plugins published online.
137
+ 5. `version`: This is the version number of the plugin, which is currently not used.
138
+
139
+ In actual development, you can modify the plugin's manifest according to your needs to declare the functionality you want to implement. For a complete introduction to each field in the manifest, please refer to: [manifest][manifest-docs-url].
140
+
141
+ ### Project Structure
142
+
143
+ The [lobe-chat-plugin-template][lobe-chat-plugin-template-url] template project uses Next.js as the development framework. Its core directory structure is as follows:
144
+
145
+ ```
146
+ ➜ chat-plugin-template
147
+ ├── public
148
+ │ └── manifest-dev.json # Manifest file
149
+ ├── src
150
+ │ └── pages
151
+ │ │ ├── api # Next.js server-side folder
152
+ │ │ │ ├── clothes.ts # Implementation of the recommendClothes interface
153
+ │ │ │ └── gateway.ts # Local plugin proxy gateway
154
+ │ │ └── index.tsx # Frontend display interface
155
+ ```
156
+
157
+ Of course, using Next.js as the development framework in the template is just because we are familiar with Next.js and it is convenient for development. You can use any frontend framework and programming language you are familiar with as long as it can implement the functionality described in the manifest.
158
+
159
+ We also welcome contributions of plugin templates in more frameworks and languages.
160
+
161
+ ### Server-side
162
+
163
+ The server-side only needs to implement the API interfaces described in the manifest. In the template, we use Vercel's [Edge Runtime](https://nextjs.org/docs/pages/api-reference/edge) as the server, which eliminates the need for operational maintenance.
164
+
165
+ #### API Implementation
166
+
167
+ For Edge Runtime, we provide the `createErrorResponse` method in `@lobehub/chat-plugin-sdk` to quickly return error responses. The currently provided error types can be found at: [PluginErrorType][plugin-error-type-url].
168
+
169
+ Here is an example of the clothes API implementation in the template:
170
+
171
+ ```ts
172
+ export default async (req: Request) => {
173
+ if (req.method !== 'POST') return createErrorResponse(PluginErrorType.MethodNotAllowed);
174
+
175
+ const { gender, mood } = (await req.json()) as RequestData;
176
+
177
+ const clothes = gender === 'man' ? manClothes : womanClothes;
178
+
179
+ const result: ResponseData = {
180
+ clothes: clothes[mood] || [],
181
+ mood,
182
+ today: Date.now(),
183
+ };
184
+
185
+ return new Response(JSON.stringify(result));
186
+ };
187
+ ```
188
+
189
+ In this example, `manClothes` and `womanClothes` are hardcoded mock data. In actual scenarios, they can be replaced with database queries.
190
+
191
+ #### Gateway
192
+
193
+ Since the default plugin gateway in LobeChat is a cloud service (<https://chat.lobehub.com/api/plugins>), which sends requests to the API addresses specified in the manifest to solve the cross-origin issue.
194
+
195
+ For custom plugins, the requests need to be sent to the local service. Therefore, by specifying the gateway in the manifest (<http://localhost:3400/api/gateway>), LobeChat will directly request this address. Then you only need to create a gateway implementation at this address.
196
+
197
+ ```ts
198
+ import { createLobeChatPluginGateway } from '@lobehub/chat-plugins-gateway';
199
+
200
+ export const config = {
201
+ runtime: 'edge',
202
+ };
203
+
204
+ export default async createLobeChatPluginGateway();
205
+ ```
206
+
207
+ [`@lobehub/chat-plugins-gateway`](https://github.com/lobehub/chat-plugins-gateway) includes the implementation of the plugin gateway in LobeChat, which you can use to create a gateway. This allows LobeChat to access the local plugin service.
208
+
209
+ ### Plugin UI Interface
210
+
211
+ For a plugin, the UI interface is optional. For example, the [Web Crawler](https://github.com/lobehub/chat-plugin-web-crawler) plugin does not provide a corresponding user interface.
212
+
213
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263241-0e765fdc-3463-4c36-a398-aef177a30df9.png)
214
+
215
+ If you want to display richer information in plugin messages or include some rich interactions, you can define a user interface for the plugin. For example, the following image shows the user interface of a search engine plugin.
216
+
217
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263427-9bdc03d5-aa61-4f62-a2ce-88683f3308d8.png)
218
+
219
+ #### Plugin UI Interface Implementation
220
+
221
+ LobeChat uses `iframe` + `postMessage` to load and communicate with plugin UI. Therefore, the implementation of the plugin UI is the same as normal web development. You can use any frontend framework and programming language you are familiar with.
222
+
223
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263653-4ea87abc-249a-49f3-a241-7ed93ddb1ddf.png)
224
+
225
+ In our template, we use React + Next.js + antd as the frontend framework. You can find the implementation of the user interface in `src/pages/index.tsx`.
226
+
227
+ Regarding plugin communication, we provide related methods in [`@lobehub/chat-plugin-sdk`](https://github.com/lobehub/chat-plugin-sdk) to simplify the communication between the plugin and LobeChat. You can use the `fetchPluginMessage` method to actively retrieve the data of the current message from LobeChat. For a detailed description of this method, please refer to: [fetchPluginMessage][fetch-plugin-message-url].
228
+
229
+ ```tsx
230
+ import { fetchPluginMessage } from '@lobehub/chat-plugin-sdk';
231
+ import { memo, useEffect, useState } from 'react';
232
+
233
+ import { ResponseData } from '@/type';
234
+
235
+ const Render = memo(() => {
236
+ const [data, setData] = useState<ResponseData>();
237
+
238
+ useEffect(() => {
239
+ // Retrieve the current plugin message from LobeChat
240
+ fetchPluginMessage().then((e: ResponseData) => {
241
+ setData(e);
242
+ });
243
+ }, []);
244
+
245
+ return <>...</>;
246
+ });
247
+
248
+ export default Render;
249
+ ```
250
+
251
+ ## Plugin Deployment and Publication
252
+
253
+ After completing the plugin development, you can deploy the plugin using your preferred method. For example, you can use Vercel or package it as a Docker image for publication.
254
+
255
+ If you want more people to use your plugin, you are welcome to submit it for review in the plugin marketplace.
256
+
257
+ <!-- LINK GROUP -->
258
+
259
+ [fetch-plugin-message-url]: https://github.com/lobehub/chat-plugin-template
260
+ [lobe-chat-plugin-template-url]: https://github.com/lobehub/chat-plugin-template
261
+ [manifest-docs-url]: https://github.com/lobehub/chat-plugin-sdk/tree/master/docs/manifest.zh-CN.md
262
+ [plugin-error-type-url]: https://github.com/lobehub/chat-plugin-template
@@ -0,0 +1,261 @@
1
+ # LobeChat 插äģļåŧ€å‘
2
+
3
+ #### TOC
4
+
5
+ - [插äģļæž„成](#插äģļæž„成)
6
+
7
+ - [č‡Ē厚䚉插äģļæĩį¨‹](#č‡Ē厚䚉插äģļæĩį¨‹)
8
+
9
+ - [1. 创åģēåšļ启动插äģļéĄšį›Ž](#1-创åģēåšļ启动插äģļéĄšį›Ž)
10
+ - [2. 在 LobeChat 角色设įŊŽä¸­æˇģ加æœŦ地插äģļ](#2-在-lobechat-角色设įŊŽä¸­æˇģ加æœŦ地插äģļ)
11
+ - [3. äŧšč¯æĩ‹č¯•插äģļ功čƒŊ](#3-äŧšč¯æĩ‹č¯•插äģļ功čƒŊ)
12
+
13
+ - [æœŦ地插äģļåŧ€å‘](#æœŦ地插äģļåŧ€å‘)
14
+
15
+ - [manifest](#manifest)
16
+ - [éĄšį›Žį쓿ž„](#éĄšį›Žį쓿ž„)
17
+ - [æœåŠĄį̝](#æœåŠĄį̝)
18
+ - [插äģļ UI į•Œéĸ](#插äģļ-ui-į•Œéĸ)
19
+
20
+ - [插äģļ部įŊ˛ä¸Žå‘布](#插äģļ部įŊ˛ä¸Žå‘布)
21
+
22
+ ## 插äģļæž„成
23
+
24
+ 一ä¸Ē LobeChat įš„æ’äģļį”ąäģĨ下几ä¸Ē部分į섿ˆīŧš
25
+
26
+ 1. **插äģļį´ĸåŧ•**īŧšį”¨äēŽåą•į¤ē插äģļįš„åŸēæœŦäŋĄæ¯īŧŒåŒ…æ‹Ŧ插äģļåį§°ã€æčŋ°ã€äŊœč€…ã€į‰ˆæœŦ、插äģļæčŋ°æ¸…å•įš„é“žæŽĨīŧŒåŽ˜æ–šįš„æ’äģļį´ĸåŧ•地址īŧš[lobe-chat-plugins](https://github.com/lobehub/lobe-chat-plugins)。č‹Ĩæƒŗä¸Šæžļ插äģļ到厘斚插äģļ市åœēīŧŒéœ€čρ[提äē¤ PR](https://github.com/lobehub/lobe-chat-plugins/pulls) 到č¯Ĩäģ“åē“īŧ›
27
+ 2. **插äģļæčŋ°æ¸…单 (manifest)**īŧšį”¨äēŽæčŋ°æ’äģļįš„åŠŸčƒŊåŽžįŽ°īŧŒåŒ…åĢä熿’äģļįš„æœåŠĄįĢ¯æčŋ°ã€å‰įĢ¯åą•į¤ēäŋĄæ¯ã€į‰ˆæœŦåˇį­‰ã€‚å…ŗäēŽ manifest įš„č¯Ļįģ†äģ‹įģīŧŒč¯Ļ见 [manifest][manifest-docs-url]īŧ›
28
+ 3. **插äģᅵåŠĄ**īŧšį”¨äēŽåŽžįŽ°æ’äģļæčŋ°æ¸…单中所描čŋ°įš„æœåŠĄįĢ¯å’Œå‰įĢ¯æ¨Ąå—īŧŒåˆ†åˆĢåς䏋īŧš
29
+ - **æœåŠĄį̝**īŧšéœ€čĻåŽžįŽ° manifest 中描čŋ°įš„ `api` éƒ¨åˆ†įš„æŽĨåŖčƒŊ力īŧ›
30
+ - **前į̝ UI**īŧˆå¯é€‰īŧ‰īŧšéœ€čĻåŽžįŽ° manifest 中描čŋ°įš„ `ui` éƒ¨åˆ†įš„į•ŒéĸīŧŒč¯Ĩį•Œéĸ将äŧšåœ¨æ’äģļæļˆæ¯ä¸­é€å‡ēīŧŒčŋ›č€ŒåŽžįŽ°æ¯”æ–‡æœŦ更加丰富地äŋĄæ¯åą•į¤ēæ–šåŧã€‚
31
+
32
+ ## č‡Ē厚䚉插äģļæĩį¨‹
33
+
34
+ 插äģļåŧ€å‘需čĻå°†æ’äģļ集成čŋ› LobeChat 中īŧŒå› æ­¤æœŦ部分将äŧšäģ‹įģåĻ‚äŊ•在 LobeChat 中æˇģ加和äŊŋᔍ䏀ä¸Ēč‡Ē厚䚉插äģļ。
35
+
36
+ ### 1. 创åģēåšļ启动插äģļéĄšį›Ž
37
+
38
+ äŊ éœ€čĻå…ˆåœ¨æœŦ地创åģē一ä¸Ē插äģļéĄšį›ŽīŧŒå¯äģĨäŊŋį”¨æˆ‘äģŦ准备åĨŊįš„ [lobe-chat-plugin-template][lobe-chat-plugin-template-url] æ¨Ąæŋīŧ›
39
+
40
+ ```bash
41
+ $ git clone https://github.com/lobehub/chat-plugin-template.git
42
+ $ cd chat-plugin-template
43
+ $ npm i
44
+ $ npm run dev
45
+ ```
46
+
47
+ åŊ“å‡ēįŽ° `ready started server on 0.0.0.0:3400, url: http://localhost:3400` æ—ļīŧŒč¯´æ˜Žæ’äģᅵåŠĄåˇ˛įģåœ¨æœŦ地启动成功。
48
+
49
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259526-9ef25272-4312-429b-93bc-a95515727ed3.png)
50
+
51
+ ### 2. 在 LobeChat 角色设įŊŽä¸­æˇģ加æœŦ地插äģļ
52
+
53
+ æŽĨ下æĨčŋ›å…Ĩ到 LobeChat 中īŧŒåˆ›åģē一ä¸Ēæ–°įš„åŠŠæ‰‹īŧŒåšļčŋ›å…ĨåŽƒįš„äŧšč¯čŽžįŊŽéĄĩīŧš
54
+
55
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259643-1a9cc34a-76f3-4ccf-928b-129654670efd.png)
56
+
57
+ į‚šå‡ģ「插äģļåˆ—čĄ¨ã€åŗäž§įš„ã€Œæˇģ加」按钎īŧŒæ‰“åŧ€č‡Ē厚䚉插äģᅫģ加åŧšįĒ—īŧš
58
+
59
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259748-2ef6a244-39bb-483c-b359-f156ffcbe1a4.png)
60
+
61
+ 在 「插äģļæčŋ°æ–‡äģļ Url 地址」中åĄĢå…Ĩ `http://localhost:3400/manifest-dev.json` īŧŒčŋ™æ˜¯æˆ‘äģŦæœŦåœ°å¯åŠ¨įš„æ’äģļæčŋ°æ¸…单地址。
62
+
63
+ æ­¤æ—ļīŧŒäŊ åē”č¯Ĩ可äģĨįœ‹åˆ°įœ‹åˆ°æ’äģļįš„æ ‡č¯†įŦĻä¸€æ åˇ˛įģčĸĢč‡ĒåŠ¨č¯†åˆĢä¸ē `chat-plugin-template`。æŽĨ下æĨäŊ éœ€čρåĄĢå†™å‰Šä¸‹įš„čĄ¨å•å­—æŽĩīŧˆåĒ有标éĸ˜åŋ…åĄĢīŧ‰īŧŒį„ļåŽį‚šå‡ģ「äŋå­˜ã€æŒ‰é’ŽīŧŒåŗå¯åŽŒæˆč‡Ē厚䚉插äģᅫģ加。
64
+
65
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259964-59f4906d-ae2e-4ec0-8b43-db36871d0869.png)
66
+
67
+ 厌成æˇģ加后īŧŒåŗå¯åœ¨æ’äģļåˆ—čĄ¨ä¸­įœ‹åˆ°åˆšåˆšæˇģåŠ įš„æ’äģļīŧŒåĻ‚æžœéœ€čρäŋŽæ”šæ’äģļįš„é…įŊŽīŧŒå¯äģĨį‚šå‡ģã€ŒčŽžįŊŽã€æŒ‰é’Žčŋ›čĄŒäŋŽæ”šã€‚
68
+
69
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260093-a0363c74-0b5b-48dd-b103-2db6b4a8262e.png)
70
+
71
+ ### 3. äŧšč¯æĩ‹č¯•插äģļ功čƒŊ
72
+
73
+ æŽĨæĨ下我äģŦ需čρæĩ‹č¯•下čŋ™ä¸Ēč‡Ē厚䚉插äģļįš„åŠŸčƒŊ是åĻæ­Ŗå¸¸ã€‚
74
+
75
+ į‚šå‡ģ「čŋ”回」按钎回到äŧšč¯åŒēīŧŒį„ļ后向劊手发送æļˆæ¯īŧšã€Œæˆ‘åē”č¯ĨįŠŋäģ€äšˆīŧŸ 」此æ—ļ劊手将äŧšå°č¯•向äŊ č¯ĸ问īŧŒäē†č§ŖäŊ įš„æ€§åˆĢ与åŊ“å‰įš„åŋƒæƒ…。
76
+
77
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260291-f0aa0e7c-0ffb-486c-a834-08e73d49896f.png)
78
+
79
+ åŊ“å›žį­”åŽŒæ¯•åŽīŧŒåŠŠæ‰‹å°†äŧšå‘čĩˇæ’äģļįš„č°ƒį”¨īŧŒæ šæŽäŊ įš„æ€§åˆĢ、åŋƒæƒ…īŧŒäģŽæœåŠĄįĢ¯čŽˇå–æŽ¨čįš„čĄŖæœæ•°æŽīŧŒåšļ推送įģ™äŊ ã€‚最后åŸēäēŽčŋ™äē›äŋĄæ¯åšä¸€čŊŽæ–‡æœŦæ€ģįģ“。
80
+
81
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260461-c22ae797-2809-464b-96fc-d0c020f4807b.png)
82
+
83
+ åŊ“厌成čŋ™ä盿“äŊœåŽīŧŒäŊ åˇ˛įģäē†č§Ŗä熿ˇģ加č‡Ē厚䚉插äģļīŧŒåšļ在 LobeChat 中äŊŋį”¨įš„åŸēįĄ€æĩį¨‹ã€‚
84
+
85
+ ## æœŦ地插äģļåŧ€å‘
86
+
87
+ 在上čŋ°æĩį¨‹ä¸­īŧŒæˆ‘äģŦ厞įģäē†č§Ŗæ’äģļįš„æˇģ加和äŊŋį”¨įš„æ–šåŧīŧŒæŽĨ下æĨé‡į‚šäģ‹įģč‡Ē厚䚉插äģļåŧ€å‘įš„čŋ‡į¨‹ã€‚
88
+
89
+ ### manifest
90
+
91
+ manifest 聚合ä熿’äģļ功čƒŊåĻ‚äŊ•åŽžįŽ°įš„äŋĄæ¯ã€‚æ ¸åŋƒįš„å­—æŽĩä¸ē `api` 与 `ui`īŧŒåˆ†åˆĢ描čŋ°ä熿’äģļįš„æœåŠĄį̝æŽĨåŖčƒŊ力与前įĢ¯æ¸˛æŸ“įš„į•Œéĸ地址。
92
+
93
+ äģĨ我äģŦæäž›įš„æ¨Ąæŋä¸­įš„ manifest ä¸ē例īŧš
94
+
95
+ ```json
96
+ {
97
+ "api": [
98
+ {
99
+ "url": "http://localhost:3400/api/clothes",
100
+ "name": "recommendClothes",
101
+ "description": "æ šæŽį”¨æˆˇįš„åŋƒæƒ…īŧŒįģ™į”¨æˆˇæŽ¨čäģ–æœ‰įš„čĄŖæœ",
102
+ "parameters": {
103
+ "properties": {
104
+ "mood": {
105
+ "description": "į”¨æˆˇåŊ“å‰įš„åŋƒæƒ…īŧŒå¯é€‰å€ŧ有īŧšåŧ€åŋƒīŧˆhappyīŧ‰, 难čŋ‡īŧˆsadīŧ‰,į”Ÿæ°” īŧˆangerīŧ‰,åŽŗæ€•īŧˆfearīŧ‰,惊喜īŧˆ surpriseīŧ‰,厌æļ īŧˆdisgustīŧ‰",
106
+ "enums": ["happy", "sad", "anger", "fear", "surprise", "disgust"],
107
+ "type": "string"
108
+ },
109
+ "gender": {
110
+ "type": "string",
111
+ "enum": ["man", "woman"],
112
+ "description": "å¯šč¯į”¨æˆˇįš„æ€§åˆĢīŧŒéœ€čρč¯ĸé—Žį”¨æˆˇåŽæ‰įŸĨ道čŋ™ä¸ĒäŋĄæ¯"
113
+ }
114
+ },
115
+ "required": ["mood", "gender"],
116
+ "type": "object"
117
+ }
118
+ }
119
+ ],
120
+ "gateway": "http://localhost:3400/api/gateway",
121
+ "identifier": "chat-plugin-template",
122
+ "ui": {
123
+ "url": "http://localhost:3400",
124
+ "height": 200
125
+ },
126
+ "version": "1"
127
+ }
128
+ ```
129
+
130
+ 在čŋ™äģŊ manifest 中īŧŒä¸ģčĻåŒ…åĢäē†äģĨ下几ä¸Ē部分īŧš
131
+
132
+ 1. `identifier`īŧščŋ™æ˜¯æ’äģļįš„å”¯ä¸€æ ‡č¯†įŦĻīŧŒį”¨æĨåŒēåˆ†ä¸åŒįš„æ’äģļīŧŒčŋ™ä¸Ē字æŽĩ需čĻå…¨åą€å”¯ä¸€ã€‚
133
+ 2. `api`īŧščŋ™æ˜¯ä¸€ä¸Ē数įģ„īŧŒåŒ…åĢä熿’äģ￉€æäž›įš„æ‰€æœ‰ API æŽĨåŖäŋĄæ¯ã€‚每ä¸ĒæŽĨåŖéƒŊ包åĢäē†url、name、description和 parameters 字æŽĩīŧŒå‡ä¸ēåŋ…åĄĢéĄšã€‚å…ļ中 `description` 和 `parameters` 两ä¸Ē字æŽĩīŧŒå°†äŧšäŊœä¸ē [Function Call](https://sspai.com/post/81986) įš„ `functions` 参数发送įģ™ gptīŧŒ parameters 需čρįŦĻ合 [JSON Schema](https://json-schema.org/) č§„čŒƒã€‚ 在čŋ™ä¸Ē䞋子中īŧŒapi æŽĨåŖåä¸ē `recommendClothes` īŧŒčŋ™ä¸ĒæŽĨåŖįš„åŠŸčƒŊæ˜¯æ šæŽį”¨æˆˇįš„åŋƒæƒ…和性åˆĢæĨæŽ¨ččĄŖæœã€‚æŽĨåŖįš„å‚æ•°åŒ…æ‹Ŧį”¨æˆˇįš„åŋƒæƒ…和性åˆĢīŧŒčŋ™ä¸¤ä¸Ē参数éƒŊ是åŋ…åĄĢéĄšã€‚
134
+ 3. `ui`īŧščŋ™ä¸Ē字æŽĩ包åĢä熿’äģļįš„į”¨æˆˇį•ŒéĸäŋĄæ¯īŧŒæŒ‡æ˜Žäē† LobeChat äģŽå“Ēä¸Ē地址加čŊŊ插äģļįš„å‰įĢ¯į•Œéĸã€‚į”ąäēŽ LobeChat 插äģļį•Œéĸ加čŊŊ是åŸēäēŽ iframe åŽžįŽ°įš„īŧŒå› æ­¤å¯äģĨ按需指厚插äģļį•Œéĸįš„é̘åēĻ、åŽŊåēĻ。
135
+ 4. `gateway`īŧščŋ™ä¸Ē字æŽĩ指厚äē† LobeChat æŸĨč¯ĸ api æŽĨåŖįš„įŊ‘å…ŗã€‚LobeChat éģ˜čŽ¤įš„æ’äģļįŊ‘å…ŗæ˜¯äē‘įĢ¯æœåŠĄīŧŒč€Œč‡Ē厚䚉插äģļįš„č¯ˇæą‚éœ€čĻå‘é€į왿œŦåœ°æœåŠĄįš„īŧŒå› æ­¤é€ščŋ‡åœ¨ manifest 中指厚įŊ‘å…ŗīŧŒLobeChat 将äŧšį›´æŽĨč¯ˇæą‚čŋ™ä¸Ē地址īŧŒčŋ›č€ŒčŽŋ闎到æœŦåœ°įš„æ’äģᅵåŠĄīŧŒå‘布到įēŋä¸Šįš„æ’äģļ可äģĨä¸į”¨æŒ‡åŽšč¯Ĩ字æŽĩ。
136
+ 5. `version`īŧščŋ™æ˜¯æ’äģļįš„į‰ˆæœŦåˇīŧŒįްé˜ļæŽĩ暂æ—￞Ąæœ‰äŊœį”¨īŧ›
137
+
138
+ 在厞际åŧ€å‘中īŧŒäŊ å¯äģĨ栚捎č‡Ēåˇąįš„éœ€æą‚īŧŒäŋŽæ”šæ’äģļįš„æčŋ°æ¸…单īŧŒåŖ°æ˜Žč‡ĒåˇąæƒŗčĻåŽžįŽ°įš„åŠŸčƒŊ。 å…ŗäēŽ manifest 各ä¸Ē字æŽĩįš„åŽŒæ•´äģ‹įģīŧŒå‚见īŧš[manifest][manifest-docs-url]。
139
+
140
+ ### éĄšį›Žį쓿ž„
141
+
142
+ [lobe-chat-plugin-template][lobe-chat-plugin-template-url] čŋ™ä¸Ēæ¨ĄæŋéĄšį›ŽäŊŋᔍäē† Next.js äŊœä¸ēåŧ€å‘æĄ†æžļīŧŒåŽƒįš„æ ¸åŋƒį›ŽåŊ•į쓿ž„åς䏋īŧš
143
+
144
+ ```
145
+ ➜ chat-plugin-template
146
+ ├── public
147
+ │ └── manifest-dev.json # 描čŋ°æ¸…单文äģļ
148
+ ├── src
149
+ │ └── pages
150
+ │ │ ├── api # nextjs æœåŠĄįĢ¯æ–‡äģļ多
151
+ │ │ │ ├── clothes.ts # recommendClothes æŽĨåŖåŽžįŽ°
152
+ │ │ │ └── gateway.ts # æœŦ地插äģļäģŖį†įŊ‘å…ŗ
153
+ │ │ └── index.tsx # 前įĢ¯åą•į¤ēį•Œéĸ
154
+ ```
155
+
156
+ åŊ“į„ļīŧŒæ¨ĄæŋäŊŋᔍ Next.js äŊœä¸ēåŧ€å‘æĄ†æžļīŧŒåĒ是因ä¸ē我äģŦį†Ÿæ‚‰ Next.jsīŧŒåŧ€å‘æ–šäžŋ。äŊ å¯äģĨäŊŋᔍäģģäŊ•äŊ į†Ÿæ‚‰įš„åŧ€å‘æĄ†æžļ与åŧ€å‘蝭荀īŧŒåĒčρčƒŊå¤ŸåŽžįŽ° manifest 中描čŋ°įš„功čƒŊåŗå¯ã€‚
157
+
158
+ 同æ—ļ也æŦĸčŋŽč´ĄįŒŽæ›´å¤šæĄ†æžļä¸Žč¯­č¨€įš„æ’äģᅪĄæŋ。
159
+
160
+ ### æœåŠĄį̝
161
+
162
+ æœåŠĄį̝åĒ需čĻåŽžįŽ° manifest 中描čŋ°įš„ api æŽĨåŖåŗå¯ã€‚åœ¨æ¨Ąæŋ中īŧŒæˆ‘äģŦäŊŋᔍäē† vercel įš„ [Edge Runtime](https://nextjs.org/docs/pages/api-reference/edge) äŊœä¸ēæœåŠĄīŧŒå…åŽģčŋįģ´æˆæœŦ。
163
+
164
+ #### api åŽžįŽ°
165
+
166
+ 针寚 Edge Runtime īŧŒæˆ‘äģŦ在 `@lobehub/chat-plugin-sdk` 提䞛äē† `createErrorResponse` æ–šæŗ•īŧŒį”¨äēŽåŋĢ速čŋ”å›žé”™č¯¯å“åē”ã€‚į›Žå‰æäž›įš„é”™č¯¯įąģ型č¯Ļ见īŧš[PluginErrorType][plugin-error-type-url]。
167
+
168
+ æ¨Ąæŋä¸­įš„ clothes æŽĨåŖåŽžįŽ°åς䏋īŧš
169
+
170
+ ```ts
171
+ export default async (req: Request) => {
172
+ if (req.method !== 'POST') return createErrorResponse(PluginErrorType.MethodNotAllowed);
173
+
174
+ const { gender, mood } = (await req.json()) as RequestData;
175
+
176
+ const clothes = gender === 'man' ? manClothes : womanClothes;
177
+
178
+ const result: ResponseData = {
179
+ clothes: clothes[mood] || [],
180
+ mood,
181
+ today: Date.now(),
182
+ };
183
+
184
+ return new Response(JSON.stringify(result));
185
+ };
186
+ ```
187
+
188
+ å…ļ中 `maniClothes` 和 `womanClothes` 是写æ­ģįš„ mock 数捎īŧŒåœ¨åŽžé™…åœē景中īŧŒå¯äģĨæ›ŋæĸä¸ē数捎åē“č¯ˇæą‚ã€‚
189
+
190
+ #### gateway
191
+
192
+ į”ąäēŽ LobeChat éģ˜čŽ¤įš„æ’äģļįŊ‘å…ŗæ˜¯äē‘įĢ¯æœåŠĄīŧˆ<https://chat.lobehub.com/api/plugins>īŧ‰īŧŒäē‘įĢ¯æœåŠĄé€ščŋ‡ manifest ä¸Šįš„ api åœ°å€å‘é€č¯ˇæą‚īŧŒäģĨč§Ŗå†ŗčˇ¨åŸŸé—Žéĸ˜ã€‚
193
+
194
+ č€Œé’ˆå¯šč‡Ē厚䚉插äģļīŧŒæ’äģļįš„č¯ˇæą‚éœ€čĻå‘é€į왿œŦåœ°æœåŠĄįš„īŧŒ 因此通čŋ‡åœ¨ manifest 中指厚įŊ‘å…ŗ (<http://localhost:3400/api/gateway>)īŧŒLobeChat 将äŧšį›´æŽĨč¯ˇæą‚č¯Ĩ地址īŧŒį„ļ后åĒ需čρ圍č¯Ĩ地址下创åģē一ä¸ĒįŊ‘å…ŗåŽžįŽ°åŗå¯ã€‚
195
+
196
+ ```ts
197
+ import { createLobeChatPluginGateway } from '@lobehub/chat-plugins-gateway';
198
+
199
+ export const config = {
200
+ runtime: 'edge',
201
+ };
202
+
203
+ export default async createLobeChatPluginGateway();
204
+ ```
205
+
206
+ [`@lobehub/chat-plugins-gateway`](https://github.com/lobehub/chat-plugins-gateway) 包åĢäē† LobeChat 中插äģļįŊ‘å…ŗįš„[åŽžįŽ°](https://github.com/lobehub/lobe-chat/blob/main/src/pages/api/plugins.api.ts)īŧŒäŊ å¯äģĨį›´æŽĨäŊŋᔍč¯Ĩ包创åģēįŊ‘å…ŗīŧŒčŋ›č€ŒčŽŠ LobeChat čŽŋ闎到æœŦåœ°įš„æ’äģᅵåŠĄã€‚
207
+
208
+ ### 插äģļ UI į•Œéĸ
209
+
210
+ 寚äēŽä¸€ä¸Ē插äģļ而言īŧŒUI į•Œéĸ是一ä¸Ēå¯é€‰éĄšã€‚äž‹åĻ‚ [「įŊ‘éĄĩ内厚提取」插äģļ](https://github.com/lobehub/chat-plugin-web-crawler)īŧŒå°ąæ˛Ąæœ‰åŽžįŽ°į›¸åē”įš„į”¨æˆˇį•Œéĸ。
211
+
212
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263241-0e765fdc-3463-4c36-a398-aef177a30df9.png)
213
+
214
+ åĻ‚æžœäŊ å¸Œæœ›åœ¨æ’äģļæļˆæ¯ä¸­åą•į¤ēæ›´åŠ ä¸°å¯Œįš„äŋĄæ¯īŧŒæˆ–č€…åŒ…åĢ一äē›å¯Œäē¤äē’īŧŒå¯äģĨä¸ē插äģļ厚䚉一ä¸Ēį”¨æˆˇį•Œéĸ。䞋åĻ‚ä¸‹å›žīŧŒåˆ™ä¸ē搜į´ĸåŧ•擎插äģļįš„į”¨æˆˇį•Œéĸ。
215
+
216
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263427-9bdc03d5-aa61-4f62-a2ce-88683f3308d8.png)
217
+
218
+ #### 插äģļ UI į•ŒéĸåŽžįŽ°
219
+
220
+ LobeChat 通čŋ‡ `iframe` + `postMessage` åŽžįŽ°æ’äģļ ui įš„åŠ čŊŊ与通äŋĄã€‚å› æ­¤īŧŒ 插äģļ UI įš„åŽžįŽ°æ–šåŧä¸Žæ™Žé€šįš„įŊ‘éĄĩåŧ€å‘一致īŧŒäŊ å¯äģĨäŊŋᔍäģģäŊ•äŊ į†Ÿæ‚‰įš„前įĢ¯æĄ†æžļ与åŧ€å‘č¯­č¨€ã€‚
221
+
222
+ ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263653-4ea87abc-249a-49f3-a241-7ed93ddb1ddf.png)
223
+
224
+ 在我äģŦæäž›įš„æ¨Ąæŋ中īŧŒæˆ‘äģŦäŊŋᔍäē† React + Next.js + antd äŊœä¸ē前įĢ¯į•ŒéĸæĄ†æžļīŧŒäŊ å¯äģĨ在 `src/pages/index.tsx` ä¸­æ‰žåˆ°į”¨æˆˇį•Œéĸįš„åŽžįŽ°ã€‚
225
+
226
+ å…ļ䏭兺äēŽæ’äģļ通äŋĄīŧŒæˆ‘äģŦ在 [`@lobehub/chat-plugin-sdk`](https://github.com/lobehub/chat-plugin-sdk) 提䞛äē†į›¸å…ŗæ–šæŗ•īŧŒį”¨äēŽįŽ€åŒ–æ’äģļ与 LobeChat įš„é€šäŋĄã€‚äŊ å¯äģĨ通čŋ‡ `fetchPluginMessage` æ–šæŗ•ä¸ģ动向 LobeChat čŽˇå–åŊ“前æļˆæ¯įš„æ•°æŽã€‚å…ŗäēŽč¯Ĩæ–šæŗ•įš„č¯Ļįģ†äģ‹įģīŧŒå‚见īŧš[fetchPluginMessage][fetch-plugin-message-url]。
227
+
228
+ ```tsx
229
+ import { fetchPluginMessage } from '@lobehub/chat-plugin-sdk';
230
+ import { memo, useEffect, useState } from 'react';
231
+
232
+ import { ResponseData } from '@/type';
233
+
234
+ const Render = memo(() => {
235
+ const [data, setData] = useState<ResponseData>();
236
+
237
+ useEffect(() => {
238
+ // äģŽ LobeChat čŽˇå–åŊ“前插äģļįš„æļˆæ¯
239
+ fetchPluginMessage().then((e: ResponseData) => {
240
+ setData(e);
241
+ });
242
+ }, []);
243
+
244
+ return <>...</>;
245
+ });
246
+
247
+ export default Render;
248
+ ```
249
+
250
+ ## 插äģļ部įŊ˛ä¸Žå‘布
251
+
252
+ åŊ“äŊ åŽŒæˆæ’äģļįš„åŧ€å‘后īŧŒäŊ å¯äģĨäŊŋᔍäŊ ä𠿃¯įš„æ–šåŧčŋ›čĄŒæ’äģļįš„éƒ¨įŊ˛ã€‚äž‹åĻ‚äŊŋᔍ vercel īŧŒæˆ–č€…æ‰“åŒ…æˆ docker å‘å¸ƒį­‰į­‰ã€‚
253
+
254
+ åĻ‚æžœäŊ å¸Œæœ›æ’äģļčĸĢæ›´å¤šäēēäŊŋᔍīŧŒæŦĸčŋŽå°†äŊ įš„æ’äģļ [提äē¤ä¸Šæžļ](https://github.com/lobehub/lobe-chat-plugins) 到插äģļ市åœē。
255
+
256
+ <!-- LINK GROUP -->
257
+
258
+ [fetch-plugin-message-url]: https://github.com/lobehub/chat-plugin-template
259
+ [lobe-chat-plugin-template-url]: https://github.com/lobehub/chat-plugin-template
260
+ [manifest-docs-url]: https://github.com/lobehub/chat-plugin-sdk/tree/master/docs/manifest.zh-CN.md
261
+ [plugin-error-type-url]: https://github.com/lobehub/chat-plugin-template
@@ -0,0 +1 @@
1
+ This is the **đŸ¤¯ / 🤖 Lobe Chat** wiki. [Wiki Home](https://github.com/lobehub/lobe-chat/wiki)
@@ -0,0 +1,16 @@
1
+ ## Lobe Chat Wiki
2
+
3
+ ### 🏠 Home
4
+
5
+ - [TOC](Home)
6
+
7
+ ### 🤖 Agents
8
+
9
+ - [Agent Index](https://github.com/lobehub/lobe-chat-agents)
10
+
11
+ ### 🧩 Plugins
12
+
13
+ - [Plugin Index](https://github.com/lobehub/lobe-chat-plugins)
14
+ - [Plugin Development](Plugin-Development.en-US)
15
+ - [English](Plugin-Development.en-US)
16
+ - [įŽ€äŊ“中文](Plugin-Development.zh-CN)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.68.1",
3
+ "version": "0.69.1",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -66,7 +66,7 @@
66
66
  "@emoji-mart/data": "^1",
67
67
  "@emoji-mart/react": "^1",
68
68
  "@icons-pack/react-simple-icons": "^9",
69
- "@lobehub/chat-plugin-sdk": "^1.15.1",
69
+ "@lobehub/chat-plugin-sdk": "^1.17.0",
70
70
  "@lobehub/chat-plugins-gateway": "^1.5.0",
71
71
  "@lobehub/ui": "latest",
72
72
  "@vercel/analytics": "^1",
@@ -85,7 +85,7 @@
85
85
  "lucide-react": "latest",
86
86
  "nanoid": "^4",
87
87
  "next": "13.4.7",
88
- "openai-edge": "^1",
88
+ "openai": "^4.4.0",
89
89
  "polished": "^4",
90
90
  "react": "^18",
91
91
  "react-dom": "^18",
@@ -4,7 +4,9 @@ import chroma from 'chroma-js';
4
4
  export const useStyles = createStyles(({ css, token, prefixCls }) => ({
5
5
  avatar: css`
6
6
  border-radius: 50%;
7
- transition: scale 400ms ${token.motionEaseOut}, box-shadow 100ms ${token.motionEaseOut};
7
+ transition:
8
+ scale 400ms ${token.motionEaseOut},
9
+ box-shadow 100ms ${token.motionEaseOut};
8
10
 
9
11
  &:hover {
10
12
  box-shadow: 0 0 0 3px ${token.colorText};
@@ -2,6 +2,7 @@ import { ActionIcon, DivProps } from '@lobehub/ui';
2
2
  import { X } from 'lucide-react';
3
3
  import Image from 'next/image';
4
4
  import { memo } from 'react';
5
+ import { Flexbox } from 'react-layout-kit';
5
6
  import useMergeState from 'use-merge-value';
6
7
 
7
8
  import { useStyles } from './style';
@@ -40,19 +41,21 @@ const Empty = memo<EmptyProps>(
40
41
  const { styles } = useStyles();
41
42
  if (!value) return null;
42
43
  return (
43
- <div className={styles.container} {...props}>
44
+ <Flexbox className={styles.container} {...props}>
44
45
  <ActionIcon
45
46
  className={styles.close}
46
47
  icon={X}
47
48
  onClick={() => setValue(false)}
48
49
  size={{ blockSize: 24, fontSize: 16 }}
49
50
  />
50
- {cover && <Image alt={alt} height={height} src={cover} width={width} />}
51
+ {cover && (
52
+ <Image alt={alt} className={styles.image} height={height} src={cover} width={width} />
53
+ )}
51
54
  <div className={styles.content}>
52
55
  {title && <h3>{title}</h3>}
53
56
  {desc && <p className={styles.desc}>{desc}</p>}
54
57
  </div>
55
- </div>
58
+ </Flexbox>
56
59
  );
57
60
  },
58
61
  );
@@ -25,4 +25,7 @@ export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
25
25
  desc: css`
26
26
  color: ${token.colorTextDescription};
27
27
  `,
28
+ image: css`
29
+ align-self: center;
30
+ `,
28
31
  }));
@@ -10,7 +10,9 @@ const useStyle = createStyles(
10
10
  ({ css, token }) => css`
11
11
  cursor: pointer;
12
12
  border-radius: 50%;
13
- transition: scale 400ms ${token.motionEaseOut}, box-shadow 100ms ${token.motionEaseOut};
13
+ transition:
14
+ scale 400ms ${token.motionEaseOut},
15
+ box-shadow 100ms ${token.motionEaseOut};
14
16
 
15
17
  &:hover {
16
18
  box-shadow: 0 0 0 3px ${token.colorText};
@@ -21,7 +21,7 @@ const useStyles = createStyles(({ css, token, prefixCls }) => ({
21
21
  }
22
22
  `,
23
23
  root: css`
24
- backdrop-filter: blur(5px);
24
+ backdrop-filter: blur(2px);
25
25
  `,
26
26
  }));
27
27
 
@@ -5,12 +5,11 @@ import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/do
5
5
  class MyDocument extends Document {
6
6
  static async getInitialProps(ctx: DocumentContext) {
7
7
  const page = await ctx.renderPage({
8
- enhanceApp: (App) => (props) =>
9
- (
10
- <StyleProvider cache={extractStaticStyle.cache}>
11
- <App {...props} />
12
- </StyleProvider>
13
- ),
8
+ enhanceApp: (App) => (props) => (
9
+ <StyleProvider cache={extractStaticStyle.cache}>
10
+ <App {...props} />
11
+ </StyleProvider>
12
+ ),
14
13
  });
15
14
 
16
15
  const styles = extractStaticStyle(page.html).map((item) => item.style);