@lobehub/chat 0.118.3 → 0.118.5

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,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.118.5](https://github.com/lobehub/lobe-chat/compare/v0.118.4...v0.118.5)
6
+
7
+ <sup>Released on **2024-01-02**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Mobile device return to the previous page error.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Mobile device return to the previous page error, closes [#886](https://github.com/lobehub/lobe-chat/issues/886) ([99cfc0f](https://github.com/lobehub/lobe-chat/commit/99cfc0f))
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
+
30
+ ### [Version 0.118.4](https://github.com/lobehub/lobe-chat/compare/v0.118.3...v0.118.4)
31
+
32
+ <sup>Released on **2024-01-02**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Update dalle identifier to fix unstable dalle function call.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Update dalle identifier to fix unstable dalle function call, closes [#896](https://github.com/lobehub/lobe-chat/issues/896) ([9d9ac32](https://github.com/lobehub/lobe-chat/commit/9d9ac32))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 0.118.3](https://github.com/lobehub/lobe-chat/compare/v0.118.2...v0.118.3)
6
56
 
7
57
  <sup>Released on **2024-01-01**</sup>
package/README.md CHANGED
@@ -208,14 +208,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
208
208
 
209
209
  <!-- AGENT LIST -->
210
210
 
211
- | Recent Submits | Description |
212
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
213
- | [Deployment Specialist Agent](https://chat-preview.lobehub.com/market?agent=deployment-agent)<br/><sup>By **[amitalokbera](https://github.com/amitalokbera)** on **2023-12-27**</sup> | An AI Deployment Specialist is an expert in managing the full deployment lifecycle of software applications, particularly web applications.<br/>`code` `deployment` `software` |
214
- | [Overview of Art Thesis Experts](https://chat-preview.lobehub.com/market?agent=thesis-overview)<br/><sup>By **[caoyang2002](https://github.com/caoyang2002)** on **2023-12-27**</sup> | Specializing in brief thesis and art criticism<br/>`art` `thesis` `critique` |
215
- | [American English Transcreation Expert](https://chat-preview.lobehub.com/market?agent=to-local-english)<br/><sup>By **[doresu](https://github.com/doresu)** on **2023-12-27**</sup> | Rough old editor, seasoned writer, and translator, proficient in translating English directly and transforming it into authentic American English<br/>`translation` `editing` `writing` `translator` |
216
- | [Academic Proofreading Expert](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | Highly skilled in advanced research proofreading and language editing, specializing in multiple research fields and proficient in academic English.<br/>`proofreading` `writing` `research` |
217
-
218
- > 📊 Total agents: [<kbd>**82**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
211
+ | Recent Submits | Description |
212
+ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
213
+ | [Amazon Title Assistant](https://chat-preview.lobehub.com/market?agent=amazon)<br/><sup>By **[cm2457618290](https://github.com/cm2457618290)** on **2024-01-02**</sup> | Provide product keywords or product links to automatically write titles and product introductions<br/>`assistant` |
214
+ | [Exam Assistant](https://chat-preview.lobehub.com/market?agent=generador-examenes)<br/><sup>By **[aitorroma](https://github.com/aitorroma)** on **2024-01-02**</sup> | I am a skills summary assistant and cannot conduct interactive exams. However, I can help you summarize your skills and knowledge in a clear and concise format.<br/>`exam` `learning` `statistics` |
215
+ | [Teaching Mentor](https://chat-preview.lobehub.com/market?agent=ljrwwjl-development)<br/><sup>By **[ljr1314](https://github.com/ljr1314)** on **2024-01-02**</sup> | A friendly and helpful mentor who customizes explanations and examples based on the user's learning level and interests to ensure clarity. Ask 4 questions, then provide explanations, examples, and analogies, and ensure understanding through questioning. Finally, have the user explain the topic in their own words and provide an example. End on a positive note and encourage further learning.<br/>`mentor` `education` `explanation` `communication` `learning` |
216
+ | [MidjourneyGPT](https://chat-preview.lobehub.com/market?agent=prompt-composition)<br/><sup>By **[richards199999](https://github.com/richards199999)** on **2023-12-30**</sup> | Write perfect and beautiful prompts for Midjourney. (Including V6!)<br/>`midjourney` `prompt` `ai` |
217
+
218
+ > 📊 Total agents: [<kbd>**87**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
219
219
 
220
220
  <!-- AGENT LIST -->
221
221
 
package/README.zh-CN.md CHANGED
@@ -184,14 +184,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
184
184
 
185
185
  <!-- AGENT LIST -->
186
186
 
187
- | 最近新增 | 助手说明 |
188
- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
189
- | [部署专家代理](https://chat-preview.lobehub.com/market?agent=deployment-agent)<br/><sup>By **[amitalokbera](https://github.com/amitalokbera)** on **2023-12-27**</sup> | AI 部署专家是管理软件应用的完整部署生命周期的专家,特别是 Web 应用。<br/>`代码` `部署` `容器化` |
190
- | [美术论文概述专家](https://chat-preview.lobehub.com/market?agent=thesis-overview)<br/><sup>By **[caoyang2002](https://github.com/caoyang2002)** on **2023-12-27**</sup> | 擅长论文简述与美术评论<br/>`美术` `论文` `评论` |
191
- | [美式英语转译专家](https://chat-preview.lobehub.com/market?agent=to-local-english)<br/><sup>By **[doresu](https://github.com/doresu)** on **2023-12-27**</sup> | 粗鲁老编辑、资深作家和翻译家,擅长直译英文并转化为地道的美式英语<br/>`翻译` `编辑` `写作` `翻译家` |
192
- | [学术润色专家](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | 高级研究校对及语言编辑,专业于多个研究领域,精通学术英语。<br/>`校对` `写作` `研究` |
193
-
194
- > 📊 Total agents: [<kbd>**82**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
187
+ | 最近新增 | 助手说明 |
188
+ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
189
+ | [Amazon Title Assistant](https://chat-preview.lobehub.com/market?agent=amazon)<br/><sup>By **[cm2457618290](https://github.com/cm2457618290)** on **2024-01-02**</sup> | Provide product keywords or product links to automatically write titles and product introductions<br/>`assistant` |
190
+ | [考试助手](https://chat-preview.lobehub.com/market?agent=generador-examenes)<br/><sup>By **[aitorroma](https://github.com/aitorroma)** on **2024-01-02**</sup> | 我是一个技能总结助手,无法进行互动式考试。但我可以帮助你以清晰简洁的格式总结你的技能和知识。<br/>`考试` `学习` `统计` |
191
+ | [教学导师](https://chat-preview.lobehub.com/market?agent=ljrwwjl-development)<br/><sup>By **[ljr1314](https://github.com/ljr1314)** on **2024-01-02**</sup> | 友好乐于助人的导师,根据用户的学习水平和兴趣定制解释和示例,确保简洁明了。问 4 个问题,然后提供解释、例子和类比,并通过提问确保用户理解。最后让用户用自己的语言解释主题,并给出一个例子。以积极正面的方式结束,并鼓励用户深入学习。<br/>`导师` `教育` `解释` `交流` `学习` |
192
+ | [MidjourneyGPT](https://chat-preview.lobehub.com/market?agent=prompt-composition)<br/><sup>By **[richards199999](https://github.com/richards199999)** on **2023-12-30**</sup> | 为 Midjourney 编写完美而美丽的提示。(包括 V6!)<br/>`midjourney` `prompt` `ai` |
193
+
194
+ > 📊 Total agents: [<kbd>**87**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
195
195
 
196
196
  <!-- AGENT LIST -->
197
197
 
@@ -17,46 +17,70 @@ LobeChat 的大模型 AI 实现主要依赖于 OpenAI 的 API,包括后端的
17
17
 
18
18
  ### 核心会话 API
19
19
 
20
- 在 `src/app/api/openai/chat/handler.ts` 文件中,我们定义了 `POST` 方法,该方法首先从请求中解析出 payload 数据(即客户端发送的会话内容),然后从请求中获取 OpenAI 的授权信息。之后,我们创建一个 `openai` 对象,并调用 `createChatCompletion` 方法,该方法负责发送会话请求到 OpenAI 并返回结果。
20
+ 在 `src/app/api/openai/chat/route.ts` 中,定义了一个处理 POST 请求的方法,主要负责从请求体中提取 `OpenAIChatStreamPayload` 类型的 payload,并使用 `createBizOpenAI` 函数根据请求和模型信息创建 OpenAI 实例。随后,该方法调用 `createChatCompletion` 来处理实际的会话,并返回响应结果。如果创建 OpenAI 实例过程中出现错误,则直接返回错误响应。
21
21
 
22
22
  ```ts
23
23
  export const POST = async (req: Request) => {
24
- const payload = await req.json();
24
+ const payload = (await req.json()) as OpenAIChatStreamPayload;
25
25
 
26
- const { apiKey, endpoint } = getOpenAIAuthFromRequest(req);
26
+ const openaiOrErrResponse = createBizOpenAI(req, payload.model);
27
27
 
28
- const openai = createOpenai(apiKey, endpoint);
28
+ // if resOrOpenAI is a Response, it means there is an error,just return it
29
+ if (openaiOrErrResponse instanceof Response) return openaiOrErrResponse;
29
30
 
30
- return createChatCompletion({ openai, payload });
31
+ return createChatCompletion({ openai: openaiOrErrResponse, payload });
31
32
  };
32
33
  ```
33
34
 
34
35
  ### 会话结果处理
35
36
 
36
- 在 `src/app/api/openai/chat/createChatCompletion.ts` 文件中,我们定义了 `createChatCompletion` 方法,该方法首先对 payload 数据进行预处理,然后调用 OpenAI 的 `chat.completions.create` 方法发送请求,并使用 [Vercel AI SDK](https://sdk.vercel.ai/docs) 中的 `OpenAIStream` 将返回的结果转化为流式响应。
37
+ 而在 `src/app/api/openai/chat/createChatCompletion.ts` 文件中,`createChatCompletion` 方法主要负责与 OpenAI API 进行交互,处理会话请求。它首先对 payload 中的消息进行预处理,然后通过 `openai.chat.completions.create` 方法发送 API 请求,并使用 `OpenAIStream` 将返回的响应转换为流式格式。如果在 API 调用过程中出现错误,方法将生成并处理相应的错误响应。
37
38
 
38
39
  ```ts
39
40
  import { OpenAIStream, StreamingTextResponse } from 'ai';
40
41
 
41
42
  export const createChatCompletion = async ({ payload, openai }: CreateChatCompletionOptions) => {
43
+ // 预处理消息
42
44
  const { messages, ...params } = payload;
43
-
44
- const formatMessages = messages.map((m) => ({
45
- content: m.content,
46
- name: m.name,
47
- role: m.role,
48
- }));
49
-
50
- const response = await openai.chat.completions.create(
51
- {
52
- messages: formatMessages,
53
- ...params,
54
- stream: true,
55
- },
56
- { headers: { Accept: '*/*' } },
57
- );
58
- const stream = OpenAIStream(response);
59
- return new StreamingTextResponse(stream);
45
+ // 发送 API 请求
46
+ try {
47
+ const response = await openai.chat.completions.create(
48
+ {
49
+ messages,
50
+ ...params,
51
+ stream: true,
52
+ } as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
53
+ { headers: { Accept: '*/*' } },
54
+ );
55
+ const stream = OpenAIStream(response);
56
+ return new StreamingTextResponse(stream);
57
+ } catch (error) {
58
+ // 检查错误是否为 OpenAI APIError
59
+ if (error instanceof OpenAI.APIError) {
60
+ let errorResult: any;
61
+ // 如果错误是 OpenAI APIError,那么会有一个 error 对象
62
+ if (error.error) {
63
+ errorResult = error.error;
64
+ } else if (error.cause) {
65
+ errorResult = error.cause;
66
+ }
67
+ // 如果没有其他请求错误,错误对象是一个类似 Response 的对象
68
+ else {
69
+ errorResult = { headers: error.headers, stack: error.stack, status: error.status };
70
+ }
71
+ console.error(errorResult);
72
+ // 返回错误响应
73
+ return createErrorResponse(ChatErrorType.OpenAIBizError, {
74
+ endpoint: openai.baseURL,
75
+ error: errorResult,
76
+ });
77
+ }
78
+ console.error(error);
79
+ return createErrorResponse(ChatErrorType.InternalServerError, {
80
+ endpoint: openai.baseURL,
81
+ error: JSON.stringify(error),
82
+ });
83
+ }
60
84
  };
61
85
  ```
62
86
 
@@ -64,35 +88,45 @@ export const createChatCompletion = async ({ payload, openai }: CreateChatComple
64
88
 
65
89
  ### 前端集成
66
90
 
67
- 在 `src/services/chatModel.ts` 文件中,我们定义了 `fetchChatModel` 方法,该方法首先对 payload 数据进行前置处理,然后发送 POST 请求到后端的 `/chat` 接口,并将请求结果返回。
91
+ 在 `src/services/chat.ts` 文件中,我们定义了 `ChatService` 类。这个类提供了一些方法来处理与 OpenAI 聊天 API 的交互。
92
+
93
+ `createAssistantMessage` 方法用于创建一个新的助手消息。它接收一个包含插件、消息和其他参数的对象,以及一个可选的 `FetchOptions` 对象。这个方法会合并默认的代理配置和传入的参数,预处理消息和工具,然后调用 `getChatCompletion` 方法获取聊天完成任务。
94
+
95
+ `getChatCompletion` 方法用于获取聊天完成任务。它接收一个 `OpenAIChatStreamPayload` 对象和一个可选的 `FetchOptions` 对象。这个方法会合并默认的代理配置和传入的参数,然后发送 POST 请求到 OpenAI 的聊天 API。
96
+
97
+ `runPluginApi` 方法用于运行插件 API 并获取结果。它接收一个 `PluginRequestPayload` 对象和一个可选的 `FetchOptions` 对象。这个方法会从工具存储中获取状态,通过插件标识符获取插件设置和清单,然后发送 POST 请求到插件的网关 URL。
98
+
99
+ `fetchPresetTaskResult` 方法用于获取预设任务的结果。它使用 `fetchAIFactory` 工厂函数创建一个新的函数,这个函数接收一个聊天完成任务的参数,并返回一个 Promise。当 Promise 解析时,返回的结果是聊天完成任务的结果。
100
+
101
+ `processMessages` 方法用于处理聊天消息。它接收一个聊天消息数组,一个可选的模型名称,和一个可选的工具数组。这个方法会处理消息内容,将输入的 `messages` 数组映射为 `OpenAIChatMessage` 类型的数组,如果存在启用的工具,将工具的系统角色添加到系统消息中。
68
102
 
69
103
  ```ts
70
- export const fetchChatModel = (
71
- { plugins: enabledPlugins, ...params }: Partial<OpenAIStreamPayload>,
72
- options?: FetchChatModelOptions,
73
- ) => {
74
- const payload = merge(
75
- {
76
- model: initialLobeAgentConfig.model,
77
- stream: true,
78
- ...initialLobeAgentConfig.params,
79
- },
80
- params,
81
- );
82
-
83
- const filterFunctions: ChatCompletionFunctions[] = pluginSelectors.enabledSchema(enabledPlugins)(
84
- usePluginStore.getState(),
85
- );
86
-
87
- const functions = filterFunctions.length === 0 ? undefined : filterFunctions;
88
-
89
- return fetch(OPENAI_URLS.chat, {
90
- body: JSON.stringify({ ...payload, functions }),
91
- headers: createHeaderWithOpenAI({ 'Content-Type': 'application/json' }),
92
- method: 'POST',
93
- signal: options?.signal,
94
- });
95
- };
104
+ class ChatService {
105
+ // 创建一个新的助手消息
106
+ createAssistantMessage(params: object, fetchOptions?: FetchOptions) {
107
+ // 实现细节...
108
+ }
109
+
110
+ // 获取聊天完成任务
111
+ getChatCompletion(payload: OpenAIChatStreamPayload, fetchOptions?: FetchOptions) {
112
+ // 实现细节...
113
+ }
114
+
115
+ // 运行插件 API 并获取结果
116
+ runPluginApi(payload: PluginRequestPayload, fetchOptions?: FetchOptions) {
117
+ // 实现细节...
118
+ }
119
+
120
+ // 获取预设任务的结果
121
+ fetchPresetTaskResult() {
122
+ // 实现细节...
123
+ }
124
+
125
+ // 处理聊天消息
126
+ processMessages(messages: ChatMessage[], modelName?: string, tools?: Tool[]) {
127
+ // 实现细节...
128
+ }
129
+ }
96
130
  ```
97
131
 
98
132
  ### 使用流式获取结果
@@ -103,6 +137,7 @@ export const fetchChatModel = (
103
137
  export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchSSEOptions = {}) => {
104
138
  const response = await fetchFn();
105
139
 
140
+ // 如果不 ok 说明有请求错误
106
141
  if (!response.ok) {
107
142
  const chatMessageError = await getMessageError(response);
108
143
 
@@ -115,7 +150,7 @@ export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchS
115
150
  const data = response.body;
116
151
 
117
152
  if (!data) return;
118
-
153
+ let output = '';
119
154
  const reader = data.getReader();
120
155
  const decoder = new TextDecoder();
121
156
 
@@ -124,11 +159,14 @@ export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchS
124
159
  while (!done) {
125
160
  const { value, done: doneReading } = await reader.read();
126
161
  done = doneReading;
127
- const chunkValue = decoder.decode(value);
162
+ const chunkValue = decoder.decode(value, { stream: true });
128
163
 
164
+ output += chunkValue;
129
165
  options.onMessageHandle?.(chunkValue);
130
166
  }
131
167
 
168
+ await options?.onFinish?.(output);
169
+
132
170
  return returnRes;
133
171
  };
134
172
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.118.3",
3
+ "version": "0.118.5",
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",
@@ -0,0 +1,53 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+
4
+ import { DalleManifest } from '@/tools/dalle';
5
+ import { BuiltinToolsRenders } from '@/tools/renders';
6
+
7
+ import BuiltinType from './index';
8
+
9
+ // Mock Render component and useParseContent hook
10
+ vi.mock('@/tools/renders', () => ({
11
+ BuiltinToolsRenders: {
12
+ dalle3: vi.fn(() => <div>Test Renderer</div>),
13
+ [DalleManifest.identifier]: vi.fn(() => <div>{DalleManifest.identifier}</div>),
14
+ },
15
+ }));
16
+
17
+ // Mock Loading component
18
+ vi.mock('../Loading', () => ({
19
+ default: vi.fn(() => <div>Loading...</div>),
20
+ }));
21
+
22
+ describe('BuiltinType', () => {
23
+ it('should render loading state if not JSON and loading is true', () => {
24
+ render(<BuiltinType content="..." id="123" loading={true} />);
25
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
26
+ });
27
+
28
+ it('should not render anything if not JSON and loading is false', () => {
29
+ const { container } = render(<BuiltinType content="..." id="123" loading={false} />);
30
+ expect(container).toBeEmptyDOMElement();
31
+ });
32
+
33
+ it('should not render anything if identifier is unknown', () => {
34
+ const { container } = render(<BuiltinType content="{}" id="123" identifier="unknown" />);
35
+ expect(container).toBeEmptyDOMElement();
36
+ });
37
+
38
+ describe('DALL·E', () => {
39
+ it('should render the correct renderer if identifier is dalle3', () => {
40
+ render(<BuiltinType content='{"some":"data"}' id="123" identifier="dalle3" />);
41
+ expect(BuiltinToolsRenders.dalle3).toHaveBeenCalled();
42
+ expect(screen.getByText('Test Renderer')).toBeInTheDocument();
43
+ });
44
+
45
+ it('should render the correct renderer if is DALL·E ', () => {
46
+ render(
47
+ <BuiltinType content='{"some":"data"}' id="123" identifier={DalleManifest.identifier} />,
48
+ );
49
+ expect(BuiltinToolsRenders.dalle3).toHaveBeenCalled();
50
+ expect(screen.getByText(DalleManifest.identifier)).toBeInTheDocument();
51
+ });
52
+ });
53
+ });
@@ -1,13 +1,12 @@
1
1
  import { useEffect, useState } from 'react';
2
2
 
3
+ import { isInStandaloneMode } from '@/utils/matchMedia';
4
+
3
5
  export const useIsPWA = () => {
4
6
  const [isPWA, setIsPWA] = useState(false);
5
7
 
6
8
  useEffect(() => {
7
- const isInStandaloneMode = () => window.matchMedia('(display-mode: standalone)').matches;
8
- if (isInStandaloneMode()) {
9
- setIsPWA(true);
10
- }
9
+ setIsPWA(isInStandaloneMode());
11
10
  }, []);
12
11
 
13
12
  return isPWA;
@@ -0,0 +1,116 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ChatService > createAssistantMessage > with tools messages > work with dalle3 1`] = `
4
+ {
5
+ "messages": [
6
+ {
7
+ "content": "## Tools
8
+
9
+ You can use these tools below:
10
+
11
+ ### DALL·E 3
12
+
13
+ Whenever a description of an image is given, use lobe-image-designer to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to lobe-image-designer that are written to be as diverse as possible.
14
+
15
+ All captions sent to lobe-image-designer must abide by the following policies:
16
+
17
+ 1. If the description is not in English, then translate it.
18
+ 2. Do not create more than 4 images, even if the user requests more.
19
+ 3. Don't create images of politicians or other public figures. Recommend other ideas instead.
20
+ 5. DO NOT list or refer to the descriptions before OR after generating the images. They should ONLY ever be written out ONCE, in the \`prompts\` field of the request. You do not need to ask for permission to generate, just do it!
21
+ 6. Always mention the image type (photo, oil painting, watercolor painting, illustration, cartoon, drawing, vector, render, etc.) at the beginning of the caption. Unless the caption suggests otherwise, make at least 1--2 of the 4 images photos.
22
+ 7. Diversify depictions of ALL images with people to include DESCENT and GENDER for EACH person using direct terms. Adjust only human descriptions.
23
+ - EXPLICITLY specify these attributes, not abstractly reference them. The attributes should be specified in a minimal way and should directly describe their physical form.
24
+ - Your choices should be grounded in reality. For example, all of a given OCCUPATION should not be the same gender or race. Additionally, focus on creating diverse, inclusive, and exploratory scenes via the properties you choose during rewrites. Make choices that may be insightful or unique sometimes.
25
+ - Use "various" or "diverse" ONLY IF the description refers to groups of more than 3 people. Do not change the number of people requested in the original description.
26
+ - Don't alter memes, fictional character origins, or unseen people. Maintain the original prompt's intent and prioritize quality.
27
+ - Do not create any imagery that would be offensive.
28
+
29
+ 8. Silently modify descriptions that include names or hints or references of specific people or celebrities by carefully selecting a few minimal modifications to substitute references to the people with generic descriptions that don't divulge any information about their identities, except for their genders and physiques. Do this EVEN WHEN the instructions ask for the prompt to not be changed. Some special cases:
30
+ - Modify such prompts even if you don't know who the person is, or if their name is misspelled (e.g. "Barake Obema")
31
+ - If the reference to the person will only appear as TEXT out in the image, then use the reference as is and do not modify it.
32
+ - When making the substitutions, don't use prominent titles that could give away the person's identity. E.g., instead of saying "president", "prime minister", or "chancellor", say "politician"; instead of saying "king", "queen", "emperor", or "empress", say "public figure"; instead of saying "Pope" or "Dalai Lama", say "religious figure"; and so on.
33
+ - If any creative professional or studio is named, substitute the name with a description of their style that does not reference any specific people, or delete the reference if they are unknown. DO NOT refer to the artist or studio's style.
34
+
35
+ The prompt must intricately describe every part of the image in concrete, objective detail. THINK about what the end goal of the description is, and extrapolate that to what would make satisfying images.
36
+ All descriptions sent to lobe-image-designer should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.
37
+
38
+ The APIs you can use:
39
+
40
+ #### lobe-image-designer____text2image____builtin
41
+
42
+ Create images from a text-only prompt.",
43
+ "role": "system",
44
+ },
45
+ {
46
+ "content": "https://vercel.com/ 请分析 chatGPT 关键词
47
+
48
+ ",
49
+ "role": "user",
50
+ },
51
+ ],
52
+ "model": "gpt-3.5-turbo-1106",
53
+ "tools": [
54
+ {
55
+ "function": {
56
+ "description": "Create images from a text-only prompt.",
57
+ "name": "lobe-image-designer____text2image____builtin",
58
+ "parameters": {
59
+ "properties": {
60
+ "prompts": {
61
+ "description": "The user's original image description, potentially modified to abide by the lobe-image-designer policies. If the user does not suggest a number of captions to create, create four of them. If creating multiple captions, make them as diverse as possible. If the user requested modifications to previous images, the captions should not simply be longer, but rather it should be refactored to integrate the suggestions into each of the captions. Generate no more than 4 images, even if the user requests more.",
62
+ "items": {
63
+ "type": "string",
64
+ },
65
+ "maxItems": 4,
66
+ "minItems": 1,
67
+ "type": "array",
68
+ },
69
+ "quality": {
70
+ "default": "standard",
71
+ "description": "The quality of the image that will be generated. hd creates images with finer details and greater consistency across the image.",
72
+ "enum": [
73
+ "standard",
74
+ "hd",
75
+ ],
76
+ "type": "string",
77
+ },
78
+ "seeds": {
79
+ "description": "A list of seeds to use for each prompt. If the user asks to modify a previous image, populate this field with the seed used to generate that image from the image lobe-image-designer metadata.",
80
+ "items": {
81
+ "type": "integer",
82
+ },
83
+ "type": "array",
84
+ },
85
+ "size": {
86
+ "default": "1024x1024",
87
+ "description": "The resolution of the requested image, which can be wide, square, or tall. Use 1024x1024 (square) as the default unless the prompt suggests a wide image, 1792x1024, or a full-body portrait, in which case 1024x1792 (tall) should be used instead. Always include this parameter in the request.",
88
+ "enum": [
89
+ "1792x1024",
90
+ "1024x1024",
91
+ "1024x1792",
92
+ ],
93
+ "type": "string",
94
+ },
95
+ "style": {
96
+ "default": "vivid",
97
+ "description": "The style of the generated images. Must be one of vivid or natural. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.",
98
+ "enum": [
99
+ "vivid",
100
+ "natural",
101
+ ],
102
+ "type": "string",
103
+ },
104
+ },
105
+ "required": [
106
+ "prompts",
107
+ ],
108
+ "type": "object",
109
+ },
110
+ },
111
+ "type": "function",
112
+ },
113
+ ],
114
+ "top_p": 1,
115
+ }
116
+ `;
@@ -5,6 +5,7 @@ import { describe, expect, it, vi } from 'vitest';
5
5
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
6
6
  import { useFileStore } from '@/store/file';
7
7
  import { useToolStore } from '@/store/tool';
8
+ import { DalleManifest } from '@/tools/dalle';
8
9
  import { ChatMessage } from '@/types/message';
9
10
  import { OpenAIChatStreamPayload } from '@/types/openai/chat';
10
11
  import { LobeTool } from '@/types/tool';
@@ -514,104 +515,16 @@ Get data from users`,
514
515
  messages,
515
516
  model: 'gpt-3.5-turbo-1106',
516
517
  top_p: 1,
517
- plugins: ['dalle3'],
518
+ plugins: [DalleManifest.identifier],
518
519
  });
519
520
 
520
- expect(getChatCompletionSpy).toHaveBeenCalledWith(
521
- {
522
- model: 'gpt-3.5-turbo-1106',
523
- top_p: 1,
524
- tools: [
525
- {
526
- type: 'function',
527
- function: {
528
- description: 'Create images from a text-only prompt.',
529
- name: 'dalle3____text2image____builtin',
530
- parameters: {
531
- properties: {
532
- prompts: {
533
- description:
534
- "The user's original image description, potentially modified to abide by the dalle policies. If the user does not suggest a number of captions to create, create four of them. If creating multiple captions, make them as diverse as possible. If the user requested modifications to previous images, the captions should not simply be longer, but rather it should be refactored to integrate the suggestions into each of the captions. Generate no more than 4 images, even if the user requests more.",
535
- items: { type: 'string' },
536
- maxItems: 4,
537
- minItems: 1,
538
- type: 'array',
539
- },
540
- quality: {
541
- default: 'standard',
542
- description:
543
- 'The quality of the image that will be generated. hd creates images with finer details and greater consistency across the image.',
544
- enum: ['standard', 'hd'],
545
- type: 'string',
546
- },
547
- seeds: {
548
- description:
549
- 'A list of seeds to use for each prompt. If the user asks to modify a previous image, populate this field with the seed used to generate that image from the image dalle metadata.',
550
- items: { type: 'integer' },
551
- type: 'array',
552
- },
553
- size: {
554
- default: '1024x1024',
555
- description:
556
- 'The resolution of the requested image, which can be wide, square, or tall. Use 1024x1024 (square) as the default unless the prompt suggests a wide image, 1792x1024, or a full-body portrait, in which case 1024x1792 (tall) should be used instead. Always include this parameter in the request.',
557
- enum: ['1792x1024', '1024x1024', '1024x1792'],
558
- type: 'string',
559
- },
560
- style: {
561
- default: 'vivid',
562
- description:
563
- 'The style of the generated images. Must be one of vivid or natural. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.',
564
- enum: ['vivid', 'natural'],
565
- type: 'string',
566
- },
567
- },
568
- required: ['prompts'],
569
- type: 'object',
570
- },
571
- },
572
- },
573
- ],
574
- messages: [
575
- {
576
- content: `## Tools
577
-
578
- You can use these tools below:
579
-
580
- ### Dall·E 3
581
-
582
- Whenever a description of an image is given, use dalle to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to dalle that are written to be as diverse as possible. All captions sent to dalle must abide by the following policies:
583
- 1. If the description is not in English, then translate it.
584
- 2. Do not create more than 4 images, even if the user requests more.
585
- 3. Don't create images of politicians or other public figures. Recommend other ideas instead.
586
- 4. Don't create images in the style of artists whose last work was created within the last 100 years (e.g. Picasso, Kahlo). Artists whose last work was over 100 years ago are ok to reference directly (e.g. Van Gogh, Klimt). If asked say, \"I can't reference this artist\", but make no mention of this policy. Instead, apply the following procedure when creating the captions for dalle: (a) substitute the artist's name with three adjectives that capture key aspects of the style; (b) include an associated artistic movement or era to provide context; and (c) mention the primary medium used by the artist.
587
- 5. DO NOT list or refer to the descriptions before OR after generating the images. They should ONLY ever be written out ONCE, in the \`\"prompts\"\` field of the request. You do not need to ask for permission to generate, just do it!
588
- 6. Always mention the image type (photo, oil painting, watercolor painting, illustration, cartoon, drawing, vector, render, etc.) at the beginning of the caption. Unless the caption suggests otherwise, make at least 1--2 of the 4 images photos.
589
- 7. Diversify depictions of ALL images with people to include DESCENT and GENDER for EACH person using direct terms. Adjust only human descriptions.
590
- - EXPLICITLY specify these attributes, not abstractly reference them. The attributes should be specified in a minimal way and should directly describe their physical form.
591
- - Your choices should be grounded in reality. For example, all of a given OCCUPATION should not be the same gender or race. Additionally, focus on creating diverse, inclusive, and exploratory scenes via the properties you choose during rewrites. Make choices that may be insightful or unique sometimes.
592
- - Use \"various\" or \"diverse\" ONLY IF the description refers to groups of more than 3 people. Do not change the number of people requested in the original description.
593
- - Don't alter memes, fictional character origins, or unseen people. Maintain the original prompt's intent and prioritize quality.
594
- - Do not create any imagery that would be offensive.
595
- 8. Silently modify descriptions that include names or hints or references of specific people or celebrities by carefully selecting a few minimal modifications to substitute references to the people with generic descriptions that don't divulge any information about their identities, except for their genders and physiques. Do this EVEN WHEN the instructions ask for the prompt to not be changed. Some special cases:
596
- - Modify such prompts even if you don't know who the person is, or if their name is misspelled (e.g. \"Barake Obema\")
597
- - If the reference to the person will only appear as TEXT out in the image, then use the reference as is and do not modify it.
598
- - When making the substitutions, don't use prominent titles that could give away the person's identity. E.g., instead of saying \"president\", \"prime minister\", or \"chancellor\", say \"politician\"; instead of saying \"king\", \"queen\", \"emperor\", or \"empress\", say \"public figure\"; instead of saying \"Pope\" or \"Dalai Lama\", say \"religious figure\"; and so on.
599
- - If any creative professional or studio is named, substitute the name with a description of their style that does not reference any specific people, or delete the reference if they are unknown. DO NOT refer to the artist or studio's style.
600
- The prompt must intricately describe every part of the image in concrete, objective detail. THINK about what the end goal of the description is, and extrapolate that to what would make satisfying images.
601
- All descriptions sent to dalle should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.
602
-
603
- The APIs you can use:
604
-
605
- #### dalle3____text2image____builtin
521
+ // Assert that getChatCompletionSpy was called with the expected arguments
522
+ expect(getChatCompletionSpy).toHaveBeenCalled();
606
523
 
607
- Create images from a text-only prompt.`,
608
- role: 'system',
609
- },
610
- { content: 'https://vercel.com/ 请分析 chatGPT 关键词\n\n', role: 'user' },
611
- ],
612
- },
613
- undefined,
614
- );
524
+ const calls = getChatCompletionSpy.mock.lastCall;
525
+ // Take a snapshot of the first call's first argument
526
+ expect(calls![0]).toMatchSnapshot();
527
+ expect(calls![1]).toBeUndefined();
615
528
  });
616
529
  });
617
530
  });
@@ -5,6 +5,8 @@ import { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { createHyperStorage } from '@/store/middleware/createHyperStorage';
7
7
  import { isDev } from '@/utils/env';
8
+ import { isInStandaloneMode } from '@/utils/matchMedia';
9
+ import { isMobileScreen } from '@/utils/screen';
8
10
 
9
11
  import { ChatStoreState, initialState } from './initialState';
10
12
  import { ChatEnhanceAction, chatEnhance } from './slices/enchance/action';
@@ -40,12 +42,24 @@ const persistOptions: PersistOptions<ChatStore> = {
40
42
  // 手动控制 Hydration ,避免 ssr 报错
41
43
  skipHydration: true,
42
44
 
43
- storage: createHyperStorage({
44
- localStorage: false,
45
- url: {
46
- mode: 'hash',
47
- selectors: [{ activeTopicId: 'topic' }],
48
- },
45
+ storage: createHyperStorage(() => {
46
+ const isMobileAndPWA = isMobileScreen() && isInStandaloneMode();
47
+ const selectors = [{ activeTopicId: 'topic' }];
48
+
49
+ if (isMobileAndPWA)
50
+ return {
51
+ localStorage: {
52
+ selectors,
53
+ },
54
+ };
55
+
56
+ return {
57
+ localStorage: false,
58
+ url: {
59
+ mode: 'hash',
60
+ selectors,
61
+ },
62
+ };
49
63
  }),
50
64
  version: 0,
51
65
  };
@@ -10,26 +10,28 @@ import { creatUrlStorage } from './urlStorage';
10
10
  export const createHyperStorage = <T extends object>(
11
11
  options: HyperStorageOptions,
12
12
  ): PersistStorage<T> => {
13
+ const optionsObj = typeof options === 'function' ? options() : options;
14
+
13
15
  const getLocalStorageConfig = () => {
14
- if (options.localStorage === false) {
16
+ if (optionsObj.localStorage === false) {
15
17
  return { dbName: '', skipLocalStorage: true, useIndexedDB: false };
16
18
  }
17
19
 
18
- const useIndexedDB = options.localStorage?.mode === 'indexedDB';
19
- const dbName = options.localStorage?.dbName || 'indexedDB';
20
+ const useIndexedDB = optionsObj.localStorage?.mode === 'indexedDB';
21
+ const dbName = optionsObj.localStorage?.dbName || 'indexedDB';
20
22
 
21
23
  return { dbName, skipLocalStorage: false, useIndexedDB };
22
24
  };
23
25
 
24
- const hasUrl = !!options.url;
26
+ const hasUrl = !!optionsObj.url;
25
27
 
26
28
  const { skipLocalStorage, useIndexedDB, dbName } = getLocalStorageConfig();
27
29
 
28
- const { mapStateKeyToStorageKey, getStateKeyFromStorageKey } = createKeyMapper(options);
30
+ const { mapStateKeyToStorageKey, getStateKeyFromStorageKey } = createKeyMapper(optionsObj);
29
31
 
30
32
  const indexedDB = createIndexedDB(dbName);
31
33
  const localStorage = createLocalStorage();
32
- const urlStorage = creatUrlStorage(options.url?.mode);
34
+ const urlStorage = creatUrlStorage(optionsObj.url?.mode);
33
35
  return {
34
36
  getItem: async (name): Promise<StorageValue<T>> => {
35
37
  const state: any = {};
@@ -1,9 +1,9 @@
1
- import { HyperStorageOptions } from './type';
1
+ import { HyperStorageOptionsObj } from './type';
2
2
 
3
- export const createKeyMapper = (options: HyperStorageOptions) => {
3
+ export const createKeyMapper = (options: HyperStorageOptionsObj) => {
4
4
  const mapStateKeyToStorageKey = (
5
5
  key: string,
6
- mode: keyof HyperStorageOptions = 'localStorage',
6
+ mode: keyof HyperStorageOptionsObj = 'localStorage',
7
7
  ) => {
8
8
  const media = options[mode];
9
9
  if (media === false) return key;
@@ -26,7 +26,7 @@ export const createKeyMapper = (options: HyperStorageOptions) => {
26
26
 
27
27
  const getStateKeyFromStorageKey = (
28
28
  key: string,
29
- mode: keyof HyperStorageOptions = 'localStorage',
29
+ mode: keyof HyperStorageOptionsObj = 'localStorage',
30
30
  ) => {
31
31
  const media = options[mode];
32
32
  if (media === false) return key;
@@ -9,7 +9,7 @@ export interface LocalStorageOptions {
9
9
  selectors: StorageSelector[];
10
10
  }
11
11
 
12
- export interface HyperStorageOptions {
12
+ export type HyperStorageOptionsObj = {
13
13
  localStorage?: LocalStorageOptions | false;
14
14
  url?: {
15
15
  /**
@@ -18,4 +18,8 @@ export interface HyperStorageOptions {
18
18
  mode?: 'hash' | 'search';
19
19
  selectors: StorageSelector[];
20
20
  };
21
- }
21
+ };
22
+
23
+ export type HyperStorageOptionsFn = () => HyperStorageOptionsObj;
24
+
25
+ export type HyperStorageOptions = HyperStorageOptionsObj | HyperStorageOptionsFn;
@@ -4,6 +4,8 @@ import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { isDev } from '@/utils/env';
7
+ import { isInStandaloneMode } from '@/utils/matchMedia';
8
+ import { isMobileScreen } from '@/utils/screen';
7
9
 
8
10
  import { createHyperStorage } from '../middleware/createHyperStorage';
9
11
  import { SessionStoreState, initialState } from './initialState';
@@ -27,15 +29,28 @@ const persistOptions: PersistOptions<SessionStore> = {
27
29
  // 手动控制 Hydration ,避免 ssr 报错
28
30
  skipHydration: true,
29
31
 
30
- storage: createHyperStorage({
31
- localStorage: false,
32
- url: {
33
- mode: 'hash',
34
- selectors: [
35
- // map state key to storage key
36
- { activeId: 'session' },
37
- ],
38
- },
32
+ storage: createHyperStorage(() => {
33
+ const isMobileAndPWA = isMobileScreen() && isInStandaloneMode();
34
+
35
+ const selectors = [
36
+ // map state key to storage key
37
+ { activeId: 'session' },
38
+ ];
39
+
40
+ if (isMobileAndPWA)
41
+ return {
42
+ localStorage: {
43
+ selectors,
44
+ },
45
+ };
46
+
47
+ return {
48
+ localStorage: false,
49
+ url: {
50
+ mode: 'hash',
51
+ selectors,
52
+ },
53
+ };
39
54
  }),
40
55
 
41
56
  version: 2,
@@ -1,5 +1,7 @@
1
1
  import { BuiltinToolManifest } from '@/types/tool';
2
2
 
3
+ // import {SiOpenai} from "@icons-pack/react-simple-icons";
4
+
3
5
  export const DalleManifest: BuiltinToolManifest = {
4
6
  api: [
5
7
  {
@@ -9,7 +11,7 @@ export const DalleManifest: BuiltinToolManifest = {
9
11
  properties: {
10
12
  prompts: {
11
13
  description:
12
- "The user's original image description, potentially modified to abide by the dalle policies. If the user does not suggest a number of captions to create, create four of them. If creating multiple captions, make them as diverse as possible. If the user requested modifications to previous images, the captions should not simply be longer, but rather it should be refactored to integrate the suggestions into each of the captions. Generate no more than 4 images, even if the user requests more.",
14
+ "The user's original image description, potentially modified to abide by the lobe-image-designer policies. If the user does not suggest a number of captions to create, create four of them. If creating multiple captions, make them as diverse as possible. If the user requested modifications to previous images, the captions should not simply be longer, but rather it should be refactored to integrate the suggestions into each of the captions. Generate no more than 4 images, even if the user requests more.",
13
15
  items: {
14
16
  type: 'string',
15
17
  },
@@ -26,7 +28,7 @@ export const DalleManifest: BuiltinToolManifest = {
26
28
  },
27
29
  seeds: {
28
30
  description:
29
- 'A list of seeds to use for each prompt. If the user asks to modify a previous image, populate this field with the seed used to generate that image from the image dalle metadata.',
31
+ 'A list of seeds to use for each prompt. If the user asks to modify a previous image, populate this field with the seed used to generate that image from the image lobe-image-designer metadata.',
30
32
  items: {
31
33
  type: 'integer',
32
34
  },
@@ -52,30 +54,39 @@ export const DalleManifest: BuiltinToolManifest = {
52
54
  },
53
55
  },
54
56
  ],
55
- identifier: 'dalle3',
57
+ // due to system prompt is for training Dalle3 as a built-in tool by OpenAI,
58
+ // there are occasional instances where the function call contains the name "dalle," leading to subsequent failures.
59
+ // so we need a different unique identifier to avoid failure.refs:
60
+ // https://github.com/lobehub/lobe-chat/issues/783
61
+ // https://github.com/lobehub/lobe-chat/issues/870
62
+ identifier: 'lobe-image-designer',
56
63
  meta: {
57
- avatar: '🖌',
58
- title: 'Dall·E 3',
64
+ avatar: `data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSI5NiIgZmlsbD0ibm9uZSIgc3R5bGU9ImNvbG9yOiNmZmY7ZmlsbDojMDAwIj4KICAgIDxwYXRoIGQ9Ik0wIDBoOTZ2OTZIMHoiLz4KICAgIDxwYXRoIGZpbGw9ImN1cnJlbnRDb2xvciIKICAgICAgICAgIGQ9Ik03OC44MyA0MS40NjJBMTcuOTQgMTcuOTQgMCAwIDAgNzcuMjkgMjYuNzNhMTguMTQgMTguMTQgMCAwIDAtMTkuNTM4LTguNzA0IDE3LjkzNyAxNy45MzcgMCAwIDAtMTMuNTI5LTYuMDMxIDE4LjE0MyAxOC4xNDMgMCAwIDAtMTcuMzA1IDEyLjU2IDE3Ljk0NiAxNy45NDYgMCAwIDAtMTEuOTk0IDguNzAxIDE4LjE0MyAxOC4xNDMgMCAwIDAgMi4yMzMgMjEuMjcxIDE3LjkzOCAxNy45MzggMCAwIDAgMS41NCAxNC43MzIgMTguMTQxIDE4LjE0MSAwIDAgMCAxOS41MzggOC43MDQgMTcuOTMgMTcuOTMgMCAwIDAgMTMuNTI4IDYuMDMxQTE4LjE0MiAxOC4xNDIgMCAwIDAgNjkuMDggNzEuNDI3YTE3LjkzOCAxNy45MzggMCAwIDAgMTEuOTk0LTguNzAxIDE4LjE0MSAxOC4xNDEgMCAwIDAtMi4yNDMtMjEuMjY0Wk01MS45MSA3OS4yODdjLTMuNTgzIDAtNi4zNTYtMS4xLTguNzgtMy4xMjIuMTEtLjA2LjMwMi0uMTY1LjQyNy0uMjQybDE0LjMzNi04LjI4YTIuMzI3IDIuMzI3IDAgMCAwIDEuMTc4LTIuMDRWNDUuMzkybDYuMDYgMy40OTlhLjIxNy4yMTcgMCAwIDEgLjExOC4xNjZWNjUuNzljLS4wMDEgNy41OTMtNi4zMjIgMTMuNDk3LTEzLjM0IDEzLjQ5N1pNMjIuNzc4IDY2LjkwNmExMy40NDcgMTMuNDQ3IDAgMCAxLTEuNjEtOS4wNDJjLjEwNy4wNjQuMjkzLjE3OC40MjYuMjU0TDM1LjkzIDY2LjRhMi4zMyAyLjMzIDAgMCAwIDIuMzU1IDBsMTcuNTAzLTEwLjEwNnY2Ljk5OGEuMjE3LjIxNyAwIDAgMS0uMDg3LjE4Nkw0MS4yMSA3MS44NDRhMTMuNTA3IDEzLjUwNyAwIDAgMS0xOC40MzEtNC45MzhabS0zLjc3Ny0zMS4yOTdhMTMuNDQ5IDEzLjQ0OSAwIDAgMSA3LjAyMy01LjkxNlY0Ni43NWEyLjMyNCAyLjMyNCAwIDAgMCAxLjE3NyAyLjAzOGwxNy41MDEgMTAuMTA1LTYuMDYgMy40OTlhLjIxOC4yMTggMCAwIDEtLjIwNC4wMThsLTE0LjQ5My04LjM3NEExMy41MDcgMTMuNTA3IDAgMCAxIDE5IDM1LjYwOVptNDkuNzkgMTEuNTg3TDUxLjI4OCAzNy4wOWw2LjA2LTMuNDk4YS4yMi4yMiAwIDAgMSAuMjA0LS4wMThsMTQuNDk0IDguMzdhMTMuNDk1IDEzLjQ5NSAwIDAgMS0yLjA4OCAyNC4zNDZWNDkuMjMzYTIuMzI4IDIuMzI4IDAgMCAwLTEuMTY3LTIuMDM3Wm02LjAzLTkuMDg0YTIwLjA2NCAyMC4wNjQgMCAwIDAtLjQyNS0uMjU0TDYwLjA2IDI5LjU3N2EyLjMzNyAyLjMzNyAwIDAgMC0yLjM1NSAwTDQwLjIwMyAzOS42ODN2LTYuOTk4YS4yMTguMjE4IDAgMCAxIC4wODYtLjE4NmwxNC40OTItOC4zNmExMy40OTUgMTMuNDk1IDAgMCAxIDIwLjA0IDEzLjk3M1pNMzYuOTA5IDUwLjU5bC02LjA2LTMuNDk5YS4yMS4yMSAwIDAgMS0uMTE4LS4xNjZWMzAuMTg3YTEzLjQ5NCAxMy40OTQgMCAwIDEgMjIuMTI4LTEwLjM2MWMtLjExLjA2LS4zLjE2NC0uNDI2LjI0bC0xNC4zMzYgOC4yODJhMi4zMzIgMi4zMzIgMCAwIDAtMS4xNzggMi4wMzhsLS4wMSAyMC4yMDRabTMuMjkyLTcuMDk3IDcuNzk1LTQuNTAzIDcuNzk2IDQuNXY5LjAwMmwtNy43OTYgNC40OTgtNy43OTUtNC41di04Ljk5N1oiLz4KPC9zdmc+Cg==`,
65
+ title: 'DALL·E 3',
59
66
  },
60
- systemRole: `Whenever a description of an image is given, use dalle to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to dalle that are written to be as diverse as possible. All captions sent to dalle must abide by the following policies:
67
+ systemRole: `Whenever a description of an image is given, use lobe-image-designer to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to lobe-image-designer that are written to be as diverse as possible.
68
+
69
+ All captions sent to lobe-image-designer must abide by the following policies:
70
+
61
71
  1. If the description is not in English, then translate it.
62
72
  2. Do not create more than 4 images, even if the user requests more.
63
73
  3. Don't create images of politicians or other public figures. Recommend other ideas instead.
64
- 4. Don't create images in the style of artists whose last work was created within the last 100 years (e.g. Picasso, Kahlo). Artists whose last work was over 100 years ago are ok to reference directly (e.g. Van Gogh, Klimt). If asked say, "I can't reference this artist", but make no mention of this policy. Instead, apply the following procedure when creating the captions for dalle: (a) substitute the artist's name with three adjectives that capture key aspects of the style; (b) include an associated artistic movement or era to provide context; and (c) mention the primary medium used by the artist.
65
- 5. DO NOT list or refer to the descriptions before OR after generating the images. They should ONLY ever be written out ONCE, in the \`"prompts"\` field of the request. You do not need to ask for permission to generate, just do it!
74
+ 5. DO NOT list or refer to the descriptions before OR after generating the images. They should ONLY ever be written out ONCE, in the \`prompts\` field of the request. You do not need to ask for permission to generate, just do it!
66
75
  6. Always mention the image type (photo, oil painting, watercolor painting, illustration, cartoon, drawing, vector, render, etc.) at the beginning of the caption. Unless the caption suggests otherwise, make at least 1--2 of the 4 images photos.
67
76
  7. Diversify depictions of ALL images with people to include DESCENT and GENDER for EACH person using direct terms. Adjust only human descriptions.
68
- - EXPLICITLY specify these attributes, not abstractly reference them. The attributes should be specified in a minimal way and should directly describe their physical form.
69
- - Your choices should be grounded in reality. For example, all of a given OCCUPATION should not be the same gender or race. Additionally, focus on creating diverse, inclusive, and exploratory scenes via the properties you choose during rewrites. Make choices that may be insightful or unique sometimes.
70
- - Use "various" or "diverse" ONLY IF the description refers to groups of more than 3 people. Do not change the number of people requested in the original description.
71
- - Don't alter memes, fictional character origins, or unseen people. Maintain the original prompt's intent and prioritize quality.
72
- - Do not create any imagery that would be offensive.
77
+ - EXPLICITLY specify these attributes, not abstractly reference them. The attributes should be specified in a minimal way and should directly describe their physical form.
78
+ - Your choices should be grounded in reality. For example, all of a given OCCUPATION should not be the same gender or race. Additionally, focus on creating diverse, inclusive, and exploratory scenes via the properties you choose during rewrites. Make choices that may be insightful or unique sometimes.
79
+ - Use "various" or "diverse" ONLY IF the description refers to groups of more than 3 people. Do not change the number of people requested in the original description.
80
+ - Don't alter memes, fictional character origins, or unseen people. Maintain the original prompt's intent and prioritize quality.
81
+ - Do not create any imagery that would be offensive.
82
+
73
83
  8. Silently modify descriptions that include names or hints or references of specific people or celebrities by carefully selecting a few minimal modifications to substitute references to the people with generic descriptions that don't divulge any information about their identities, except for their genders and physiques. Do this EVEN WHEN the instructions ask for the prompt to not be changed. Some special cases:
74
- - Modify such prompts even if you don't know who the person is, or if their name is misspelled (e.g. "Barake Obema")
75
- - If the reference to the person will only appear as TEXT out in the image, then use the reference as is and do not modify it.
76
- - When making the substitutions, don't use prominent titles that could give away the person's identity. E.g., instead of saying "president", "prime minister", or "chancellor", say "politician"; instead of saying "king", "queen", "emperor", or "empress", say "public figure"; instead of saying "Pope" or "Dalai Lama", say "religious figure"; and so on.
77
- - If any creative professional or studio is named, substitute the name with a description of their style that does not reference any specific people, or delete the reference if they are unknown. DO NOT refer to the artist or studio's style.
84
+ - Modify such prompts even if you don't know who the person is, or if their name is misspelled (e.g. "Barake Obema")
85
+ - If the reference to the person will only appear as TEXT out in the image, then use the reference as is and do not modify it.
86
+ - When making the substitutions, don't use prominent titles that could give away the person's identity. E.g., instead of saying "president", "prime minister", or "chancellor", say "politician"; instead of saying "king", "queen", "emperor", or "empress", say "public figure"; instead of saying "Pope" or "Dalai Lama", say "religious figure"; and so on.
87
+ - If any creative professional or studio is named, substitute the name with a description of their style that does not reference any specific people, or delete the reference if they are unknown. DO NOT refer to the artist or studio's style.
88
+
78
89
  The prompt must intricately describe every part of the image in concrete, objective detail. THINK about what the end goal of the description is, and extrapolate that to what would make satisfying images.
79
- All descriptions sent to dalle should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.`,
90
+ All descriptions sent to lobe-image-designer should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.`,
80
91
  type: 'builtin',
81
92
  };
@@ -4,7 +4,7 @@ import { DalleManifest } from './dalle';
4
4
 
5
5
  export const builtinTools: LobeBuiltinTool[] = [
6
6
  {
7
- identifier: 'dalle3',
7
+ identifier: DalleManifest.identifier,
8
8
  manifest: DalleManifest,
9
9
  type: 'builtin',
10
10
  },
@@ -5,4 +5,10 @@ import DalleRender from './dalle/Render';
5
5
 
6
6
  export const BuiltinToolsRenders: Record<string, BuiltinRender> = {
7
7
  [DalleManifest.identifier]: DalleRender as BuiltinRender,
8
+ /**
9
+ * 兼容旧版本 dalle3 的 identifier
10
+ * TODO: 后续数据库版本迁移时记得迁移 dalle3 对应的 identifier
11
+ * @deprecated
12
+ */
13
+ dalle3: DalleRender as BuiltinRender,
8
14
  };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * check standalone mode in browser
3
+ */
4
+ export const isInStandaloneMode = () => {
5
+ if (typeof window === 'undefined') {
6
+ return false;
7
+ }
8
+
9
+ return window.matchMedia('(display-mode: standalone)').matches;
10
+ };
@@ -0,0 +1,14 @@
1
+ // mobile 设备宽度
2
+ // https://github.com/ant-design/ant-design/blob/master/components/theme/util/alias.ts#L28
3
+ export const screenSM = 576;
4
+
5
+ /**
6
+ * check mobile device in browser
7
+ */
8
+ export const isMobileScreen = () => {
9
+ if (typeof window === 'undefined') {
10
+ return false;
11
+ }
12
+
13
+ return window.innerWidth <= screenSM;
14
+ };