mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-22 08:47:10 +08:00
Compare commits
1 Commits
v0.26.3-be
...
v0.16.3-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6040ce3593 |
@@ -18,11 +18,13 @@ import {
|
|||||||
fitContent,
|
fitContent,
|
||||||
ImageBlockModel,
|
ImageBlockModel,
|
||||||
InsertBelowIcon,
|
InsertBelowIcon,
|
||||||
|
LightLoadingIcon,
|
||||||
NoteDisplayMode,
|
NoteDisplayMode,
|
||||||
ResetIcon,
|
ResetIcon,
|
||||||
} from '@blocksuite/blocks';
|
} from '@blocksuite/blocks';
|
||||||
import { assertExists, Bound } from '@blocksuite/global/utils';
|
import { assertExists, Bound } from '@blocksuite/global/utils';
|
||||||
import type { TemplateResult } from 'lit';
|
import { html, type TemplateResult } from 'lit';
|
||||||
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
import { AIPenIcon, ChatWithAIIcon } from '../_common/icons';
|
import { AIPenIcon, ChatWithAIIcon } from '../_common/icons';
|
||||||
import { insertFromMarkdown } from '../_common/markdown-utils';
|
import { insertFromMarkdown } from '../_common/markdown-utils';
|
||||||
@@ -98,27 +100,55 @@ export function retry(panel: AffineAIPanelWidget): AIItemConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const extraConditions: Record<string, (data: any) => boolean> = {
|
||||||
|
createSlides: data => !!data.contents,
|
||||||
|
};
|
||||||
export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
export function createInsertResp<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
id: T,
|
id: T,
|
||||||
handler: (host: EditorHost, ctx: CtxRecord) => void,
|
handler: (host: EditorHost, ctx: CtxRecord) => void,
|
||||||
host: EditorHost,
|
host: EditorHost,
|
||||||
ctx: CtxRecord,
|
ctx: CtxRecord,
|
||||||
buttonText: string = 'Insert below'
|
buttonText: string = 'Insert below'
|
||||||
): AIItemConfig {
|
): AIItemConfig[] {
|
||||||
return {
|
const extraCondition = extraConditions[id] || ((_: any) => true);
|
||||||
name: buttonText,
|
return [
|
||||||
icon: InsertBelowIcon,
|
{
|
||||||
showWhen: () => {
|
name: `${buttonText} - Loading...`,
|
||||||
const panel = getAIPanel(host);
|
icon: html`<div style=${styleMap({ height: '20px', width: '20px' })}>
|
||||||
return !EXCLUDING_INSERT_ACTIONS.includes(id) && !!panel.answer;
|
${LightLoadingIcon}
|
||||||
|
</div>`,
|
||||||
|
showWhen: () => {
|
||||||
|
const panel = getAIPanel(host);
|
||||||
|
const data = ctx.get();
|
||||||
|
return (
|
||||||
|
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
||||||
|
!!panel.answer &&
|
||||||
|
// required data for insert
|
||||||
|
!extraCondition(data)
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
handler: () => {
|
{
|
||||||
reportResponse('result:insert');
|
name: buttonText,
|
||||||
handler(host, ctx);
|
icon: InsertBelowIcon,
|
||||||
const panel = getAIPanel(host);
|
showWhen: () => {
|
||||||
panel.hide();
|
const panel = getAIPanel(host);
|
||||||
|
const data = ctx.get();
|
||||||
|
return (
|
||||||
|
!EXCLUDING_INSERT_ACTIONS.includes(id) &&
|
||||||
|
!!panel.answer &&
|
||||||
|
// required data for insert
|
||||||
|
!!extraCondition(data)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handler: () => {
|
||||||
|
reportResponse('result:insert');
|
||||||
|
handler(host, ctx);
|
||||||
|
const panel = getAIPanel(host);
|
||||||
|
panel.hide();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
export function asCaption<T extends keyof BlockSuitePresets.AIActions>(
|
||||||
@@ -555,7 +585,7 @@ export function actionToResponse<T extends keyof BlockSuitePresets.AIActions>(
|
|||||||
panel.hide();
|
panel.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
getInsertAndReplaceHandler(id, host, ctx, variants),
|
...getInsertAndReplaceHandler(id, host, ctx, variants),
|
||||||
asCaption(id, host),
|
asCaption(id, host),
|
||||||
retry(getAIPanel(host)),
|
retry(getAIPanel(host)),
|
||||||
discard(getAIPanel(host), getEdgelessCopilotWidget(host)),
|
discard(getAIPanel(host), getEdgelessCopilotWidget(host)),
|
||||||
@@ -603,7 +633,7 @@ export function actionToErrorResponse<
|
|||||||
responses: [
|
responses: [
|
||||||
{
|
{
|
||||||
name: 'Response',
|
name: 'Response',
|
||||||
items: [getInsertAndReplaceHandler(id, host, ctx, variants)],
|
items: getInsertAndReplaceHandler(id, host, ctx, variants),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
import type { EditorHost } from '@blocksuite/block-std';
|
|
||||||
import type { EdgelessRootService } from '@blocksuite/blocks';
|
|
||||||
import type { BlockSnapshot } from '@blocksuite/store';
|
|
||||||
|
|
||||||
import { markdownToSnapshot } from '../_common/markdown-utils';
|
|
||||||
import { getSurfaceElementFromEditor } from '../_common/selection-utils';
|
|
||||||
import { basicTheme } from '../slides/template';
|
|
||||||
|
|
||||||
type PPTSection = {
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
keywords: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PPTDoc = {
|
|
||||||
isCover: boolean;
|
|
||||||
title: string;
|
|
||||||
sections: PPTSection[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PPTBuilder = (host: EditorHost) => {
|
|
||||||
const service = host.spec.getService<EdgelessRootService>('affine:page');
|
|
||||||
const docs: PPTDoc[] = [];
|
|
||||||
let done = false;
|
|
||||||
const addDoc = async (block: BlockSnapshot) => {
|
|
||||||
const sections = block.children.map(v => {
|
|
||||||
const title = getText(v);
|
|
||||||
const keywords = getText(v.children[0]);
|
|
||||||
const content = getText(v.children[1]);
|
|
||||||
return {
|
|
||||||
title,
|
|
||||||
keywords,
|
|
||||||
content,
|
|
||||||
} satisfies PPTSection;
|
|
||||||
});
|
|
||||||
const doc: PPTDoc = {
|
|
||||||
isCover: docs.length === 0,
|
|
||||||
title: getText(block),
|
|
||||||
sections,
|
|
||||||
};
|
|
||||||
docs.push(doc);
|
|
||||||
|
|
||||||
if (doc.sections.length !== 3 || doc.isCover) return;
|
|
||||||
if (done) return;
|
|
||||||
done = true;
|
|
||||||
const job = service.createTemplateJob('template');
|
|
||||||
const { images, content } = await basicTheme(doc);
|
|
||||||
|
|
||||||
if (images.length) {
|
|
||||||
await Promise.all(
|
|
||||||
images.map(({ id, url }) =>
|
|
||||||
fetch(url)
|
|
||||||
.then(res => res.blob())
|
|
||||||
.then(blob => job.job.assets.set(id, blob))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await job.insertTemplate(content);
|
|
||||||
getSurfaceElementFromEditor(host).refresh();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
process: async (text: string) => {
|
|
||||||
const snapshot = await markdownToSnapshot(text, host);
|
|
||||||
|
|
||||||
const block = snapshot.snapshot.content[0];
|
|
||||||
for (const child of block.children) {
|
|
||||||
await addDoc(child);
|
|
||||||
const { centerX, centerY, zoom } = service.getFitToScreenData();
|
|
||||||
service.viewport.setViewport(zoom, [centerX, centerY]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
done: async (text: string) => {
|
|
||||||
const snapshot = await markdownToSnapshot(text, host);
|
|
||||||
const block = snapshot.snapshot.content[0];
|
|
||||||
await addDoc(block.children[block.children.length - 1]);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getText = (block: BlockSnapshot) => {
|
|
||||||
// @ts-expect-error allow
|
|
||||||
return block.props.text?.delta?.[0]?.insert ?? '';
|
|
||||||
};
|
|
||||||
@@ -85,6 +85,10 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
|||||||
contents: res.contents,
|
contents: res.contents,
|
||||||
images: res.images,
|
images: res.images,
|
||||||
});
|
});
|
||||||
|
// refresh loading menu item
|
||||||
|
getAIPanel(this.host)
|
||||||
|
.shadowRoot?.querySelector('ai-panel-answer')
|
||||||
|
?.requestUpdate();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user