feat(core): support ai insert image, mindmap, slides and make it real in page mode (#9164)
Support issue [BS-2085](https://linear.app/affine-design/issue/BS-2085). ### What changed? - Refactor the `actionToAnswerRenderer` function to support reuse in both page mode and edgeless mode. - Add a new `page-response.ts` module to handle AI-generated answers in page mode. - Remove the redundant `edgelessHandler` function from `_common/config.ts`. - Introduce the `AIContext` class along with the `ctx` TypeScript type to standardize context management. - Implement the `createTemplateJob` function to enable AI slide insertion in both page mode and edgeless mode. Insert mindmap on page mode: <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/30630d3e-ebd9-416b-9bb9-5f27086e48a3.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/30630d3e-ebd9-416b-9bb9-5f27086e48a3.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/30630d3e-ebd9-416b-9bb9-5f27086e48a3.mov">mindmap.mov</video> Insert image on edgeless note <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/b850ee5a-a06b-4ae7-8b68-ed5929a6e81a.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/b850ee5a-a06b-4ae7-8b68-ed5929a6e81a.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/b850ee5a-a06b-4ae7-8b68-ed5929a6e81a.mov">image3.mov</video> Insert image on page mode: <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/c4f98e2d-0b15-4310-b3e0-0725e330302b.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/c4f98e2d-0b15-4310-b3e0-0725e330302b.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/c4f98e2d-0b15-4310-b3e0-0725e330302b.mov">image.mov</video> Generate image from image: <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/2776a55f-cbb7-47ce-8e7d-7cae243fa3e9.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/2776a55f-cbb7-47ce-8e7d-7cae243fa3e9.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/2776a55f-cbb7-47ce-8e7d-7cae243fa3e9.mov">image2.mov</video> Insert presentation on page mode: <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/4e228fa5-88f4-478c-8b79-647612d5515c.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/4e228fa5-88f4-478c-8b79-647612d5515c.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/4e228fa5-88f4-478c-8b79-647612d5515c.mov">ppt.mov</video> Insert make it real on page mode: <div class='graphite__hidden'> <div>🎥 Video uploaded on Graphite:</div> <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/c71139b2-fb55-4d89-84e2-d52eeb905b57.mov"> <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/c71139b2-fb55-4d89-84e2-d52eeb905b57.mov"> </a> </div> <video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/c71139b2-fb55-4d89-84e2-d52eeb905b57.mov">make it real.mov</video>
This commit is contained in:
2
packages/common/env/package.json
vendored
2
packages/common/env/package.json
vendored
@@ -3,7 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"vitest": "2.1.8"
|
"vitest": "2.1.8"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"@affine/debug": "workspace:*",
|
"@affine/debug": "workspace:*",
|
||||||
"@affine/env": "workspace:*",
|
"@affine/env": "workspace:*",
|
||||||
"@affine/templates": "workspace:*",
|
"@affine/templates": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@datastructures-js/binary-search-tree": "^5.3.2",
|
"@datastructures-js/binary-search-tree": "^5.3.2",
|
||||||
"eventemitter2": "^6.4.9",
|
"eventemitter2": "^6.4.9",
|
||||||
"foxact": "^0.2.43",
|
"foxact": "^0.2.43",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"@affine/component": "workspace:*",
|
"@affine/component": "workspace:*",
|
||||||
"@affine/core": "workspace:*",
|
"@affine/core": "workspace:*",
|
||||||
"@affine/i18n": "workspace:*",
|
"@affine/i18n": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@blocksuite/icons": "2.1.75",
|
"@blocksuite/icons": "2.1.75",
|
||||||
"@capacitor/android": "^6.2.0",
|
"@capacitor/android": "^6.2.0",
|
||||||
"@capacitor/core": "^6.2.0",
|
"@capacitor/core": "^6.2.0",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"@affine/i18n": "workspace:*",
|
"@affine/i18n": "workspace:*",
|
||||||
"@affine/native": "workspace:*",
|
"@affine/native": "workspace:*",
|
||||||
"@affine/nbstore": "workspace:*",
|
"@affine/nbstore": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@electron-forge/cli": "^7.6.0",
|
"@electron-forge/cli": "^7.6.0",
|
||||||
"@electron-forge/core": "^7.6.0",
|
"@electron-forge/core": "^7.6.0",
|
||||||
"@electron-forge/core-utils": "^7.6.0",
|
"@electron-forge/core-utils": "^7.6.0",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"@affine/component": "workspace:*",
|
"@affine/component": "workspace:*",
|
||||||
"@affine/core": "workspace:*",
|
"@affine/core": "workspace:*",
|
||||||
"@affine/i18n": "workspace:*",
|
"@affine/i18n": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@blocksuite/icons": "2.1.75",
|
"@blocksuite/icons": "2.1.75",
|
||||||
"@capacitor/app": "^6.0.2",
|
"@capacitor/app": "^6.0.2",
|
||||||
"@capacitor/browser": "^6.0.4",
|
"@capacitor/browser": "^6.0.4",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"@affine/component": "workspace:*",
|
"@affine/component": "workspace:*",
|
||||||
"@affine/core": "workspace:*",
|
"@affine/core": "workspace:*",
|
||||||
"@affine/i18n": "workspace:*",
|
"@affine/i18n": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@blocksuite/icons": "2.1.75",
|
"@blocksuite/icons": "2.1.75",
|
||||||
"@sentry/react": "^8.44.0",
|
"@sentry/react": "^8.44.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
"zod": "^3.24.1"
|
"zod": "^3.24.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@blocksuite/icons": "2.1.75",
|
"@blocksuite/icons": "2.1.75",
|
||||||
"@chromatic-com/storybook": "^3.2.2",
|
"@chromatic-com/storybook": "^3.2.2",
|
||||||
"@storybook/addon-essentials": "^8.4.7",
|
"@storybook/addon-essentials": "^8.4.7",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"@affine/i18n": "workspace:*",
|
"@affine/i18n": "workspace:*",
|
||||||
"@affine/templates": "workspace:*",
|
"@affine/templates": "workspace:*",
|
||||||
"@affine/track": "workspace:*",
|
"@affine/track": "workspace:*",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@blocksuite/icons": "2.1.75",
|
"@blocksuite/icons": "2.1.75",
|
||||||
"@capacitor/app": "^6.0.2",
|
"@capacitor/app": "^6.0.2",
|
||||||
"@capacitor/browser": "^6.0.4",
|
"@capacitor/browser": "^6.0.4",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { flip, offset } from '@floating-ui/dom';
|
|||||||
import { css, html, LitElement } from 'lit';
|
import { css, html, LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
|
|
||||||
import { getAIPanel } from '../../ai-panel';
|
|
||||||
import { AIProvider } from '../../provider';
|
import { AIProvider } from '../../provider';
|
||||||
|
import { getAIPanelWidget } from '../../utils/ai-widgets';
|
||||||
import { extractContext } from '../../utils/extract';
|
import { extractContext } from '../../utils/extract';
|
||||||
|
|
||||||
export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
||||||
@@ -33,7 +33,7 @@ export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
|||||||
accessor actionGroups!: AIItemGroupConfig[];
|
accessor actionGroups!: AIItemGroupConfig[];
|
||||||
|
|
||||||
private readonly _onItemClick = () => {
|
private readonly _onItemClick = () => {
|
||||||
const aiPanel = getAIPanel(this.host);
|
const aiPanel = getAIPanelWidget(this.host);
|
||||||
aiPanel.restoreSelection();
|
aiPanel.restoreSelection();
|
||||||
this._clearAbortController();
|
this._clearAbortController();
|
||||||
};
|
};
|
||||||
@@ -45,7 +45,7 @@ export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
|||||||
|
|
||||||
private readonly _openAIPanel = () => {
|
private readonly _openAIPanel = () => {
|
||||||
this._clearAbortController();
|
this._clearAbortController();
|
||||||
const aiPanel = getAIPanel(this.host);
|
const aiPanel = getAIPanelWidget(this.host);
|
||||||
this._abortController = new AbortController();
|
this._abortController = new AbortController();
|
||||||
this._panelRoot = createLitPortal({
|
this._panelRoot = createLitPortal({
|
||||||
template: html`
|
template: html`
|
||||||
@@ -69,7 +69,7 @@ export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
|||||||
private readonly _generateAnswer: AffineAIPanelWidgetConfig['generateAnswer'] =
|
private readonly _generateAnswer: AffineAIPanelWidgetConfig['generateAnswer'] =
|
||||||
({ finish, input }) => {
|
({ finish, input }) => {
|
||||||
finish('success');
|
finish('success');
|
||||||
const aiPanel = getAIPanel(this.host);
|
const aiPanel = getAIPanelWidget(this.host);
|
||||||
aiPanel.discard();
|
aiPanel.discard();
|
||||||
AIProvider.slots.requestOpenWithChat.emit({ host: this.host });
|
AIProvider.slots.requestOpenWithChat.emit({ host: this.host });
|
||||||
extractContext(this.host)
|
extractContext(this.host)
|
||||||
@@ -80,7 +80,7 @@ export class AskAIToolbarButton extends WithDisposable(LitElement) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _onClick = () => {
|
private readonly _onClick = () => {
|
||||||
const aiPanel = getAIPanel(this.host);
|
const aiPanel = getAIPanelWidget(this.host);
|
||||||
if (!aiPanel.config) return;
|
if (!aiPanel.config) return;
|
||||||
aiPanel.config.generateAnswer = this._generateAnswer;
|
aiPanel.config.generateAnswer = this._generateAnswer;
|
||||||
aiPanel.config.inputCallback = text => {
|
aiPanel.config.inputCallback = text => {
|
||||||
|
|||||||
@@ -1,32 +1,19 @@
|
|||||||
import type {
|
import type { Chain, InitCommandCtx } from '@blocksuite/affine/block-std';
|
||||||
Chain,
|
|
||||||
EditorHost,
|
|
||||||
InitCommandCtx,
|
|
||||||
} from '@blocksuite/affine/block-std';
|
|
||||||
import {
|
import {
|
||||||
type AIItemGroupConfig,
|
type AIItemGroupConfig,
|
||||||
type AISubItemConfig,
|
type AISubItemConfig,
|
||||||
EDGELESS_ELEMENT_TOOLBAR_WIDGET,
|
|
||||||
type EdgelessElementToolbarWidget,
|
|
||||||
matchFlavours,
|
matchFlavours,
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import type { TemplateResult } from 'lit';
|
|
||||||
|
|
||||||
import { actionToHandler } from '../actions/doc-handler';
|
import { actionToHandler } from '../actions/doc-handler';
|
||||||
import { actionToHandler as edgelessActionToHandler } from '../actions/edgeless-handler';
|
|
||||||
import {
|
import {
|
||||||
imageFilterStyles,
|
imageFilterStyles,
|
||||||
imageProcessingTypes,
|
imageProcessingTypes,
|
||||||
textTones,
|
textTones,
|
||||||
translateLangs,
|
translateLangs,
|
||||||
} from '../actions/types';
|
} from '../actions/types';
|
||||||
import { getAIPanel } from '../ai-panel';
|
|
||||||
import { AIProvider } from '../provider';
|
import { AIProvider } from '../provider';
|
||||||
import {
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
getSelectedImagesAsBlobs,
|
|
||||||
getSelectedTextContent,
|
|
||||||
getSelections,
|
|
||||||
} from '../utils/selection-utils';
|
|
||||||
import {
|
import {
|
||||||
AIDoneIcon,
|
AIDoneIcon,
|
||||||
AIImageIcon,
|
AIImageIcon,
|
||||||
@@ -71,7 +58,7 @@ export function createImageFilterSubItem(
|
|||||||
return imageFilterStyles.map(style => {
|
return imageFilterStyles.map(style => {
|
||||||
return {
|
return {
|
||||||
type: style,
|
type: style,
|
||||||
handler: edgelessHandler(
|
handler: actionToHandler(
|
||||||
'filterImage',
|
'filterImage',
|
||||||
AIImageIconWithAnimation,
|
AIImageIconWithAnimation,
|
||||||
{
|
{
|
||||||
@@ -89,7 +76,7 @@ export function createImageProcessingSubItem(
|
|||||||
return imageProcessingTypes.map(type => {
|
return imageProcessingTypes.map(type => {
|
||||||
return {
|
return {
|
||||||
type,
|
type,
|
||||||
handler: edgelessHandler(
|
handler: actionToHandler(
|
||||||
'processImage',
|
'processImage',
|
||||||
AIImageIconWithAnimation,
|
AIImageIconWithAnimation,
|
||||||
{
|
{
|
||||||
@@ -224,59 +211,6 @@ const DraftAIGroup: AIItemGroupConfig = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
// actions that initiated from a note in edgeless mode
|
|
||||||
// 1. when running in doc mode, call requestRunInEdgeless (let affine to show toast)
|
|
||||||
// 2. when running in edgeless mode
|
|
||||||
// a. get selected in the note and let the edgeless action to handle it
|
|
||||||
// b. insert the result using the note shape
|
|
||||||
function edgelessHandler<T extends keyof BlockSuitePresets.AIActions>(
|
|
||||||
id: T,
|
|
||||||
generatingIcon: TemplateResult<1>,
|
|
||||||
variants?: Omit<
|
|
||||||
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
|
||||||
keyof BlockSuitePresets.AITextActionOptions
|
|
||||||
>,
|
|
||||||
trackerOptions?: BlockSuitePresets.TrackerOptions
|
|
||||||
) {
|
|
||||||
return (host: EditorHost) => {
|
|
||||||
if (host.doc.root?.id === undefined) return;
|
|
||||||
const edgeless = (
|
|
||||||
host.view.getWidget(
|
|
||||||
EDGELESS_ELEMENT_TOOLBAR_WIDGET,
|
|
||||||
host.doc.root.id
|
|
||||||
) as EdgelessElementToolbarWidget
|
|
||||||
)?.edgeless;
|
|
||||||
|
|
||||||
if (!edgeless) {
|
|
||||||
AIProvider.slots.requestRunInEdgeless.emit({ host });
|
|
||||||
} else {
|
|
||||||
const selectedElements = edgeless.service.selection.selectedElements;
|
|
||||||
if (!selectedElements.length) return;
|
|
||||||
|
|
||||||
return edgelessActionToHandler(
|
|
||||||
id,
|
|
||||||
generatingIcon,
|
|
||||||
variants,
|
|
||||||
async () => {
|
|
||||||
const selections = getSelections(host);
|
|
||||||
const [markdown, attachments] = await Promise.all([
|
|
||||||
getSelectedTextContent(host),
|
|
||||||
getSelectedImagesAsBlobs(host),
|
|
||||||
]);
|
|
||||||
// for now if there are more than one selected blocks, we will not omit the attachments
|
|
||||||
const sendAttachments =
|
|
||||||
selections?.selectedBlocks?.length === 1 && attachments.length > 0;
|
|
||||||
return {
|
|
||||||
attachments: sendAttachments ? attachments : undefined,
|
|
||||||
input: sendAttachments ? '' : markdown,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
trackerOptions
|
|
||||||
)(host);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReviewWIthAIGroup: AIItemGroupConfig = {
|
const ReviewWIthAIGroup: AIItemGroupConfig = {
|
||||||
name: 'review with ai',
|
name: 'review with ai',
|
||||||
items: [
|
items: [
|
||||||
@@ -353,7 +287,7 @@ const GenerateWithAIGroup: AIItemGroupConfig = {
|
|||||||
name: 'Generate an image',
|
name: 'Generate an image',
|
||||||
icon: AIImageIcon,
|
icon: AIImageIcon,
|
||||||
showWhen: textBlockShowWhen,
|
showWhen: textBlockShowWhen,
|
||||||
handler: edgelessHandler('createImage', AIImageIconWithAnimation),
|
handler: actionToHandler('createImage', AIImageIconWithAnimation),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Generate outline',
|
name: 'Generate outline',
|
||||||
@@ -365,13 +299,13 @@ const GenerateWithAIGroup: AIItemGroupConfig = {
|
|||||||
name: 'Brainstorm ideas with mind map',
|
name: 'Brainstorm ideas with mind map',
|
||||||
icon: AIMindMapIcon,
|
icon: AIMindMapIcon,
|
||||||
showWhen: textBlockShowWhen,
|
showWhen: textBlockShowWhen,
|
||||||
handler: edgelessHandler('brainstormMindmap', AIPenIconWithAnimation),
|
handler: actionToHandler('brainstormMindmap', AIPenIconWithAnimation),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Generate presentation',
|
name: 'Generate presentation',
|
||||||
icon: AIPresentationIcon,
|
icon: AIPresentationIcon,
|
||||||
showWhen: textBlockShowWhen,
|
showWhen: textBlockShowWhen,
|
||||||
handler: edgelessHandler('createSlides', AIPresentationIconWithAnimation),
|
handler: actionToHandler('createSlides', AIPresentationIconWithAnimation),
|
||||||
beta: true,
|
beta: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -379,7 +313,7 @@ const GenerateWithAIGroup: AIItemGroupConfig = {
|
|||||||
icon: MakeItRealIcon,
|
icon: MakeItRealIcon,
|
||||||
beta: true,
|
beta: true,
|
||||||
showWhen: textBlockShowWhen,
|
showWhen: textBlockShowWhen,
|
||||||
handler: edgelessHandler('makeItReal', MakeItRealIconWithAnimation),
|
handler: actionToHandler('makeItReal', MakeItRealIconWithAnimation),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Find actions',
|
name: 'Find actions',
|
||||||
@@ -398,7 +332,7 @@ const OthersAIGroup: AIItemGroupConfig = {
|
|||||||
name: 'Continue with AI',
|
name: 'Continue with AI',
|
||||||
icon: CommentIcon,
|
icon: CommentIcon,
|
||||||
handler: host => {
|
handler: host => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
AIProvider.slots.requestOpenWithChat.emit({
|
AIProvider.slots.requestOpenWithChat.emit({
|
||||||
host,
|
host,
|
||||||
autoSelect: true,
|
autoSelect: true,
|
||||||
@@ -411,7 +345,7 @@ const OthersAIGroup: AIItemGroupConfig = {
|
|||||||
name: 'Open AI Chat',
|
name: 'Open AI Chat',
|
||||||
icon: ChatWithAIIcon,
|
icon: ChatWithAIIcon,
|
||||||
handler: host => {
|
handler: host => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
AIProvider.slots.requestOpenWithChat.emit({
|
AIProvider.slots.requestOpenWithChat.emit({
|
||||||
host,
|
host,
|
||||||
appendCard: true,
|
appendCard: true,
|
||||||
@@ -422,7 +356,7 @@ const OthersAIGroup: AIItemGroupConfig = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AIItemGroups: AIItemGroupConfig[] = [
|
export const pageAIGroups: AIItemGroupConfig[] = [
|
||||||
ReviewWIthAIGroup,
|
ReviewWIthAIGroup,
|
||||||
EditAIGroup,
|
EditAIGroup,
|
||||||
GenerateWithAIGroup,
|
GenerateWithAIGroup,
|
||||||
@@ -455,7 +389,7 @@ export function buildAIImageItemGroups(): AIItemGroupConfig[] {
|
|||||||
name: 'Generate an image',
|
name: 'Generate an image',
|
||||||
icon: AIImageIcon,
|
icon: AIImageIcon,
|
||||||
showWhen: () => true,
|
showWhen: () => true,
|
||||||
handler: edgelessHandler(
|
handler: actionToHandler(
|
||||||
'createImage',
|
'createImage',
|
||||||
AIImageIconWithAnimation,
|
AIImageIconWithAnimation,
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||||
|
import type {
|
||||||
|
AffineAIPanelWidget,
|
||||||
|
MindmapElementModel,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
|
|
||||||
|
import { createTextRenderer } from '../../_common';
|
||||||
|
import {
|
||||||
|
createMindmapExecuteRenderer,
|
||||||
|
createMindmapRenderer,
|
||||||
|
} from '../messages/mindmap';
|
||||||
|
import { createSlidesRenderer } from '../messages/slides-renderer';
|
||||||
|
import { createIframeRenderer, createImageRenderer } from '../messages/wrapper';
|
||||||
|
import type { AIContext } from '../utils/context';
|
||||||
|
import { isMindmapChild, isMindMapRoot } from '../utils/edgeless';
|
||||||
|
import { IMAGE_ACTIONS } from './consts';
|
||||||
|
import { responseToExpandMindmap } from './edgeless-response';
|
||||||
|
|
||||||
|
type AnswerRenderer = NonNullable<
|
||||||
|
AffineAIPanelWidget['config']
|
||||||
|
>['answerRenderer'];
|
||||||
|
|
||||||
|
export function actionToAnswerRenderer<
|
||||||
|
T extends keyof BlockSuitePresets.AIActions,
|
||||||
|
>(id: T, host: EditorHost, ctx: AIContext): AnswerRenderer {
|
||||||
|
if (id === 'brainstormMindmap') {
|
||||||
|
const selectedElements = ctx.get().selectedElements;
|
||||||
|
if (
|
||||||
|
selectedElements &&
|
||||||
|
(isMindMapRoot(selectedElements[0]) ||
|
||||||
|
isMindmapChild(selectedElements[0]))
|
||||||
|
) {
|
||||||
|
const mindmap = selectedElements[0].group as MindmapElementModel;
|
||||||
|
|
||||||
|
return createMindmapRenderer(host, ctx, mindmap.style);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createMindmapRenderer(host, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === 'expandMindmap') {
|
||||||
|
return createMindmapExecuteRenderer(host, ctx, responseToExpandMindmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === 'createSlides') {
|
||||||
|
return createSlidesRenderer(host, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === 'makeItReal') {
|
||||||
|
return createIframeRenderer(host, { height: 300 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IMAGE_ACTIONS.includes(id)) {
|
||||||
|
return createImageRenderer(host, { height: 300 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return createTextRenderer(host, { maxHeight: 320 });
|
||||||
|
}
|
||||||
@@ -9,6 +9,16 @@ export const EXCLUDING_COPY_ACTIONS = [
|
|||||||
'processImage',
|
'processImage',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const EXCLUDING_REPLACE_ACTIONS = [
|
||||||
|
'brainstormMindmap',
|
||||||
|
'expandMindmap',
|
||||||
|
'makeItReal',
|
||||||
|
'createSlides',
|
||||||
|
'createImage',
|
||||||
|
'filterImage',
|
||||||
|
'processImage',
|
||||||
|
];
|
||||||
|
|
||||||
export const EXCLUDING_INSERT_ACTIONS = ['generateCaption'];
|
export const EXCLUDING_INSERT_ACTIONS = ['generateCaption'];
|
||||||
|
|
||||||
export const IMAGE_ACTIONS = ['createImage', 'processImage', 'filterImage'];
|
export const IMAGE_ACTIONS = ['createImage', 'processImage', 'filterImage'];
|
||||||
|
|||||||
@@ -7,22 +7,23 @@ import type {
|
|||||||
import { assertExists } from '@blocksuite/affine/global/utils';
|
import { assertExists } from '@blocksuite/affine/global/utils';
|
||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
|
|
||||||
import { createTextRenderer } from '../../_common';
|
|
||||||
import {
|
import {
|
||||||
buildCopyConfig,
|
buildCopyConfig,
|
||||||
buildErrorConfig,
|
buildErrorConfig,
|
||||||
buildFinishConfig,
|
buildFinishConfig,
|
||||||
buildGeneratingConfig,
|
buildGeneratingConfig,
|
||||||
getAIPanel,
|
|
||||||
} from '../ai-panel';
|
} from '../ai-panel';
|
||||||
import { AIProvider } from '../provider';
|
import { AIProvider } from '../provider';
|
||||||
import { reportResponse } from '../utils/action-reporter';
|
import { reportResponse } from '../utils/action-reporter';
|
||||||
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import { AIContext } from '../utils/context';
|
||||||
import {
|
import {
|
||||||
getSelectedImagesAsBlobs,
|
getSelectedImagesAsBlobs,
|
||||||
getSelectedTextContent,
|
getSelectedTextContent,
|
||||||
getSelections,
|
getSelections,
|
||||||
selectAboveBlocks,
|
selectAboveBlocks,
|
||||||
} from '../utils/selection-utils';
|
} from '../utils/selection-utils';
|
||||||
|
import { actionToAnswerRenderer } from './answer-renderer';
|
||||||
|
|
||||||
export function bindTextStream(
|
export function bindTextStream(
|
||||||
stream: BlockSuitePresets.TextStream,
|
stream: BlockSuitePresets.TextStream,
|
||||||
@@ -174,8 +175,10 @@ function updateAIPanelConfig<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
variants,
|
variants,
|
||||||
trackerOptions
|
trackerOptions
|
||||||
)(host);
|
)(host);
|
||||||
config.answerRenderer = createTextRenderer(host, { maxHeight: 320 });
|
|
||||||
config.finishStateConfig = buildFinishConfig(aiPanel, id);
|
const ctx = new AIContext();
|
||||||
|
config.answerRenderer = actionToAnswerRenderer(id, host, ctx);
|
||||||
|
config.finishStateConfig = buildFinishConfig(aiPanel, id, ctx);
|
||||||
config.generatingStateConfig = buildGeneratingConfig(generatingIcon);
|
config.generatingStateConfig = buildGeneratingConfig(generatingIcon);
|
||||||
config.errorStateConfig = buildErrorConfig(aiPanel);
|
config.errorStateConfig = buildErrorConfig(aiPanel);
|
||||||
config.copy = buildCopyConfig(aiPanel);
|
config.copy = buildCopyConfig(aiPanel);
|
||||||
@@ -194,7 +197,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
trackerOptions?: BlockSuitePresets.TrackerOptions
|
trackerOptions?: BlockSuitePresets.TrackerOptions
|
||||||
) {
|
) {
|
||||||
return (host: EditorHost) => {
|
return (host: EditorHost) => {
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
updateAIPanelConfig(aiPanel, id, generatingIcon, variants, trackerOptions);
|
updateAIPanelConfig(aiPanel, id, generatingIcon, variants, trackerOptions);
|
||||||
const { selectedBlocks: blocks } = getSelections(aiPanel.host);
|
const { selectedBlocks: blocks } = getSelections(aiPanel.host);
|
||||||
if (!blocks || blocks.length === 0) return;
|
if (!blocks || blocks.length === 0) return;
|
||||||
@@ -205,7 +208,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function handleInlineAskAIAction(host: EditorHost) {
|
export function handleInlineAskAIAction(host: EditorHost) {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const selection = host.selection.find('text');
|
const selection = host.selection.find('text');
|
||||||
const lastBlockPath = selection
|
const lastBlockPath = selection
|
||||||
? (selection.to?.blockId ?? selection.blockId)
|
? (selection.to?.blockId ?? selection.blockId)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import type {
|
|||||||
AffineAIPanelWidget,
|
AffineAIPanelWidget,
|
||||||
AIError,
|
AIError,
|
||||||
EdgelessCopilotWidget,
|
EdgelessCopilotWidget,
|
||||||
MindmapElementModel,
|
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import {
|
import {
|
||||||
BlocksUtils,
|
BlocksUtils,
|
||||||
@@ -20,16 +19,11 @@ import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
|||||||
import { AIChatBlockModel } from '@toeverything/infra';
|
import { AIChatBlockModel } from '@toeverything/infra';
|
||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
|
|
||||||
import { createTextRenderer, getContentFromSlice } from '../../_common';
|
import { getContentFromSlice } from '../../_common';
|
||||||
import { getAIPanel } from '../ai-panel';
|
|
||||||
import {
|
|
||||||
createMindmapExecuteRenderer,
|
|
||||||
createMindmapRenderer,
|
|
||||||
} from '../messages/mindmap';
|
|
||||||
import { createSlidesRenderer } from '../messages/slides-renderer';
|
|
||||||
import { createIframeRenderer, createImageRenderer } from '../messages/wrapper';
|
|
||||||
import { AIProvider } from '../provider';
|
import { AIProvider } from '../provider';
|
||||||
import { reportResponse } from '../utils/action-reporter';
|
import { reportResponse } from '../utils/action-reporter';
|
||||||
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import { AIContext } from '../utils/context';
|
||||||
import {
|
import {
|
||||||
getEdgelessCopilotWidget,
|
getEdgelessCopilotWidget,
|
||||||
isMindmapChild,
|
isMindmapChild,
|
||||||
@@ -41,63 +35,15 @@ import {
|
|||||||
getSelectedNoteAnchor,
|
getSelectedNoteAnchor,
|
||||||
getSelections,
|
getSelections,
|
||||||
} from '../utils/selection-utils';
|
} from '../utils/selection-utils';
|
||||||
import { EXCLUDING_COPY_ACTIONS, IMAGE_ACTIONS } from './consts';
|
import { actionToAnswerRenderer } from './answer-renderer';
|
||||||
|
import { EXCLUDING_COPY_ACTIONS } from './consts';
|
||||||
import { bindTextStream } from './doc-handler';
|
import { bindTextStream } from './doc-handler';
|
||||||
import {
|
import {
|
||||||
actionToErrorResponse,
|
actionToErrorResponse,
|
||||||
actionToGenerating,
|
actionToGenerating,
|
||||||
actionToResponse,
|
actionToResponse,
|
||||||
getElementToolbar,
|
getElementToolbar,
|
||||||
responses,
|
|
||||||
} from './edgeless-response';
|
} from './edgeless-response';
|
||||||
import type { CtxRecord } from './types';
|
|
||||||
|
|
||||||
type AnswerRenderer = NonNullable<
|
|
||||||
AffineAIPanelWidget['config']
|
|
||||||
>['answerRenderer'];
|
|
||||||
|
|
||||||
function actionToRenderer<T extends keyof BlockSuitePresets.AIActions>(
|
|
||||||
id: T,
|
|
||||||
host: EditorHost,
|
|
||||||
ctx: CtxRecord
|
|
||||||
): AnswerRenderer {
|
|
||||||
if (id === 'brainstormMindmap') {
|
|
||||||
const selectedElements = ctx.get()[
|
|
||||||
'selectedElements'
|
|
||||||
] as BlockSuite.EdgelessModel[];
|
|
||||||
|
|
||||||
if (
|
|
||||||
isMindMapRoot(selectedElements[0]) ||
|
|
||||||
isMindmapChild(selectedElements[0])
|
|
||||||
) {
|
|
||||||
const mindmap = selectedElements[0].group as MindmapElementModel;
|
|
||||||
|
|
||||||
return createMindmapRenderer(host, ctx, mindmap.style);
|
|
||||||
}
|
|
||||||
|
|
||||||
return createMindmapRenderer(host, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id === 'expandMindmap') {
|
|
||||||
return createMindmapExecuteRenderer(host, ctx, ctx => {
|
|
||||||
responses['expandMindmap']?.(host, ctx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id === 'createSlides') {
|
|
||||||
return createSlidesRenderer(host, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id === 'makeItReal') {
|
|
||||||
return createIframeRenderer(host, { height: 300 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IMAGE_ACTIONS.includes(id)) {
|
|
||||||
return createImageRenderer(host, { height: 300 });
|
|
||||||
}
|
|
||||||
|
|
||||||
return createTextRenderer(host, { maxHeight: 320 });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getContentFromEmbedSyncedDocModel(
|
async function getContentFromEmbedSyncedDocModel(
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
@@ -212,7 +158,7 @@ function actionToStream<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
>,
|
>,
|
||||||
extract?: (
|
extract?: (
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord
|
ctx: AIContext
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
content?: string;
|
content?: string;
|
||||||
attachments?: (string | Blob)[];
|
attachments?: (string | Blob)[];
|
||||||
@@ -226,7 +172,7 @@ function actionToStream<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
if (!action || typeof action !== 'function') return;
|
if (!action || typeof action !== 'function') return;
|
||||||
|
|
||||||
if (extract && typeof extract === 'function') {
|
if (extract && typeof extract === 'function') {
|
||||||
return (host: EditorHost, ctx: CtxRecord): BlockSuitePresets.TextStream => {
|
return (host: EditorHost, ctx: AIContext): BlockSuitePresets.TextStream => {
|
||||||
let stream: BlockSuitePresets.TextStream | undefined;
|
let stream: BlockSuitePresets.TextStream | undefined;
|
||||||
const control = trackerOptions?.control || 'format-bar';
|
const control = trackerOptions?.control || 'format-bar';
|
||||||
const where = trackerOptions?.where || 'ai-panel';
|
const where = trackerOptions?.where || 'ai-panel';
|
||||||
@@ -270,7 +216,7 @@ function actionToStream<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
let stream: BlockSuitePresets.TextStream | undefined;
|
let stream: BlockSuitePresets.TextStream | undefined;
|
||||||
return {
|
return {
|
||||||
async *[Symbol.asyncIterator]() {
|
async *[Symbol.asyncIterator]() {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const models = getCopilotSelectedElems(host);
|
const models = getCopilotSelectedElems(host);
|
||||||
const markdown = await getTextFromSelected(panel.host);
|
const markdown = await getTextFromSelected(panel.host);
|
||||||
|
|
||||||
@@ -304,7 +250,7 @@ function actionToGeneration<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
>,
|
>,
|
||||||
extract?: (
|
extract?: (
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord
|
ctx: AIContext
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
content?: string;
|
content?: string;
|
||||||
attachments?: (string | Blob)[];
|
attachments?: (string | Blob)[];
|
||||||
@@ -312,7 +258,7 @@ function actionToGeneration<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
} | void>,
|
} | void>,
|
||||||
trackerOptions?: BlockSuitePresets.TrackerOptions
|
trackerOptions?: BlockSuitePresets.TrackerOptions
|
||||||
) {
|
) {
|
||||||
return (host: EditorHost, ctx: CtxRecord) => {
|
return (host: EditorHost, ctx: AIContext) => {
|
||||||
return ({
|
return ({
|
||||||
input,
|
input,
|
||||||
signal,
|
signal,
|
||||||
@@ -352,14 +298,14 @@ function updateEdgelessAIPanelConfig<
|
|||||||
edgelessCopilot: EdgelessCopilotWidget,
|
edgelessCopilot: EdgelessCopilotWidget,
|
||||||
id: T,
|
id: T,
|
||||||
generatingIcon: TemplateResult<1>,
|
generatingIcon: TemplateResult<1>,
|
||||||
ctx: CtxRecord,
|
ctx: AIContext,
|
||||||
variants?: Omit<
|
variants?: Omit<
|
||||||
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
||||||
keyof BlockSuitePresets.AITextActionOptions
|
keyof BlockSuitePresets.AITextActionOptions
|
||||||
>,
|
>,
|
||||||
customInput?: (
|
customInput?: (
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord
|
ctx: AIContext
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
input?: string;
|
input?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
@@ -371,7 +317,7 @@ function updateEdgelessAIPanelConfig<
|
|||||||
const host = aiPanel.host;
|
const host = aiPanel.host;
|
||||||
const { config } = aiPanel;
|
const { config } = aiPanel;
|
||||||
assertExists(config);
|
assertExists(config);
|
||||||
config.answerRenderer = actionToRenderer(id, host, ctx);
|
config.answerRenderer = actionToAnswerRenderer(id, host, ctx);
|
||||||
config.generateAnswer = actionToGeneration(
|
config.generateAnswer = actionToGeneration(
|
||||||
id,
|
id,
|
||||||
variants,
|
variants,
|
||||||
@@ -420,7 +366,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
>,
|
>,
|
||||||
customInput?: (
|
customInput?: (
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord
|
ctx: AIContext
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
input?: string;
|
input?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
@@ -430,22 +376,11 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
trackerOptions?: BlockSuitePresets.TrackerOptions
|
trackerOptions?: BlockSuitePresets.TrackerOptions
|
||||||
) {
|
) {
|
||||||
return (host: EditorHost) => {
|
return (host: EditorHost) => {
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
||||||
let internal: Record<string, unknown> = {};
|
|
||||||
const selectedElements = getCopilotSelectedElems(host);
|
const selectedElements = getCopilotSelectedElems(host);
|
||||||
const { selectedBlocks } = getSelections(host);
|
const { selectedBlocks } = getSelections(host);
|
||||||
const ctx = {
|
const ctx = new AIContext({ selectedElements });
|
||||||
get() {
|
|
||||||
return {
|
|
||||||
...internal,
|
|
||||||
selectedElements,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
set(data: Record<string, unknown>) {
|
|
||||||
internal = data;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
edgelessCopilot.hideCopilotPanel();
|
edgelessCopilot.hideCopilotPanel();
|
||||||
edgelessCopilot.lockToolbar(true);
|
edgelessCopilot.lockToolbar(true);
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ import { styleMap } from 'lit/directives/style-map.js';
|
|||||||
|
|
||||||
import { insertFromMarkdown } from '../../_common';
|
import { insertFromMarkdown } from '../../_common';
|
||||||
import { AIPenIcon, ChatWithAIIcon } from '../_common/icons';
|
import { AIPenIcon, ChatWithAIIcon } from '../_common/icons';
|
||||||
import { getAIPanel } from '../ai-panel';
|
|
||||||
import { AIProvider } from '../provider';
|
import { AIProvider } from '../provider';
|
||||||
import { reportResponse } from '../utils/action-reporter';
|
import { reportResponse } from '../utils/action-reporter';
|
||||||
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import type { AIContext } from '../utils/context';
|
||||||
import {
|
import {
|
||||||
getEdgelessCopilotWidget,
|
getEdgelessCopilotWidget,
|
||||||
getService,
|
getService,
|
||||||
@@ -47,8 +48,8 @@ import {
|
|||||||
getEdgelessService,
|
getEdgelessService,
|
||||||
getSurfaceElementFromEditor,
|
getSurfaceElementFromEditor,
|
||||||
} from '../utils/selection-utils';
|
} from '../utils/selection-utils';
|
||||||
|
import { createTemplateJob } from '../utils/template-job';
|
||||||
import { EXCLUDING_INSERT_ACTIONS, generatingStages } from './consts';
|
import { EXCLUDING_INSERT_ACTIONS, generatingStages } from './consts';
|
||||||
import type { CtxRecord } from './types';
|
|
||||||
|
|
||||||
type FinishConfig = Exclude<
|
type FinishConfig = Exclude<
|
||||||
AffineAIPanelWidget['config'],
|
AffineAIPanelWidget['config'],
|
||||||
@@ -106,14 +107,17 @@ export function retry(panel: AffineAIPanelWidget): AIItemConfig {
|
|||||||
const extraConditions: Record<string, (data: any) => boolean> = {
|
const extraConditions: Record<string, (data: any) => boolean> = {
|
||||||
createSlides: data => !!data.contents,
|
createSlides: data => !!data.contents,
|
||||||
};
|
};
|
||||||
export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
export function createInsertItems<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
id: T,
|
id: T,
|
||||||
handler: (host: EditorHost, ctx: CtxRecord) => void,
|
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord,
|
ctx: AIContext,
|
||||||
buttonText: string = 'Insert below'
|
variants?: Omit<
|
||||||
|
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
||||||
|
keyof BlockSuitePresets.AITextActionOptions
|
||||||
|
>
|
||||||
): AIItemConfig[] {
|
): AIItemConfig[] {
|
||||||
const extraCondition = extraConditions[id] || ((_: any) => true);
|
const extraCondition = extraConditions[id] || ((_: any) => true);
|
||||||
|
const buttonText = getButtonText[id]?.(variants) ?? 'Insert below';
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: `${buttonText} - Loading...`,
|
name: `${buttonText} - Loading...`,
|
||||||
@@ -121,7 +125,7 @@ export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
${LightLoadingIcon}
|
${LightLoadingIcon}
|
||||||
</div>`,
|
</div>`,
|
||||||
showWhen: () => {
|
showWhen: () => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const data = ctx.get();
|
const data = ctx.get();
|
||||||
return (
|
return (
|
||||||
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
||||||
@@ -135,7 +139,7 @@ export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
name: buttonText,
|
name: buttonText,
|
||||||
icon: InsertBelowIcon,
|
icon: InsertBelowIcon,
|
||||||
showWhen: () => {
|
showWhen: () => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const data = ctx.get();
|
const data = ctx.get();
|
||||||
return (
|
return (
|
||||||
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
||||||
@@ -146,14 +150,41 @@ export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
},
|
},
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:insert');
|
reportResponse('result:insert');
|
||||||
handler(host, ctx);
|
edgelessResponseHandler(id, host, ctx).catch(console.error);
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.hide();
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function edgelessResponseHandler<
|
||||||
|
T extends keyof BlockSuitePresets.AIActions,
|
||||||
|
>(id: T, host: EditorHost, ctx: AIContext) {
|
||||||
|
switch (id) {
|
||||||
|
case 'expandMindmap':
|
||||||
|
responseToExpandMindmap(host, ctx);
|
||||||
|
break;
|
||||||
|
case 'brainstormMindmap':
|
||||||
|
responseToBrainstormMindmap(host, ctx);
|
||||||
|
break;
|
||||||
|
case 'makeItReal':
|
||||||
|
responseToMakeItReal(host, ctx);
|
||||||
|
break;
|
||||||
|
case 'createSlides':
|
||||||
|
await responseToCreateSlides(host, ctx);
|
||||||
|
break;
|
||||||
|
case 'createImage':
|
||||||
|
case 'filterImage':
|
||||||
|
case 'processImage':
|
||||||
|
responseToCreateImage(host);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
defaultHandler(host);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
id: T,
|
id: T,
|
||||||
host: EditorHost
|
host: EditorHost
|
||||||
@@ -162,12 +193,12 @@ export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
name: 'Use as caption',
|
name: 'Use as caption',
|
||||||
icon: AIPenIcon,
|
icon: AIPenIcon,
|
||||||
showWhen: () => {
|
showWhen: () => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
return id === 'generateCaption' && !!panel.answer;
|
return id === 'generateCaption' && !!panel.answer;
|
||||||
},
|
},
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:use-as-caption');
|
reportResponse('result:use-as-caption');
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const caption = panel.answer;
|
const caption = panel.answer;
|
||||||
if (!caption) return;
|
if (!caption) return;
|
||||||
|
|
||||||
@@ -183,11 +214,6 @@ export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type MindMapNode = {
|
|
||||||
text: string;
|
|
||||||
children: MindMapNode[];
|
|
||||||
};
|
|
||||||
|
|
||||||
function insertBelow(
|
function insertBelow(
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
markdown: string,
|
markdown: string,
|
||||||
@@ -256,7 +282,7 @@ function createBlockAndInsert(
|
|||||||
* @param host EditorHost
|
* @param host EditorHost
|
||||||
*/
|
*/
|
||||||
const defaultHandler = (host: EditorHost) => {
|
const defaultHandler = (host: EditorHost) => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const selectedElements = getCopilotSelectedElems(host);
|
const selectedElements = getCopilotSelectedElems(host);
|
||||||
|
|
||||||
assertExists(panel.answer);
|
assertExists(panel.answer);
|
||||||
@@ -282,8 +308,8 @@ const defaultHandler = (host: EditorHost) => {
|
|||||||
* Should make the inserting image size same with the input image if there is an input image.
|
* Should make the inserting image size same with the input image if there is an input image.
|
||||||
* @param host
|
* @param host
|
||||||
*/
|
*/
|
||||||
const imageHandler = (host: EditorHost) => {
|
function responseToCreateImage(host: EditorHost) {
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
// `DataURL` or `URL`
|
// `DataURL` or `URL`
|
||||||
const data = aiPanel.answer;
|
const data = aiPanel.answer;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
@@ -334,36 +360,25 @@ const imageHandler = (host: EditorHost) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
};
|
}
|
||||||
|
|
||||||
export const responses: {
|
export function responseToExpandMindmap(host: EditorHost, ctx: AIContext) {
|
||||||
[key in keyof Partial<BlockSuitePresets.AIActions>]: (
|
|
||||||
host: EditorHost,
|
|
||||||
ctx: CtxRecord
|
|
||||||
) => void;
|
|
||||||
} = {
|
|
||||||
expandMindmap: (host, ctx) => {
|
|
||||||
const [surface] = host.doc.getBlockByFlavour(
|
const [surface] = host.doc.getBlockByFlavour(
|
||||||
'affine:surface'
|
'affine:surface'
|
||||||
) as SurfaceBlockModel[];
|
) as SurfaceBlockModel[];
|
||||||
|
|
||||||
const elements = ctx.get()[
|
const elements = ctx.get().selectedElements;
|
||||||
'selectedElements'
|
const mindmapNode = ctx.get().node;
|
||||||
] as BlockSuite.EdgelessModel[];
|
|
||||||
const data = ctx.get() as {
|
|
||||||
node: MindMapNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
getAIPanel(host).hide();
|
getAIPanelWidget(host).hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!mindmapNode || !elements) return;
|
||||||
|
|
||||||
const mindmap = elements[0].group as MindmapElementModel;
|
const mindmap = elements[0].group as MindmapElementModel;
|
||||||
|
if (mindmapNode.children) {
|
||||||
if (!data?.node) return;
|
mindmapNode.children.forEach(childTree => {
|
||||||
|
|
||||||
if (data.node.children) {
|
|
||||||
data.node.children.forEach(childTree => {
|
|
||||||
MindmapUtils.addTree(mindmap, elements[0].id, childTree);
|
MindmapUtils.addTree(mindmap, elements[0].id, childTree);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -392,33 +407,28 @@ export const responses: {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
brainstormMindmap: (host, ctx) => {
|
|
||||||
const aiPanel = getAIPanel(host);
|
function responseToBrainstormMindmap(host: EditorHost, ctx: AIContext) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
const edgelessService = getEdgelessService(host);
|
const edgelessService = getEdgelessService(host);
|
||||||
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
const edgelessCopilot = getEdgelessCopilotWidget(host);
|
||||||
const selectionRect = edgelessCopilot.selectionModelRect;
|
const selectionRect = edgelessCopilot.selectionModelRect;
|
||||||
const [surface] = host.doc.getBlockByFlavour(
|
const [surface] = host.doc.getBlockByFlavour(
|
||||||
'affine:surface'
|
'affine:surface'
|
||||||
) as SurfaceBlockModel[];
|
) as SurfaceBlockModel[];
|
||||||
const elements = ctx.get()[
|
|
||||||
'selectedElements'
|
|
||||||
] as BlockSuite.EdgelessModel[];
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const data = ctx.get() as any;
|
|
||||||
let newGenerated = true;
|
|
||||||
|
|
||||||
|
const { node, style, selectedElements } = ctx.get();
|
||||||
|
if (!node) return;
|
||||||
|
const elements = selectedElements;
|
||||||
// This means regenerate
|
// This means regenerate
|
||||||
if (isMindMapRoot(elements[0])) {
|
if (elements && isMindMapRoot(elements[0])) {
|
||||||
const mindmap = elements[0].group as MindmapElementModel;
|
const mindmap = elements[0].group as MindmapElementModel;
|
||||||
const xywh = mindmap.tree.element.xywh;
|
const xywh = mindmap.tree.element.xywh;
|
||||||
|
|
||||||
surface.deleteElement(mindmap.id);
|
surface.deleteElement(mindmap.id);
|
||||||
|
node.xywh = xywh;
|
||||||
if (data.node) {
|
} else {
|
||||||
data.node.xywh = xywh;
|
node.xywh = `[${selectionRect.x + selectionRect.width + 100},${selectionRect.y},0,0]`;
|
||||||
newGenerated = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edgelessCopilot.hideCopilotPanel();
|
edgelessCopilot.hideCopilotPanel();
|
||||||
@@ -426,8 +436,8 @@ export const responses: {
|
|||||||
|
|
||||||
const mindmapId = surface.addElement({
|
const mindmapId = surface.addElement({
|
||||||
type: 'mindmap',
|
type: 'mindmap',
|
||||||
children: data.node,
|
children: node,
|
||||||
style: data.style,
|
style: style,
|
||||||
});
|
});
|
||||||
const mindmap = surface.getElementById(mindmapId) as MindmapElementModel;
|
const mindmap = surface.getElementById(mindmapId) as MindmapElementModel;
|
||||||
|
|
||||||
@@ -446,17 +456,6 @@ export const responses: {
|
|||||||
type: 'mindmap',
|
type: 'mindmap',
|
||||||
});
|
});
|
||||||
|
|
||||||
queueMicrotask(() => {
|
|
||||||
if (newGenerated && selectionRect) {
|
|
||||||
mindmap.moveTo([
|
|
||||||
selectionRect.x,
|
|
||||||
selectionRect.y,
|
|
||||||
selectionRect.width,
|
|
||||||
selectionRect.height,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is a workaround to make sure mindmap and other microtask are done
|
// This is a workaround to make sure mindmap and other microtask are done
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
edgelessService.viewport.setViewportByBound(
|
edgelessService.viewport.setViewportByBound(
|
||||||
@@ -470,9 +469,10 @@ export const responses: {
|
|||||||
editing: false,
|
editing: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
makeItReal: (host, ctx) => {
|
|
||||||
const aiPanel = getAIPanel(host);
|
function responseToMakeItReal(host: EditorHost, ctx: AIContext) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
let html = aiPanel.answer;
|
let html = aiPanel.answer;
|
||||||
if (!html) return;
|
if (!html) return;
|
||||||
html = preprocessHtml(html);
|
html = preprocessHtml(html);
|
||||||
@@ -484,8 +484,8 @@ export const responses: {
|
|||||||
|
|
||||||
const data = ctx.get();
|
const data = ctx.get();
|
||||||
const bounds = edgelessCopilot.determineInsertionBounds(
|
const bounds = edgelessCopilot.determineInsertionBounds(
|
||||||
(data['width'] as number) || 800,
|
data.width || 800,
|
||||||
(data['height'] as number) || 600
|
data.height || 600
|
||||||
);
|
);
|
||||||
|
|
||||||
edgelessCopilot.hideCopilotPanel();
|
edgelessCopilot.hideCopilotPanel();
|
||||||
@@ -504,36 +504,37 @@ export const responses: {
|
|||||||
surface.id
|
surface.id
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
createSlides: (host, ctx) => {
|
|
||||||
|
async function responseToCreateSlides(host: EditorHost, ctx: AIContext) {
|
||||||
const data = ctx.get();
|
const data = ctx.get();
|
||||||
const contents = data.contents as unknown[];
|
const { contents = [], images = [] } = data;
|
||||||
if (!contents) return;
|
if (contents.length === 0) return;
|
||||||
const images = data.images as { url: string; id: string }[][];
|
|
||||||
const service = host.std.getService<EdgelessRootService>('affine:page');
|
const service = host.std.getService<EdgelessRootService>('affine:page');
|
||||||
if (!service) return;
|
if (!service) return;
|
||||||
|
|
||||||
(async function () {
|
try {
|
||||||
for (let i = 0; i < contents.length - 1; i++) {
|
for (let i = 0; i < contents.length; i++) {
|
||||||
const image = images[i];
|
const image = images[i] || [];
|
||||||
const content = contents[i];
|
const content = contents[i];
|
||||||
const job = service.createTemplateJob('template');
|
const job = createTemplateJob(host);
|
||||||
await Promise.all(
|
|
||||||
image.map(({ id, url }) =>
|
const imagePromises = image.map(async ({ id, url }) => {
|
||||||
fetch(url)
|
const response = await fetch(url);
|
||||||
.then(res => res.blob())
|
const blob = await response.blob();
|
||||||
.then(blob => job.job.assets.set(id, blob))
|
job.job.assets.set(id, blob);
|
||||||
)
|
});
|
||||||
);
|
|
||||||
|
await Promise.all(imagePromises);
|
||||||
await job.insertTemplate(content);
|
await job.insertTemplate(content);
|
||||||
getSurfaceElementFromEditor(host).refresh();
|
|
||||||
}
|
}
|
||||||
})().catch(console.error);
|
|
||||||
},
|
getSurfaceElementFromEditor(host).refresh();
|
||||||
createImage: imageHandler,
|
} catch (error) {
|
||||||
processImage: imageHandler,
|
console.error('Error creating slides:', error);
|
||||||
filterImage: imageHandler,
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const getButtonText: {
|
const getButtonText: {
|
||||||
[key in keyof Partial<BlockSuitePresets.AIActions>]: (
|
[key in keyof Partial<BlockSuitePresets.AIActions>]: (
|
||||||
@@ -548,27 +549,10 @@ const getButtonText: {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getInsertAndReplaceHandler<
|
|
||||||
T extends keyof BlockSuitePresets.AIActions,
|
|
||||||
>(
|
|
||||||
id: T,
|
|
||||||
host: EditorHost,
|
|
||||||
ctx: CtxRecord,
|
|
||||||
variants?: Omit<
|
|
||||||
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
|
||||||
keyof BlockSuitePresets.AITextActionOptions
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const handler = responses[id] ?? defaultHandler;
|
|
||||||
const buttonText = getButtonText[id]?.(variants) ?? undefined;
|
|
||||||
|
|
||||||
return createInsertResp(id, handler, host, ctx, buttonText);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function actionToResponse<T extends keyof BlockSuitePresets.AIActions>(
|
export function actionToResponse<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
id: T,
|
id: T,
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord,
|
ctx: AIContext,
|
||||||
variants?: Omit<
|
variants?: Omit<
|
||||||
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
||||||
keyof BlockSuitePresets.AITextActionOptions
|
keyof BlockSuitePresets.AITextActionOptions
|
||||||
@@ -584,7 +568,7 @@ export function actionToResponse<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
icon: ChatWithAIIcon,
|
icon: ChatWithAIIcon,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:continue-in-chat');
|
reportResponse('result:continue-in-chat');
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
AIProvider.slots.requestOpenWithChat.emit({
|
AIProvider.slots.requestOpenWithChat.emit({
|
||||||
host,
|
host,
|
||||||
appendCard: true,
|
appendCard: true,
|
||||||
@@ -592,10 +576,10 @@ export function actionToResponse<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
panel.hide();
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...getInsertAndReplaceHandler(id, host, ctx, variants),
|
...createInsertItems(id, host, ctx, variants),
|
||||||
asCaption(id, host),
|
asCaption(id, host),
|
||||||
retry(getAIPanel(host)),
|
retry(getAIPanelWidget(host)),
|
||||||
discard(getAIPanel(host), getEdgelessCopilotWidget(host)),
|
discard(getAIPanelWidget(host), getEdgelessCopilotWidget(host)),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -619,7 +603,7 @@ export function actionToErrorResponse<
|
|||||||
panel: AffineAIPanelWidget,
|
panel: AffineAIPanelWidget,
|
||||||
id: T,
|
id: T,
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord,
|
ctx: AIContext,
|
||||||
variants?: Omit<
|
variants?: Omit<
|
||||||
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
Parameters<BlockSuitePresets.AIActions[T]>[0],
|
||||||
keyof BlockSuitePresets.AITextActionOptions
|
keyof BlockSuitePresets.AITextActionOptions
|
||||||
@@ -640,13 +624,13 @@ export function actionToErrorResponse<
|
|||||||
responses: [
|
responses: [
|
||||||
{
|
{
|
||||||
name: 'Response',
|
name: 'Response',
|
||||||
items: getInsertAndReplaceHandler(id, host, ctx, variants),
|
items: createInsertItems(id, host, ctx, variants),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
items: [
|
items: [
|
||||||
retry(getAIPanel(host)),
|
retry(getAIPanelWidget(host)),
|
||||||
discard(getAIPanel(host), getEdgelessCopilotWidget(host)),
|
discard(getAIPanelWidget(host), getEdgelessCopilotWidget(host)),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,309 @@
|
|||||||
|
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||||
|
import {
|
||||||
|
GfxBlockElementModel,
|
||||||
|
type GfxModel,
|
||||||
|
LayerManager,
|
||||||
|
} from '@blocksuite/affine/block-std/gfx';
|
||||||
|
import type {
|
||||||
|
MindmapElementModel,
|
||||||
|
ShapeElementModel,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
|
import {
|
||||||
|
fitContent,
|
||||||
|
getSurfaceBlock,
|
||||||
|
SurfaceBlockModel,
|
||||||
|
TelemetryProvider,
|
||||||
|
uploadBlobForImage,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
|
import { Bound, getCommonBound } from '@blocksuite/affine/global/utils';
|
||||||
|
import { type BlockProps, DocCollection, Text } from '@blocksuite/affine/store';
|
||||||
|
|
||||||
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import type { AffineNode, AIContext } from '../utils/context';
|
||||||
|
import { insertAbove, insertBelow, replace } from '../utils/editor-actions';
|
||||||
|
import { preprocessHtml } from '../utils/html';
|
||||||
|
import { fetchImageToFile } from '../utils/image';
|
||||||
|
import { getSelections } from '../utils/selection-utils';
|
||||||
|
import { createTemplateJob } from '../utils/template-job';
|
||||||
|
|
||||||
|
const PADDING = 100;
|
||||||
|
|
||||||
|
type Place = 'after' | 'before';
|
||||||
|
|
||||||
|
export async function pageResponseHandler<
|
||||||
|
T extends keyof BlockSuitePresets.AIActions,
|
||||||
|
>(id: T, host: EditorHost, ctx: AIContext, place: Place = 'after') {
|
||||||
|
switch (id) {
|
||||||
|
case 'brainstormMindmap':
|
||||||
|
responseToBrainstormMindmap(host, ctx, place);
|
||||||
|
break;
|
||||||
|
case 'makeItReal':
|
||||||
|
responseToMakeItReal(host, ctx, place);
|
||||||
|
break;
|
||||||
|
case 'createSlides':
|
||||||
|
await responseToCreateSlides(host, ctx, place);
|
||||||
|
break;
|
||||||
|
case 'createImage':
|
||||||
|
case 'filterImage':
|
||||||
|
case 'processImage':
|
||||||
|
responseToCreateImage(host, place);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await (place === 'after'
|
||||||
|
? insertMarkdownBelow(host)
|
||||||
|
: insertMarkdownAbove(host));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function responseToBrainstormMindmap(
|
||||||
|
host: EditorHost,
|
||||||
|
ctx: AIContext,
|
||||||
|
place: Place
|
||||||
|
) {
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
if (!surface) return;
|
||||||
|
|
||||||
|
host.doc.transact(() => {
|
||||||
|
const { node, style } = ctx.get();
|
||||||
|
if (!node) return;
|
||||||
|
const bound = getEdgelessContentBound(host);
|
||||||
|
if (bound) {
|
||||||
|
node.xywh = `[${bound.x + bound.w + PADDING * 2},${bound.y},0,0]`;
|
||||||
|
}
|
||||||
|
const mindmapId = surface.addElement({
|
||||||
|
type: 'mindmap',
|
||||||
|
children: node,
|
||||||
|
style: style,
|
||||||
|
});
|
||||||
|
const mindmap = surface.getElementById(mindmapId) as MindmapElementModel;
|
||||||
|
mindmap.childElements.forEach(shape => {
|
||||||
|
fitContent(shape as ShapeElementModel);
|
||||||
|
});
|
||||||
|
// wait for mindmap xywh update
|
||||||
|
setTimeout(() => {
|
||||||
|
const frameBound = expandBound(mindmap.elementBound, PADDING);
|
||||||
|
addSurfaceRefBlock(host, frameBound, place);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const telemetryService = host.std.getOptional(TelemetryProvider);
|
||||||
|
telemetryService?.track('CanvasElementAdded', {
|
||||||
|
control: 'ai',
|
||||||
|
page: 'doc editor',
|
||||||
|
module: 'toolbar',
|
||||||
|
segment: 'toolbar',
|
||||||
|
type: 'mindmap',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function responseToMakeItReal(host: EditorHost, ctx: AIContext, place: Place) {
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
|
if (!aiPanel.answer || !surface) return;
|
||||||
|
|
||||||
|
const { width, height } = ctx.get();
|
||||||
|
const bound = getEdgelessContentBound(host);
|
||||||
|
const x = bound ? bound.x + bound.w + PADDING * 2 : 0;
|
||||||
|
const y = bound ? bound.y : 0;
|
||||||
|
const htmlBound = new Bound(x, y, width || 800, height || 600);
|
||||||
|
const html = preprocessHtml(aiPanel.answer);
|
||||||
|
host.doc.transact(() => {
|
||||||
|
host.doc.addBlock(
|
||||||
|
'affine:embed-html',
|
||||||
|
{
|
||||||
|
html,
|
||||||
|
design: 'ai:makeItReal', // as tag
|
||||||
|
xywh: htmlBound.serialize(),
|
||||||
|
},
|
||||||
|
surface.id
|
||||||
|
);
|
||||||
|
const frameBound = expandBound(htmlBound, PADDING);
|
||||||
|
addSurfaceRefBlock(host, frameBound, place);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function responseToCreateSlides(
|
||||||
|
host: EditorHost,
|
||||||
|
ctx: AIContext,
|
||||||
|
place: Place
|
||||||
|
) {
|
||||||
|
const { contents, images = [] } = ctx.get();
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
if (!contents || !surface) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const frameIds: string[] = [];
|
||||||
|
for (let i = 0; i < contents.length; i++) {
|
||||||
|
const image = images[i];
|
||||||
|
const content = contents[i];
|
||||||
|
const job = createTemplateJob(host);
|
||||||
|
await Promise.all(
|
||||||
|
image.map(({ id, url }) =>
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.blob())
|
||||||
|
.then(blob => job.job.assets.set(id, blob))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await job.insertTemplate(content);
|
||||||
|
const frame = findFrameObject(content.blocks);
|
||||||
|
frame && frameIds.push(frame.id);
|
||||||
|
}
|
||||||
|
const props = frameIds.map(id => ({
|
||||||
|
flavour: 'affine:surface-ref',
|
||||||
|
refFlavour: 'affine:frame',
|
||||||
|
reference: id,
|
||||||
|
}));
|
||||||
|
addSiblingBlocks(host, props, place);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating slides:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function responseToCreateImage(host: EditorHost, place: Place) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
|
const { answer } = aiPanel;
|
||||||
|
if (!answer) return;
|
||||||
|
const filename = 'image';
|
||||||
|
const imageProxy = host.std.clipboard.configs.get('imageProxy');
|
||||||
|
|
||||||
|
fetchImageToFile(answer, filename, imageProxy)
|
||||||
|
.then(file => {
|
||||||
|
if (!file) return;
|
||||||
|
host.doc.transact(() => {
|
||||||
|
const props = {
|
||||||
|
flavour: 'affine:image',
|
||||||
|
size: file.size,
|
||||||
|
};
|
||||||
|
const blockId = addSiblingBlocks(host, [props], place)?.[0];
|
||||||
|
blockId && uploadBlobForImage(host, blockId, file).catch(console.error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function replaceWithMarkdown(host: EditorHost) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
|
const { answer } = aiPanel;
|
||||||
|
const selection = getSelection(host);
|
||||||
|
if (!answer || !selection) return;
|
||||||
|
|
||||||
|
const { textSelection, firstBlock, selectedModels } = selection;
|
||||||
|
await replace(host, answer, firstBlock, selectedModels, textSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertMarkdownBelow(host: EditorHost) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
|
const { answer } = aiPanel;
|
||||||
|
const selection = getSelection(host);
|
||||||
|
if (!answer || !selection) return;
|
||||||
|
|
||||||
|
const { lastBlock } = selection;
|
||||||
|
await insertBelow(host, answer, lastBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertMarkdownAbove(host: EditorHost) {
|
||||||
|
const aiPanel = getAIPanelWidget(host);
|
||||||
|
const { answer } = aiPanel;
|
||||||
|
const selection = getSelection(host);
|
||||||
|
if (!answer || !selection) return;
|
||||||
|
|
||||||
|
const { firstBlock } = selection;
|
||||||
|
await insertAbove(host, answer, firstBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelection(host: EditorHost) {
|
||||||
|
const textSelection = host.selection.find('text');
|
||||||
|
const mode = textSelection ? 'flat' : 'highest';
|
||||||
|
const { selectedBlocks } = getSelections(host, mode);
|
||||||
|
if (!selectedBlocks) return;
|
||||||
|
const length = selectedBlocks.length;
|
||||||
|
const firstBlock = selectedBlocks[0];
|
||||||
|
const lastBlock = selectedBlocks[length - 1];
|
||||||
|
const selectedModels = selectedBlocks.map(block => block.model);
|
||||||
|
return {
|
||||||
|
textSelection,
|
||||||
|
selectedModels,
|
||||||
|
firstBlock,
|
||||||
|
lastBlock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEdgelessContentBound(host: EditorHost) {
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
if (!surface) return;
|
||||||
|
|
||||||
|
const elements = (
|
||||||
|
host.doc
|
||||||
|
.getBlocks()
|
||||||
|
.filter(
|
||||||
|
model =>
|
||||||
|
model instanceof GfxBlockElementModel &&
|
||||||
|
(model.parent instanceof SurfaceBlockModel ||
|
||||||
|
model.parent?.role === 'root')
|
||||||
|
) as GfxModel[]
|
||||||
|
).concat(surface.elementModels ?? []);
|
||||||
|
const bounds = elements.map(element => Bound.deserialize(element.xywh));
|
||||||
|
const bound = getCommonBound(bounds);
|
||||||
|
return bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandBound(bound: Bound, margin: number) {
|
||||||
|
const x = bound.x - margin;
|
||||||
|
const y = bound.y - margin;
|
||||||
|
const w = bound.w + margin * 2;
|
||||||
|
const h = bound.h + margin * 2;
|
||||||
|
return new Bound(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSurfaceRefBlock(host: EditorHost, bound: Bound, place: Place) {
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
if (!surface) return;
|
||||||
|
const frame = host.doc.addBlock(
|
||||||
|
'affine:frame',
|
||||||
|
{
|
||||||
|
title: new Text(new DocCollection.Y.Text('Frame')),
|
||||||
|
xywh: bound.serialize(),
|
||||||
|
index: LayerManager.INITIAL_INDEX,
|
||||||
|
},
|
||||||
|
surface
|
||||||
|
);
|
||||||
|
const props = {
|
||||||
|
flavour: 'affine:surface-ref',
|
||||||
|
refFlavour: 'affine:frame',
|
||||||
|
reference: frame,
|
||||||
|
};
|
||||||
|
return addSiblingBlocks(host, [props], place);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSiblingBlocks(
|
||||||
|
host: EditorHost,
|
||||||
|
props: Array<Partial<BlockProps>>,
|
||||||
|
place: Place
|
||||||
|
) {
|
||||||
|
const { selectedModels } = getSelection(host) || {};
|
||||||
|
if (!selectedModels) return;
|
||||||
|
const targetModel =
|
||||||
|
place === 'before'
|
||||||
|
? selectedModels[0]
|
||||||
|
: selectedModels[selectedModels.length - 1];
|
||||||
|
|
||||||
|
return host.doc.addSiblingBlocks(targetModel, props, place);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findFrameObject(obj: AffineNode): AffineNode | null {
|
||||||
|
if (obj.flavour === 'affine:frame') {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.children) {
|
||||||
|
for (const child of obj.children) {
|
||||||
|
const result = findFrameObject(child);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -36,11 +36,6 @@ export const imageProcessingTypes = [
|
|||||||
'Convert to sticker',
|
'Convert to sticker',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type CtxRecord = {
|
|
||||||
get(): Record<string, unknown>;
|
|
||||||
set(data: Record<string, unknown>): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
namespace BlockSuitePresets {
|
namespace BlockSuitePresets {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { EditorHost } from '@blocksuite/affine/block-std';
|
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||||
import {
|
import {
|
||||||
AFFINE_AI_PANEL_WIDGET,
|
type AffineAIPanelWidget,
|
||||||
AffineAIPanelWidget,
|
|
||||||
type AffineAIPanelWidgetConfig,
|
type AffineAIPanelWidgetConfig,
|
||||||
type AIItemConfig,
|
type AIItemConfig,
|
||||||
ImageBlockModel,
|
ImageBlockModel,
|
||||||
@@ -24,35 +23,22 @@ import {
|
|||||||
ReplaceIcon,
|
ReplaceIcon,
|
||||||
RetryIcon,
|
RetryIcon,
|
||||||
} from './_common/icons';
|
} from './_common/icons';
|
||||||
import { INSERT_ABOVE_ACTIONS } from './actions/consts';
|
import {
|
||||||
|
EXCLUDING_REPLACE_ACTIONS,
|
||||||
|
INSERT_ABOVE_ACTIONS,
|
||||||
|
} from './actions/consts';
|
||||||
|
import {
|
||||||
|
pageResponseHandler,
|
||||||
|
replaceWithMarkdown,
|
||||||
|
} from './actions/page-response';
|
||||||
import { AIProvider } from './provider';
|
import { AIProvider } from './provider';
|
||||||
import { reportResponse } from './utils/action-reporter';
|
import { reportResponse } from './utils/action-reporter';
|
||||||
|
import { getAIPanelWidget } from './utils/ai-widgets';
|
||||||
|
import { AIContext } from './utils/context';
|
||||||
import { findNoteBlockModel, getService } from './utils/edgeless';
|
import { findNoteBlockModel, getService } from './utils/edgeless';
|
||||||
import {
|
import { copyTextAnswer } from './utils/editor-actions';
|
||||||
copyTextAnswer,
|
|
||||||
insertAbove,
|
|
||||||
insertBelow,
|
|
||||||
replace,
|
|
||||||
} from './utils/editor-actions';
|
|
||||||
import { getSelections } from './utils/selection-utils';
|
import { getSelections } from './utils/selection-utils';
|
||||||
|
|
||||||
function getSelection(host: EditorHost) {
|
|
||||||
const textSelection = host.selection.find('text');
|
|
||||||
const mode = textSelection ? 'flat' : 'highest';
|
|
||||||
const { selectedBlocks } = getSelections(host, mode);
|
|
||||||
assertExists(selectedBlocks);
|
|
||||||
const length = selectedBlocks.length;
|
|
||||||
const firstBlock = selectedBlocks[0];
|
|
||||||
const lastBlock = selectedBlocks[length - 1];
|
|
||||||
const selectedModels = selectedBlocks.map(block => block.model);
|
|
||||||
return {
|
|
||||||
textSelection,
|
|
||||||
selectedModels,
|
|
||||||
firstBlock,
|
|
||||||
lastBlock,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
id?: T
|
id?: T
|
||||||
@@ -61,12 +47,12 @@ function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
name: 'Use as caption',
|
name: 'Use as caption',
|
||||||
icon: AIPenIcon,
|
icon: AIPenIcon,
|
||||||
showWhen: () => {
|
showWhen: () => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
return id === 'generateCaption' && !!panel.answer;
|
return id === 'generateCaption' && !!panel.answer;
|
||||||
},
|
},
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:use-as-caption');
|
reportResponse('result:use-as-caption');
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const caption = panel.answer;
|
const caption = panel.answer;
|
||||||
if (!caption) return;
|
if (!caption) return;
|
||||||
|
|
||||||
@@ -87,7 +73,7 @@ function createNewNote(host: EditorHost): AIItemConfig {
|
|||||||
name: 'Create new note',
|
name: 'Create new note',
|
||||||
icon: CreateIcon,
|
icon: CreateIcon,
|
||||||
showWhen: () => {
|
showWhen: () => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
return !!panel.answer && isInsideEdgelessEditor(host);
|
return !!panel.answer && isInsideEdgelessEditor(host);
|
||||||
},
|
},
|
||||||
handler: () => {
|
handler: () => {
|
||||||
@@ -103,7 +89,7 @@ function createNewNote(host: EditorHost): AIItemConfig {
|
|||||||
const bound = Bound.deserialize(noteModel.xywh);
|
const bound = Bound.deserialize(noteModel.xywh);
|
||||||
const newBound = new Bound(bound.x - bound.w - 20, bound.y, bound.w, 72);
|
const newBound = new Bound(bound.x - bound.w - 20, bound.y, bound.w, 72);
|
||||||
const doc = host.doc;
|
const doc = host.doc;
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
const service = getService(host);
|
const service = getService(host);
|
||||||
doc.transact(() => {
|
doc.transact(() => {
|
||||||
assertExists(doc.root);
|
assertExists(doc.root);
|
||||||
@@ -147,43 +133,11 @@ function createNewNote(host: EditorHost): AIItemConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function replaceWithAnswer(panel: AffineAIPanelWidget) {
|
function buildPageResponseConfig<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
const { host } = panel;
|
panel: AffineAIPanelWidget,
|
||||||
const selection = getSelection(host);
|
id: T,
|
||||||
if (!selection || !panel.answer) return;
|
ctx: AIContext
|
||||||
|
) {
|
||||||
const { textSelection, firstBlock, selectedModels } = selection;
|
|
||||||
await replace(host, panel.answer, firstBlock, selectedModels, textSelection);
|
|
||||||
|
|
||||||
panel.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function insertAnswerBelow(panel: AffineAIPanelWidget) {
|
|
||||||
const { host } = panel;
|
|
||||||
const selection = getSelection(host);
|
|
||||||
|
|
||||||
if (!selection || !panel.answer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { lastBlock } = selection;
|
|
||||||
await insertBelow(host, panel.answer, lastBlock);
|
|
||||||
panel.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function insertAnswerAbove(panel: AffineAIPanelWidget) {
|
|
||||||
const { host } = panel;
|
|
||||||
const selection = getSelection(host);
|
|
||||||
if (!selection || !panel.answer) return;
|
|
||||||
|
|
||||||
const { firstBlock } = selection;
|
|
||||||
await insertAbove(host, panel.answer, firstBlock);
|
|
||||||
panel.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildTextResponseConfig<
|
|
||||||
T extends keyof BlockSuitePresets.AIActions,
|
|
||||||
>(panel: AffineAIPanelWidget, id?: T) {
|
|
||||||
const host = panel.host;
|
const host = panel.host;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -197,7 +151,8 @@ export function buildTextResponseConfig<
|
|||||||
!!panel.answer && (!id || !INSERT_ABOVE_ACTIONS.includes(id)),
|
!!panel.answer && (!id || !INSERT_ABOVE_ACTIONS.includes(id)),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:insert');
|
reportResponse('result:insert');
|
||||||
insertAnswerBelow(panel).catch(console.error);
|
pageResponseHandler(id, host, ctx, 'after').catch(console.error);
|
||||||
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -207,17 +162,20 @@ export function buildTextResponseConfig<
|
|||||||
!!panel.answer && !!id && INSERT_ABOVE_ACTIONS.includes(id),
|
!!panel.answer && !!id && INSERT_ABOVE_ACTIONS.includes(id),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:insert');
|
reportResponse('result:insert');
|
||||||
insertAnswerAbove(panel).catch(console.error);
|
pageResponseHandler(id, host, ctx, 'before').catch(console.error);
|
||||||
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
asCaption(host, id),
|
asCaption(host, id),
|
||||||
{
|
{
|
||||||
name: 'Replace selection',
|
name: 'Replace selection',
|
||||||
icon: ReplaceIcon,
|
icon: ReplaceIcon,
|
||||||
showWhen: () => !!panel.answer,
|
showWhen: () =>
|
||||||
|
!!panel.answer && !EXCLUDING_REPLACE_ACTIONS.includes(id),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reportResponse('result:replace');
|
reportResponse('result:replace');
|
||||||
replaceWithAnswer(panel).catch(console.error);
|
replaceWithMarkdown(host).catch(console.error);
|
||||||
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createNewNote(host),
|
createNewNote(host),
|
||||||
@@ -258,46 +216,8 @@ export function buildTextResponseConfig<
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildErrorResponseConfig<
|
export function buildErrorResponseConfig(panel: AffineAIPanelWidget) {
|
||||||
T extends keyof BlockSuitePresets.AIActions,
|
|
||||||
>(panel: AffineAIPanelWidget, id?: T) {
|
|
||||||
const host = panel.host;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
name: 'Response',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
name: 'Replace selection',
|
|
||||||
icon: ReplaceIcon,
|
|
||||||
showWhen: () => !!panel.answer,
|
|
||||||
handler: () => {
|
|
||||||
replaceWithAnswer(panel).catch(console.error);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Insert below',
|
|
||||||
icon: InsertBelowIcon,
|
|
||||||
showWhen: () =>
|
|
||||||
!!panel.answer && (!id || !INSERT_ABOVE_ACTIONS.includes(id)),
|
|
||||||
handler: () => {
|
|
||||||
insertAnswerBelow(panel).catch(console.error);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Insert above',
|
|
||||||
icon: InsertTopIcon,
|
|
||||||
showWhen: () =>
|
|
||||||
!!panel.answer && !!id && INSERT_ABOVE_ACTIONS.includes(id),
|
|
||||||
handler: () => {
|
|
||||||
reportResponse('result:insert');
|
|
||||||
insertAnswerAbove(panel).catch(console.error);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
asCaption(host, id),
|
|
||||||
createNewNote(host),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
items: [
|
items: [
|
||||||
@@ -325,18 +245,16 @@ export function buildErrorResponseConfig<
|
|||||||
|
|
||||||
export function buildFinishConfig<T extends keyof BlockSuitePresets.AIActions>(
|
export function buildFinishConfig<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
panel: AffineAIPanelWidget,
|
panel: AffineAIPanelWidget,
|
||||||
id?: T
|
id: T,
|
||||||
|
ctx: AIContext
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
responses: buildTextResponseConfig(panel, id),
|
responses: buildPageResponseConfig(panel, id, ctx),
|
||||||
actions: [],
|
actions: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildErrorConfig<T extends keyof BlockSuitePresets.AIActions>(
|
export function buildErrorConfig(panel: AffineAIPanelWidget) {
|
||||||
panel: AffineAIPanelWidget,
|
|
||||||
id?: T
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
upgrade: () => {
|
upgrade: () => {
|
||||||
AIProvider.slots.requestUpgradePlan.emit({ host: panel.host });
|
AIProvider.slots.requestUpgradePlan.emit({ host: panel.host });
|
||||||
@@ -349,7 +267,7 @@ export function buildErrorConfig<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
cancel: () => {
|
cancel: () => {
|
||||||
panel.hide();
|
panel.hide();
|
||||||
},
|
},
|
||||||
responses: buildErrorResponseConfig(panel, id),
|
responses: buildErrorResponseConfig(panel),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,22 +289,12 @@ export function buildCopyConfig(panel: AffineAIPanelWidget) {
|
|||||||
export function buildAIPanelConfig(
|
export function buildAIPanelConfig(
|
||||||
panel: AffineAIPanelWidget
|
panel: AffineAIPanelWidget
|
||||||
): AffineAIPanelWidgetConfig {
|
): AffineAIPanelWidgetConfig {
|
||||||
|
const ctx = new AIContext();
|
||||||
return {
|
return {
|
||||||
answerRenderer: createTextRenderer(panel.host, { maxHeight: 320 }),
|
answerRenderer: createTextRenderer(panel.host, { maxHeight: 320 }),
|
||||||
finishStateConfig: buildFinishConfig(panel),
|
finishStateConfig: buildFinishConfig(panel, 'chat', ctx),
|
||||||
generatingStateConfig: buildGeneratingConfig(),
|
generatingStateConfig: buildGeneratingConfig(),
|
||||||
errorStateConfig: buildErrorConfig(panel),
|
errorStateConfig: buildErrorConfig(panel),
|
||||||
copy: buildCopyConfig(panel),
|
copy: buildCopyConfig(panel),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAIPanel = (host: EditorHost): AffineAIPanelWidget => {
|
|
||||||
const rootBlockId = host.doc.root?.id;
|
|
||||||
assertExists(rootBlockId);
|
|
||||||
const aiPanel = host.view.getWidget(AFFINE_AI_PANEL_WIDGET, rootBlockId);
|
|
||||||
assertExists(aiPanel);
|
|
||||||
if (!(aiPanel instanceof AffineAIPanelWidget)) {
|
|
||||||
throw new Error('AI panel not found');
|
|
||||||
}
|
|
||||||
return aiPanel;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ const cardsStyles = css`
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--affine-text-secondary-color);
|
color: var(--affine-text-secondary-color);
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -398,15 +398,13 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollToEnd() {
|
scrollToEnd() {
|
||||||
this.updateComplete
|
requestAnimationFrame(() => {
|
||||||
.then(() => {
|
|
||||||
if (!this.messagesContainer) return;
|
if (!this.messagesContainer) return;
|
||||||
this.messagesContainer.scrollTo({
|
this.messagesContainer.scrollTo({
|
||||||
top: this.messagesContainer.scrollHeight,
|
top: this.messagesContainer.scrollHeight,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
.catch(console.error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retry = async () => {
|
retry = async () => {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _scrollToEnd = () => {
|
private readonly _scrollToEnd = () => {
|
||||||
requestAnimationFrame(() => this._chatMessages.value?.scrollToEnd());
|
this._chatMessages.value?.scrollToEnd();
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _cleanupHistories = async () => {
|
private readonly _cleanupHistories = async () => {
|
||||||
@@ -199,10 +199,18 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
!this.isLoading &&
|
!this.isLoading &&
|
||||||
_changedProperties.has('chatContextValue') &&
|
_changedProperties.has('chatContextValue') &&
|
||||||
this.chatContextValue.status !== 'idle'
|
this.chatContextValue.status !== 'idle'
|
||||||
|
) {
|
||||||
|
if (this.chatContextValue.status === 'transmitting') {
|
||||||
|
this._scrollToEnd();
|
||||||
|
} else if (
|
||||||
|
this.chatContextValue.status === 'loading' ||
|
||||||
|
this.chatContextValue.status === 'error' ||
|
||||||
|
this.chatContextValue.status === 'success'
|
||||||
) {
|
) {
|
||||||
setTimeout(this._scrollToEnd, 500);
|
setTimeout(this._scrollToEnd, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ import {
|
|||||||
textTones,
|
textTones,
|
||||||
translateLangs,
|
translateLangs,
|
||||||
} from '../../actions/types';
|
} from '../../actions/types';
|
||||||
import { getAIPanel } from '../../ai-panel';
|
|
||||||
import { AIProvider } from '../../provider';
|
import { AIProvider } from '../../provider';
|
||||||
|
import { getAIPanelWidget } from '../../utils/ai-widgets';
|
||||||
import { mindMapToMarkdown } from '../../utils/edgeless';
|
import { mindMapToMarkdown } from '../../utils/edgeless';
|
||||||
import { canvasToBlob, randomSeed } from '../../utils/image';
|
import { canvasToBlob, randomSeed } from '../../utils/image';
|
||||||
import {
|
import {
|
||||||
@@ -105,7 +105,7 @@ const othersGroup: AIItemGroupConfig = {
|
|||||||
icon: CommentIcon,
|
icon: CommentIcon,
|
||||||
showWhen: () => true,
|
showWhen: () => true,
|
||||||
handler: host => {
|
handler: host => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
AIProvider.slots.requestOpenWithChat.emit({
|
AIProvider.slots.requestOpenWithChat.emit({
|
||||||
host,
|
host,
|
||||||
mode: 'edgeless',
|
mode: 'edgeless',
|
||||||
@@ -120,7 +120,7 @@ const othersGroup: AIItemGroupConfig = {
|
|||||||
icon: ChatWithAIIcon,
|
icon: ChatWithAIIcon,
|
||||||
showWhen: () => true,
|
showWhen: () => true,
|
||||||
handler: host => {
|
handler: host => {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
AIProvider.slots.requestOpenWithChat.emit({
|
AIProvider.slots.requestOpenWithChat.emit({
|
||||||
host,
|
host,
|
||||||
mode: 'edgeless',
|
mode: 'edgeless',
|
||||||
@@ -286,7 +286,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
const selectedElements = getCopilotSelectedElems(host);
|
const selectedElements = getCopilotSelectedElems(host);
|
||||||
const len = selectedElements.length;
|
const len = selectedElements.length;
|
||||||
|
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
// text to image
|
// text to image
|
||||||
// from user input
|
// from user input
|
||||||
if (len === 0) {
|
if (len === 0) {
|
||||||
@@ -297,7 +297,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = (ctx.get()['content'] as string) || '';
|
let content = ctx.get().content || '';
|
||||||
|
|
||||||
// from user input
|
// from user input
|
||||||
if (content.length === 0) {
|
if (content.length === 0) {
|
||||||
@@ -419,7 +419,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
|
|
||||||
// from user input
|
// from user input
|
||||||
if (selectedElements.length === 0) {
|
if (selectedElements.length === 0) {
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
const content = aiPanel.inputText?.trim();
|
const content = aiPanel.inputText?.trim();
|
||||||
if (!content) return;
|
if (!content) return;
|
||||||
return {
|
return {
|
||||||
@@ -438,7 +438,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
if (f + i + n + s + e === 0) {
|
if (f + i + n + s + e === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let content = (ctx.get()['content'] as string) || '';
|
let content = ctx.get().content || '';
|
||||||
|
|
||||||
// single note, text
|
// single note, text
|
||||||
if (
|
if (
|
||||||
@@ -455,7 +455,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
|
|
||||||
// from user input
|
// from user input
|
||||||
if (content.length === 0) {
|
if (content.length === 0) {
|
||||||
const aiPanel = getAIPanel(host);
|
const aiPanel = getAIPanelWidget(host);
|
||||||
content = aiPanel.inputText?.trim() || '';
|
content = aiPanel.inputText?.trim() || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,7 +521,7 @@ const generateGroup: AIItemGroupConfig = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const edgelessActionGroups = [
|
export const edgelessAIGroups: AIItemGroupConfig[] = [
|
||||||
reviewGroup,
|
reviewGroup,
|
||||||
editGroup,
|
editGroup,
|
||||||
generateGroup,
|
generateGroup,
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ import { EdgelessCopilotToolbarEntry } from '@blocksuite/affine/blocks';
|
|||||||
import { noop } from '@blocksuite/affine/global/utils';
|
import { noop } from '@blocksuite/affine/global/utils';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
|
|
||||||
import { getAIPanel } from '../../ai-panel';
|
|
||||||
import { AIProvider } from '../../provider';
|
import { AIProvider } from '../../provider';
|
||||||
|
import { getAIPanelWidget } from '../../utils/ai-widgets';
|
||||||
import { getEdgelessCopilotWidget } from '../../utils/edgeless';
|
import { getEdgelessCopilotWidget } from '../../utils/edgeless';
|
||||||
import { extractContext } from '../../utils/extract';
|
import { extractContext } from '../../utils/extract';
|
||||||
import { edgelessActionGroups } from './actions-config';
|
import { edgelessAIGroups } from './actions-config';
|
||||||
|
|
||||||
noop(EdgelessCopilotToolbarEntry);
|
noop(EdgelessCopilotToolbarEntry);
|
||||||
|
|
||||||
export function setupEdgelessCopilot(widget: EdgelessCopilotWidget) {
|
export function setupEdgelessCopilot(widget: EdgelessCopilotWidget) {
|
||||||
widget.groups = edgelessActionGroups;
|
widget.groups = edgelessAIGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupEdgelessElementToolbarAIEntry(
|
export function setupEdgelessElementToolbarAIEntry(
|
||||||
@@ -30,7 +30,7 @@ export function setupEdgelessElementToolbarAIEntry(
|
|||||||
},
|
},
|
||||||
render: (edgeless: EdgelessRootBlockComponent) => {
|
render: (edgeless: EdgelessRootBlockComponent) => {
|
||||||
const chain = edgeless.service.std.command.chain();
|
const chain = edgeless.service.std.command.chain();
|
||||||
const filteredGroups = edgelessActionGroups.reduce((pre, group) => {
|
const filteredGroups = edgelessAIGroups.reduce((pre, group) => {
|
||||||
const filtered = group.items.filter(item =>
|
const filtered = group.items.filter(item =>
|
||||||
item.showWhen?.(chain, 'edgeless' as DocMode, edgeless.host)
|
item.showWhen?.(chain, 'edgeless' as DocMode, edgeless.host)
|
||||||
);
|
);
|
||||||
@@ -43,7 +43,7 @@ export function setupEdgelessElementToolbarAIEntry(
|
|||||||
if (filteredGroups.every(group => group.items.length === 0)) return null;
|
if (filteredGroups.every(group => group.items.length === 0)) return null;
|
||||||
|
|
||||||
const handler = () => {
|
const handler = () => {
|
||||||
const aiPanel = getAIPanel(edgeless.host);
|
const aiPanel = getAIPanelWidget(edgeless.host);
|
||||||
if (aiPanel.config) {
|
if (aiPanel.config) {
|
||||||
aiPanel.config.generateAnswer = ({ finish, input }) => {
|
aiPanel.config.generateAnswer = ({ finish, input }) => {
|
||||||
finish('success');
|
finish('success');
|
||||||
@@ -70,7 +70,7 @@ export function setupEdgelessElementToolbarAIEntry(
|
|||||||
return html`<edgeless-copilot-toolbar-entry
|
return html`<edgeless-copilot-toolbar-entry
|
||||||
.edgeless=${edgeless}
|
.edgeless=${edgeless}
|
||||||
.host=${edgeless.host}
|
.host=${edgeless.host}
|
||||||
.groups=${edgelessActionGroups}
|
.groups=${edgelessAIGroups}
|
||||||
.onClick=${handler}
|
.onClick=${handler}
|
||||||
></edgeless-copilot-toolbar-entry>`;
|
></edgeless-copilot-toolbar-entry>`;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import { html, type TemplateResult } from 'lit';
|
import { html, type TemplateResult } from 'lit';
|
||||||
|
|
||||||
import { AIItemGroups } from '../../_common/config';
|
import { pageAIGroups } from '../../_common/config';
|
||||||
|
|
||||||
export function setupFormatBarAIEntry(formatBar: AffineFormatBarWidget) {
|
export function setupFormatBarAIEntry(formatBar: AffineFormatBarWidget) {
|
||||||
toolbarDefaultConfig(formatBar);
|
toolbarDefaultConfig(formatBar);
|
||||||
@@ -18,7 +18,7 @@ export function setupFormatBarAIEntry(formatBar: AffineFormatBarWidget) {
|
|||||||
return html`
|
return html`
|
||||||
<ask-ai-toolbar-button
|
<ask-ai-toolbar-button
|
||||||
.host=${formatBar.host}
|
.host=${formatBar.host}
|
||||||
.actionGroups=${AIItemGroups}
|
.actionGroups=${pageAIGroups}
|
||||||
></ask-ai-toolbar-button>
|
></ask-ai-toolbar-button>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import {
|
|||||||
import { assertExists } from '@blocksuite/affine/global/utils';
|
import { assertExists } from '@blocksuite/affine/global/utils';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
|
|
||||||
import { AIItemGroups } from '../../_common/config';
|
import { pageAIGroups } from '../../_common/config';
|
||||||
import { handleInlineAskAIAction } from '../../actions/doc-handler';
|
import { handleInlineAskAIAction } from '../../actions/doc-handler';
|
||||||
import { AIProvider } from '../../provider';
|
import { AIProvider } from '../../provider';
|
||||||
|
|
||||||
export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
|
export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
|
||||||
const AIItems = AIItemGroups.map(group => group.items).flat();
|
const AIItems = pageAIGroups.map(group => group.items).flat();
|
||||||
|
|
||||||
const iconWrapper = (icon: AIItemConfig['icon']) => {
|
const iconWrapper = (icon: AIItemConfig['icon']) => {
|
||||||
return html`<div style="color: var(--affine-primary-color)">
|
return html`<div style="color: var(--affine-primary-color)">
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
import { noop } from '@blocksuite/affine/global/utils';
|
import { noop } from '@blocksuite/affine/global/utils';
|
||||||
import { html, nothing } from 'lit';
|
import { html, nothing } from 'lit';
|
||||||
|
|
||||||
import { getAIPanel } from '../ai-panel';
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import type { AIContext } from '../utils/context';
|
||||||
|
|
||||||
noop(MiniMindmapPreview);
|
noop(MiniMindmapPreview);
|
||||||
|
|
||||||
@@ -19,15 +20,12 @@ export const createMindmapRenderer: (
|
|||||||
/**
|
/**
|
||||||
* Used to store data for later use during rendering.
|
* Used to store data for later use during rendering.
|
||||||
*/
|
*/
|
||||||
ctx: {
|
ctx: AIContext,
|
||||||
get: () => Record<string, unknown>;
|
|
||||||
set: (data: Record<string, unknown>) => void;
|
|
||||||
},
|
|
||||||
style?: MindmapStyle
|
style?: MindmapStyle
|
||||||
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx, style) => {
|
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx, style) => {
|
||||||
return (answer, state) => {
|
return (answer, state) => {
|
||||||
if (state === 'generating') {
|
if (state === 'generating') {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.generatingElement?.updateLoadingProgress(2);
|
panel.generatingElement?.updateLoadingProgress(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,18 +53,12 @@ export const createMindmapExecuteRenderer: (
|
|||||||
/**
|
/**
|
||||||
* Used to store data for later use during rendering.
|
* Used to store data for later use during rendering.
|
||||||
*/
|
*/
|
||||||
ctx: {
|
ctx: AIContext,
|
||||||
get: () => Record<string, unknown>;
|
handler: (host: EditorHost, ctx: AIContext) => void
|
||||||
set: (data: Record<string, unknown>) => void;
|
|
||||||
},
|
|
||||||
handler: (ctx: {
|
|
||||||
get: () => Record<string, unknown>;
|
|
||||||
set: (data: Record<string, unknown>) => void;
|
|
||||||
}) => void
|
|
||||||
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx, handler) => {
|
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx, handler) => {
|
||||||
return (answer, state) => {
|
return (answer, state) => {
|
||||||
if (state !== 'finished') {
|
if (state !== 'finished') {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.generatingElement?.updateLoadingProgress(2);
|
panel.generatingElement?.updateLoadingProgress(2);
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
@@ -75,7 +67,7 @@ export const createMindmapExecuteRenderer: (
|
|||||||
node: markdownToMindmap(answer, host.doc),
|
node: markdownToMindmap(answer, host.doc),
|
||||||
});
|
});
|
||||||
|
|
||||||
handler(ctx);
|
handler(host, ctx);
|
||||||
|
|
||||||
return nothing;
|
return nothing;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,19 +11,17 @@ import { css, html, LitElement, nothing } from 'lit';
|
|||||||
import { property, query } from 'lit/decorators.js';
|
import { property, query } from 'lit/decorators.js';
|
||||||
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
||||||
|
|
||||||
import { getAIPanel } from '../ai-panel';
|
|
||||||
import { PPTBuilder } from '../slides/index';
|
import { PPTBuilder } from '../slides/index';
|
||||||
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
|
import type { AIContext } from '../utils/context';
|
||||||
|
|
||||||
export const createSlidesRenderer: (
|
export const createSlidesRenderer: (
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: {
|
ctx: AIContext
|
||||||
get: () => Record<string, unknown>;
|
|
||||||
set: (data: Record<string, unknown>) => void;
|
|
||||||
}
|
|
||||||
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx) => {
|
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, ctx) => {
|
||||||
return (answer, state) => {
|
return (answer, state) => {
|
||||||
if (state === 'generating') {
|
if (state === 'generating') {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.generatingElement?.updateLoadingProgress(2);
|
panel.generatingElement?.updateLoadingProgress(2);
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
@@ -77,7 +75,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
|||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (!this._editorHost) return;
|
if (!this._editorHost) return;
|
||||||
PPTBuilder(this._editorHost)
|
PPTBuilder(this._editorHost)
|
||||||
.process(this.text)
|
?.process(this.text)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res && this.ctx) {
|
if (res && this.ctx) {
|
||||||
this.ctx.set({
|
this.ctx.set({
|
||||||
@@ -85,7 +83,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
|||||||
images: res.images,
|
images: res.images,
|
||||||
});
|
});
|
||||||
// refresh loading menu item
|
// refresh loading menu item
|
||||||
getAIPanel(this.host)
|
getAIPanelWidget(this.host)
|
||||||
.shadowRoot?.querySelector('ai-panel-answer')
|
.shadowRoot?.querySelector('ai-panel-answer')
|
||||||
?.requestUpdate();
|
?.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { AffineAIPanelWidgetConfig } from '@blocksuite/affine/blocks';
|
|||||||
import { css, html, LitElement, nothing } from 'lit';
|
import { css, html, LitElement, nothing } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
|
|
||||||
import { getAIPanel } from '../ai-panel';
|
import { getAIPanelWidget } from '../utils/ai-widgets';
|
||||||
import { preprocessHtml } from '../utils/html';
|
import { preprocessHtml } from '../utils/html';
|
||||||
|
|
||||||
type AIAnswerWrapperOptions = {
|
type AIAnswerWrapperOptions = {
|
||||||
@@ -62,7 +62,7 @@ export const createIframeRenderer: (
|
|||||||
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, options) => {
|
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, options) => {
|
||||||
return (answer, state) => {
|
return (answer, state) => {
|
||||||
if (state === 'generating') {
|
if (state === 'generating') {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.generatingElement?.updateLoadingProgress(2);
|
panel.generatingElement?.updateLoadingProgress(2);
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ export const createImageRenderer: (
|
|||||||
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, options) => {
|
) => AffineAIPanelWidgetConfig['answerRenderer'] = (host, options) => {
|
||||||
return (answer, state) => {
|
return (answer, state) => {
|
||||||
if (state === 'generating') {
|
if (state === 'generating') {
|
||||||
const panel = getAIPanel(host);
|
const panel = getAIPanelWidget(host);
|
||||||
panel.generatingElement?.updateLoadingProgress(2);
|
panel.generatingElement?.updateLoadingProgress(2);
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ export class AIProvider {
|
|||||||
}>(),
|
}>(),
|
||||||
requestLogin: new Slot<{ host: EditorHost }>(),
|
requestLogin: new Slot<{ host: EditorHost }>(),
|
||||||
requestUpgradePlan: new Slot<{ host: EditorHost }>(),
|
requestUpgradePlan: new Slot<{ host: EditorHost }>(),
|
||||||
// when an action is requested to run in edgeless mode (show a toast in affine)
|
|
||||||
requestRunInEdgeless: new Slot<{ host: EditorHost }>(),
|
|
||||||
// stream of AI actions triggered by users
|
// stream of AI actions triggered by users
|
||||||
actions: new Slot<{
|
actions: new Slot<{
|
||||||
action: keyof BlockSuitePresets.AIActions;
|
action: keyof BlockSuitePresets.AIActions;
|
||||||
@@ -311,7 +309,6 @@ export class AIProvider {
|
|||||||
options: BlockSuitePresets.AIForkChatSessionOptions
|
options: BlockSuitePresets.AIForkChatSessionOptions
|
||||||
) => string | Promise<string>;
|
) => string | Promise<string>;
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
AIProvider.instance.provideAction(id as any, action as any);
|
AIProvider.instance.provideAction(id as any, action as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { BlockSnapshot } from '@blocksuite/affine/store';
|
|||||||
|
|
||||||
import { markdownToSnapshot } from '../../_common';
|
import { markdownToSnapshot } from '../../_common';
|
||||||
import { getSurfaceElementFromEditor } from '../utils/selection-utils';
|
import { getSurfaceElementFromEditor } from '../utils/selection-utils';
|
||||||
|
import { createTemplateJob } from '../utils/template-job';
|
||||||
import {
|
import {
|
||||||
basicTheme,
|
basicTheme,
|
||||||
type PPTDoc,
|
type PPTDoc,
|
||||||
@@ -16,6 +17,7 @@ export const PPTBuilder = (host: EditorHost) => {
|
|||||||
const docs: PPTDoc[] = [];
|
const docs: PPTDoc[] = [];
|
||||||
const contents: unknown[] = [];
|
const contents: unknown[] = [];
|
||||||
const allImages: TemplateImage[][] = [];
|
const allImages: TemplateImage[][] = [];
|
||||||
|
if (!service) return;
|
||||||
|
|
||||||
const addDoc = async (block: BlockSnapshot) => {
|
const addDoc = async (block: BlockSnapshot) => {
|
||||||
const sections = block.children.map(v => {
|
const sections = block.children.map(v => {
|
||||||
@@ -35,8 +37,7 @@ export const PPTBuilder = (host: EditorHost) => {
|
|||||||
};
|
};
|
||||||
docs.push(doc);
|
docs.push(doc);
|
||||||
|
|
||||||
if (doc.isCover || !service) return;
|
const job = createTemplateJob(host);
|
||||||
const job = service.createTemplateJob('template');
|
|
||||||
const { images, content } = await basicTheme(doc);
|
const { images, content } = await basicTheme(doc);
|
||||||
contents.push(content);
|
contents.push(content);
|
||||||
allImages.push(images);
|
allImages.push(images);
|
||||||
@@ -56,7 +57,6 @@ export const PPTBuilder = (host: EditorHost) => {
|
|||||||
return {
|
return {
|
||||||
process: async (text: string) => {
|
process: async (text: string) => {
|
||||||
try {
|
try {
|
||||||
if (!service) return;
|
|
||||||
const snapshot = await markdownToSnapshot(text, host);
|
const snapshot = await markdownToSnapshot(text, host);
|
||||||
|
|
||||||
const block = snapshot.snapshot.content[0];
|
const block = snapshot.snapshot.content[0];
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { nanoid } from '@blocksuite/affine/store';
|
|||||||
|
|
||||||
import { AIProvider } from '../provider';
|
import { AIProvider } from '../provider';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const replaceText = (text: Record<string, string>, template: any) => {
|
const replaceText = (text: Record<string, string>, template: any) => {
|
||||||
if (template != null && typeof template === 'object') {
|
if (template != null && typeof template === 'object') {
|
||||||
if (Array.isArray(template)) {
|
if (Array.isArray(template)) {
|
||||||
@@ -55,7 +54,7 @@ const getImageUrlByKeyword =
|
|||||||
|
|
||||||
const getImages = async (
|
const getImages = async (
|
||||||
images: Record<string, (w: number, h: number) => Promise<string> | string>,
|
images: Record<string, (w: number, h: number) => Promise<string> | string>,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
template: any
|
template: any
|
||||||
): Promise<TemplateImage[]> => {
|
): Promise<TemplateImage[]> => {
|
||||||
const imgs: Record<
|
const imgs: Record<
|
||||||
@@ -66,7 +65,7 @@ const getImages = async (
|
|||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
> = {};
|
> = {};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const run = (data: any) => {
|
const run = (data: any) => {
|
||||||
if (data != null && typeof data === 'object') {
|
if (data != null && typeof data === 'object') {
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
@@ -93,19 +92,21 @@ const getImages = async (
|
|||||||
Object.entries(imgs).map(async ([name, data]) => {
|
Object.entries(imgs).map(async ([name, data]) => {
|
||||||
const getImage = images[name];
|
const getImage = images[name];
|
||||||
if (!getImage) {
|
if (!getImage) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
const url = await getImage(data.width, data.height);
|
const url = await getImage(data.width, data.height);
|
||||||
return {
|
return {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
url,
|
url,
|
||||||
} satisfies TemplateImage;
|
} as TemplateImage;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting image:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const notNull = (v?: TemplateImage): v is TemplateImage => {
|
return list.filter(v => !!v);
|
||||||
return v != null;
|
|
||||||
};
|
|
||||||
return list.filter(notNull);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PPTSection = {
|
export type PPTSection = {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||||
|
import {
|
||||||
|
AFFINE_AI_PANEL_WIDGET,
|
||||||
|
AffineAIPanelWidget,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
|
import { assertExists } from '@blocksuite/affine/global/utils';
|
||||||
|
|
||||||
|
export const getAIPanelWidget = (host: EditorHost): AffineAIPanelWidget => {
|
||||||
|
const rootBlockId = host.doc.root?.id;
|
||||||
|
assertExists(rootBlockId);
|
||||||
|
const aiPanel = host.view.getWidget(AFFINE_AI_PANEL_WIDGET, rootBlockId);
|
||||||
|
assertExists(aiPanel);
|
||||||
|
if (!(aiPanel instanceof AffineAIPanelWidget)) {
|
||||||
|
throw new Error('AI panel not found');
|
||||||
|
}
|
||||||
|
return aiPanel;
|
||||||
|
};
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import type { MindmapStyle } from '@blocksuite/affine/blocks';
|
||||||
|
import type { SerializedXYWH } from '@blocksuite/affine/global/utils';
|
||||||
|
|
||||||
|
import type { TemplateImage } from '../slides/template';
|
||||||
|
|
||||||
|
export interface ContextValue {
|
||||||
|
selectedElements?: BlockSuite.EdgelessModel[];
|
||||||
|
content?: string;
|
||||||
|
// make it real
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
// mindmap
|
||||||
|
node?: MindMapNode | null;
|
||||||
|
style?: MindmapStyle;
|
||||||
|
centerPosition?: SerializedXYWH;
|
||||||
|
// slides
|
||||||
|
contents?: Array<{ blocks: AffineNode }>;
|
||||||
|
images?: TemplateImage[][];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AffineNode {
|
||||||
|
id: string;
|
||||||
|
flavour: string;
|
||||||
|
children: AffineNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type MindMapNode = {
|
||||||
|
xywh?: SerializedXYWH;
|
||||||
|
text: string;
|
||||||
|
children: MindMapNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AIContext {
|
||||||
|
private _value: ContextValue;
|
||||||
|
|
||||||
|
constructor(initData: ContextValue = {}) {
|
||||||
|
this._value = initData;
|
||||||
|
}
|
||||||
|
|
||||||
|
get = () => {
|
||||||
|
return this._value;
|
||||||
|
};
|
||||||
|
|
||||||
|
set = (data: ContextValue) => {
|
||||||
|
this._value = {
|
||||||
|
...this._value,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||||
|
import { LayerManager } from '@blocksuite/affine/block-std/gfx';
|
||||||
|
import {
|
||||||
|
getSurfaceBlock,
|
||||||
|
TemplateJob,
|
||||||
|
TemplateMiddlewares,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
|
import {
|
||||||
|
assertExists,
|
||||||
|
Bound,
|
||||||
|
getCommonBound,
|
||||||
|
} from '@blocksuite/affine/global/utils';
|
||||||
|
|
||||||
|
export function createTemplateJob(host: EditorHost) {
|
||||||
|
const surface = getSurfaceBlock(host.doc);
|
||||||
|
assertExists(surface);
|
||||||
|
|
||||||
|
const middlewares: ((job: TemplateJob) => void)[] = [];
|
||||||
|
const layer = new LayerManager(host.doc, surface, {
|
||||||
|
watch: false,
|
||||||
|
});
|
||||||
|
const bounds = [...layer.blocks, ...layer.canvasElements].map(i =>
|
||||||
|
Bound.deserialize(i.xywh)
|
||||||
|
);
|
||||||
|
const currentContentBound = getCommonBound(bounds);
|
||||||
|
|
||||||
|
if (currentContentBound) {
|
||||||
|
currentContentBound.x += currentContentBound.w + 100;
|
||||||
|
middlewares.push(
|
||||||
|
TemplateMiddlewares.createInsertPlaceMiddleware(currentContentBound)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const idxGenerator = layer.createIndexGenerator();
|
||||||
|
middlewares.push(
|
||||||
|
TemplateMiddlewares.createRegenerateIndexMiddleware(() => idxGenerator())
|
||||||
|
);
|
||||||
|
middlewares.push(TemplateMiddlewares.replaceIdMiddleware);
|
||||||
|
|
||||||
|
return TemplateJob.create({
|
||||||
|
model: surface,
|
||||||
|
type: 'template',
|
||||||
|
middlewares,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { notify, Scrollable } from '@affine/component';
|
import { Scrollable } from '@affine/component';
|
||||||
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||||
import type { ChatPanel } from '@affine/core/blocksuite/presets/ai';
|
import type { ChatPanel } from '@affine/core/blocksuite/presets/ai';
|
||||||
import { AIProvider } from '@affine/core/blocksuite/presets/ai';
|
import { AIProvider } from '@affine/core/blocksuite/presets/ai';
|
||||||
@@ -10,7 +10,6 @@ import { useDocMetaHelper } from '@affine/core/components/hooks/use-block-suite-
|
|||||||
import { EditorService } from '@affine/core/modules/editor';
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
import { RecentDocsService } from '@affine/core/modules/quicksearch';
|
import { RecentDocsService } from '@affine/core/modules/quicksearch';
|
||||||
import { ViewService } from '@affine/core/modules/workbench/services/view';
|
import { ViewService } from '@affine/core/modules/workbench/services/view';
|
||||||
import { useI18n } from '@affine/i18n';
|
|
||||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/blocks';
|
import { RefNodeSlotsProvider } from '@blocksuite/affine/blocks';
|
||||||
import { DisposableGroup } from '@blocksuite/affine/global/utils';
|
import { DisposableGroup } from '@blocksuite/affine/global/utils';
|
||||||
import { type AffineEditorContainer } from '@blocksuite/affine/presets';
|
import { type AffineEditorContainer } from '@blocksuite/affine/presets';
|
||||||
@@ -102,7 +101,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
|||||||
// TODO(@eyhn): remove jotai here
|
// TODO(@eyhn): remove jotai here
|
||||||
const [_, setActiveBlockSuiteEditor] = useActiveBlocksuiteEditor();
|
const [_, setActiveBlockSuiteEditor] = useActiveBlocksuiteEditor();
|
||||||
|
|
||||||
const t = useI18n();
|
|
||||||
const enableAI = featureFlagService.flags.enable_ai.value;
|
const enableAI = featureFlagService.flags.enable_ai.value;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -203,22 +201,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disposable.add(
|
|
||||||
AIProvider.slots.requestRunInEdgeless.on(({ host }) => {
|
|
||||||
if (host === editorHost) {
|
|
||||||
notify.warning({
|
|
||||||
title: t['com.affine.ai.action.edgeless-only.dialog-title'](),
|
|
||||||
action: {
|
|
||||||
label: t['Switch'](),
|
|
||||||
onClick: () => {
|
|
||||||
editor.setMode('edgeless');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const unbind = editor.bindEditorContainer(
|
const unbind = editor.bindEditorContainer(
|
||||||
editorContainer,
|
editorContainer,
|
||||||
(editorContainer as any).docTitle, // set from proxy
|
(editorContainer as any).docTitle, // set from proxy
|
||||||
@@ -230,7 +212,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
|||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[editor, openPage, docCollection.id, jumpToPageBlock, t]
|
[editor, openPage, docCollection.id, jumpToPageBlock]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [hasScrollTop, setHasScrollTop] = useState(false);
|
const [hasScrollTop, setHasScrollTop] = useState(false);
|
||||||
|
|||||||
@@ -368,6 +368,18 @@ test.describe('chat with block', () => {
|
|||||||
return answer.innerText();
|
return answer.innerText();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const collectCanvasAnswer = async (page: Page, tagName: string) => {
|
||||||
|
// wait ai response
|
||||||
|
await page.waitForSelector(
|
||||||
|
'affine-ai-panel-widget .response-list-container',
|
||||||
|
{ timeout: 5 * ONE_MINUTE }
|
||||||
|
);
|
||||||
|
const answer = await page.waitForSelector(
|
||||||
|
`affine-ai-panel-widget ai-panel-answer ${tagName}`
|
||||||
|
);
|
||||||
|
return answer;
|
||||||
|
};
|
||||||
|
|
||||||
const collectImageAnswer = async (page: Page, timeout = TEN_SECONDS) => {
|
const collectImageAnswer = async (page: Page, timeout = TEN_SECONDS) => {
|
||||||
// wait ai response
|
// wait ai response
|
||||||
await page.waitForSelector(
|
await page.waitForSelector(
|
||||||
@@ -431,6 +443,10 @@ test.describe('chat with block', () => {
|
|||||||
'Generate headings',
|
'Generate headings',
|
||||||
'Generate outline',
|
'Generate outline',
|
||||||
'Find actions',
|
'Find actions',
|
||||||
|
'Generate an image',
|
||||||
|
'Brainstorm ideas with mind map',
|
||||||
|
'Generate presentation',
|
||||||
|
'Make it real',
|
||||||
// draft with ai
|
// draft with ai
|
||||||
'Write an article about this',
|
'Write an article about this',
|
||||||
'Write a tweet about this',
|
'Write a tweet about this',
|
||||||
@@ -446,7 +462,31 @@ test.describe('chat with block', () => {
|
|||||||
`.ai-item-${option.replaceAll(' ', '-').toLowerCase()}`
|
`.ai-item-${option.replaceAll(' ', '-').toLowerCase()}`
|
||||||
)
|
)
|
||||||
.then(i => i.click());
|
.then(i => i.click());
|
||||||
|
|
||||||
|
if (option === 'Generate an image') {
|
||||||
|
const mindmap = await collectCanvasAnswer(page, '.ai-answer-image');
|
||||||
|
expect(mindmap).toBeTruthy();
|
||||||
|
} else if (option === 'Brainstorm ideas with mind map') {
|
||||||
|
const mindmap = await collectCanvasAnswer(
|
||||||
|
page,
|
||||||
|
'mini-mindmap-preview'
|
||||||
|
);
|
||||||
|
expect(mindmap).toBeTruthy();
|
||||||
|
} else if (option === 'Generate presentation') {
|
||||||
|
const presentation = await collectCanvasAnswer(
|
||||||
|
page,
|
||||||
|
'ai-slides-renderer'
|
||||||
|
);
|
||||||
|
expect(presentation).toBeTruthy();
|
||||||
|
} else if (option === 'Make it real') {
|
||||||
|
const makeItReal = await collectCanvasAnswer(
|
||||||
|
page,
|
||||||
|
'.ai-answer-iframe'
|
||||||
|
);
|
||||||
|
expect(makeItReal).toBeTruthy();
|
||||||
|
} else {
|
||||||
expect(await collectTextAnswer(page)).toBeTruthy();
|
expect(await collectTextAnswer(page)).toBeTruthy();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"@affine/env": "workspace:*",
|
"@affine/env": "workspace:*",
|
||||||
"@affine/templates": "workspace:*",
|
"@affine/templates": "workspace:*",
|
||||||
"@aws-sdk/client-s3": "^3.709.0",
|
"@aws-sdk/client-s3": "^3.709.0",
|
||||||
"@blocksuite/affine": "0.19.0",
|
"@blocksuite/affine": "0.19.1",
|
||||||
"@clack/core": "^0.3.5",
|
"@clack/core": "^0.3.5",
|
||||||
"@clack/prompts": "^0.8.2",
|
"@clack/prompts": "^0.8.2",
|
||||||
"@magic-works/i18n-codegen": "^0.6.1",
|
"@magic-works/i18n-codegen": "^0.6.1",
|
||||||
|
|||||||
330
yarn.lock
330
yarn.lock
@@ -215,7 +215,7 @@ __metadata:
|
|||||||
"@affine/component": "workspace:*"
|
"@affine/component": "workspace:*"
|
||||||
"@affine/core": "workspace:*"
|
"@affine/core": "workspace:*"
|
||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:2.1.75"
|
"@blocksuite/icons": "npm:2.1.75"
|
||||||
"@capacitor/android": "npm:^6.2.0"
|
"@capacitor/android": "npm:^6.2.0"
|
||||||
"@capacitor/cli": "npm:^6.2.0"
|
"@capacitor/cli": "npm:^6.2.0"
|
||||||
@@ -262,7 +262,7 @@ __metadata:
|
|||||||
"@affine/env": "workspace:*"
|
"@affine/env": "workspace:*"
|
||||||
"@affine/templates": "workspace:*"
|
"@affine/templates": "workspace:*"
|
||||||
"@aws-sdk/client-s3": "npm:^3.709.0"
|
"@aws-sdk/client-s3": "npm:^3.709.0"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@clack/core": "npm:^0.3.5"
|
"@clack/core": "npm:^0.3.5"
|
||||||
"@clack/prompts": "npm:^0.8.2"
|
"@clack/prompts": "npm:^0.8.2"
|
||||||
"@magic-works/i18n-codegen": "npm:^0.6.1"
|
"@magic-works/i18n-codegen": "npm:^0.6.1"
|
||||||
@@ -319,7 +319,7 @@ __metadata:
|
|||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "patch:@atlaskit/pragmatic-drag-and-drop@npm%3A1.4.0#~/.yarn/patches/@atlaskit-pragmatic-drag-and-drop-npm-1.4.0-75c45f52d3.patch"
|
"@atlaskit/pragmatic-drag-and-drop": "patch:@atlaskit/pragmatic-drag-and-drop@npm%3A1.4.0#~/.yarn/patches/@atlaskit-pragmatic-drag-and-drop-npm-1.4.0-75c45f52d3.patch"
|
||||||
"@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3"
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:2.1.75"
|
"@blocksuite/icons": "npm:2.1.75"
|
||||||
"@chromatic-com/storybook": "npm:^3.2.2"
|
"@chromatic-com/storybook": "npm:^3.2.2"
|
||||||
"@emotion/react": "npm:^11.14.0"
|
"@emotion/react": "npm:^11.14.0"
|
||||||
@@ -406,7 +406,7 @@ __metadata:
|
|||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@affine/templates": "workspace:*"
|
"@affine/templates": "workspace:*"
|
||||||
"@affine/track": "workspace:*"
|
"@affine/track": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:2.1.75"
|
"@blocksuite/icons": "npm:2.1.75"
|
||||||
"@capacitor/app": "npm:^6.0.2"
|
"@capacitor/app": "npm:^6.0.2"
|
||||||
"@capacitor/browser": "npm:^6.0.4"
|
"@capacitor/browser": "npm:^6.0.4"
|
||||||
@@ -519,7 +519,7 @@ __metadata:
|
|||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@affine/native": "workspace:*"
|
"@affine/native": "workspace:*"
|
||||||
"@affine/nbstore": "workspace:*"
|
"@affine/nbstore": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@electron-forge/cli": "npm:^7.6.0"
|
"@electron-forge/cli": "npm:^7.6.0"
|
||||||
"@electron-forge/core": "npm:^7.6.0"
|
"@electron-forge/core": "npm:^7.6.0"
|
||||||
"@electron-forge/core-utils": "npm:^7.6.0"
|
"@electron-forge/core-utils": "npm:^7.6.0"
|
||||||
@@ -579,7 +579,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@affine/env@workspace:packages/common/env"
|
resolution: "@affine/env@workspace:packages/common/env"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
vitest: "npm:2.1.8"
|
vitest: "npm:2.1.8"
|
||||||
zod: "npm:^3.24.1"
|
zod: "npm:^3.24.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -628,7 +628,7 @@ __metadata:
|
|||||||
"@affine/component": "workspace:*"
|
"@affine/component": "workspace:*"
|
||||||
"@affine/core": "workspace:*"
|
"@affine/core": "workspace:*"
|
||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:2.1.75"
|
"@blocksuite/icons": "npm:2.1.75"
|
||||||
"@capacitor/app": "npm:^6.0.2"
|
"@capacitor/app": "npm:^6.0.2"
|
||||||
"@capacitor/browser": "npm:^6.0.4"
|
"@capacitor/browser": "npm:^6.0.4"
|
||||||
@@ -655,7 +655,7 @@ __metadata:
|
|||||||
"@affine/component": "workspace:*"
|
"@affine/component": "workspace:*"
|
||||||
"@affine/core": "workspace:*"
|
"@affine/core": "workspace:*"
|
||||||
"@affine/i18n": "workspace:*"
|
"@affine/i18n": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:2.1.75"
|
"@blocksuite/icons": "npm:2.1.75"
|
||||||
"@sentry/react": "npm:^8.44.0"
|
"@sentry/react": "npm:^8.44.0"
|
||||||
"@types/react": "npm:^19.0.1"
|
"@types/react": "npm:^19.0.1"
|
||||||
@@ -3263,19 +3263,19 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-block-embed@npm:0.19.0":
|
"@blocksuite/affine-block-embed@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-block-embed@npm:0.19.0"
|
resolution: "@blocksuite/affine-block-embed@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-block-surface": "npm:0.19.0"
|
"@blocksuite/affine-block-surface": "npm:0.19.1"
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:^2.1.75"
|
"@blocksuite/icons": "npm:^2.1.75"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
@@ -3283,21 +3283,21 @@ __metadata:
|
|||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
minimatch: "npm:^10.0.1"
|
minimatch: "npm:^10.0.1"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/f60180d09267bae0a6dff3ef790e2fc82f3442bd6aa3832e565b48288d36ea770f4c25263c5a032ebdfc2a6f70f20d4548ea790a78bf678a5c75c004bf530c5e
|
checksum: 10/730ca715738f1b29b2a2561610e9d86a2cc2498e94ab9ae0a00e1acf8c8457158bb27e7d9122cc8788c2d8e61c912d39896775e90868f0640fa25bc2c2d6f2dc
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-block-list@npm:0.19.0":
|
"@blocksuite/affine-block-list@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-block-list@npm:0.19.0"
|
resolution: "@blocksuite/affine-block-list@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
@@ -3306,21 +3306,21 @@ __metadata:
|
|||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
minimatch: "npm:^10.0.1"
|
minimatch: "npm:^10.0.1"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/fb57e7da4e03d7a3b9b04bc91bfa3a0b38ce71a8d915309dd820070d30d1ae33bb05c84a3d455d858f772566b0cb568c376b5fb478d8ec09baf5b0f0a66ce9cc
|
checksum: 10/752c00e86403557c2ec80e39f5c60af67543c52f22578872c650a343d9525dac7d63e35c0a56bc3d405fdbed50f03143936ec2076b716e5b2b90be18a0a4341b
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-block-paragraph@npm:0.19.0":
|
"@blocksuite/affine-block-paragraph@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-block-paragraph@npm:0.19.0"
|
resolution: "@blocksuite/affine-block-paragraph@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
@@ -3329,21 +3329,21 @@ __metadata:
|
|||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
minimatch: "npm:^10.0.1"
|
minimatch: "npm:^10.0.1"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/d7e2bd3e6df92da184b4cfa4db985f2fbc9f82d0a42ca50c36c2d2628799576bba2d08f7f784ec9d1d4a0bea144ab90bd3d2114c76c097d673651fc90d7bda5b
|
checksum: 10/971760676b9463dc2d93ee6475dfd3b8a634ebd14e27ac7b999e42afc6b069b6743dcfcb803d9b4e6c20b1d64cabae35635b71f710fa7a416544b322fbbf77f7
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-block-surface@npm:0.19.0":
|
"@blocksuite/affine-block-surface@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-block-surface@npm:0.19.0"
|
resolution: "@blocksuite/affine-block-surface@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@toeverything/theme": "npm:^1.1.1"
|
"@toeverything/theme": "npm:^1.1.1"
|
||||||
@@ -3352,21 +3352,21 @@ __metadata:
|
|||||||
lodash.chunk: "npm:^4.2.0"
|
lodash.chunk: "npm:^4.2.0"
|
||||||
nanoid: "npm:^5.0.7"
|
nanoid: "npm:^5.0.7"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/94ba8a4c9253518a3b75e32929493c4bba074ccc31acf7471bbb49216a82db9ceecd61a81e61dc445d4775b312a51d68859054b7a04282c11aaaaa5e02d58ccd
|
checksum: 10/6ec358f345e3f362bf4aa5799b4df18338afd2e101f8cf12189c717d9b7a531de65026be558e21b80717c41dded87c872f572abbbeabfb6594bfa5e17791e34f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-components@npm:0.19.0":
|
"@blocksuite/affine-components@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-components@npm:0.19.0"
|
resolution: "@blocksuite/affine-components@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:^2.1.75"
|
"@blocksuite/icons": "npm:^2.1.75"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
||||||
@@ -3379,33 +3379,33 @@ __metadata:
|
|||||||
lodash.clonedeep: "npm:^4.5.0"
|
lodash.clonedeep: "npm:^4.5.0"
|
||||||
shiki: "npm:^1.12.0"
|
shiki: "npm:^1.12.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/a9941e5f467ecd130c3a98e05ffb0d35f1aa9ec9c54cc2810c8a3d90e69ba227c3dd737a4339971ba5ce630fba1d91fc23262bff3943f82d4ec105c9c726370e
|
checksum: 10/dde2e4b8d79bc7fce1add519b3dd4eed35b187c8f90cb609880349d100f9262694124fd673c9e9606eb1c3912632cf69dcded46ee10c79241141a9d30ebf4f3e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-model@npm:0.19.0":
|
"@blocksuite/affine-model@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-model@npm:0.19.0"
|
resolution: "@blocksuite/affine-model@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
fractional-indexing: "npm:^3.2.0"
|
fractional-indexing: "npm:^3.2.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/f71a128e21a7a2926c9b972447e5cba436ef79d562fc8d3d829cb4de22ca51f6d417a30a9aa1053b20197b32adbbe2c7e6b9ced06ed49d395fde92975db4257f
|
checksum: 10/f306c7c44e31c4f0e63a706f801775dc492246daf65247827a7553dbed3d15916cdea5d94f55ff519947de18d074e901f52d01bf1dde7e16774c58b102d1bc49
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-shared@npm:0.19.0":
|
"@blocksuite/affine-shared@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-shared@npm:0.19.0"
|
resolution: "@blocksuite/affine-shared@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
@@ -3417,46 +3417,46 @@ __metadata:
|
|||||||
lodash.mergewith: "npm:^4.6.2"
|
lodash.mergewith: "npm:^4.6.2"
|
||||||
minimatch: "npm:^10.0.1"
|
minimatch: "npm:^10.0.1"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/f413128946b800bdc3f2a066b22045b1a5c26ffd76fcf0aecd0fddfcb8aaf8ce197d40057ffa51f4e6bfbf74f85becca300894a0b1372b14fc50a01e1e75fd59
|
checksum: 10/f84e0f5d4fba7de1f6eba99195326072036a5662f5b73930322031c56fa472d68cbe1e20450de50e30fb3b9e7d688af1ef63b595f730c8fa08c7c385c8bacba3
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine-widget-scroll-anchoring@npm:0.19.0":
|
"@blocksuite/affine-widget-scroll-anchoring@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine-widget-scroll-anchoring@npm:0.19.0"
|
resolution: "@blocksuite/affine-widget-scroll-anchoring@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@toeverything/theme": "npm:^1.1.1"
|
"@toeverything/theme": "npm:^1.1.1"
|
||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
checksum: 10/f69a480e532057499cc2c2a733bcd8d9465d651c5623e6b2852f19c220758aaaaf6fa5efa981d3aaf064c640bb8f88093cf6f869b8c9ebf361d8f2d0188b541f
|
checksum: 10/87f5a9c9a3d370f210ff631b310821c78ce57c6cb4f7ddd7d76e7f2da0e7c15a34b8dc27ea05d046b39159e0eb46055a284346c73c74df5d144a969d753e7177
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/affine@npm:0.19.0":
|
"@blocksuite/affine@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/affine@npm:0.19.0"
|
resolution: "@blocksuite/affine@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/blocks": "npm:0.19.0"
|
"@blocksuite/blocks": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/presets": "npm:0.19.0"
|
"@blocksuite/presets": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
checksum: 10/e3aad22d3a308a7016b0b95d5e9271b0582d4c4fa634487015b51269b2039077d8f87fab56b480480839bdab0bda832ad5ab42631f809f05f4d843a36ee7b9d6
|
checksum: 10/6414914385610553cbda8859420b11a24d3e420b97c548b77d6aed865a91350d9eacd2e3502084a7fa40d7d3affb7cc0e9d03036c359e6b8666f1f44ea1c155a
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/block-std@npm:0.19.0":
|
"@blocksuite/block-std@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/block-std@npm:0.19.0"
|
resolution: "@blocksuite/block-std@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@types/hast": "npm:^3.0.4"
|
"@types/hast": "npm:^3.0.4"
|
||||||
@@ -3468,28 +3468,28 @@ __metadata:
|
|||||||
unified: "npm:^11.0.5"
|
unified: "npm:^11.0.5"
|
||||||
w3c-keyname: "npm:^2.2.8"
|
w3c-keyname: "npm:^2.2.8"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/8870dffc946961a7f8332714776c984107d2e4328f1f64a5195b7b4e2d8af222173f5f197de4845240ccc9cf8df942e4afd2b71d89239c20cd363f79a0d950ef
|
checksum: 10/3cedc263249a3efc01b06ca6ce8c6a8dd345bbd4584537e8ccee1c45900961e92b893df823720e5b834e46860556ac78cc3b3616b00b2c852f440cccbd1b8368
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/blocks@npm:0.19.0":
|
"@blocksuite/blocks@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/blocks@npm:0.19.0"
|
resolution: "@blocksuite/blocks@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-block-embed": "npm:0.19.0"
|
"@blocksuite/affine-block-embed": "npm:0.19.1"
|
||||||
"@blocksuite/affine-block-list": "npm:0.19.0"
|
"@blocksuite/affine-block-list": "npm:0.19.1"
|
||||||
"@blocksuite/affine-block-paragraph": "npm:0.19.0"
|
"@blocksuite/affine-block-paragraph": "npm:0.19.1"
|
||||||
"@blocksuite/affine-block-surface": "npm:0.19.0"
|
"@blocksuite/affine-block-surface": "npm:0.19.1"
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/affine-widget-scroll-anchoring": "npm:0.19.0"
|
"@blocksuite/affine-widget-scroll-anchoring": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/data-view": "npm:0.19.0"
|
"@blocksuite/data-view": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:^2.1.75"
|
"@blocksuite/icons": "npm:^2.1.75"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
@@ -3527,20 +3527,20 @@ __metadata:
|
|||||||
simple-xml-to-json: "npm:^1.2.2"
|
simple-xml-to-json: "npm:^1.2.2"
|
||||||
unified: "npm:^11.0.5"
|
unified: "npm:^11.0.5"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/f9df45732416218a6234785f7b981554d34a62d4c017c50abf57aa57c21f21d128b905be0c296aa9aa5a199a10474ae77d6921ac439574a8aa41e85d553ade93
|
checksum: 10/f89fdce1ea320528595dbf99a5ecb4fbc8684d0b1da27bb67dc62d91409ea3cd5f97e07ed481b716fc02dcfd9918d1ebbf2137ba05e6a80bd36ce506a033f146
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/data-view@npm:0.19.0":
|
"@blocksuite/data-view@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/data-view@npm:0.19.0"
|
resolution: "@blocksuite/data-view@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-components": "npm:0.19.0"
|
"@blocksuite/affine-components": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/icons": "npm:^2.1.75"
|
"@blocksuite/icons": "npm:^2.1.75"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@emotion/hash": "npm:^0.9.2"
|
"@emotion/hash": "npm:^0.9.2"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
@@ -3549,19 +3549,19 @@ __metadata:
|
|||||||
date-fns: "npm:^4.0.0"
|
date-fns: "npm:^4.0.0"
|
||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/793cc9f0b5a3542bee95226b191fdbca519dafcef1a863fe7e85f7907700078cbc8691e60be6088746d2d8c61fb425d8168a462a35f454b4036724646e864837
|
checksum: 10/ee2b511cc10ed95efeae07126004128127fa4dea8dac58e2f583e5d56dd3f77c02831fa51ae6746a4a912e5d89a38b2b03e19a2a8ba76d95e8fdd7c4cf29911c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/global@npm:0.19.0":
|
"@blocksuite/global@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/global@npm:0.19.0"
|
resolution: "@blocksuite/global@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
lib0: "npm:^0.2.97"
|
lib0: "npm:^0.2.97"
|
||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/b90a00f3873848a9554cfe338f67e2e7d234a0db3270671f1ea8f08d355a2e54f1eb697094cb796eb34decbf13b14df054c878dc120f94f6e65a6a4a0da5154f
|
checksum: 10/65edbe50f29fb741266b84203c460297eaacbf633e4d6ff5b6d234ce13fa3e09920bcc3a924a70ef16a6bde63e89680b31cb6a157deb785b9113c3c902ee16e4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -3581,49 +3581,49 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/inline@npm:0.19.0":
|
"@blocksuite/inline@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/inline@npm:0.19.0"
|
resolution: "@blocksuite/inline@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
lit: ^3.2.0
|
lit: ^3.2.0
|
||||||
yjs: ^13.6.18
|
yjs: ^13.6.18
|
||||||
checksum: 10/4b28b3fc7e06bbacc74f7d2bc9394009c07bbdc75b52d1af6d8e72e6523403b2b4edc6dec31f063bc0cd7468d08670a6eb938222ab0110d385df018f20ae61b1
|
checksum: 10/39b7a2c1088a573e41b73118ac7e891a2ba055247133567210b8e71dd27b54146955a2a43680179c8e4ebd00dbb0486fcdd88fe2a4267892d0ebac55573c262d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/presets@npm:0.19.0":
|
"@blocksuite/presets@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/presets@npm:0.19.0"
|
resolution: "@blocksuite/presets@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-block-surface": "npm:0.19.0"
|
"@blocksuite/affine-block-surface": "npm:0.19.1"
|
||||||
"@blocksuite/affine-model": "npm:0.19.0"
|
"@blocksuite/affine-model": "npm:0.19.1"
|
||||||
"@blocksuite/affine-shared": "npm:0.19.0"
|
"@blocksuite/affine-shared": "npm:0.19.1"
|
||||||
"@blocksuite/block-std": "npm:0.19.0"
|
"@blocksuite/block-std": "npm:0.19.1"
|
||||||
"@blocksuite/blocks": "npm:0.19.0"
|
"@blocksuite/blocks": "npm:0.19.1"
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/store": "npm:0.19.0"
|
"@blocksuite/store": "npm:0.19.1"
|
||||||
"@floating-ui/dom": "npm:^1.6.10"
|
"@floating-ui/dom": "npm:^1.6.10"
|
||||||
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@toeverything/theme": "npm:^1.1.1"
|
"@toeverything/theme": "npm:^1.1.1"
|
||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
checksum: 10/f9d3de1f5a1f2c1f5ed8206efe7d88059eec9a5520be4e2044b75ffc15d5b5b29f9a28a720f33866fa64c17af5303493a85909fe8e1bd826afa73cd3ca4f40fd
|
checksum: 10/08250d42105e7c499ef3c8a35f9e721389129e4a51ce2c9667414edfe9c10da7b048ab0a3cd4b623da1d30be96c11d6bd2091328c4efa1a4a521adb861324f93
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/store@npm:0.19.0":
|
"@blocksuite/store@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/store@npm:0.19.0"
|
resolution: "@blocksuite/store@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
"@blocksuite/inline": "npm:0.19.0"
|
"@blocksuite/inline": "npm:0.19.1"
|
||||||
"@blocksuite/sync": "npm:0.19.0"
|
"@blocksuite/sync": "npm:0.19.1"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@types/flexsearch": "npm:^0.7.6"
|
"@types/flexsearch": "npm:^0.7.6"
|
||||||
"@types/lodash.ismatch": "npm:^4.4.9"
|
"@types/lodash.ismatch": "npm:^4.4.9"
|
||||||
@@ -3639,21 +3639,21 @@ __metadata:
|
|||||||
zod: "npm:^3.23.8"
|
zod: "npm:^3.23.8"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
yjs: ^13.6.18
|
yjs: ^13.6.18
|
||||||
checksum: 10/ff6daaa737e779311b61436a6caf422bd2558c46a6d11880844db331862a82a20f29546499f2fd2c464ed9b2962ca4b4ee3207d483029f00e31961f1fc784e49
|
checksum: 10/33c6f5ef863488ef899b34eccb42a41bc49186bef746e8fdd82373b86ef902b1ff94593149a3b5c00e5c7405e5a25af6fa93fd2c6f7f3c776c4184bb1483a266
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@blocksuite/sync@npm:0.19.0":
|
"@blocksuite/sync@npm:0.19.1":
|
||||||
version: 0.19.0
|
version: 0.19.1
|
||||||
resolution: "@blocksuite/sync@npm:0.19.0"
|
resolution: "@blocksuite/sync@npm:0.19.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/global": "npm:0.19.0"
|
"@blocksuite/global": "npm:0.19.1"
|
||||||
idb: "npm:^8.0.0"
|
idb: "npm:^8.0.0"
|
||||||
idb-keyval: "npm:^6.2.1"
|
idb-keyval: "npm:^6.2.1"
|
||||||
y-protocols: "npm:^1.0.6"
|
y-protocols: "npm:^1.0.6"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
yjs: ^13.6.15
|
yjs: ^13.6.15
|
||||||
checksum: 10/a989e6c1ed1f640d003e6691062ac5422b1d8277a0946c057f4ca4c77a69c9d58260d4accba1d5b1aff9f6b2c252852bcf1ea1a0b413ca89bdf39063c1685571
|
checksum: 10/bf777974625ecf8cfe377b5ce8a82ff7550aa77ecd88d9dcbe6f75a924a581b214a8f5181f867fedda606ed59e6db8290c53db0c9f6455412bac1e7174361277
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -13776,7 +13776,7 @@ __metadata:
|
|||||||
"@affine/debug": "workspace:*"
|
"@affine/debug": "workspace:*"
|
||||||
"@affine/env": "workspace:*"
|
"@affine/env": "workspace:*"
|
||||||
"@affine/templates": "workspace:*"
|
"@affine/templates": "workspace:*"
|
||||||
"@blocksuite/affine": "npm:0.19.0"
|
"@blocksuite/affine": "npm:0.19.1"
|
||||||
"@datastructures-js/binary-search-tree": "npm:^5.3.2"
|
"@datastructures-js/binary-search-tree": "npm:^5.3.2"
|
||||||
"@emotion/react": "npm:^11.14.0"
|
"@emotion/react": "npm:^11.14.0"
|
||||||
"@swc/core": "npm:^1.10.1"
|
"@swc/core": "npm:^1.10.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user