@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,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);
|
package/src/protocol.ts
ADDED
|
@@ -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
|
+
}
|