@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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/es/ai-native-code-block.d.ts +4 -0
  4. package/es/ai-native-code-block.d.ts.map +1 -0
  5. package/es/ai-native-code-block.js +176 -0
  6. package/es/ai-native-command-contribution.d.ts +16 -0
  7. package/es/ai-native-command-contribution.d.ts.map +1 -0
  8. package/es/ai-native-command-contribution.js +297 -0
  9. package/es/ai-native-command.d.ts +5 -0
  10. package/es/ai-native-command.d.ts.map +1 -0
  11. package/es/ai-native-command.js +17 -0
  12. package/es/ai-native-for-cell-view.d.ts +20 -0
  13. package/es/ai-native-for-cell-view.d.ts.map +1 -0
  14. package/es/ai-native-for-cell-view.js +190 -0
  15. package/es/ai-native-output-top.d.ts +6 -0
  16. package/es/ai-native-output-top.d.ts.map +1 -0
  17. package/es/ai-native-output-top.js +37 -0
  18. package/es/ai-native-service.d.ts +13 -0
  19. package/es/ai-native-service.d.ts.map +1 -0
  20. package/es/ai-native-service.js +75 -0
  21. package/es/ai-side-toolbar-selector.d.ts +3 -0
  22. package/es/ai-side-toolbar-selector.d.ts.map +1 -0
  23. package/es/ai-side-toolbar-selector.js +47 -0
  24. package/es/chat-slot-contribution.d.ts +15 -0
  25. package/es/chat-slot-contribution.d.ts.map +1 -0
  26. package/es/chat-slot-contribution.js +71 -0
  27. package/es/chat-view.d.ts +15 -0
  28. package/es/chat-view.d.ts.map +1 -0
  29. package/es/chat-view.js +114 -0
  30. package/es/error-output-model.d.ts +8 -0
  31. package/es/error-output-model.d.ts.map +1 -0
  32. package/es/error-output-model.js +140 -0
  33. package/es/icon.d.ts +4 -0
  34. package/es/icon.d.ts.map +1 -0
  35. package/es/icon.js +92 -0
  36. package/es/index.d.ts +6 -0
  37. package/es/index.d.ts.map +1 -0
  38. package/es/index.js +5 -0
  39. package/es/index.less +297 -0
  40. package/es/libro-ai-msg-item-model.d.ts +18 -0
  41. package/es/libro-ai-msg-item-model.d.ts.map +1 -0
  42. package/es/libro-ai-msg-item-model.js +85 -0
  43. package/es/libro-ai-native-chat-service.d.ts +8 -0
  44. package/es/libro-ai-native-chat-service.d.ts.map +1 -0
  45. package/es/libro-ai-native-chat-service.js +157 -0
  46. package/es/libro-ai-native-chat-view.d.ts +42 -0
  47. package/es/libro-ai-native-chat-view.d.ts.map +1 -0
  48. package/es/libro-ai-native-chat-view.js +88 -0
  49. package/es/libro-ai-native-color-registry.d.ts +6 -0
  50. package/es/libro-ai-native-color-registry.d.ts.map +1 -0
  51. package/es/libro-ai-native-color-registry.js +46 -0
  52. package/es/module.d.ts +3 -0
  53. package/es/module.d.ts.map +1 -0
  54. package/es/module.js +28 -0
  55. package/es/protocol.d.ts +10 -0
  56. package/es/protocol.d.ts.map +1 -0
  57. package/es/protocol.js +1 -0
  58. package/es/utils.js +114 -0
  59. package/package.json +74 -0
  60. package/src/ai-native-code-block.tsx +138 -0
  61. package/src/ai-native-command-contribution.tsx +248 -0
  62. package/src/ai-native-command.ts +23 -0
  63. package/src/ai-native-for-cell-view.tsx +156 -0
  64. package/src/ai-native-output-top.tsx +43 -0
  65. package/src/ai-native-service.ts +39 -0
  66. package/src/ai-side-toolbar-selector.tsx +51 -0
  67. package/src/chat-slot-contribution.ts +36 -0
  68. package/src/chat-view.tsx +141 -0
  69. package/src/error-output-model.tsx +103 -0
  70. package/src/icon.tsx +80 -0
  71. package/src/index.less +330 -0
  72. package/src/index.spec.ts +8 -0
  73. package/src/index.ts +5 -0
  74. package/src/libro-ai-msg-item-model.ts +69 -0
  75. package/src/libro-ai-native-chat-service.ts +95 -0
  76. package/src/libro-ai-native-chat-view.tsx +54 -0
  77. package/src/libro-ai-native-color-registry.ts +33 -0
  78. package/src/module.ts +44 -0
  79. package/src/protocol.ts +18 -0
  80. package/src/utils.tsx +115 -0
@@ -0,0 +1,69 @@
1
+ import { AnswerState, ChatEvent } from '@difizen/magent-chat';
2
+ import type {
3
+ IChatMessageSender,
4
+ ErrorMessage,
5
+ IChatEvent,
6
+ ChatEventChunk,
7
+ ChatEventError,
8
+ ChatEventResult,
9
+ IChatMessageItem,
10
+ } from '@difizen/magent-chat';
11
+ import { autoFactory, AutoFactoryOption } from '@difizen/magent-core';
12
+ import { inject, prop } from '@difizen/mana-app';
13
+
14
+ @autoFactory()
15
+ export class LibroAIChatMessageItemModel {
16
+ id?: string;
17
+ sender: IChatMessageSender;
18
+
19
+ @prop()
20
+ state: AnswerState;
21
+
22
+ @prop()
23
+ protected _content = '';
24
+ get content(): string {
25
+ return this._content;
26
+ }
27
+ set content(v) {
28
+ this._content = v;
29
+ }
30
+
31
+ option: IChatMessageItem;
32
+
33
+ @prop()
34
+ error?: ErrorMessage;
35
+
36
+ constructor(@inject(AutoFactoryOption) option: IChatMessageItem) {
37
+ if (option.content) {
38
+ this.state = AnswerState.SUCCESS;
39
+ } else {
40
+ this.state = AnswerState.WAITING;
41
+ }
42
+ }
43
+
44
+ handleEventData(e: IChatEvent) {
45
+ if (ChatEvent.isChunk(e)) {
46
+ this.appendChunk(e);
47
+ }
48
+ if (ChatEvent.isError(e)) {
49
+ this.handleError(e);
50
+ }
51
+ if (ChatEvent.isResult(e)) {
52
+ this.handleResult(e);
53
+ }
54
+ }
55
+
56
+ appendChunk(e: ChatEventChunk) {
57
+ this.content = `${this.content}${e.output}`;
58
+ }
59
+
60
+ handleResult(e: ChatEventResult) {
61
+ this.content = e.output;
62
+ this.state = AnswerState.SUCCESS;
63
+ }
64
+
65
+ handleError(e: ChatEventError) {
66
+ this.error = { message: e.message };
67
+ this.state = AnswerState.FAIL;
68
+ }
69
+ }
@@ -0,0 +1,95 @@
1
+ import type { IChatEvent, IChatMessageItem } from '@difizen/magent-chat';
2
+ import { ChatEvent } from '@difizen/magent-chat';
3
+ import { LibroChatService } from '@difizen/magent-libro';
4
+ import { singleton } from '@difizen/mana-app';
5
+ import { EventSourceParserStream } from 'eventsource-parser/stream';
6
+
7
+ import type { LibroAINativeChatMessageItemOption } from './protocol.js';
8
+ import { stringToReadableStream } from './utils.js';
9
+
10
+ @singleton()
11
+ export class LibroAINativeChatService extends LibroChatService {
12
+ override chat = async (
13
+ option: LibroAINativeChatMessageItemOption,
14
+ ): Promise<IChatMessageItem[]> => {
15
+ const { content, system_prompt } = option;
16
+ const res = await this.fetcher.post<any>(`/libro/api/chat`, {
17
+ prompt: content,
18
+ system_prompt,
19
+ });
20
+
21
+ if (res.status === 200) {
22
+ if (res.data.output) {
23
+ return [
24
+ {
25
+ sender: { type: 'AI', id: 'libro' },
26
+ content: res.data.output,
27
+ },
28
+ ];
29
+ }
30
+ }
31
+ return [];
32
+ };
33
+ override chatStream = async (
34
+ option: LibroAINativeChatMessageItemOption,
35
+ messgeCallback: (event: IChatMessageItem) => void,
36
+ eventCallback: (event: IChatEvent) => void,
37
+ ) => {
38
+ const { content, system_prompt } = option;
39
+
40
+ const url = `/libro/api/chatstream`;
41
+ const msg = {
42
+ prompt: content,
43
+ system_prompt,
44
+ };
45
+ const res = await this.fetcher.post<ReadableStream<Uint8Array>>(url, msg, {
46
+ headers: {
47
+ Accept: 'text/event-stream',
48
+ },
49
+ responseType: 'stream',
50
+ adapter: 'fetch',
51
+ });
52
+ if (res.status === 200) {
53
+ let reader;
54
+ if (typeof res.data === 'string') {
55
+ reader = stringToReadableStream(res.data)
56
+ .pipeThrough(new TextDecoderStream())
57
+ .pipeThrough(new EventSourceParserStream())
58
+ .getReader();
59
+ } else {
60
+ const stream = res.data;
61
+ reader = stream
62
+ .pipeThrough(new TextDecoderStream())
63
+ .pipeThrough(new EventSourceParserStream())
64
+ .getReader();
65
+ }
66
+
67
+ messgeCallback({
68
+ sender: { type: 'AI', id: 'libro' },
69
+ content: '',
70
+ });
71
+ let alreayDone = false;
72
+ try {
73
+ while (!alreayDone) {
74
+ const { value, done } = await reader.read();
75
+ if (done) {
76
+ alreayDone = true;
77
+ eventCallback({
78
+ type: 'done',
79
+ });
80
+
81
+ break;
82
+ }
83
+ const data = JSON.parse(value.data);
84
+ const event = ChatEvent.format(value.event || 'chunk', data);
85
+ eventCallback(event);
86
+ }
87
+ } catch {
88
+ eventCallback({
89
+ type: 'error',
90
+ });
91
+ }
92
+ return;
93
+ }
94
+ };
95
+ }
@@ -0,0 +1,54 @@
1
+ import type { CellView, LibroView } from '@difizen/libro-jupyter';
2
+ import { ChatView } from '@difizen/magent-chat';
3
+ import { inject, prop, transient, view, ViewOption } from '@difizen/mana-app';
4
+ import breaks from 'remark-breaks';
5
+ import remarkGfm from 'remark-gfm';
6
+
7
+ import { CodeBlockInChat } from './ai-native-code-block.js';
8
+ import './index.less';
9
+ import type { AiNativeChatViewOption } from './protocol.js';
10
+ import { ImageModal } from './utils.js';
11
+
12
+ const viewId = 'magent-chat';
13
+
14
+ @transient()
15
+ @view(viewId)
16
+ export class LibroAiNativeChatView extends ChatView {
17
+ @prop()
18
+ isCellChat = false;
19
+
20
+ libro?: LibroView;
21
+
22
+ cell?: CellView;
23
+
24
+ constructor(@inject(ViewOption) option: AiNativeChatViewOption) {
25
+ super(option);
26
+ this.option = option;
27
+ this.isCellChat = option.isCellChat;
28
+ }
29
+
30
+ override getMarkdownProps() {
31
+ return {
32
+ components: { code: CodeBlockInChat, img: ImageModal },
33
+ remarkPlugins: [remarkGfm, breaks],
34
+ };
35
+ }
36
+
37
+ protected override toMessageOption(msgContent: string) {
38
+ if (this.isCellChat) {
39
+ return {
40
+ stream: true,
41
+ ...this.option,
42
+ sender: { type: 'HUMAN' },
43
+ input: msgContent,
44
+ system_prompt: `有如下的代码作为对话的上下文:${this.cell?.model.value}`,
45
+ };
46
+ }
47
+ return {
48
+ stream: true,
49
+ ...this.option,
50
+ sender: { type: 'HUMAN' },
51
+ input: msgContent,
52
+ };
53
+ }
54
+ }
@@ -0,0 +1,33 @@
1
+ import type { ColorRegistry } from '@difizen/mana-app';
2
+ import { Color } from '@difizen/mana-app';
3
+ import { singleton, ColorContribution } from '@difizen/mana-app';
4
+
5
+ @singleton({ contrib: ColorContribution })
6
+ export class LibroAINativeColorRegistry implements ColorContribution {
7
+ registerColors(colors: ColorRegistry): void {
8
+ colors.register(
9
+ // #region antd variable
10
+ {
11
+ id: 'libro.ai.native.color',
12
+ defaults: { dark: '#bd74e8', light: '#bd74e8' },
13
+ description: '',
14
+ },
15
+ {
16
+ id: 'libro.ai.native.box.shadow',
17
+ defaults: {
18
+ dark: Color.rgba(203, 146, 197, 0.37),
19
+ light: Color.rgba(203, 146, 197, 0.37),
20
+ },
21
+ description: '',
22
+ },
23
+ {
24
+ id: 'libro.ai.native.btn.hover.color',
25
+ defaults: {
26
+ dark: Color.rgba(255, 255, 255, 0.2),
27
+ light: Color.rgba(0, 10, 26, 0.16),
28
+ },
29
+ description: '',
30
+ },
31
+ );
32
+ }
33
+ }
package/src/module.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { CellOutputTopProvider, ErrorOutputModel } from '@difizen/libro-jupyter';
2
+ import { ChatView } from '@difizen/magent-chat';
3
+ import { LibroChatModule, LibroChatService } from '@difizen/magent-libro';
4
+ import { ManaModule } from '@difizen/mana-app';
5
+
6
+ import { LibroAINativeCommandContribution } from './ai-native-command-contribution.js';
7
+ import { LibroAINativeForCellView } from './ai-native-for-cell-view.js';
8
+ import { LibroAINativeCellTopBlank } from './ai-native-output-top.js';
9
+ import { LibroAINativeService } from './ai-native-service.js';
10
+ import { LibroAIChatSlotContribution } from './chat-slot-contribution.js';
11
+ import { LibroChatView } from './chat-view.js';
12
+ import { AIErrorOutputModel } from './error-output-model.js';
13
+ import { LibroAIChatMessageItemModel } from './libro-ai-msg-item-model.js';
14
+ import { LibroAINativeChatService } from './libro-ai-native-chat-service.js';
15
+ import { LibroAiNativeChatView } from './libro-ai-native-chat-view.js';
16
+ import { LibroAINativeColorRegistry } from './libro-ai-native-color-registry.js';
17
+
18
+ export const LibroAINativeModule = ManaModule.create()
19
+ .register(
20
+ LibroAINativeColorRegistry,
21
+ LibroChatView,
22
+ LibroAIChatSlotContribution,
23
+ LibroAINativeCommandContribution,
24
+ LibroAINativeService,
25
+ LibroAIChatMessageItemModel,
26
+ LibroAINativeForCellView,
27
+ {
28
+ token: ErrorOutputModel,
29
+ useClass: AIErrorOutputModel,
30
+ },
31
+ {
32
+ token: ChatView,
33
+ useClass: LibroAiNativeChatView,
34
+ },
35
+ {
36
+ token: LibroChatService,
37
+ useClass: LibroAINativeChatService,
38
+ },
39
+ {
40
+ token: CellOutputTopProvider,
41
+ useValue: LibroAINativeCellTopBlank,
42
+ },
43
+ )
44
+ .dependOn(LibroChatModule);
@@ -0,0 +1,18 @@
1
+ import type { CellView } from '@difizen/libro-jupyter';
2
+ import type { ChatViewOption, IChatMessageItem } from '@difizen/magent-chat';
3
+
4
+ export interface IAINativeForCellViewOption {
5
+ cell: CellView;
6
+ [key: string]: any;
7
+ }
8
+
9
+ export interface LibroAINativeChatMessageItemOption extends IChatMessageItem {
10
+ chat_key?: string;
11
+ }
12
+
13
+ export interface AiNativeChatViewOption extends ChatViewOption {
14
+ id: string;
15
+ chat_key?: string;
16
+ isCellChat: boolean;
17
+ cell?: CellView;
18
+ }
package/src/utils.tsx ADDED
@@ -0,0 +1,115 @@
1
+ import type { CellView } from '@difizen/libro-jupyter';
2
+ import { Modal } from 'antd';
3
+ import { useEffect, useState } from 'react';
4
+ import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch';
5
+
6
+ export function stringToReadableStream(inputString: string) {
7
+ // Convert the string into a Uint8Array
8
+ const encoder = new TextEncoder();
9
+ const uint8Array = encoder.encode(inputString);
10
+
11
+ // Create a new ReadableStream
12
+ const readableStream = new ReadableStream({
13
+ start(controller) {
14
+ // Enqueue the Uint8Array into the stream
15
+ controller.enqueue(uint8Array);
16
+ // Close the stream
17
+ controller.close();
18
+ },
19
+ });
20
+
21
+ return readableStream;
22
+ }
23
+
24
+ export function addCellAIClassname(cell: CellView) {
25
+ if (cell.className?.includes('ai-cell-focus')) {
26
+ return;
27
+ } else {
28
+ cell.className = cell.className + ' ai-cell-focus';
29
+ }
30
+ }
31
+
32
+ export function cancelCellAIClassname(cell: CellView) {
33
+ if (cell.className?.includes(' ai-cell-focus')) {
34
+ cell.className = cell.className?.replace(' ai-cell-focus', '');
35
+ }
36
+ }
37
+
38
+ export function ImageModal({ src, alt }: any) {
39
+ const [visible, setVisible] = useState(false);
40
+ const [imageDimensions, setImageDimensions] = useState({
41
+ width: 0,
42
+ height: 0,
43
+ });
44
+
45
+ useEffect(() => {
46
+ const img = new Image();
47
+ img.src = src;
48
+ img.onload = () => {
49
+ setImageDimensions({
50
+ width: img.width,
51
+ height: img.height,
52
+ });
53
+ };
54
+ }, [src]);
55
+
56
+ const maxModalWidth = window.innerWidth * 0.8; // 80% of the viewport width
57
+ const maxModalHeight = window.innerHeight * 0.8; // 80% of the viewport height
58
+
59
+ let adjustedWidth, adjustedHeight;
60
+
61
+ const aspectRatio = imageDimensions.width / imageDimensions.height;
62
+
63
+ if (imageDimensions.width > maxModalWidth) {
64
+ adjustedWidth = maxModalWidth;
65
+ adjustedHeight = adjustedWidth / aspectRatio;
66
+ } else if (imageDimensions.height > maxModalHeight) {
67
+ adjustedHeight = maxModalHeight;
68
+ adjustedWidth = adjustedHeight * aspectRatio;
69
+ } else {
70
+ adjustedWidth = imageDimensions.width;
71
+ adjustedHeight = imageDimensions.height;
72
+ }
73
+
74
+ return (
75
+ <div>
76
+ <img
77
+ src={src}
78
+ alt={alt}
79
+ style={{ cursor: 'pointer' }}
80
+ onClick={() => setVisible(true)}
81
+ onLoad={() => {
82
+ // 解决生成图片没有滚动到最下方的问题。
83
+ document.getElementById('chat-main-scroll')?.scrollIntoView(false);
84
+ }}
85
+ />
86
+ <Modal
87
+ open={visible}
88
+ closeIcon={false}
89
+ footer={null}
90
+ width={adjustedWidth + 30}
91
+ onCancel={() => setVisible(false)}
92
+ bodyStyle={{
93
+ padding: 0,
94
+ display: 'flex',
95
+ justifyContent: 'center',
96
+ alignItems: 'center',
97
+ height: adjustedHeight,
98
+ }}
99
+ >
100
+ <TransformWrapper initialScale={1} initialPositionX={0} initialPositionY={0}>
101
+ <TransformComponent>
102
+ <img
103
+ src={src}
104
+ alt={alt}
105
+ style={{
106
+ width: '100%',
107
+ height: '100%',
108
+ }}
109
+ />
110
+ </TransformComponent>
111
+ </TransformWrapper>
112
+ </Modal>
113
+ </div>
114
+ );
115
+ }