@difizen/libro-prompt-cell 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -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 +54 -0
- package/es/libro-llm-render.d.ts +10 -0
- package/es/libro-llm-render.d.ts.map +1 -0
- package/es/libro-llm-render.js +71 -0
- package/es/module.d.ts +3 -0
- package/es/module.d.ts.map +1 -0
- package/es/module.js +23 -0
- package/es/prompt-cell-command-contribution.d.ts +18 -0
- package/es/prompt-cell-command-contribution.d.ts.map +1 -0
- package/es/prompt-cell-command-contribution.js +62 -0
- package/es/prompt-cell-contribution.d.ts +13 -0
- package/es/prompt-cell-contribution.d.ts.map +1 -0
- package/es/prompt-cell-contribution.js +66 -0
- package/es/prompt-cell-model.d.ts +33 -0
- package/es/prompt-cell-model.d.ts.map +1 -0
- package/es/prompt-cell-model.js +163 -0
- package/es/prompt-cell-output-area.d.ts +14 -0
- package/es/prompt-cell-output-area.d.ts.map +1 -0
- package/es/prompt-cell-output-area.js +74 -0
- package/es/prompt-cell-protocol.d.ts +5 -0
- package/es/prompt-cell-protocol.d.ts.map +1 -0
- package/es/prompt-cell-protocol.js +1 -0
- package/es/prompt-cell-script.d.ts +4 -0
- package/es/prompt-cell-script.d.ts.map +1 -0
- package/es/prompt-cell-script.js +4 -0
- package/es/prompt-cell-utils.d.ts +2 -0
- package/es/prompt-cell-utils.d.ts.map +1 -0
- package/es/prompt-cell-utils.js +7 -0
- package/es/prompt-cell-view.d.ts +50 -0
- package/es/prompt-cell-view.d.ts.map +1 -0
- package/es/prompt-cell-view.js +543 -0
- package/es/prompt-output-render.d.ts +6 -0
- package/es/prompt-output-render.d.ts.map +1 -0
- package/es/prompt-output-render.js +120 -0
- package/es/prompt-output-rendermime-contribution.d.ts +13 -0
- package/es/prompt-output-rendermime-contribution.d.ts.map +1 -0
- package/es/prompt-output-rendermime-contribution.js +22 -0
- package/package.json +72 -0
- package/src/index.less +54 -0
- package/src/index.spec.ts +9 -0
- package/src/index.ts +5 -0
- package/src/libro-llm-render.tsx +63 -0
- package/src/module.ts +35 -0
- package/src/prompt-cell-command-contribution.ts +61 -0
- package/src/prompt-cell-contribution.ts +34 -0
- package/src/prompt-cell-model.ts +117 -0
- package/src/prompt-cell-output-area.tsx +59 -0
- package/src/prompt-cell-protocol.ts +8 -0
- package/src/prompt-cell-script.ts +4 -0
- package/src/prompt-cell-utils.ts +6 -0
- package/src/prompt-cell-view.tsx +446 -0
- package/src/prompt-output-render.tsx +83 -0
- package/src/prompt-output-rendermime-contribution.ts +16 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// import { l10n } from '@difizen/mana-l10n';
|
|
2
|
+
import type { IOutputAreaOption } from '@difizen/libro-core';
|
|
3
|
+
import { LibroOutputArea } from '@difizen/libro-core';
|
|
4
|
+
import type { IRenderMimeRegistry } from '@difizen/libro-jupyter';
|
|
5
|
+
import { RenderMimeRegistry } from '@difizen/libro-jupyter';
|
|
6
|
+
import type { ViewComponent } from '@difizen/mana-app';
|
|
7
|
+
import {
|
|
8
|
+
useInject,
|
|
9
|
+
ViewInstance,
|
|
10
|
+
ViewRender,
|
|
11
|
+
prop,
|
|
12
|
+
view,
|
|
13
|
+
inject,
|
|
14
|
+
transient,
|
|
15
|
+
ViewOption,
|
|
16
|
+
} from '@difizen/mana-app';
|
|
17
|
+
import React from 'react';
|
|
18
|
+
|
|
19
|
+
import './index.less';
|
|
20
|
+
|
|
21
|
+
export const LibroPromptOutputAreaRender = React.forwardRef<HTMLDivElement>(
|
|
22
|
+
function LibroPromptOutputAreaRender(_props, ref) {
|
|
23
|
+
const outputArea = useInject<LibroPromptOutputArea>(ViewInstance);
|
|
24
|
+
const defaultRenderMime = useInject<IRenderMimeRegistry>(RenderMimeRegistry);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="libro-output-area prompt-cell" ref={ref}>
|
|
28
|
+
{outputArea.outputs.map((output) => {
|
|
29
|
+
if (
|
|
30
|
+
defaultRenderMime.preferredMimeType(output) !==
|
|
31
|
+
'application/vnd.libro.prompt+json'
|
|
32
|
+
) {
|
|
33
|
+
return <ViewRender view={output} key={output.id} />;
|
|
34
|
+
} else {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
})}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
@transient()
|
|
44
|
+
@view('libro-prompt-output-area')
|
|
45
|
+
export class LibroPromptOutputArea extends LibroOutputArea {
|
|
46
|
+
override view: ViewComponent = LibroPromptOutputAreaRender;
|
|
47
|
+
@prop()
|
|
48
|
+
promptExecutionTipVisiable = false;
|
|
49
|
+
@prop()
|
|
50
|
+
promptExecutionTipShown = true;
|
|
51
|
+
|
|
52
|
+
constructor(@inject(ViewOption) option: IOutputAreaOption) {
|
|
53
|
+
super(option);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setSqlExecutionTipVisiable = (value: boolean) => {
|
|
57
|
+
this.promptExecutionTipVisiable = value;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CellOptions } from '@difizen/libro-core';
|
|
2
|
+
|
|
3
|
+
import type { LibroPromptCellModel } from './prompt-cell-model.js';
|
|
4
|
+
|
|
5
|
+
export type LibroPromptCellModelFactory = (
|
|
6
|
+
options: CellOptions,
|
|
7
|
+
) => LibroPromptCellModel;
|
|
8
|
+
export const LibroPromptCellModelFactory = Symbol('LibroPromptCellModelFactory');
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export namespace PromptScript {
|
|
2
|
+
export const get_models =
|
|
3
|
+
'import json\nfrom aistudio_notebook.prompt_flow import prompt_model_registry\nmodel_list = list(prompt_model_registry.promptModelRegistry.get_models().keys())\nmodel_data = json.dumps(model_list)\nprint(model_data)\n';
|
|
4
|
+
}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import type { CodeEditorViewOptions, IRange } from '@difizen/libro-code-editor';
|
|
2
|
+
import { CodeEditorView } from '@difizen/libro-code-editor';
|
|
3
|
+
import { CodeMirrorEditor, codeMirrorEditorFactory } from '@difizen/libro-codemirror';
|
|
4
|
+
import type { ICodeCell, IOutput } from '@difizen/libro-common';
|
|
5
|
+
import { isOutput } from '@difizen/libro-common';
|
|
6
|
+
import type {
|
|
7
|
+
IOutputAreaOption,
|
|
8
|
+
LibroCell,
|
|
9
|
+
CellViewOptions,
|
|
10
|
+
} from '@difizen/libro-core';
|
|
11
|
+
import {
|
|
12
|
+
CellService,
|
|
13
|
+
LibroExecutableCellView,
|
|
14
|
+
LibroOutputArea,
|
|
15
|
+
LibroViewTracker,
|
|
16
|
+
} from '@difizen/libro-core';
|
|
17
|
+
import type { ExecutionMeta, KernelMessage } from '@difizen/libro-jupyter';
|
|
18
|
+
import { KernelError, LibroJupyterModel } from '@difizen/libro-jupyter';
|
|
19
|
+
import {
|
|
20
|
+
getOrigin,
|
|
21
|
+
inject,
|
|
22
|
+
prop,
|
|
23
|
+
transient,
|
|
24
|
+
useInject,
|
|
25
|
+
view,
|
|
26
|
+
ViewInstance,
|
|
27
|
+
ViewManager,
|
|
28
|
+
ViewOption,
|
|
29
|
+
ViewRender,
|
|
30
|
+
watch,
|
|
31
|
+
} from '@difizen/mana-app';
|
|
32
|
+
import { Deferred } from '@difizen/mana-app';
|
|
33
|
+
import { Select } from 'antd';
|
|
34
|
+
import React, { useEffect, useState } from 'react';
|
|
35
|
+
|
|
36
|
+
import type { LibroPromptCellModel } from './prompt-cell-model.js';
|
|
37
|
+
import { PromptScript } from './prompt-cell-script.js';
|
|
38
|
+
|
|
39
|
+
export interface IModelSelectionItem {
|
|
40
|
+
value: string;
|
|
41
|
+
label: string;
|
|
42
|
+
}
|
|
43
|
+
export interface IModelItem {
|
|
44
|
+
value: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const CellEditor: React.FC = () => {
|
|
48
|
+
const instance = useInject<LibroPromptCellView>(ViewInstance);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (instance.editorView?.editor) {
|
|
51
|
+
instance.editor = getOrigin(instance.editorView?.editor);
|
|
52
|
+
}
|
|
53
|
+
}, [instance, instance.editorView?.editor]);
|
|
54
|
+
return <>{instance.editorView && <ViewRender view={instance.editorView} />}</>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const CellEditorMemo = React.memo(CellEditor);
|
|
58
|
+
|
|
59
|
+
const PropmtEditorViewComponent = React.forwardRef<HTMLDivElement>(
|
|
60
|
+
function MaxPropmtEditorViewComponent(props, ref) {
|
|
61
|
+
const instance = useInject<LibroPromptCellView>(ViewInstance);
|
|
62
|
+
const [selectedModel, setSelectedModel] = useState<string>('暂无内置模型');
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
instance
|
|
65
|
+
.fetch(
|
|
66
|
+
{ code: PromptScript.get_models, store_history: false },
|
|
67
|
+
instance.handleQueryResponse,
|
|
68
|
+
)
|
|
69
|
+
.then(() => {
|
|
70
|
+
if (instance.modelSelection.length > 0) {
|
|
71
|
+
setSelectedModel(instance.modelSelection[0].label);
|
|
72
|
+
instance.model.modelType = instance.modelSelection[0].label;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
})
|
|
77
|
+
.catch(() => {
|
|
78
|
+
//
|
|
79
|
+
});
|
|
80
|
+
}, [instance]);
|
|
81
|
+
|
|
82
|
+
const handleChange = (value: string) => {
|
|
83
|
+
instance.model.modelType = value;
|
|
84
|
+
setSelectedModel(value);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div
|
|
89
|
+
className={instance.className}
|
|
90
|
+
ref={ref}
|
|
91
|
+
tabIndex={10}
|
|
92
|
+
onBlur={instance.blur}
|
|
93
|
+
>
|
|
94
|
+
<div className="libro-prompt-cell-header">
|
|
95
|
+
<div className="libro-prompt-cell-header-model-config">
|
|
96
|
+
<Select
|
|
97
|
+
value={selectedModel}
|
|
98
|
+
style={{ width: 160 }}
|
|
99
|
+
onChange={handleChange}
|
|
100
|
+
options={instance.modelSelection}
|
|
101
|
+
bordered={false}
|
|
102
|
+
onFocus={async () => {
|
|
103
|
+
await instance.fetch(
|
|
104
|
+
{ code: PromptScript.get_models, store_history: false },
|
|
105
|
+
instance.handleQueryResponse,
|
|
106
|
+
);
|
|
107
|
+
}}
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
<CellEditorMemo />
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
@transient()
|
|
118
|
+
@view('prompt-editor-cell-view')
|
|
119
|
+
export class LibroPromptCellView extends LibroExecutableCellView {
|
|
120
|
+
override view = PropmtEditorViewComponent;
|
|
121
|
+
|
|
122
|
+
declare model: LibroPromptCellModel;
|
|
123
|
+
|
|
124
|
+
@prop()
|
|
125
|
+
modelSelection: IModelSelectionItem[] = [];
|
|
126
|
+
|
|
127
|
+
viewManager: ViewManager;
|
|
128
|
+
|
|
129
|
+
outputs: IOutput[];
|
|
130
|
+
|
|
131
|
+
libroViewTracker: LibroViewTracker;
|
|
132
|
+
|
|
133
|
+
@prop()
|
|
134
|
+
editorView?: CodeEditorView;
|
|
135
|
+
|
|
136
|
+
protected outputAreaDeferred = new Deferred<LibroOutputArea>();
|
|
137
|
+
get outputAreaReady() {
|
|
138
|
+
return this.outputAreaDeferred.promise;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected editorViewReadyDeferred: Deferred<void> = new Deferred<void>();
|
|
142
|
+
|
|
143
|
+
get editorReady() {
|
|
144
|
+
return this.editorViewReadyDeferred.promise;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
constructor(
|
|
148
|
+
@inject(ViewOption) options: CellViewOptions,
|
|
149
|
+
@inject(CellService) cellService: CellService,
|
|
150
|
+
@inject(ViewManager) viewManager: ViewManager,
|
|
151
|
+
@inject(LibroViewTracker) libroViewTracker: LibroViewTracker,
|
|
152
|
+
) {
|
|
153
|
+
super(options, cellService);
|
|
154
|
+
this.options = options;
|
|
155
|
+
this.viewManager = viewManager;
|
|
156
|
+
this.className = this.className + ' prompt';
|
|
157
|
+
|
|
158
|
+
this.outputs = options.cell?.outputs as IOutput[];
|
|
159
|
+
this.libroViewTracker = libroViewTracker;
|
|
160
|
+
|
|
161
|
+
// 创建outputArea
|
|
162
|
+
this.viewManager
|
|
163
|
+
.getOrCreateView<LibroOutputArea, IOutputAreaOption>(LibroOutputArea, {
|
|
164
|
+
cellId: this.id,
|
|
165
|
+
cell: this,
|
|
166
|
+
})
|
|
167
|
+
.then(async (outputArea) => {
|
|
168
|
+
this.outputArea = outputArea;
|
|
169
|
+
const output = this.outputs;
|
|
170
|
+
if (isOutput(output)) {
|
|
171
|
+
await this.outputArea.fromJSON(output);
|
|
172
|
+
}
|
|
173
|
+
this.outputAreaDeferred.resolve(outputArea);
|
|
174
|
+
this.outputWatch();
|
|
175
|
+
return;
|
|
176
|
+
})
|
|
177
|
+
.catch(() => {
|
|
178
|
+
//
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override outputWatch() {
|
|
183
|
+
this.toDispose.push(
|
|
184
|
+
watch(this.outputArea, 'outputs', () => {
|
|
185
|
+
this.parent.model.onChange?.();
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
override toJSON(): LibroCell {
|
|
191
|
+
const meta = super.toJSON();
|
|
192
|
+
return {
|
|
193
|
+
...meta,
|
|
194
|
+
source: meta.source ?? this.options.cell.source,
|
|
195
|
+
outputs: this.outputArea?.toJSON() ?? this.outputs,
|
|
196
|
+
} as ICodeCell;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
override onViewMount() {
|
|
200
|
+
this.createEditor();
|
|
201
|
+
//选中cell时才focus
|
|
202
|
+
if (this.parent.model.active?.id === this.id) {
|
|
203
|
+
this.focus(!this.parent.model.commandMode);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
protected getEditorOption(): CodeEditorViewOptions {
|
|
208
|
+
const option: CodeEditorViewOptions = {
|
|
209
|
+
factory: (editorOption) =>
|
|
210
|
+
codeMirrorEditorFactory({
|
|
211
|
+
...editorOption,
|
|
212
|
+
config: {
|
|
213
|
+
...editorOption.config,
|
|
214
|
+
...{ readOnly: this.parent.model.readOnly },
|
|
215
|
+
},
|
|
216
|
+
}),
|
|
217
|
+
model: this.model,
|
|
218
|
+
config: {
|
|
219
|
+
readOnly: this.parent.model.readOnly,
|
|
220
|
+
editable: !this.parent.model.readOnly,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
return option;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async createEditor() {
|
|
227
|
+
const option = this.getEditorOption();
|
|
228
|
+
this.viewManager
|
|
229
|
+
.getOrCreateView<CodeEditorView, CodeEditorViewOptions>(CodeEditorView, option)
|
|
230
|
+
.then((editorView) => {
|
|
231
|
+
this.editorView = editorView;
|
|
232
|
+
this.editorViewReadyDeferred.resolve();
|
|
233
|
+
watch(this.parent.model, 'readOnly', () => {
|
|
234
|
+
this.editorView?.editor?.setOption('readOnly', this.parent.model.readOnly);
|
|
235
|
+
if (this.editorView?.editor instanceof CodeMirrorEditor) {
|
|
236
|
+
this.editorView?.editor.setOption('placeholder', '请输入代码');
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return;
|
|
240
|
+
})
|
|
241
|
+
.catch(() => {
|
|
242
|
+
//
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
override shouldEnterEditorMode(e: React.FocusEvent<HTMLElement>) {
|
|
247
|
+
return getOrigin(this.editorView)?.editor?.host?.contains(
|
|
248
|
+
e.target as HTMLElement,
|
|
249
|
+
) && this.parent.model.commandMode
|
|
250
|
+
? true
|
|
251
|
+
: false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
override blur = () => {
|
|
255
|
+
this.editorView?.editor?.setOption('styleActiveLine', false);
|
|
256
|
+
this.editorView?.editor?.setOption('highlightActiveLineGutter', false);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
override focus = (toEdit: boolean) => {
|
|
260
|
+
if (toEdit) {
|
|
261
|
+
if (this.parent.model.readOnly === true) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (!this.editorView) {
|
|
265
|
+
this.editorReady
|
|
266
|
+
.then(async () => {
|
|
267
|
+
await this.editorView?.editorReady;
|
|
268
|
+
this.editorView?.editor?.setOption('styleActiveLine', true);
|
|
269
|
+
this.editorView?.editor?.setOption('highlightActiveLineGutter', true);
|
|
270
|
+
if (this.editorView?.editor?.hasFocus()) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
this.editorView?.editor?.focus();
|
|
274
|
+
return;
|
|
275
|
+
})
|
|
276
|
+
.catch(() => {
|
|
277
|
+
//
|
|
278
|
+
});
|
|
279
|
+
} else {
|
|
280
|
+
if (!this.editorView?.editor) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
this.editorView.editor.setOption('styleActiveLine', true);
|
|
284
|
+
this.editorView.editor.setOption('highlightActiveLineGutter', true);
|
|
285
|
+
if (this.editorView.editor.hasFocus()) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
this.editorView.editor.focus();
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
if (this.container?.current?.parentElement?.contains(document.activeElement)) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
this.container?.current?.parentElement?.focus();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
override clearExecution = () => {
|
|
299
|
+
this.model.clearExecution();
|
|
300
|
+
this.outputArea.clear();
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
override getSelections = (): [] => {
|
|
304
|
+
return this.editor?.getSelections() as [];
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
override getSelectionsOffsetAt = (selection: IRange) => {
|
|
308
|
+
const isSelect = selection;
|
|
309
|
+
const start = this.editor?.getOffsetAt(isSelect.start) ?? 0;
|
|
310
|
+
const end = this.editor?.getOffsetAt(isSelect.end) ?? 0;
|
|
311
|
+
return { start: start, end: end };
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
override async run() {
|
|
315
|
+
const libroModel = this.parent.model;
|
|
316
|
+
|
|
317
|
+
if (
|
|
318
|
+
!libroModel ||
|
|
319
|
+
!(libroModel instanceof LibroJupyterModel) ||
|
|
320
|
+
!libroModel.kernelConnection ||
|
|
321
|
+
libroModel.kernelConnection.isDisposed
|
|
322
|
+
) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const kernelConnection = getOrigin(libroModel.kernelConnection);
|
|
327
|
+
|
|
328
|
+
// const cellContent = '%prompt ' + toBase64(this.model.value) + ',model:';
|
|
329
|
+
const promptObj = {
|
|
330
|
+
model_name: this.model.modelType || 'CodeGPT',
|
|
331
|
+
prompt: this.model.value,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const cellContent = `%%prompt \n${JSON.stringify(promptObj)}`;
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
// Promise.resolve().then(() => {
|
|
338
|
+
this.clearExecution();
|
|
339
|
+
// });
|
|
340
|
+
const future = kernelConnection.requestExecute({
|
|
341
|
+
code: cellContent,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
let startTimeStr = null;
|
|
345
|
+
this.model.executing = true;
|
|
346
|
+
|
|
347
|
+
this.model.metadata['execution'] = {
|
|
348
|
+
'shell.execute_reply.started': '',
|
|
349
|
+
'shell.execute_reply.end': '',
|
|
350
|
+
to_execute: new Date().toISOString(),
|
|
351
|
+
} as ExecutionMeta;
|
|
352
|
+
|
|
353
|
+
// Handle iopub messages
|
|
354
|
+
future.onIOPub = (msg: any) => {
|
|
355
|
+
this.model.msgChangeEmitter.fire(msg);
|
|
356
|
+
if (msg.header.msg_type === 'execute_input') {
|
|
357
|
+
this.model.kernelExecuting = true;
|
|
358
|
+
startTimeStr = msg.header.date as string;
|
|
359
|
+
const meta = this.model.metadata.execution as ExecutionMeta;
|
|
360
|
+
if (meta) {
|
|
361
|
+
meta['shell.execute_reply.started'] = startTimeStr;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (msg.header.msg_type === 'error') {
|
|
365
|
+
this.model.hasExecutedError = true;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const msgPromise = await future.done;
|
|
370
|
+
this.model.executing = false;
|
|
371
|
+
this.model.kernelExecuting = false;
|
|
372
|
+
this.model.hasExecutedSuccess = !this.model.hasExecutedError;
|
|
373
|
+
|
|
374
|
+
startTimeStr = msgPromise.metadata['started'] as string; // 更新startTimeStr
|
|
375
|
+
const endTimeStr = msgPromise.header.date;
|
|
376
|
+
|
|
377
|
+
this.model.metadata['execution']['shell.execute_reply.started'] = startTimeStr;
|
|
378
|
+
this.model.metadata['execution']['shell.execute_reply.end'] = endTimeStr;
|
|
379
|
+
|
|
380
|
+
if (!msgPromise) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
if (msgPromise.content.status === 'ok') {
|
|
384
|
+
return true;
|
|
385
|
+
} else {
|
|
386
|
+
throw new KernelError(msgPromise.content);
|
|
387
|
+
}
|
|
388
|
+
} catch (reason: any) {
|
|
389
|
+
if (reason.message.startsWith('Canceled')) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
throw reason;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
fetch = async (
|
|
397
|
+
content: KernelMessage.IExecuteRequestMsg['content'],
|
|
398
|
+
ioCallback: (msg: KernelMessage.IIOPubMessage) => any,
|
|
399
|
+
) => {
|
|
400
|
+
const model = this.parent!.model! as LibroJupyterModel;
|
|
401
|
+
await model.kcReady;
|
|
402
|
+
const connection = model.kernelConnection!;
|
|
403
|
+
const future = connection.requestExecute(content);
|
|
404
|
+
future.onIOPub = (msg) => {
|
|
405
|
+
ioCallback(msg);
|
|
406
|
+
};
|
|
407
|
+
return future.done as Promise<KernelMessage.IExecuteReplyMsg>;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
handleQueryResponse = (response: KernelMessage.IIOPubMessage) => {
|
|
411
|
+
const msgType = response.header.msg_type;
|
|
412
|
+
switch (msgType) {
|
|
413
|
+
case 'execute_result': {
|
|
414
|
+
const payload = response as KernelMessage.IExecuteResultMsg;
|
|
415
|
+
let content: string = payload.content.data['text/plain'] as string;
|
|
416
|
+
if (content.slice(0, 1) === "'" || content.slice(0, 1) === '"') {
|
|
417
|
+
content = content.slice(1, -1);
|
|
418
|
+
content = content.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const update = JSON.parse(content) as string[];
|
|
422
|
+
this.modelSelection = update.map((item) => {
|
|
423
|
+
return { value: item, label: item };
|
|
424
|
+
});
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
case 'stream': {
|
|
428
|
+
const payloadDisplay = response as KernelMessage.IStreamMsg;
|
|
429
|
+
let contentStream: string = payloadDisplay.content.text as string;
|
|
430
|
+
if (contentStream.slice(0, 1) === "'" || contentStream.slice(0, 1) === '"') {
|
|
431
|
+
contentStream = contentStream.slice(1, -1);
|
|
432
|
+
contentStream = contentStream.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const updateStream = JSON.parse(contentStream) as string[];
|
|
436
|
+
|
|
437
|
+
this.modelSelection = updateStream.map((item) => {
|
|
438
|
+
return { value: item, label: item };
|
|
439
|
+
});
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
default:
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IMimeBundle,
|
|
3
|
+
MultilineString,
|
|
4
|
+
PartialJSONObject,
|
|
5
|
+
} from '@difizen/libro-common';
|
|
6
|
+
import { concatMultilineString } from '@difizen/libro-common';
|
|
7
|
+
import type { BaseOutputView } from '@difizen/libro-jupyter';
|
|
8
|
+
import { NotebookCommands } from '@difizen/libro-jupyter';
|
|
9
|
+
import { CommandRegistry, useInject } from '@difizen/mana-app';
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { v4 } from 'uuid';
|
|
12
|
+
|
|
13
|
+
import { LibroLLMRenderMemo } from './libro-llm-render.js';
|
|
14
|
+
import { getPythonCode } from './prompt-cell-utils.js';
|
|
15
|
+
|
|
16
|
+
const getModelOutput = (data: PartialJSONObject | MultilineString) => {
|
|
17
|
+
if (typeof data === 'string' || Array.isArray(data)) {
|
|
18
|
+
return concatMultilineString(data);
|
|
19
|
+
} else {
|
|
20
|
+
return JSON.stringify(data);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const PromptOutputRender: React.FC<{
|
|
25
|
+
model: BaseOutputView;
|
|
26
|
+
}> = (props: { model: BaseOutputView }) => {
|
|
27
|
+
const { model } = props;
|
|
28
|
+
const renderHTMLRef = React.createRef<HTMLDivElement>();
|
|
29
|
+
const commandRegistry = useInject(CommandRegistry);
|
|
30
|
+
|
|
31
|
+
if (!model.data['application/vnd.libro.prompt+json']) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { data } = model.data['application/vnd.libro.prompt+json'] as IMimeBundle;
|
|
36
|
+
|
|
37
|
+
if (!data) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const modelData = getModelOutput(data);
|
|
41
|
+
const sourceArr = getPythonCode(modelData ?? '');
|
|
42
|
+
const handleOutput = async () => {
|
|
43
|
+
const libro = model.cell.parent;
|
|
44
|
+
const insertIndex = libro.model.cells.findIndex((c) => c.id === model.cell.id);
|
|
45
|
+
|
|
46
|
+
await Promise.all(
|
|
47
|
+
sourceArr.map(async (value, index) => {
|
|
48
|
+
const newView = await libro.addCell(
|
|
49
|
+
{
|
|
50
|
+
id: v4(),
|
|
51
|
+
cell: { cell_type: 'code', source: value, metadata: {} },
|
|
52
|
+
},
|
|
53
|
+
insertIndex + index + 1,
|
|
54
|
+
);
|
|
55
|
+
return newView;
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
await Promise.all(
|
|
60
|
+
sourceArr.map(async (_, index) => {
|
|
61
|
+
await commandRegistry.executeCommand(
|
|
62
|
+
NotebookCommands['RunCell'].id,
|
|
63
|
+
libro.model.cells[insertIndex + index + 1],
|
|
64
|
+
libro,
|
|
65
|
+
);
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
return (
|
|
70
|
+
<div className="libro-prompt-output-render-container">
|
|
71
|
+
<div className="prompt-output-render" ref={renderHTMLRef}>
|
|
72
|
+
<div className="libro-prompt-output-llm-render">
|
|
73
|
+
<LibroLLMRenderMemo data={modelData} />
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{sourceArr.length > 0 && (
|
|
77
|
+
<span onClick={handleOutput} className="libro-prompt-output-btn">
|
|
78
|
+
插入并运行
|
|
79
|
+
</span>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BaseOutputView } from '@difizen/libro-jupyter';
|
|
2
|
+
import { RenderMimeContribution } from '@difizen/libro-jupyter';
|
|
3
|
+
import { singleton } from '@difizen/mana-app';
|
|
4
|
+
|
|
5
|
+
import { PromptOutputRender } from './prompt-output-render.js';
|
|
6
|
+
|
|
7
|
+
@singleton({ contrib: RenderMimeContribution })
|
|
8
|
+
export class LibroPromptOutputMimeTypeContribution implements RenderMimeContribution {
|
|
9
|
+
canHandle = (model: BaseOutputView) => {
|
|
10
|
+
return 200;
|
|
11
|
+
};
|
|
12
|
+
renderType = 'promptOutputRender';
|
|
13
|
+
safe = true;
|
|
14
|
+
mimeTypes = ['application/vnd.libro.prompt+json'];
|
|
15
|
+
render = PromptOutputRender;
|
|
16
|
+
}
|