@lobehub/chat 0.114.1 → 0.114.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,48 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.114.3](https://github.com/lobehub/lobe-chat/compare/v0.114.2...v0.114.3)
6
+
7
+ <sup>Released on **2023-12-18**</sup>
8
+
9
+ <br/>
10
+
11
+ <details>
12
+ <summary><kbd>Improvements and Fixes</kbd></summary>
13
+
14
+ </details>
15
+
16
+ <div align="right">
17
+
18
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
19
+
20
+ </div>
21
+
22
+ ### [Version 0.114.2](https://github.com/lobehub/lobe-chat/compare/v0.114.1...v0.114.2)
23
+
24
+ <sup>Released on **2023-12-17**</sup>
25
+
26
+ #### 🐛 Bug Fixes
27
+
28
+ - **misc**: Fix chat error when message has image with non-vision model.
29
+
30
+ <br/>
31
+
32
+ <details>
33
+ <summary><kbd>Improvements and Fixes</kbd></summary>
34
+
35
+ #### What's fixed
36
+
37
+ - **misc**: Fix chat error when message has image with non-vision model, closes [#698](https://github.com/lobehub/lobe-chat/issues/698) [#693](https://github.com/lobehub/lobe-chat/issues/693) ([b142c17](https://github.com/lobehub/lobe-chat/commit/b142c17))
38
+
39
+ </details>
40
+
41
+ <div align="right">
42
+
43
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
44
+
45
+ </div>
46
+
5
47
  ### [Version 0.114.1](https://github.com/lobehub/lobe-chat/compare/v0.114.0...v0.114.1)
6
48
 
7
49
  <sup>Released on **2023-12-16**</sup>
package/README.md CHANGED
@@ -150,6 +150,8 @@ such as automatically fetching the latest news headlines to provide users with i
150
150
  Moreover, these plugins are not limited to news aggregation but can also extend to other practical functions, such as quick document retrieval,
151
151
  e-commerce platform data access, and various third-party services.
152
152
 
153
+ [Learn More →](./docs/Usage/Plugins.md)
154
+
153
155
  <video controls src="https://github.com/lobehub/lobe-chat/assets/28616219/f29475a3-f346-4196-a435-41a6373ab9e2" muted="false"></video>
154
156
 
155
157
  > \[!TIP]
@@ -165,16 +167,16 @@ e-commerce platform data access, and various third-party services.
165
167
 
166
168
  <!-- PLUGIN LIST -->
167
169
 
168
- | Recent Submits | Repository | Description |
169
- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
170
- | [weather GPT](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Steven Tey** on **undefined**</sup> | [steven-tey/weathergpt](https://github.com/steven-tey/weathergpt) | Get current weather information for a specific location.<br/>`weather` |
171
- | [Ask Your PDF](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AskYourPDF** on **undefined**</sup> | [undefined](https://askyourpdf.com/) | Unlock the power of your PDFs!, dive into your documents, find answers, and bring information to your fingertips.<br/>`pdf` `document` `web` |
172
- | [Clock Time](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | Display a clock to show current time<br/>`clock` `time` |
173
- | [Pollinate drawing](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AI0x0** on **undefined**</sup> | [mushan0x0/lobe-pollinations-ai](https://github.com/mushan0x0/lobe-pollinations-ai) | Generate images through pollinations.ai<br/>`drawing` `image` |
174
- | [Realtime Weather](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | Get realtime weather information<br/>`weather` `realtime` |
175
- | [Search Engine](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | Query search engine to get information<br/>`web` `search` |
176
- | [SEO](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Orren Prunckun** on **undefined**</sup> | [undefined](https://orrenprunckun.com) | Enter any URL and keyword and get an On-Page SEO analysis & insights!<br/>`seo` |
177
- | [Website Crawler](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | Extract content from web links<br/>`web` `content-crawler` |
170
+ | Recent Submits | Repository | Description |
171
+ | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
172
+ | [weather GPT](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Steven Tey** on **2023-12-16**</sup> | [steven-tey/weathergpt](https://github.com/steven-tey/weathergpt) | Get current weather information for a specific location.<br/>`weather` |
173
+ | [Ask Your PDF](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AskYourPDF** on **2023-12-16**</sup> | [undefined](https://askyourpdf.com/) | Unlock the power of your PDFs!, dive into your documents, find answers, and bring information to your fingertips.<br/>`pdf` `document` `web` |
174
+ | [Clock Time](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-11-01**</sup> | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | Display a clock to show current time<br/>`clock` `time` |
175
+ | [Pollinate drawing](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AI0x0** on **2023-12-10**</sup> | [mushan0x0/lobe-pollinations-ai](https://github.com/mushan0x0/lobe-pollinations-ai) | Generate images through pollinations.ai<br/>`drawing` `image` |
176
+ | [Realtime Weather](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-12**</sup> | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | Get realtime weather information<br/>`weather` `realtime` |
177
+ | [Search Engine](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-15**</sup> | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | Query search engine to get information<br/>`web` `search` |
178
+ | [SEO](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Orren Prunckun** on **2023-12-16**</sup> | [undefined](https://orrenprunckun.com) | Enter any URL and keyword and get an On-Page SEO analysis & insights!<br/>`seo` |
179
+ | [Website Crawler](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-17**</sup> | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | Extract content from web links<br/>`web` `content-crawler` |
178
180
 
179
181
  > 📊 Total plugins: [<kbd>**8**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
180
182
 
@@ -208,14 +210,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
208
210
 
209
211
  <!-- AGENT LIST -->
210
212
 
211
- | Recent Submits | Description |
212
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
213
- | [Simulated ChatGPT Web](https://chat-preview.lobehub.com/market?agent=chat-gpt-web)<br/><sup>By **[pzcn](https://github.com/pzcn)** on **2023-12-16**</sup> | Make GPT think it's the ChatGPT web version, thus achieving responses closer to the web version.<br/>`assistant` `conversation` |
214
- | [Greeting](https://chat-preview.lobehub.com/market?agent=congratulations-with-smileys)<br/><sup>By **[almaziphone](https://github.com/almaziphone)** on **2023-12-16**</sup> | Compose a beautiful and brief greeting with emojis<br/>`greeting` `celebration` `kind` |
215
- | [Criminal Defense Expert](https://chat-preview.lobehub.com/market?agent=yundaodev-1)<br/><sup>By **[SuperLande](https://github.com/SuperLande)** on **2023-12-16**</sup> | A Chinese criminal law expert who has been engaged in criminal defense practice for many years and understands the theory of criminal law and criminal procedure law<br/>`criminal-defense` |
216
- | [ShortBookGPT](https://chat-preview.lobehub.com/market?agent=book-summary-agent)<br/><sup>By **[thelapyae](https://github.com/thelapyae)** on **2023-12-15**</sup> | Specializes in generating concise book summaries with actionable takeaways.<br/>`book-summaries` `ai-assistant` `bullet-point-summaries` `actionable-takeaways` |
213
+ | Recent Submits | Description |
214
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
215
+ | [Simulated ChatGPT Web](https://chat-preview.lobehub.com/market?agent=chat-gpt-web)<br/><sup>By **[pzcn](https://github.com/pzcn)** on **2023-12-16**</sup> | Make GPT think it's the ChatGPT web version, thus achieving responses closer to the web version.<br/>`assistant` `conversation` |
216
+ | [Greeting](https://chat-preview.lobehub.com/market?agent=congratulations-with-smileys)<br/><sup>By **[almaziphone](https://github.com/almaziphone)** on **2023-12-16**</sup> | Compose a beautiful and brief greeting with emojis<br/>`greeting` `celebration` `kind` |
217
+ | [Real Estate Agent](https://chat-preview.lobehub.com/market?agent=estate-agency)<br/><sup>By **[ccsen](https://github.com/ccsen)** on **2023-12-16**</sup> | Professional real estate agent expert, proficient in property consultation and management.<br/>`real-estate` `real-estate-agent` `knowledge-expert` `property-appraisal` `buying-a-house` `property-management` |
218
+ | [Criminal Defense Expert](https://chat-preview.lobehub.com/market?agent=yundaodev-1)<br/><sup>By **[SuperLande](https://github.com/SuperLande)** on **2023-12-16**</sup> | A Chinese criminal law expert who has been engaged in criminal defense practice for many years and understands the theory of criminal law and criminal procedure law<br/>`criminal-defense` |
217
219
 
218
- > 📊 Total agents: [<kbd>**72**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
220
+ > 📊 Total agents: [<kbd>**73**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
219
221
 
220
222
  <!-- AGENT LIST -->
221
223
 
@@ -523,8 +525,8 @@ Every bit counts and your one-time donation sparkles in our galaxy of support! Y
523
525
 
524
526
  <a href="https://opencollective.com/lobehub" target="_blank">
525
527
  <picture>
526
- <source media="(prefers-color-scheme: dark)" srcset="https://readme-wizard.lobehub.com/api/sponsor?themeMode=dark">
527
- <img src="https://readme-wizard.lobehub.com/api/sponsor">
528
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/lobehub/.github/blob/main/static/sponsor-dark.png?raw=true">
529
+ <img src="https://github.com/lobehub/.github/blob/main/static/sponsor-light.png?raw=true">
528
530
  </picture>
529
531
  </a>
530
532
 
package/README.zh-CN.md CHANGED
@@ -133,7 +133,9 @@ LobeChat 支持文字转语音(Text-to-Speech,TTS)和语音转文字(Spe
133
133
  LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地增强了 ChatGPT 的实用性和灵活性。通过利用插件,ChatGPT 能够实现实时信息的获取和处理,例如自动获取最新新闻头条,为用户提供即时且相关的资讯。
134
134
  此外,这些插件不仅局限于新闻聚合,还可以扩展到其他实用的功能,如快速检索文档、获取电商平台数据、以及其他各式各样的第三方服务。
135
135
 
136
- <https://github.com/lobehub/lobe-chat/assets/28616219/f29475a3-f346-4196-a435-41a6373ab9e2>
136
+ [了解更多 →](./docs/Usage/Plugins.zh-CN.md)
137
+
138
+ <video controls src="https://github.com/lobehub/lobe-chat/assets/28616219/f29475a3-f346-4196-a435-41a6373ab9e2" muted="false"></video>
137
139
 
138
140
  > \[!TIP]
139
141
  >
@@ -146,16 +148,16 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
146
148
 
147
149
  <!-- PLUGIN LIST -->
148
150
 
149
- | 最近新增 | 仓库 | 插件描述 |
150
- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
151
- | [天气 GPT](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Steven Tey** on **undefined**</sup> | [steven-tey/weathergpt](https://github.com/steven-tey/weathergpt) | 获取特定位置的当前天气信息。<br/>`天气` |
152
- | [AskYouPDF](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AskYourPDF** on **undefined**</sup> | [undefined](https://askyourpdf.com/) | 释放您的 PDF 的力量!深入您的文档,找到答案,并将信息带到您的指尖。<br/>`pdf` `文档` `web` |
153
- | [时钟时间](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | 显示一个时钟来展示当前时间<br/>`时钟` `时间` |
154
- | [授粉绘画](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AI0x0** on **undefined**</sup> | [mushan0x0/lobe-pollinations-ai](https://github.com/mushan0x0/lobe-pollinations-ai) | 通过 pollinations.ai 进行图像生成<br/>`drawing` `image` |
155
- | [实时天气](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | 获取实时天气信息<br/>`天气` `实时` |
156
- | [搜索引擎](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | 查询搜索引擎以获取信息<br/>`网络` `搜索` |
157
- | [SEO](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Orren Prunckun** on **undefined**</sup> | [undefined](https://orrenprunckun.com) | 输入任何 URL 和关键词,获取页面 SEO 分析和见解!<br/>`seo` |
158
- | [网站爬虫](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **undefined**</sup> | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | 从网页链接中提取内容<br/>`网页` `内容爬取器` |
151
+ | 最近新增 | 仓库 | 插件描述 |
152
+ | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
153
+ | [天气 GPT](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Steven Tey** on **2023-12-16**</sup> | [steven-tey/weathergpt](https://github.com/steven-tey/weathergpt) | 获取特定位置的当前天气信息。<br/>`天气` |
154
+ | [AskYouPDF](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AskYourPDF** on **2023-12-16**</sup> | [undefined](https://askyourpdf.com/) | 释放您的 PDF 的力量!深入您的文档,找到答案,并将信息带到您的指尖。<br/>`pdf` `文档` `web` |
155
+ | [时钟时间](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-11-01**</sup> | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | 显示一个时钟来展示当前时间<br/>`时钟` `时间` |
156
+ | [授粉绘画](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **AI0x0** on **2023-12-10**</sup> | [mushan0x0/lobe-pollinations-ai](https://github.com/mushan0x0/lobe-pollinations-ai) | 通过 pollinations.ai 进行图像生成<br/>`drawing` `image` |
157
+ | [实时天气](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-12**</sup> | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | 获取实时天气信息<br/>`天气` `实时` |
158
+ | [搜索引擎](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-15**</sup> | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | 查询搜索引擎以获取信息<br/>`网络` `搜索` |
159
+ | [SEO](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Orren Prunckun** on **2023-12-16**</sup> | [undefined](https://orrenprunckun.com) | 输入任何 URL 和关键词,获取页面 SEO 分析和见解!<br/>`seo` |
160
+ | [网站爬虫](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2023-08-17**</sup> | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | 从网页链接中提取内容<br/>`网页` `内容爬取器` |
159
161
 
160
162
  > 📊 Total plugins: [<kbd>**8**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
161
163
 
@@ -185,14 +187,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
185
187
 
186
188
  <!-- AGENT LIST -->
187
189
 
188
- | 最近新增 | 助手说明 |
189
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
190
- | [模拟 ChatGPT Web](https://chat-preview.lobehub.com/market?agent=chat-gpt-web)<br/><sup>By **[pzcn](https://github.com/pzcn)** on **2023-12-16**</sup> | 使 GPT 认为自己是 ChatGPT 网页版,从而达到更加接近于网页版的回复<br/>`助手` `对话` |
191
- | [祝贺](https://chat-preview.lobehub.com/market?agent=congratulations-with-smileys)<br/><sup>By **[almaziphone](https://github.com/almaziphone)** on **2023-12-16**</sup> | 用表情符号编写美丽而简短的祝贺<br/>`祝贺` `节日` `善良` |
192
- | [刑辩专家](https://chat-preview.lobehub.com/market?agent=yundaodev-1)<br/><sup>By **[SuperLande](https://github.com/SuperLande)** on **2023-12-16**</sup> | 一位中国刑事法律专家,从事多年刑事辩护实务工作,了解刑法与刑事诉讼法理论<br/>`刑辩` |
193
- | [ShortBookGPT](https://chat-preview.lobehub.com/market?agent=book-summary-agent)<br/><sup>By **[thelapyae](https://github.com/thelapyae)** on **2023-12-15**</sup> | 专注于生成简洁的书籍摘要,带有可操作的要点。<br/>`书籍摘要` `ai助手` `要点摘要` `可操作的要点` |
190
+ | 最近新增 | 助手说明 |
191
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
192
+ | [模拟 ChatGPT Web](https://chat-preview.lobehub.com/market?agent=chat-gpt-web)<br/><sup>By **[pzcn](https://github.com/pzcn)** on **2023-12-16**</sup> | 使 GPT 认为自己是 ChatGPT 网页版,从而达到更加接近于网页版的回复<br/>`助手` `对话` |
193
+ | [祝贺](https://chat-preview.lobehub.com/market?agent=congratulations-with-smileys)<br/><sup>By **[almaziphone](https://github.com/almaziphone)** on **2023-12-16**</sup> | 用表情符号编写美丽而简短的祝贺<br/>`祝贺` `节日` `善良` |
194
+ | [房地产经纪人](https://chat-preview.lobehub.com/market?agent=estate-agency)<br/><sup>By **[ccsen](https://github.com/ccsen)** on **2023-12-16**</sup> | 专业的房地产经纪人专家,精通房地产咨询和管理。<br/>`房地产` `房地产经纪人` `知识专家` `房产评估` `购房` `物业管理` |
195
+ | [刑辩专家](https://chat-preview.lobehub.com/market?agent=yundaodev-1)<br/><sup>By **[SuperLande](https://github.com/SuperLande)** on **2023-12-16**</sup> | 一位中国刑事法律专家,从事多年刑事辩护实务工作,了解刑法与刑事诉讼法理论<br/>`刑辩` |
194
196
 
195
- > 📊 Total agents: [<kbd>**72**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
197
+ > 📊 Total agents: [<kbd>**73**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
196
198
 
197
199
  <!-- AGENT LIST -->
198
200
 
@@ -495,8 +497,8 @@ $ bun run dev
495
497
 
496
498
  <a href="https://opencollective.com/lobehub" target="_blank">
497
499
  <picture>
498
- <source media="(prefers-color-scheme: dark)" srcset="https://readme-wizard.lobehub.com/api/sponsor?themeMode=dark">
499
- <img src="https://readme-wizard.lobehub.com/api/sponsor">
500
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/lobehub/.github/blob/main/static/sponsor-dark.png?raw=true">
501
+ <img src="https://github.com/lobehub/.github/blob/main/static/sponsor-light.png?raw=true">
500
502
  </picture>
501
503
  </a>
502
504
 
package/docs/Home.md CHANGED
@@ -67,6 +67,8 @@ LobeChat is a open-source, extensible ([Function Calling][fc-url]), high-perform
67
67
 
68
68
  <!-- DOCS LIST -->
69
69
 
70
+ ---
71
+
70
72
  <details><summary><h4>📝 License</h4></summary>
71
73
 
72
74
  [![][fossa-license-shield]][fossa-license-url]
@@ -0,0 +1,53 @@
1
+ # Plugin Usage
2
+
3
+ The plugin system is a key element in expanding the capabilities of the assistant in LobeChat. You can enhance the assistant's abilities by enabling a variety of plugins.
4
+
5
+ Watch the following video to quickly get started with using LobeChat plugins:
6
+
7
+ <https://github.com/lobehub/lobe-chat/assets/28616219/94d4c312-1699-4e24-8782-138883678c9e>
8
+
9
+ ## Plugin Store
10
+
11
+ You can access the Plugin Store by navigating to "Extension Tools" -> "Plugin Store" in the chat toolbar.
12
+
13
+ ![Plugin Store](https://github.com/lobehub/lobe-chat/assets/28616219/ab4e60d0-1293-49ac-8798-cb29b3b789e6)
14
+
15
+ The Plugin Store contains plugins that can be directly installed and used in LobeChat.
16
+
17
+ ![Plugin Store](https://github.com/lobehub/lobe-chat/assets/28616219/d7a5d821-116f-4be6-8a1a-38d81a5ea0ea)
18
+
19
+ ## Using Plugins
20
+
21
+ After installing a plugin, simply enable it under the current assistant to use it.
22
+
23
+ ![Enable Plugin](https://github.com/lobehub/lobe-chat/assets/28616219/76ab1ae7-a4f9-4285-8ebd-45b90251aba1)
24
+
25
+ ## Plugin Configuration
26
+
27
+ Some plugins may require specific configurations, such as API keys.
28
+
29
+ After installing a plugin, you can click on "Settings" to enter the plugin's settings and fill in the required configurations:
30
+
31
+ ![Plugin Settings](https://github.com/lobehub/lobe-chat/assets/28616219/10eb3023-4528-4b06-8092-062e7b3865cc)
32
+
33
+ ![Plugin Settings](https://github.com/lobehub/lobe-chat/assets/28616219/ab2e4c25-4b11-431b-9266-442d8b14cb41)
34
+
35
+ ## Installing Custom Plugins
36
+
37
+ If you wish to install a plugin that is not available in the LobeChat Plugin Store, such as a custom LobeChat plugin you developed, you can click on "Custom Plugins" to install it:
38
+
39
+ [Custom Plugin Installation](https://github.com/lobehub/lobe-chat/assets/28616219/034a328c-8465-4499-8f93-fdcdb03343cd)
40
+
41
+ Additionally, LobeChat's plugin mechanism is compatible with ChatGPT plugins, allowing you to easily install corresponding ChatGPT plugins.
42
+
43
+ If you want to try installing custom plugins on your own, you can use the following links:
44
+
45
+ - `Custom Lobe Plugin` Mock Credit Card: [Mock Credit Card Plugin](https://lobe-plugin-mock-credit-card.vercel.app/manifest.json)
46
+ - `ChatGPT Plugin` Access Links: [Access Links Plugin](https://www.accesslinks.ai/.well-known/ai-plugin.json)
47
+
48
+ ![Custom Plugin](https://github.com/lobehub/lobe-chat/assets/28616219/bb9cd00f-b20c-4d7b-9c60-b921d350e319)
49
+ ![Custom Plugin](https://github.com/lobehub/lobe-chat/assets/28616219/bdeb678e-6502-4667-86b1-504221ee7ded)
50
+
51
+ ## Developing Plugins
52
+
53
+ If you want to develop a LobeChat plugin on your own, feel free to refer to the [Lobe Plugin Development Guide](https://chat-plugin-sdk.lobehub.com/guides/intro) to expand the possibilities of your AI assistant!
@@ -0,0 +1,59 @@
1
+ # 插件使用
2
+
3
+ 插件体系是 LobeChat 中扩展助理的能力的关键要素,你可以通过为助手启用各式各样的插件来增强助手的各项能力。
4
+
5
+ 查看以下视频,快速上手使用 LobeChat 插件:
6
+
7
+ https://github.com/lobehub/lobe-chat/assets/28616219/94d4c312-1699-4e24-8782-138883678c9e
8
+
9
+
10
+ ## 插件商店
11
+
12
+ 你可以在会话工具条中的 「扩展工具」 -> 「插件商店」,进入插件商店。
13
+
14
+ ![820shots_so](https://github.com/lobehub/lobe-chat/assets/28616219/ab4e60d0-1293-49ac-8798-cb29b3b789e6)
15
+
16
+ 插件商店中会在 LobeChat 中可以直接安装并使用的插件。
17
+
18
+ ![image](https://github.com/lobehub/lobe-chat/assets/28616219/d7a5d821-116f-4be6-8a1a-38d81a5ea0ea)
19
+
20
+
21
+ ## 使用插件
22
+
23
+ 安装完毕插件后,只需在当前助手下开启插件即可使用。
24
+
25
+ ![809shots_so](https://github.com/lobehub/lobe-chat/assets/28616219/76ab1ae7-a4f9-4285-8ebd-45b90251aba1)
26
+
27
+
28
+ ## 插件配置
29
+
30
+ 部分插件可能需要你进行相应的配置,例如 API Key 等。
31
+
32
+ 你可以在安装插件后,点击设置进入插件的设置填写配置:
33
+
34
+ ![image](https://github.com/lobehub/lobe-chat/assets/28616219/10eb3023-4528-4b06-8092-062e7b3865cc)
35
+
36
+ ![image](https://github.com/lobehub/lobe-chat/assets/28616219/ab2e4c25-4b11-431b-9266-442d8b14cb41)
37
+
38
+
39
+ ## 安装自定义插件
40
+
41
+ 如果你希望安装一个不在 LobeChat 插件商店中的插件,例如自己开发的 LobeChat,你可以点击「自定义插件」进行安装:
42
+
43
+
44
+ https://github.com/lobehub/lobe-chat/assets/28616219/034a328c-8465-4499-8f93-fdcdb03343cd
45
+
46
+ 此外,LobeChat 的插件机制兼容了 ChatGPT 的插件,因此你可以一键安装相应的 ChatGPT 插件。
47
+
48
+ 如果你希望尝试自行安装自定义插件,你可以使用以下链接来尝试:
49
+ - `自定义 Lobe 插件` Mock Credit Card:https://lobe-plugin-mock-credit-card.vercel.app/manifest.json
50
+ - `ChatGPT 插件` Access Links:https://www.accesslinks.ai/.well-known/ai-plugin.json
51
+
52
+
53
+ ![image](https://github.com/lobehub/lobe-chat/assets/28616219/bb9cd00f-b20c-4d7b-9c60-b921d350e319)
54
+ ![image](https://github.com/lobehub/lobe-chat/assets/28616219/bdeb678e-6502-4667-86b1-504221ee7ded)
55
+
56
+
57
+ ## 开发插件
58
+
59
+ 如果你希望自行开发一个 LobeChat 的插件,欢迎查阅 [Lobe 插件开发指南](https://chat-plugin-sdk.lobehub.com/zh-CN/guides/intro) 以扩展你的AI智能助手的可能性边界!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.114.1",
3
+ "version": "0.114.3",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -174,7 +174,8 @@
174
174
  "typescript": "^5",
175
175
  "unified": "^11",
176
176
  "unist-util-visit": "^5",
177
- "vitest": "0.34.6"
177
+ "vitest": "0.34.6",
178
+ "vitest-canvas-mock": "^0.3.3"
178
179
  },
179
180
  "publishConfig": {
180
181
  "access": "public",
@@ -1,6 +1,6 @@
1
1
  export interface DataItem {
2
2
  author: string;
3
- createAt: string;
3
+ createdAt: string;
4
4
  homepage: string;
5
5
  identifier: string;
6
6
  meta: { avatar: string; description: string; tags: string[]; title: string };
@@ -16,7 +16,7 @@ const genAgentTable = (data: DataItem[], lang: string) => {
16
16
  url: MARKET_URL,
17
17
  }),
18
18
  ),
19
- `<sup>By **${genLink(item.author, item.homepage)}** on **${item.createAt}**</sup>`,
19
+ `<sup>By **${genLink(item.author, item.homepage)}** on **${(item as any).createAt}**</sup>`,
20
20
  ].join('<br/>'),
21
21
  [item.meta.description, genTags(item.meta.tags)].join('<br/>'),
22
22
  ]);
@@ -9,7 +9,7 @@ const genPluginTable = (data: DataItem[], lang: string) => {
9
9
  const content = data.map((item) => [
10
10
  [
11
11
  genLink(item.meta.title, PLGUIN_URL),
12
- `<sup>By **${item.author}** on **${item.createAt}**</sup>`,
12
+ `<sup>By **${item.author}** on **${item.createdAt}**</sup>`,
13
13
  ].join('<br/>'),
14
14
  genLink(item.homepage.split('github.com/')[1], item.homepage),
15
15
  [item.meta.description, genTags(item.meta.tags)].join('<br/>'),
@@ -2,8 +2,8 @@ import { ActionIcon } from '@lobehub/ui';
2
2
  import { LucideSettings } from 'lucide-react';
3
3
  import { memo, useState } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
- import PluginDetailModal from 'src/features/PluginDetailModal';
6
5
 
6
+ import PluginDetailModal from '@/features/PluginDetailModal';
7
7
  import { pluginHelpers, useToolStore } from '@/store/tool';
8
8
  import { pluginSelectors } from '@/store/tool/selectors';
9
9
 
@@ -3,7 +3,7 @@ import { useResponsive } from 'antd-style';
3
3
  import { memo } from 'react';
4
4
  import { Flexbox } from 'react-layout-kit';
5
5
 
6
- import FileItem from '@/components/FileList/FileItem';
6
+ import ImageFileItem from '@/components/FileList/ImageFileItem';
7
7
 
8
8
  interface EditableFileListProps {
9
9
  alwaysShowClose?: boolean;
@@ -24,7 +24,7 @@ const EditableFileList = memo<EditableFileListProps>(
24
24
  >
25
25
  <ImageGallery>
26
26
  {items.map((i) => (
27
- <FileItem alwaysShowClose={alwaysShowClose} editable={editable} id={i} key={i} />
27
+ <ImageFileItem alwaysShowClose={alwaysShowClose} editable={editable} id={i} key={i} />
28
28
  ))}
29
29
  </ImageGallery>
30
30
  </Flexbox>
@@ -34,7 +34,7 @@ interface FileItemProps {
34
34
  onClick?: () => void;
35
35
  style?: CSSProperties;
36
36
  }
37
- const FileItem = memo<FileItemProps>(({ editable, id, alwaysShowClose }) => {
37
+ const ImageFileItem = memo<FileItemProps>(({ editable, id, alwaysShowClose }) => {
38
38
  const [useFetchFile, removeFile] = useFileStore((s) => [s.useFetchFile, s.removeFile]);
39
39
  const IMAGE_SIZE = editable ? MIN_IMAGE_SIZE : '100%';
40
40
  const { data, isLoading } = useFetchFile(id);
@@ -74,4 +74,4 @@ const FileItem = memo<FileItemProps>(({ editable, id, alwaysShowClose }) => {
74
74
  );
75
75
  });
76
76
 
77
- export default FileItem;
77
+ export default ImageFileItem;
@@ -6,7 +6,7 @@ import { Flexbox } from 'react-layout-kit';
6
6
  import { MAX_SIZE_DESKTOP, MAX_SIZE_MOBILE } from '@/components/FileList/style';
7
7
 
8
8
  import FileGrid from './FileGrid';
9
- import FileItem from './FileItem';
9
+ import ImageFileItem from './ImageFileItem';
10
10
 
11
11
  interface FileListProps {
12
12
  items: string[];
@@ -44,13 +44,13 @@ const FileList = memo<FileListProps>(({ items }) => {
44
44
  <Flexbox gap={gap}>
45
45
  <FileGrid col={firstRow.length} gap={gap} max={max}>
46
46
  {firstRow.map((i) => (
47
- <FileItem id={i} key={i} />
47
+ <ImageFileItem id={i} key={i} />
48
48
  ))}
49
49
  </FileGrid>
50
50
  {lastRow.length > 0 && (
51
51
  <FileGrid col={lastRow.length > 2 ? 3 : lastRow.length} gap={gap} max={max}>
52
52
  {lastRow.map((i) => (
53
- <FileItem id={i} key={i} />
53
+ <ImageFileItem id={i} key={i} />
54
54
  ))}
55
55
  </FileGrid>
56
56
  )}
@@ -84,102 +84,150 @@ describe('ChatService', () => {
84
84
  );
85
85
  });
86
86
 
87
- it('should correctly process messages and handle content for vision models', async () => {
88
- const messages = [
89
- { content: 'Hello', role: 'user', files: ['file1'] }, // Message with files
90
- { content: 'Hi', role: 'function', plugin: { identifier: 'plugin1' } }, // Message with function role
91
- { content: 'Hey', role: 'assistant' }, // Regular user message
92
- ] as ChatMessage[];
93
-
94
- // Mock file store state to return a specific image URL or Base64 for the given files
95
- act(() => {
96
- useFileStore.setState({
97
- imagesMap: {
98
- file1: {
99
- name: 'abc.png',
100
- saveMode: 'url',
101
- fileType: 'image/png',
102
- url: 'http://example.com/image.jpg',
87
+ describe('should handle content correctly for vision models', () => {
88
+ it('should include image content when with vision model', async () => {
89
+ const messages = [
90
+ { content: 'Hello', role: 'user', files: ['file1'] }, // Message with files
91
+ { content: 'Hi', role: 'function', plugin: { identifier: 'plugin1' } }, // Message with function role
92
+ { content: 'Hey', role: 'assistant' }, // Regular user message
93
+ ] as ChatMessage[];
94
+
95
+ // Mock file store state to return a specific image URL or Base64 for the given files
96
+ act(() => {
97
+ useFileStore.setState({
98
+ imagesMap: {
99
+ file1: {
100
+ name: 'abc.png',
101
+ saveMode: 'url',
102
+ fileType: 'image/png',
103
+ url: 'http://example.com/image.jpg',
104
+ },
103
105
  },
104
- },
106
+ });
107
+ });
108
+
109
+ const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
110
+ await chatService.createAssistantMessage({
111
+ messages,
112
+ plugins: [],
113
+ model: 'gpt-4-vision-preview',
105
114
  });
115
+
116
+ expect(getChatCompletionSpy).toHaveBeenCalledWith(
117
+ {
118
+ messages: [
119
+ {
120
+ content: [
121
+ { text: 'Hello', type: 'text' },
122
+ {
123
+ image_url: { detail: 'auto', url: 'http://example.com/image.jpg' },
124
+ type: 'image_url',
125
+ },
126
+ ],
127
+ role: 'user',
128
+ },
129
+ {
130
+ content: 'Hi',
131
+ name: 'plugin1',
132
+ role: 'function',
133
+ },
134
+ {
135
+ content: 'Hey',
136
+ role: 'assistant',
137
+ },
138
+ ],
139
+ model: 'gpt-4-vision-preview',
140
+ },
141
+ undefined,
142
+ );
106
143
  });
107
144
 
108
- const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
109
- await chatService.createAssistantMessage({ messages, plugins: [] });
145
+ it('should not include image content when default model', async () => {
146
+ const messages = [
147
+ { content: 'Hello', role: 'user', files: ['file1'] }, // Message with files
148
+ { content: 'Hi', role: 'function', plugin: { identifier: 'plugin1' } }, // Message with function role
149
+ { content: 'Hey', role: 'assistant' }, // Regular user message
150
+ ] as ChatMessage[];
110
151
 
111
- expect(getChatCompletionSpy).toHaveBeenCalledWith(
112
- {
113
- messages: [
114
- {
115
- content: [
116
- { text: 'Hello', type: 'text' },
117
- {
118
- image_url: { detail: 'auto', url: 'http://example.com/image.jpg' },
119
- type: 'image_url',
120
- },
121
- ],
122
- role: 'user',
123
- },
124
- {
125
- content: 'Hi',
126
- name: 'plugin1',
127
- role: 'function',
128
- },
129
- {
130
- content: 'Hey',
131
- role: 'assistant',
152
+ // Mock file store state to return a specific image URL or Base64 for the given files
153
+ act(() => {
154
+ useFileStore.setState({
155
+ imagesMap: {
156
+ file1: {
157
+ name: 'abc.png',
158
+ saveMode: 'url',
159
+ fileType: 'image/png',
160
+ url: 'http://example.com/image.jpg',
161
+ },
132
162
  },
133
- ],
134
- },
135
- undefined,
136
- );
137
- });
163
+ });
164
+ });
138
165
 
139
- it('should correctly process messages and handle content for vision models', async () => {
140
- const messages = [
141
- { content: 'Hello', role: 'user', files: ['file2'] }, // Message with files
142
- { content: 'Hi', role: 'function', plugin: { identifier: 'plugin1' } }, // Message with function role
143
- { content: 'Hey', role: 'assistant' }, // Regular user message
144
- ] as ChatMessage[];
145
-
146
- // Mock file store state to return a specific image URL or Base64 for the given files
147
- act(() => {
148
- useFileStore.setState({
149
- imagesMap: {
150
- file1: {
151
- name: 'abc.png',
152
- saveMode: 'url',
153
- fileType: 'image/png',
154
- url: 'http://example.com/image.jpg',
155
- },
156
- },
166
+ const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
167
+ await chatService.createAssistantMessage({
168
+ messages,
169
+ plugins: [],
170
+ model: 'gpt-3.5-turbo',
157
171
  });
172
+
173
+ expect(getChatCompletionSpy).toHaveBeenCalledWith(
174
+ {
175
+ messages: [
176
+ { content: 'Hello', role: 'user' },
177
+ { content: 'Hi', name: 'plugin1', role: 'function' },
178
+ { content: 'Hey', role: 'assistant' },
179
+ ],
180
+ model: 'gpt-3.5-turbo',
181
+ },
182
+ undefined,
183
+ );
158
184
  });
159
185
 
160
- const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
161
- await chatService.createAssistantMessage({ messages, plugins: [] });
186
+ it('should not include image with vision models when can not find the image', async () => {
187
+ const messages = [
188
+ { content: 'Hello', role: 'user', files: ['file2'] }, // Message with files
189
+ { content: 'Hi', role: 'function', plugin: { identifier: 'plugin1' } }, // Message with function role
190
+ { content: 'Hey', role: 'assistant' }, // Regular user message
191
+ ] as ChatMessage[];
162
192
 
163
- expect(getChatCompletionSpy).toHaveBeenCalledWith(
164
- {
165
- messages: [
166
- {
167
- content: 'Hello',
168
- role: 'user',
169
- },
170
- {
171
- content: 'Hi',
172
- name: 'plugin1',
173
- role: 'function',
174
- },
175
- {
176
- content: 'Hey',
177
- role: 'assistant',
193
+ // Mock file store state to return a specific image URL or Base64 for the given files
194
+ act(() => {
195
+ useFileStore.setState({
196
+ imagesMap: {
197
+ file1: {
198
+ name: 'abc.png',
199
+ saveMode: 'url',
200
+ fileType: 'image/png',
201
+ url: 'http://example.com/image.jpg',
202
+ },
178
203
  },
179
- ],
180
- },
181
- undefined,
182
- );
204
+ });
205
+ });
206
+
207
+ const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
208
+ await chatService.createAssistantMessage({ messages, plugins: [] });
209
+
210
+ expect(getChatCompletionSpy).toHaveBeenCalledWith(
211
+ {
212
+ messages: [
213
+ {
214
+ content: 'Hello',
215
+ role: 'user',
216
+ },
217
+ {
218
+ content: 'Hi',
219
+ name: 'plugin1',
220
+ role: 'function',
221
+ },
222
+ {
223
+ content: 'Hey',
224
+ role: 'assistant',
225
+ },
226
+ ],
227
+ },
228
+ undefined,
229
+ );
230
+ });
183
231
  });
184
232
 
185
233
  describe('with tools messages', () => {
@@ -15,6 +15,8 @@ import { fetchAIFactory, getMessageError } from '@/utils/fetch';
15
15
  import { createHeaderWithOpenAI } from './_header';
16
16
  import { OPENAI_URLS, URLS } from './_url';
17
17
 
18
+ const isVisionModel = (model?: string) => model && VISION_MODEL_WHITE_LIST.includes(model);
19
+
18
20
  interface FetchOptions {
19
21
  signal?: AbortSignal | undefined;
20
22
  }
@@ -38,7 +40,11 @@ class ChatService {
38
40
  );
39
41
  // ============ 1. preprocess messages ============ //
40
42
 
41
- const oaiMessages = this.processMessages(messages, enabledPlugins);
43
+ const oaiMessages = this.processMessages({
44
+ messages,
45
+ model: payload.model,
46
+ tools: enabledPlugins,
47
+ });
42
48
 
43
49
  // ============ 2. preprocess tools ============ //
44
50
 
@@ -48,8 +54,7 @@ class ChatService {
48
54
  // 1. tools is not empty
49
55
  // 2. model is not in vision white list, because vision model can't use tools
50
56
  // TODO: we need to find some method to let vision model use tools
51
- const shouldUseTools =
52
- filterTools.length > 0 && !VISION_MODEL_WHITE_LIST.includes(payload.model);
57
+ const shouldUseTools = filterTools.length > 0 && !isVisionModel(payload.model);
53
58
 
54
59
  const functions = shouldUseTools ? filterTools : undefined;
55
60
 
@@ -103,7 +108,15 @@ class ChatService {
103
108
 
104
109
  fetchPresetTaskResult = fetchAIFactory(this.getChatCompletion);
105
110
 
106
- private processMessages = (messages: ChatMessage[], tools?: string[]): OpenAIChatMessage[] => {
111
+ private processMessages = ({
112
+ messages,
113
+ tools,
114
+ model,
115
+ }: {
116
+ messages: ChatMessage[];
117
+ model?: string;
118
+ tools?: string[];
119
+ }): OpenAIChatMessage[] => {
107
120
  // handle content type for vision model
108
121
  // for the models with visual ability, add image url to content
109
122
  // refs: https://platform.openai.com/docs/guides/vision/quick-start
@@ -114,6 +127,10 @@ class ChatService {
114
127
 
115
128
  if (imageList.length === 0) return m.content;
116
129
 
130
+ if (!isVisionModel(model)) {
131
+ return m.content;
132
+ }
133
+
117
134
  return [
118
135
  { text: m.content, type: 'text' },
119
136
  ...imageList.map(
@@ -1,14 +1,47 @@
1
1
  import { FileModel } from '@/database/models/file';
2
2
  import { DB_File } from '@/database/schemas/files';
3
3
  import { FilePreview } from '@/types/files';
4
+ import compressImage from '@/utils/compressImage';
4
5
 
5
6
  class FileService {
7
+ private isImage(fileType: string) {
8
+ const imageRegex = /^image\//;
9
+ return imageRegex.test(fileType);
10
+ }
6
11
  async uploadFile(file: DB_File) {
12
+ // 跳过图片上传测试
13
+ const isTestData = file.size === 1;
14
+ if (this.isImage(file.fileType) && !isTestData) {
15
+ return this.uploadImageFile(file);
16
+ }
7
17
  // save to local storage
8
18
  // we may want to save to a remote server later
9
19
  return FileModel.create(file);
10
20
  }
11
21
 
22
+ async uploadImageFile(file: DB_File) {
23
+ // 加载图片
24
+ const url = file.url || URL.createObjectURL(new Blob([file.data]));
25
+ const img = new Image();
26
+ img.src = url;
27
+ await (() =>
28
+ new Promise((resolve) => {
29
+ img.addEventListener('load', resolve);
30
+ }))();
31
+
32
+ // 压缩图片
33
+ const fileType = 'image/webp';
34
+ const base64String = compressImage({
35
+ img,
36
+ type: fileType,
37
+ });
38
+ const binaryString = atob(base64String.split('base64,')[1]);
39
+ const uint8Array = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
40
+ file.data = uint8Array.buffer;
41
+
42
+ return FileModel.create(file);
43
+ }
44
+
12
45
  async removeFile(id: string) {
13
46
  return FileModel.delete(id);
14
47
  }
@@ -0,0 +1,59 @@
1
+ import compressImage from './compressImage';
2
+
3
+ const getContextSpy = vi.spyOn(global.HTMLCanvasElement.prototype, 'getContext');
4
+ const drawImageSpy = vi.spyOn(CanvasRenderingContext2D.prototype, 'drawImage');
5
+
6
+ beforeEach(() => {
7
+ getContextSpy.mockClear();
8
+ drawImageSpy.mockClear();
9
+ });
10
+
11
+ describe('compressImage', () => {
12
+ it('should compress image with maxWidth', () => {
13
+ const img = document.createElement('img');
14
+ img.width = 3000;
15
+ img.height = 2000;
16
+
17
+ const r = compressImage({ img });
18
+
19
+ expect(r).toMatch(/^data:image\/webp;base64,/);
20
+
21
+ expect(getContextSpy).toBeCalledTimes(1);
22
+ expect(getContextSpy).toBeCalledWith('2d');
23
+
24
+ expect(drawImageSpy).toBeCalledTimes(1);
25
+ expect(drawImageSpy).toBeCalledWith(img, 0, 0, 3000, 2000, 0, 0, 2160, 1440);
26
+ });
27
+
28
+ it('should compress image with maxHeight', () => {
29
+ const img = document.createElement('img');
30
+ img.width = 2000;
31
+ img.height = 3000;
32
+
33
+ const r = compressImage({ img });
34
+
35
+ expect(r).toMatch(/^data:image\/webp;base64,/);
36
+
37
+ expect(getContextSpy).toBeCalledTimes(1);
38
+ expect(getContextSpy).toBeCalledWith('2d');
39
+
40
+ expect(drawImageSpy).toBeCalledTimes(1);
41
+ expect(drawImageSpy).toBeCalledWith(img, 0, 0, 2000, 3000, 0, 0, 1440, 2160);
42
+ });
43
+
44
+ it('should not compress image', () => {
45
+ const img = document.createElement('img');
46
+ img.width = 2000;
47
+ img.height = 2000;
48
+
49
+ const r = compressImage({ img });
50
+
51
+ expect(r).toMatch(/^data:image\/webp;base64,/);
52
+
53
+ expect(getContextSpy).toBeCalledTimes(1);
54
+ expect(getContextSpy).toBeCalledWith('2d');
55
+
56
+ expect(drawImageSpy).toBeCalledTimes(1);
57
+ expect(drawImageSpy).toBeCalledWith(img, 0, 0, 2000, 2000, 0, 0, 2000, 2000);
58
+ });
59
+ });
@@ -0,0 +1,29 @@
1
+ const compressImage = ({ img, type = 'image/webp' }: { img: HTMLImageElement; type?: string }) => {
2
+ // 设置最大宽高
3
+ const maxWidth = 2160;
4
+ const maxHeight = 2160;
5
+ let width = img.width;
6
+ let height = img.height;
7
+
8
+ if (width > height && width > maxWidth) {
9
+ // 如果图片宽度大于高度且大于最大宽度限制
10
+ width = maxWidth;
11
+ height = Math.round((maxWidth / img.width) * img.height);
12
+ } else if (height > width && height > maxHeight) {
13
+ // 如果图片高度大于宽度且大于最大高度限制
14
+ height = maxHeight;
15
+ width = Math.round((maxHeight / img.height) * img.width);
16
+ }
17
+
18
+ const canvas = document.createElement('canvas');
19
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
20
+
21
+ canvas.width = width;
22
+ canvas.height = height;
23
+
24
+ ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height);
25
+
26
+ return canvas.toDataURL(type);
27
+ };
28
+
29
+ export default compressImage;
package/tests/setup.ts CHANGED
@@ -5,6 +5,7 @@ import { theme } from 'antd';
5
5
  // refs: https://github.com/dumbmatter/fakeIndexedDB#dexie-and-other-indexeddb-api-wrappers
6
6
  import 'fake-indexeddb/auto';
7
7
  import React from 'react';
8
+ import 'vitest-canvas-mock';
8
9
 
9
10
  // remove antd hash on test
10
11
  theme.defaultConfig.hashed = false;
package/vitest.config.ts CHANGED
@@ -16,6 +16,10 @@ export default defineConfig({
16
16
  provider: 'v8',
17
17
  reporter: ['text', 'json', 'lcov', 'text-summary'],
18
18
  },
19
+ deps: {
20
+ inline: ['vitest-canvas-mock'],
21
+ },
22
+ // threads: false,
19
23
  environment: 'jsdom',
20
24
  globals: true,
21
25
  setupFiles: './tests/setup.ts',