@difizen/libro-ai-native 0.2.41-next.0
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/LICENSE +21 -0
- package/README.md +1 -0
- package/es/ai-native-code-block.d.ts +4 -0
- package/es/ai-native-code-block.d.ts.map +1 -0
- package/es/ai-native-code-block.js +176 -0
- package/es/ai-native-command-contribution.d.ts +16 -0
- package/es/ai-native-command-contribution.d.ts.map +1 -0
- package/es/ai-native-command-contribution.js +297 -0
- package/es/ai-native-command.d.ts +5 -0
- package/es/ai-native-command.d.ts.map +1 -0
- package/es/ai-native-command.js +17 -0
- package/es/ai-native-for-cell-view.d.ts +20 -0
- package/es/ai-native-for-cell-view.d.ts.map +1 -0
- package/es/ai-native-for-cell-view.js +190 -0
- package/es/ai-native-output-top.d.ts +6 -0
- package/es/ai-native-output-top.d.ts.map +1 -0
- package/es/ai-native-output-top.js +37 -0
- package/es/ai-native-service.d.ts +13 -0
- package/es/ai-native-service.d.ts.map +1 -0
- package/es/ai-native-service.js +75 -0
- package/es/ai-side-toolbar-selector.d.ts +3 -0
- package/es/ai-side-toolbar-selector.d.ts.map +1 -0
- package/es/ai-side-toolbar-selector.js +47 -0
- package/es/chat-slot-contribution.d.ts +15 -0
- package/es/chat-slot-contribution.d.ts.map +1 -0
- package/es/chat-slot-contribution.js +71 -0
- package/es/chat-view.d.ts +15 -0
- package/es/chat-view.d.ts.map +1 -0
- package/es/chat-view.js +114 -0
- package/es/error-output-model.d.ts +8 -0
- package/es/error-output-model.d.ts.map +1 -0
- package/es/error-output-model.js +140 -0
- package/es/icon.d.ts +4 -0
- package/es/icon.d.ts.map +1 -0
- package/es/icon.js +92 -0
- package/es/index.d.ts +6 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +5 -0
- package/es/index.less +297 -0
- package/es/libro-ai-msg-item-model.d.ts +18 -0
- package/es/libro-ai-msg-item-model.d.ts.map +1 -0
- package/es/libro-ai-msg-item-model.js +85 -0
- package/es/libro-ai-native-chat-service.d.ts +8 -0
- package/es/libro-ai-native-chat-service.d.ts.map +1 -0
- package/es/libro-ai-native-chat-service.js +157 -0
- package/es/libro-ai-native-chat-view.d.ts +42 -0
- package/es/libro-ai-native-chat-view.d.ts.map +1 -0
- package/es/libro-ai-native-chat-view.js +88 -0
- package/es/libro-ai-native-color-registry.d.ts +6 -0
- package/es/libro-ai-native-color-registry.d.ts.map +1 -0
- package/es/libro-ai-native-color-registry.js +46 -0
- package/es/module.d.ts +3 -0
- package/es/module.d.ts.map +1 -0
- package/es/module.js +28 -0
- package/es/protocol.d.ts +10 -0
- package/es/protocol.d.ts.map +1 -0
- package/es/protocol.js +1 -0
- package/es/utils.js +114 -0
- package/package.json +74 -0
- package/src/ai-native-code-block.tsx +138 -0
- package/src/ai-native-command-contribution.tsx +248 -0
- package/src/ai-native-command.ts +23 -0
- package/src/ai-native-for-cell-view.tsx +156 -0
- package/src/ai-native-output-top.tsx +43 -0
- package/src/ai-native-service.ts +39 -0
- package/src/ai-side-toolbar-selector.tsx +51 -0
- package/src/chat-slot-contribution.ts +36 -0
- package/src/chat-view.tsx +141 -0
- package/src/error-output-model.tsx +103 -0
- package/src/icon.tsx +80 -0
- package/src/index.less +330 -0
- package/src/index.spec.ts +8 -0
- package/src/index.ts +5 -0
- package/src/libro-ai-msg-item-model.ts +69 -0
- package/src/libro-ai-native-chat-service.ts +95 -0
- package/src/libro-ai-native-chat-view.tsx +54 -0
- package/src/libro-ai-native-color-registry.ts +33 -0
- package/src/module.ts +44 -0
- package/src/protocol.ts +18 -0
- package/src/utils.tsx +115 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { CommentOutlined } from '@ant-design/icons';
|
|
2
|
+
import {
|
|
3
|
+
LibroCommandRegister,
|
|
4
|
+
LibroSlotManager,
|
|
5
|
+
LibroSlotView,
|
|
6
|
+
LibroToolbarArea,
|
|
7
|
+
LibroCellView,
|
|
8
|
+
LibroView,
|
|
9
|
+
} from '@difizen/libro-jupyter';
|
|
10
|
+
import type { CommandRegistry, ToolbarRegistry } from '@difizen/mana-app';
|
|
11
|
+
import { inject } from '@difizen/mana-app';
|
|
12
|
+
import { CommandContribution } from '@difizen/mana-app';
|
|
13
|
+
import { singleton, ToolbarContribution, ViewManager } from '@difizen/mana-app';
|
|
14
|
+
import { l10n } from '@difizen/mana-l10n';
|
|
15
|
+
|
|
16
|
+
import { AINativeCommands } from './ai-native-command.js';
|
|
17
|
+
import { LibroAINativeService } from './ai-native-service.js';
|
|
18
|
+
import { AIToolbarSelector } from './ai-side-toolbar-selector.js';
|
|
19
|
+
import { LibroAIChatSlotContribution } from './chat-slot-contribution.js';
|
|
20
|
+
import { AIIcon } from './icon.js';
|
|
21
|
+
import { addCellAIClassname } from './utils.js';
|
|
22
|
+
|
|
23
|
+
@singleton({ contrib: [CommandContribution, ToolbarContribution] })
|
|
24
|
+
export class LibroAINativeCommandContribution
|
|
25
|
+
implements ToolbarContribution, CommandContribution
|
|
26
|
+
{
|
|
27
|
+
@inject(LibroCommandRegister) protected readonly libroCommand: LibroCommandRegister;
|
|
28
|
+
@inject(LibroAIChatSlotContribution)
|
|
29
|
+
libroAIChatSlotContribution: LibroAIChatSlotContribution;
|
|
30
|
+
@inject(LibroSlotManager) libroSlotManager: LibroSlotManager;
|
|
31
|
+
@inject(LibroAINativeService) libroAINativeService: LibroAINativeService;
|
|
32
|
+
@inject(ViewManager) viewManager: ViewManager;
|
|
33
|
+
|
|
34
|
+
registerToolbarItems(registry: ToolbarRegistry): void {
|
|
35
|
+
registry.registerItem({
|
|
36
|
+
id: AINativeCommands['AISideToolbarSelect'].id,
|
|
37
|
+
command: AINativeCommands['AISideToolbarSelect'].id,
|
|
38
|
+
icon: AIToolbarSelector,
|
|
39
|
+
showLabelInline: true,
|
|
40
|
+
order: 'b',
|
|
41
|
+
});
|
|
42
|
+
registry.registerItem({
|
|
43
|
+
id: AINativeCommands['Chat'].id,
|
|
44
|
+
command: AINativeCommands['Chat'].id,
|
|
45
|
+
icon: AIIcon,
|
|
46
|
+
order: 'a',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
registry.registerItem({
|
|
50
|
+
id: AINativeCommands['CellChat'].id,
|
|
51
|
+
command: AINativeCommands['CellChat'].id,
|
|
52
|
+
icon: <CommentOutlined className="libro-ai-native-cell-chat-icon" />,
|
|
53
|
+
order: 'a',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
registerCommands(command: CommandRegistry): void {
|
|
58
|
+
this.libroCommand.registerLibroCommand(
|
|
59
|
+
command,
|
|
60
|
+
AINativeCommands['AISideToolbarSelect'],
|
|
61
|
+
{
|
|
62
|
+
execute: async () => {
|
|
63
|
+
// this.libroService.active?.enterEditMode();
|
|
64
|
+
},
|
|
65
|
+
isVisible: (cell, libro, path) => {
|
|
66
|
+
if (!cell || !libro || !(libro instanceof LibroView)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return path === LibroToolbarArea.CellRight;
|
|
70
|
+
},
|
|
71
|
+
isEnabled: (cell, libro) => {
|
|
72
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
this.libroCommand.registerLibroCommand(command, AINativeCommands['CellChat'], {
|
|
81
|
+
execute: async (cell, libro) => {
|
|
82
|
+
if (!libro || !cell) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
addCellAIClassname(cell);
|
|
86
|
+
const chatView = this.libroAINativeService.chatViewMap.get(libro.id);
|
|
87
|
+
const showChat = this.libroAINativeService.showChatMap.get(libro.id);
|
|
88
|
+
if (chatView) {
|
|
89
|
+
chatView.setAINativeChatView({
|
|
90
|
+
id: cell.id,
|
|
91
|
+
isCellChat: true,
|
|
92
|
+
cell: cell,
|
|
93
|
+
});
|
|
94
|
+
if (showChat) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.libroAINativeService.showChatMap.set(libro.id, !showChat);
|
|
98
|
+
this.libroAINativeService.cellAIChatMap.set(cell.id, !showChat);
|
|
99
|
+
this.libroSlotManager.slotViewManager.addView(
|
|
100
|
+
chatView,
|
|
101
|
+
this.libroSlotManager.getSlotName(
|
|
102
|
+
libro,
|
|
103
|
+
this.libroAIChatSlotContribution.slot,
|
|
104
|
+
),
|
|
105
|
+
{
|
|
106
|
+
reveal: true,
|
|
107
|
+
order: 'a',
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
//优化交互,用于控制点击按钮后菜单消失
|
|
112
|
+
this.libroAINativeService.showSideToolbar = false;
|
|
113
|
+
},
|
|
114
|
+
isEnabled: (cell, libro) => {
|
|
115
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
},
|
|
120
|
+
isVisible: (cell, libro, path) => {
|
|
121
|
+
if (!cell || !libro || !(libro instanceof LibroView)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return path === LibroToolbarArea.CellRight;
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
this.libroCommand.registerLibroCommand(command, AINativeCommands['Chat'], {
|
|
128
|
+
execute: async (cell, libro) => {
|
|
129
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const chatView = this.libroAINativeService.chatViewMap.get(libro.id);
|
|
133
|
+
const showChat = this.libroAINativeService.showChatMap.get(libro.id);
|
|
134
|
+
this.libroAINativeService.showChatMap;
|
|
135
|
+
if (chatView) {
|
|
136
|
+
if (showChat && chatView.chatView.isCellChat) {
|
|
137
|
+
chatView.setAINativeChatView({
|
|
138
|
+
id: libro.id,
|
|
139
|
+
isCellChat: false,
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
chatView.setAINativeChatView({
|
|
144
|
+
id: libro.id,
|
|
145
|
+
isCellChat: false,
|
|
146
|
+
});
|
|
147
|
+
this.libroAINativeService.showChatMap.set(libro.id, !showChat);
|
|
148
|
+
if (showChat) {
|
|
149
|
+
const slotview = this.libroSlotManager.slotViewManager.getSlotView(
|
|
150
|
+
this.libroSlotManager.getSlotName(libro, 'right'),
|
|
151
|
+
);
|
|
152
|
+
if (slotview instanceof LibroSlotView) {
|
|
153
|
+
slotview.revertActive();
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
this.libroSlotManager.slotViewManager.addView(
|
|
157
|
+
chatView,
|
|
158
|
+
this.libroSlotManager.getSlotName(
|
|
159
|
+
libro,
|
|
160
|
+
this.libroAIChatSlotContribution.slot,
|
|
161
|
+
),
|
|
162
|
+
{
|
|
163
|
+
reveal: true,
|
|
164
|
+
order: 'a',
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.libroAINativeService.showSideToolbar = false;
|
|
170
|
+
},
|
|
171
|
+
isVisible: (cell, libro, path) => {
|
|
172
|
+
if (!cell || !libro || !(libro instanceof LibroView)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return path === LibroToolbarArea.HeaderRight;
|
|
176
|
+
},
|
|
177
|
+
isEnabled: (cell, libro) => {
|
|
178
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
this.libroCommand.registerLibroCommand(command, AINativeCommands['Explain'], {
|
|
185
|
+
execute: async (cell, libro) => {
|
|
186
|
+
if (
|
|
187
|
+
!cell ||
|
|
188
|
+
!(cell instanceof LibroCellView) ||
|
|
189
|
+
!libro ||
|
|
190
|
+
!(libro instanceof LibroView)
|
|
191
|
+
) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const libroAINativeForCellView =
|
|
195
|
+
await this.libroAINativeService.getOrCreateLibroAINativeForCellView(
|
|
196
|
+
cell.id,
|
|
197
|
+
cell,
|
|
198
|
+
);
|
|
199
|
+
libroAINativeForCellView.showAI = true;
|
|
200
|
+
addCellAIClassname(cell);
|
|
201
|
+
libroAINativeForCellView.chatStream({
|
|
202
|
+
content: l10n.getLang()
|
|
203
|
+
? `Could you please explain this piece of code?:${cell.model.value},Provide the reasons and the results of the optimization.`
|
|
204
|
+
: `帮忙优化一下这段代码:${cell.model.value},给出原因以及优化结果`,
|
|
205
|
+
});
|
|
206
|
+
// this.libroService.active?.enterEditMode();
|
|
207
|
+
},
|
|
208
|
+
isEnabled: (cell, libro) => {
|
|
209
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
this.libroCommand.registerLibroCommand(command, AINativeCommands['Optimize'], {
|
|
217
|
+
execute: async (cell, libro) => {
|
|
218
|
+
if (
|
|
219
|
+
!cell ||
|
|
220
|
+
!(cell instanceof LibroCellView) ||
|
|
221
|
+
!libro ||
|
|
222
|
+
!(libro instanceof LibroView)
|
|
223
|
+
) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const libroAINativeForCellView =
|
|
227
|
+
await this.libroAINativeService.getOrCreateLibroAINativeForCellView(
|
|
228
|
+
cell.id,
|
|
229
|
+
cell,
|
|
230
|
+
);
|
|
231
|
+
libroAINativeForCellView.showAI = true;
|
|
232
|
+
addCellAIClassname(cell);
|
|
233
|
+
libroAINativeForCellView.chatStream({
|
|
234
|
+
content: l10n.getLang()
|
|
235
|
+
? `Please help optimize this piece of code: ${cell.model.value},provide reasons and the optimized result.`
|
|
236
|
+
: `帮忙优化一下这段代码:${cell.model.value},给出原因以及优化结果`,
|
|
237
|
+
});
|
|
238
|
+
// this.libroService.active?.enterEditMode();
|
|
239
|
+
},
|
|
240
|
+
isEnabled: (cell, libro) => {
|
|
241
|
+
if (!libro || !(libro instanceof LibroView)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Command } from '@difizen/mana-app';
|
|
2
|
+
|
|
3
|
+
export const AINativeCommands: Record<string, Command & { keybind?: string }> = {
|
|
4
|
+
Explain: {
|
|
5
|
+
id: 'ai-native:explain',
|
|
6
|
+
label: 'EXPLAIN',
|
|
7
|
+
},
|
|
8
|
+
Chat: {
|
|
9
|
+
id: 'ai-native:chat',
|
|
10
|
+
label: 'Chat',
|
|
11
|
+
},
|
|
12
|
+
CellChat: {
|
|
13
|
+
id: 'ai-native:cell-chat',
|
|
14
|
+
label: 'Cell Chat',
|
|
15
|
+
},
|
|
16
|
+
AISideToolbarSelect: {
|
|
17
|
+
id: 'ai-native:side-toolbat-select',
|
|
18
|
+
},
|
|
19
|
+
Optimize: {
|
|
20
|
+
id: 'ai-native:optimize',
|
|
21
|
+
label: 'Optimize',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { CloseOutlined } from '@ant-design/icons';
|
|
2
|
+
import type { CellView } from '@difizen/libro-jupyter';
|
|
3
|
+
import type { IChatMessage } from '@difizen/magent-chat';
|
|
4
|
+
import { AnswerState } from '@difizen/magent-chat';
|
|
5
|
+
import { ChatComponents } from '@difizen/magent-chat';
|
|
6
|
+
import { ChatEvent } from '@difizen/magent-chat';
|
|
7
|
+
import type { ToAutoFactory } from '@difizen/magent-core';
|
|
8
|
+
import { Fetcher } from '@difizen/magent-core';
|
|
9
|
+
import { toAutoFactory } from '@difizen/magent-core';
|
|
10
|
+
import type { ViewComponent } from '@difizen/mana-app';
|
|
11
|
+
import { ViewOption } from '@difizen/mana-app';
|
|
12
|
+
import { prop } from '@difizen/mana-app';
|
|
13
|
+
import { useObserve } from '@difizen/mana-app';
|
|
14
|
+
import { useInject, ViewInstance } from '@difizen/mana-app';
|
|
15
|
+
import { inject } from '@difizen/mana-app';
|
|
16
|
+
import { BaseView, transient, view } from '@difizen/mana-app';
|
|
17
|
+
import { l10n } from '@difizen/mana-l10n';
|
|
18
|
+
import { Button } from 'antd';
|
|
19
|
+
import { EventSourceParserStream } from 'eventsource-parser/stream';
|
|
20
|
+
import breaks from 'remark-breaks';
|
|
21
|
+
import remarkGfm from 'remark-gfm';
|
|
22
|
+
|
|
23
|
+
import { CodeBlockInCell } from './ai-native-code-block.js';
|
|
24
|
+
import { LibroAINativeService } from './ai-native-service.js';
|
|
25
|
+
import { AILoadding } from './icon.js';
|
|
26
|
+
import { LibroAIChatMessageItemModel } from './libro-ai-msg-item-model.js';
|
|
27
|
+
import type { IAINativeForCellViewOption } from './protocol.js';
|
|
28
|
+
import { cancelCellAIClassname, stringToReadableStream } from './utils.js';
|
|
29
|
+
|
|
30
|
+
export function LibroAINativeForCellRender() {
|
|
31
|
+
const LLMRender = ChatComponents.Markdown;
|
|
32
|
+
|
|
33
|
+
const instance = useInject<LibroAINativeForCellView>(ViewInstance);
|
|
34
|
+
const libroAINativeService = useInject<LibroAINativeService>(LibroAINativeService);
|
|
35
|
+
|
|
36
|
+
const msgItem = useObserve(instance.libroAIChatMessageItemModel);
|
|
37
|
+
if (!instance.showAI) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="libro-ai-native-for-cell-container">
|
|
43
|
+
{msgItem?.state === AnswerState.FAIL ? (
|
|
44
|
+
<div className="libro-ai-native-for-cell-error">{l10n.t('请求报错~')}</div>
|
|
45
|
+
) : (
|
|
46
|
+
<LLMRender
|
|
47
|
+
type="message"
|
|
48
|
+
components={{ code: CodeBlockInCell }}
|
|
49
|
+
remarkPlugins={[remarkGfm, breaks]}
|
|
50
|
+
>
|
|
51
|
+
{msgItem?.content || ''}
|
|
52
|
+
</LLMRender>
|
|
53
|
+
)}
|
|
54
|
+
<Button
|
|
55
|
+
color="default"
|
|
56
|
+
variant="outlined"
|
|
57
|
+
className={`libro-ai-native-for-cell-cancel-btn ${msgItem?.state === AnswerState.FAIL ? 'error' : ''}`}
|
|
58
|
+
onClick={() => {
|
|
59
|
+
instance.showAI = false;
|
|
60
|
+
if (!libroAINativeService.cellAIChatMap.get(instance.cell.id)) {
|
|
61
|
+
cancelCellAIClassname(instance.cell);
|
|
62
|
+
}
|
|
63
|
+
}}
|
|
64
|
+
icon={
|
|
65
|
+
msgItem?.state === AnswerState.SUCCESS ||
|
|
66
|
+
msgItem?.state === AnswerState.FAIL ? (
|
|
67
|
+
<CloseOutlined />
|
|
68
|
+
) : (
|
|
69
|
+
<AILoadding />
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
>
|
|
73
|
+
{l10n.t('取消')}
|
|
74
|
+
</Button>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@transient()
|
|
80
|
+
@view('libro-ai-native-for-cell-view')
|
|
81
|
+
export class LibroAINativeForCellView extends BaseView {
|
|
82
|
+
override view: ViewComponent = LibroAINativeForCellRender;
|
|
83
|
+
@inject(Fetcher) fetcher: Fetcher;
|
|
84
|
+
cell: CellView;
|
|
85
|
+
@inject(toAutoFactory(LibroAIChatMessageItemModel))
|
|
86
|
+
libroAiChatMessageItemFactory: ToAutoFactory<typeof LibroAIChatMessageItemModel>;
|
|
87
|
+
@prop()
|
|
88
|
+
libroAIChatMessageItemModel?: LibroAIChatMessageItemModel;
|
|
89
|
+
|
|
90
|
+
@prop()
|
|
91
|
+
showAI = false;
|
|
92
|
+
constructor(@inject(ViewOption) options: IAINativeForCellViewOption) {
|
|
93
|
+
super();
|
|
94
|
+
this.cell = options.cell;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
chatStream = async (option: IChatMessage) => {
|
|
98
|
+
const { chat_key, content, language } = option;
|
|
99
|
+
|
|
100
|
+
const url = `/libro/api/chatstream`;
|
|
101
|
+
const msg = {
|
|
102
|
+
chat_key: chat_key,
|
|
103
|
+
prompt: content,
|
|
104
|
+
language: language,
|
|
105
|
+
};
|
|
106
|
+
const res = await this.fetcher.post<ReadableStream<Uint8Array>>(url, msg, {
|
|
107
|
+
headers: {
|
|
108
|
+
Accept: 'text/event-stream',
|
|
109
|
+
},
|
|
110
|
+
responseType: 'stream',
|
|
111
|
+
adapter: 'fetch',
|
|
112
|
+
});
|
|
113
|
+
if (res.status === 200) {
|
|
114
|
+
let reader;
|
|
115
|
+
if (typeof res.data === 'string') {
|
|
116
|
+
reader = stringToReadableStream(res.data)
|
|
117
|
+
.pipeThrough(new TextDecoderStream())
|
|
118
|
+
.pipeThrough(new EventSourceParserStream())
|
|
119
|
+
.getReader();
|
|
120
|
+
} else {
|
|
121
|
+
const stream = res.data;
|
|
122
|
+
reader = stream
|
|
123
|
+
.pipeThrough(new TextDecoderStream())
|
|
124
|
+
.pipeThrough(new EventSourceParserStream())
|
|
125
|
+
.getReader();
|
|
126
|
+
}
|
|
127
|
+
const msgItem = this.libroAiChatMessageItemFactory({
|
|
128
|
+
sender: { type: 'AI', id: 'libro' },
|
|
129
|
+
content: '',
|
|
130
|
+
});
|
|
131
|
+
this.libroAIChatMessageItemModel = msgItem;
|
|
132
|
+
let alreayDone = false;
|
|
133
|
+
try {
|
|
134
|
+
while (!alreayDone) {
|
|
135
|
+
const { value, done } = await reader.read();
|
|
136
|
+
if (done) {
|
|
137
|
+
alreayDone = true;
|
|
138
|
+
msgItem.handleEventData({
|
|
139
|
+
type: 'done',
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
const data = JSON.parse(value.data);
|
|
145
|
+
const event = ChatEvent.format(value.event || 'chunk', data);
|
|
146
|
+
msgItem.handleEventData(event);
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
msgItem.handleEventData({
|
|
150
|
+
type: 'error',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CellView } from '@difizen/libro-jupyter';
|
|
2
|
+
import { useInject, ViewManager, ViewRender } from '@difizen/mana-app';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import './index.less';
|
|
5
|
+
|
|
6
|
+
import type { LibroAINativeForCellView } from './ai-native-for-cell-view.js';
|
|
7
|
+
import { LibroAINativeService } from './ai-native-service.js';
|
|
8
|
+
|
|
9
|
+
export function LibroAINativeCellTopBlank({ cell }: { cell: CellView }) {
|
|
10
|
+
const viewManager = useInject<ViewManager>(ViewManager);
|
|
11
|
+
|
|
12
|
+
const [aiNativeForCellView, setAiNativeForCellView] =
|
|
13
|
+
useState<LibroAINativeForCellView>();
|
|
14
|
+
const libroAINativeService = useInject<LibroAINativeService>(LibroAINativeService);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
libroAINativeService
|
|
18
|
+
.getOrCreateLibroAINativeForCellView(cell.id, cell)
|
|
19
|
+
.then((view) => {
|
|
20
|
+
setAiNativeForCellView(view);
|
|
21
|
+
return;
|
|
22
|
+
})
|
|
23
|
+
.catch(() => {
|
|
24
|
+
//
|
|
25
|
+
});
|
|
26
|
+
}, [
|
|
27
|
+
cell,
|
|
28
|
+
cell.id,
|
|
29
|
+
libroAINativeService,
|
|
30
|
+
libroAINativeService.libroAINativeForCellViewMap,
|
|
31
|
+
viewManager,
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
if (!aiNativeForCellView) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="libro-ai-native-output-top">
|
|
40
|
+
<ViewRender view={aiNativeForCellView}></ViewRender>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CellView } from '@difizen/libro-jupyter';
|
|
2
|
+
import { getOrigin, inject, prop, singleton, ViewManager } from '@difizen/mana-app';
|
|
3
|
+
|
|
4
|
+
import { LibroAINativeForCellView } from './ai-native-for-cell-view.js';
|
|
5
|
+
import type { LibroChatView } from './chat-view.js';
|
|
6
|
+
import type { LibroAiNativeChatView } from './libro-ai-native-chat-view.js';
|
|
7
|
+
|
|
8
|
+
@singleton()
|
|
9
|
+
export class LibroAINativeService {
|
|
10
|
+
@prop()
|
|
11
|
+
showSideToolbar = false;
|
|
12
|
+
|
|
13
|
+
chatViewMap: Map<string, LibroChatView> = new Map();
|
|
14
|
+
|
|
15
|
+
//用于控制是否显示当前 libro 层级的 chat 面板
|
|
16
|
+
showChatMap: Map<string, boolean> = new Map();
|
|
17
|
+
|
|
18
|
+
cellAIChatMap: Map<string, boolean> = new Map();
|
|
19
|
+
@inject(ViewManager)
|
|
20
|
+
viewManager: ViewManager;
|
|
21
|
+
|
|
22
|
+
libroAINativeForCellViewMap: Map<string, LibroAINativeForCellView> = new Map();
|
|
23
|
+
|
|
24
|
+
libroAINativeChatViewMap: Map<string, LibroAiNativeChatView> = new Map();
|
|
25
|
+
|
|
26
|
+
async getOrCreateLibroAINativeForCellView(id: string, cell: CellView) {
|
|
27
|
+
let libroAINativeForCellView = this.libroAINativeForCellViewMap.get(id);
|
|
28
|
+
if (libroAINativeForCellView) {
|
|
29
|
+
return libroAINativeForCellView;
|
|
30
|
+
} else {
|
|
31
|
+
libroAINativeForCellView = await this.viewManager.getOrCreateView(
|
|
32
|
+
LibroAINativeForCellView,
|
|
33
|
+
{ id: id, cell: getOrigin(cell) },
|
|
34
|
+
);
|
|
35
|
+
this.libroAINativeForCellViewMap.set(cell.id, libroAINativeForCellView);
|
|
36
|
+
}
|
|
37
|
+
return libroAINativeForCellView;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { LibroSideToolbarMenuItemType } from '@difizen/libro-jupyter';
|
|
2
|
+
import { LibroSideToolbarMenu } from '@difizen/libro-jupyter';
|
|
3
|
+
import { useInject } from '@difizen/mana-app';
|
|
4
|
+
import { l10n } from '@difizen/mana-l10n';
|
|
5
|
+
import { Popover } from 'antd';
|
|
6
|
+
|
|
7
|
+
import { AINativeCommands } from './ai-native-command.js';
|
|
8
|
+
import { LibroAINativeService } from './ai-native-service.js';
|
|
9
|
+
import { AIIcon } from './icon.js';
|
|
10
|
+
|
|
11
|
+
export const AIToolbarSelector: React.FC = () => {
|
|
12
|
+
const items: LibroSideToolbarMenuItemType[] = [
|
|
13
|
+
{
|
|
14
|
+
id: AINativeCommands['Explain'].id,
|
|
15
|
+
label: (
|
|
16
|
+
<>
|
|
17
|
+
<span className="libro-menu-item-label">{l10n.t('代码解释')}</span>
|
|
18
|
+
</>
|
|
19
|
+
),
|
|
20
|
+
group: 'ai',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: AINativeCommands['Optimize'].id,
|
|
24
|
+
label: (
|
|
25
|
+
<>
|
|
26
|
+
<span className="libro-menu-item-label">{l10n.t('代码优化')}</span>
|
|
27
|
+
</>
|
|
28
|
+
),
|
|
29
|
+
group: 'ai',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
const libroAINativeService = useInject<LibroAINativeService>(LibroAINativeService);
|
|
33
|
+
const handleOpenChange = (newOpen: boolean) => {
|
|
34
|
+
libroAINativeService.showSideToolbar = newOpen;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Popover
|
|
39
|
+
placement="leftTop"
|
|
40
|
+
content={<LibroSideToolbarMenu items={items} />}
|
|
41
|
+
trigger="hover"
|
|
42
|
+
open={libroAINativeService.showSideToolbar}
|
|
43
|
+
onOpenChange={handleOpenChange}
|
|
44
|
+
overlayClassName="libro-popover-side-toolbar-menu libro-side-toolbar-ai-select-menu"
|
|
45
|
+
>
|
|
46
|
+
<div>
|
|
47
|
+
<AIIcon />
|
|
48
|
+
</div>
|
|
49
|
+
</Popover>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LibroView,
|
|
3
|
+
LibroExtensionSlotFactory,
|
|
4
|
+
LibroSlot,
|
|
5
|
+
} from '@difizen/libro-jupyter';
|
|
6
|
+
import { LibroExtensionSlotContribution } from '@difizen/libro-jupyter';
|
|
7
|
+
import { ViewManager } from '@difizen/mana-app';
|
|
8
|
+
import { inject, singleton } from '@difizen/mana-app';
|
|
9
|
+
|
|
10
|
+
import { LibroAINativeService } from './ai-native-service.js';
|
|
11
|
+
import { LibroChatView } from './chat-view.js';
|
|
12
|
+
|
|
13
|
+
@singleton({ contrib: [LibroExtensionSlotContribution] })
|
|
14
|
+
export class LibroAIChatSlotContribution implements LibroExtensionSlotContribution {
|
|
15
|
+
@inject(ViewManager) viewManager: ViewManager;
|
|
16
|
+
@inject(LibroAINativeService) libroAINativeService: LibroAINativeService;
|
|
17
|
+
|
|
18
|
+
public readonly slot: LibroSlot = 'right';
|
|
19
|
+
|
|
20
|
+
factory: LibroExtensionSlotFactory = async (libro: LibroView) => {
|
|
21
|
+
const view = await this.viewManager.getOrCreateView(LibroChatView, {
|
|
22
|
+
parentId: libro.id,
|
|
23
|
+
});
|
|
24
|
+
view.parent = libro;
|
|
25
|
+
this.libroAINativeService.chatViewMap.set(libro.id, view);
|
|
26
|
+
this.libroAINativeService.showChatMap.set(libro.id, false);
|
|
27
|
+
view.onDisposed(() => {
|
|
28
|
+
this.libroAINativeService.chatViewMap.delete(libro.id);
|
|
29
|
+
});
|
|
30
|
+
return view;
|
|
31
|
+
};
|
|
32
|
+
viewOpenOption = {
|
|
33
|
+
reveal: false,
|
|
34
|
+
order: 'a',
|
|
35
|
+
};
|
|
36
|
+
}
|