mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 20:57:08 +08:00
refactor(core): display selected doc & attachment chip (#13443)
<img width="1275" height="997" alt="截屏2025-08-08 15 13 59" src="https://github.com/user-attachments/assets/b429239d-84dc-490d-ad1e-957652e3caba" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced support for attachment chips in AI chat, allowing individual attachments to be displayed, added, and removed as separate chips. * Added a new visual component for displaying attachment chips in the chat interface. * **Improvements** * Enhanced chat composer to handle attachments and document chips separately, improving clarity and control over shared content. * Expanded criteria for triggering chat actions to include both document and attachment selections. * **Refactor** * Updated context management to process attachments individually rather than in batches, streamlining the addition and removal of context items. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -361,12 +361,12 @@ declare global {
|
|||||||
op: string,
|
op: string,
|
||||||
updates: string
|
updates: string
|
||||||
) => Promise<string>;
|
) => Promise<string>;
|
||||||
addContextBlobs: (options: {
|
addContextBlob: (options: {
|
||||||
blobIds: string[];
|
blobId: string;
|
||||||
contextId: string;
|
contextId: string;
|
||||||
}) => Promise<CopilotContextBlob[]>;
|
}) => Promise<CopilotContextBlob>;
|
||||||
removeContextBlobs: (options: {
|
removeContextBlob: (options: {
|
||||||
blobIds: string[];
|
blobId: string;
|
||||||
contextId: string;
|
contextId: string;
|
||||||
}) => Promise<boolean>;
|
}) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { getAttachmentFileIcon } from '@blocksuite/affine/components/icons';
|
||||||
|
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
|
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||||
|
import { html } from 'lit';
|
||||||
|
import { property } from 'lit/decorators.js';
|
||||||
|
|
||||||
|
import type { AttachmentChip } from './type';
|
||||||
|
import { getChipIcon, getChipTooltip } from './utils';
|
||||||
|
|
||||||
|
export class ChatPanelAttachmentChip extends SignalWatcher(
|
||||||
|
WithDisposable(ShadowlessElement)
|
||||||
|
) {
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor chip!: AttachmentChip;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor removeChip!: (chip: AttachmentChip) => void;
|
||||||
|
|
||||||
|
override render() {
|
||||||
|
const { state, name } = this.chip;
|
||||||
|
const isLoading = state === 'processing';
|
||||||
|
const tooltip = getChipTooltip(state, name, this.chip.tooltip);
|
||||||
|
const fileType = name.split('.').pop() ?? '';
|
||||||
|
const fileIcon = getAttachmentFileIcon(fileType);
|
||||||
|
const icon = getChipIcon(state, fileIcon);
|
||||||
|
|
||||||
|
return html`<chat-panel-chip
|
||||||
|
.state=${state}
|
||||||
|
.name=${name}
|
||||||
|
.tooltip=${tooltip}
|
||||||
|
.icon=${icon}
|
||||||
|
.closeable=${!isLoading}
|
||||||
|
.onChipDelete=${this.onChipDelete}
|
||||||
|
></chat-panel-chip>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly onChipDelete = () => {
|
||||||
|
this.removeChip(this.chip);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import type { ChatChip, DocChip, DocDisplayConfig, FileChip } from './type';
|
|||||||
import {
|
import {
|
||||||
estimateTokenCount,
|
estimateTokenCount,
|
||||||
getChipKey,
|
getChipKey,
|
||||||
|
isAttachmentChip,
|
||||||
isCollectionChip,
|
isCollectionChip,
|
||||||
isDocChip,
|
isDocChip,
|
||||||
isFileChip,
|
isFileChip,
|
||||||
@@ -160,6 +161,12 @@ export class ChatPanelChips extends SignalWatcher(
|
|||||||
.removeChip=${this.removeChip}
|
.removeChip=${this.removeChip}
|
||||||
></chat-panel-file-chip>`;
|
></chat-panel-file-chip>`;
|
||||||
}
|
}
|
||||||
|
if (isAttachmentChip(chip)) {
|
||||||
|
return html`<chat-panel-attachment-chip
|
||||||
|
.chip=${chip}
|
||||||
|
.removeChip=${this.removeChip}
|
||||||
|
></chat-panel-attachment-chip>`;
|
||||||
|
}
|
||||||
if (isTagChip(chip)) {
|
if (isTagChip(chip)) {
|
||||||
const tag = this._tags.value.find(tag => tag.id === chip.tagId);
|
const tag = this._tags.value.find(tag => tag.id === chip.tagId);
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
|
|||||||
@@ -36,10 +36,13 @@ export interface CollectionChip extends BaseChip {
|
|||||||
collectionId: string;
|
collectionId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AttachmentChip extends BaseChip {
|
||||||
|
sourceId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SelectedContextChip extends BaseChip {
|
export interface SelectedContextChip extends BaseChip {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
attachments: { sourceId: string; name: string }[];
|
|
||||||
docs: string[];
|
|
||||||
snapshot: string | null;
|
snapshot: string | null;
|
||||||
combinedElementsMarkdown: string | null;
|
combinedElementsMarkdown: string | null;
|
||||||
html: string | null;
|
html: string | null;
|
||||||
@@ -50,6 +53,7 @@ export type ChatChip =
|
|||||||
| FileChip
|
| FileChip
|
||||||
| TagChip
|
| TagChip
|
||||||
| CollectionChip
|
| CollectionChip
|
||||||
|
| AttachmentChip
|
||||||
| SelectedContextChip;
|
| SelectedContextChip;
|
||||||
|
|
||||||
export interface DocDisplayConfig {
|
export interface DocDisplayConfig {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { WarningIcon } from '@blocksuite/icons/lit';
|
|||||||
import { type TemplateResult } from 'lit';
|
import { type TemplateResult } from 'lit';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
AttachmentChip,
|
||||||
ChatChip,
|
ChatChip,
|
||||||
ChipState,
|
ChipState,
|
||||||
CollectionChip,
|
CollectionChip,
|
||||||
@@ -66,11 +67,11 @@ export function isCollectionChip(chip: ChatChip): chip is CollectionChip {
|
|||||||
export function isSelectedContextChip(
|
export function isSelectedContextChip(
|
||||||
chip: ChatChip
|
chip: ChatChip
|
||||||
): chip is SelectedContextChip {
|
): chip is SelectedContextChip {
|
||||||
return (
|
return 'snapshot' in chip && 'combinedElementsMarkdown' in chip;
|
||||||
'attachments' in chip &&
|
}
|
||||||
'snapshot' in chip &&
|
|
||||||
'combinedElementsMarkdown' in chip
|
export function isAttachmentChip(chip: ChatChip): chip is AttachmentChip {
|
||||||
);
|
return 'sourceId' in chip && 'name' in chip;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChipKey(chip: ChatChip) {
|
export function getChipKey(chip: ChatChip) {
|
||||||
@@ -130,6 +131,9 @@ export function findChipIndex(chips: ChatChip[], chip: ChatChip) {
|
|||||||
if (isSelectedContextChip(chip)) {
|
if (isSelectedContextChip(chip)) {
|
||||||
return isSelectedContextChip(item) && item.uuid === chip.uuid;
|
return isSelectedContextChip(item) && item.uuid === chip.uuid;
|
||||||
}
|
}
|
||||||
|
if (isAttachmentChip(chip)) {
|
||||||
|
return isAttachmentChip(item) && item.sourceId === chip.sourceId;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-86
@@ -6,12 +6,13 @@ import type {
|
|||||||
} from '@affine/core/modules/ai-button';
|
} from '@affine/core/modules/ai-button';
|
||||||
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import type {
|
import type {
|
||||||
|
ContextEmbedStatus,
|
||||||
ContextWorkspaceEmbeddingStatus,
|
ContextWorkspaceEmbeddingStatus,
|
||||||
CopilotChatHistoryFragment,
|
CopilotChatHistoryFragment,
|
||||||
|
CopilotContextBlob,
|
||||||
CopilotContextDoc,
|
CopilotContextDoc,
|
||||||
CopilotContextFile,
|
CopilotContextFile,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { ContextEmbedStatus } from '@affine/graphql';
|
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
import type { EditorHost } from '@blocksuite/affine/std';
|
import type { EditorHost } from '@blocksuite/affine/std';
|
||||||
import { ShadowlessElement } from '@blocksuite/affine/std';
|
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||||
@@ -23,9 +24,14 @@ import type {
|
|||||||
import { css, html, type PropertyValues } from 'lit';
|
import { css, html, type PropertyValues } from 'lit';
|
||||||
import { property, state } from 'lit/decorators.js';
|
import { property, state } from 'lit/decorators.js';
|
||||||
|
|
||||||
import { AIProvider } from '../../provider';
|
import {
|
||||||
|
type AIChatParams,
|
||||||
|
AIProvider,
|
||||||
|
type AISendParams,
|
||||||
|
} from '../../provider';
|
||||||
import type { SearchMenuConfig } from '../ai-chat-add-context';
|
import type { SearchMenuConfig } from '../ai-chat-add-context';
|
||||||
import type {
|
import type {
|
||||||
|
AttachmentChip,
|
||||||
ChatChip,
|
ChatChip,
|
||||||
CollectionChip,
|
CollectionChip,
|
||||||
DocChip,
|
DocChip,
|
||||||
@@ -36,6 +42,7 @@ import type {
|
|||||||
} from '../ai-chat-chips';
|
} from '../ai-chat-chips';
|
||||||
import {
|
import {
|
||||||
findChipIndex,
|
findChipIndex,
|
||||||
|
isAttachmentChip,
|
||||||
isCollectionChip,
|
isCollectionChip,
|
||||||
isDocChip,
|
isDocChip,
|
||||||
isFileChip,
|
isFileChip,
|
||||||
@@ -207,44 +214,10 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._disposables.add(
|
this._disposables.add(
|
||||||
AIProvider.slots.requestOpenWithChat.subscribe(params => {
|
AIProvider.slots.requestOpenWithChat.subscribe(this.beforeChatContextSend)
|
||||||
if (!params) return;
|
|
||||||
|
|
||||||
const { context, host } = params;
|
|
||||||
if (this.host !== host || !context) return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
context.attachments ||
|
|
||||||
context.snapshot ||
|
|
||||||
context.combinedElementsMarkdown ||
|
|
||||||
context.html
|
|
||||||
) {
|
|
||||||
// Wait for context value updated next frame
|
|
||||||
setTimeout(() => {
|
|
||||||
this.addSelectedContextChip().catch(console.error);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
this._disposables.add(
|
this._disposables.add(
|
||||||
AIProvider.slots.requestSendWithChat.subscribe(params => {
|
AIProvider.slots.requestSendWithChat.subscribe(this.beforeChatContextSend)
|
||||||
if (!params) return;
|
|
||||||
|
|
||||||
const { context, host } = params;
|
|
||||||
if (this.host !== host || !context) return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
context.attachments ||
|
|
||||||
context.snapshot ||
|
|
||||||
context.combinedElementsMarkdown ||
|
|
||||||
context.html
|
|
||||||
) {
|
|
||||||
// Wait for context value updated next frame
|
|
||||||
setTimeout(() => {
|
|
||||||
this.addSelectedContextChip().catch(console.error);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
this.initComposer().catch(console.error);
|
this.initComposer().catch(console.error);
|
||||||
}
|
}
|
||||||
@@ -266,6 +239,31 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly beforeChatContextSend = (
|
||||||
|
params: AISendParams | AIChatParams | null
|
||||||
|
) => {
|
||||||
|
if (!params) return;
|
||||||
|
|
||||||
|
const { context, host } = params;
|
||||||
|
if (this.host !== host || !context) return;
|
||||||
|
|
||||||
|
if (context) {
|
||||||
|
this.updateContext(context);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
context.docs ||
|
||||||
|
context.attachments ||
|
||||||
|
context.snapshot ||
|
||||||
|
context.combinedElementsMarkdown ||
|
||||||
|
context.html
|
||||||
|
) {
|
||||||
|
// Wait for context value updated next frame
|
||||||
|
setTimeout(() => {
|
||||||
|
this.addSelectedContextChip().catch(console.error);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private get isContextProcessing() {
|
private get isContextProcessing() {
|
||||||
return this.chips.some(chip => chip.state === 'processing');
|
return this.chips.some(chip => chip.state === 'processing');
|
||||||
}
|
}
|
||||||
@@ -414,19 +412,45 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly addSelectedContextChip = async () => {
|
private readonly addSelectedContextChip = async () => {
|
||||||
const { attachments, snapshot, combinedElementsMarkdown, docs, html } =
|
const {
|
||||||
this.chatContextValue;
|
attachments = [],
|
||||||
|
snapshot,
|
||||||
|
combinedElementsMarkdown,
|
||||||
|
docs = [],
|
||||||
|
html,
|
||||||
|
} = this.chatContextValue;
|
||||||
await this.removeSelectedContextChip();
|
await this.removeSelectedContextChip();
|
||||||
const chip: SelectedContextChip = {
|
const chip: SelectedContextChip = {
|
||||||
uuid: uuidv4(),
|
uuid: uuidv4(),
|
||||||
attachments,
|
|
||||||
docs,
|
|
||||||
snapshot,
|
snapshot,
|
||||||
combinedElementsMarkdown,
|
combinedElementsMarkdown,
|
||||||
html,
|
html,
|
||||||
state: attachments.length > 0 ? 'processing' : 'finished',
|
state: 'finished',
|
||||||
};
|
};
|
||||||
await this.addChip(chip, true);
|
await this.addChip(chip, true);
|
||||||
|
await Promise.all(
|
||||||
|
docs.map(docId =>
|
||||||
|
this.addChip(
|
||||||
|
{
|
||||||
|
docId,
|
||||||
|
state: 'processing',
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await Promise.all(
|
||||||
|
attachments.map(attachment =>
|
||||||
|
this.addChip(
|
||||||
|
{
|
||||||
|
sourceId: attachment.sourceId,
|
||||||
|
name: attachment.name,
|
||||||
|
state: 'processing',
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly removeSelectedContextChip = async () => {
|
private readonly removeSelectedContextChip = async () => {
|
||||||
@@ -449,8 +473,8 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
if (isCollectionChip(chip)) {
|
if (isCollectionChip(chip)) {
|
||||||
return await this.addCollectionToContext(chip);
|
return await this.addCollectionToContext(chip);
|
||||||
}
|
}
|
||||||
if (isSelectedContextChip(chip)) {
|
if (isAttachmentChip(chip)) {
|
||||||
return await this.addSelectedContextChipToContext(chip);
|
return await this.addAttachmentChipToContext(chip);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@@ -546,26 +570,29 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly addSelectedContextChipToContext = async (
|
private readonly addAttachmentChipToContext = async (
|
||||||
chip: SelectedContextChip
|
chip: AttachmentChip
|
||||||
) => {
|
) => {
|
||||||
const { attachments, docs } = chip;
|
|
||||||
const contextId = await this.createContextId();
|
const contextId = await this.createContextId();
|
||||||
if (!contextId || !AIProvider.context) {
|
if (!contextId || !AIProvider.context) {
|
||||||
throw new Error('Context not found');
|
throw new Error('Context not found');
|
||||||
}
|
}
|
||||||
await AIProvider.context.addContextBlobs({
|
try {
|
||||||
blobIds: attachments.map(attachment => attachment.sourceId),
|
const contextBlob = await AIProvider.context.addContextBlob({
|
||||||
contextId,
|
blobId: chip.sourceId,
|
||||||
});
|
contextId,
|
||||||
await Promise.all(
|
});
|
||||||
docs.map(docId =>
|
this.updateChip(chip, {
|
||||||
AIProvider.context?.addContextDoc({
|
state: contextBlob.status || 'processing',
|
||||||
contextId,
|
blobId: chip.sourceId,
|
||||||
docId,
|
});
|
||||||
})
|
} catch (e) {
|
||||||
)
|
this.updateChip(chip, {
|
||||||
);
|
state: 'failed',
|
||||||
|
tooltip:
|
||||||
|
e instanceof Error ? e.message : 'Add context attachment error',
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly removeFromContext = async (
|
private readonly removeFromContext = async (
|
||||||
@@ -600,20 +627,18 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
collectionId: chip.collectionId,
|
collectionId: chip.collectionId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (isSelectedContextChip(chip)) {
|
if (isAttachmentChip(chip)) {
|
||||||
const { attachments, docs } = chip;
|
return await AIProvider.context.removeContextBlob({
|
||||||
await AIProvider.context.removeContextBlobs({
|
|
||||||
contextId,
|
contextId,
|
||||||
blobIds: attachments.map(attachment => attachment.sourceId),
|
blobId: chip.sourceId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isSelectedContextChip(chip)) {
|
||||||
|
this.updateContext({
|
||||||
|
...this.chatContextValue,
|
||||||
|
snapshot: null,
|
||||||
|
combinedElementsMarkdown: null,
|
||||||
});
|
});
|
||||||
await Promise.all(
|
|
||||||
docs.map(docId =>
|
|
||||||
AIProvider.context?.removeContextDoc({
|
|
||||||
contextId,
|
|
||||||
docId,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
@@ -707,7 +732,7 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
];
|
];
|
||||||
const hashMap = new Map<
|
const hashMap = new Map<
|
||||||
string,
|
string,
|
||||||
CopilotContextDoc | CopilotContextFile | { status: ContextEmbedStatus }
|
CopilotContextDoc | CopilotContextFile | CopilotContextBlob
|
||||||
>();
|
>();
|
||||||
const count: Record<ContextEmbedStatus, number> = {
|
const count: Record<ContextEmbedStatus, number> = {
|
||||||
finished: 0,
|
finished: 0,
|
||||||
@@ -722,18 +747,10 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
hashMap.set(file.id, file);
|
hashMap.set(file.id, file);
|
||||||
file.status && count[file.status]++;
|
file.status && count[file.status]++;
|
||||||
});
|
});
|
||||||
const selectedChip = this.chips.find(c => isSelectedContextChip(c));
|
blobs.forEach(blob => {
|
||||||
if (selectedChip) {
|
hashMap.set(blob.id, blob);
|
||||||
const status: ContextEmbedStatus = blobs.every(
|
blob.status && count[blob.status]++;
|
||||||
blob => blob.status === 'finished'
|
});
|
||||||
)
|
|
||||||
? ContextEmbedStatus.finished
|
|
||||||
: ContextEmbedStatus.processing;
|
|
||||||
hashMap.set(selectedChip.uuid, {
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
count[status]++;
|
|
||||||
}
|
|
||||||
const nextChips = this.chips.map(chip => {
|
const nextChips = this.chips.map(chip => {
|
||||||
if (isTagChip(chip) || isCollectionChip(chip)) {
|
if (isTagChip(chip) || isCollectionChip(chip)) {
|
||||||
return chip;
|
return chip;
|
||||||
@@ -742,7 +759,11 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
? chip.docId
|
? chip.docId
|
||||||
: isFileChip(chip)
|
: isFileChip(chip)
|
||||||
? chip.fileId
|
? chip.fileId
|
||||||
: chip.uuid;
|
: isAttachmentChip(chip)
|
||||||
|
? chip.sourceId
|
||||||
|
: isSelectedContextChip(chip)
|
||||||
|
? chip.uuid
|
||||||
|
: undefined;
|
||||||
const item = id && hashMap.get(id);
|
const item = id && hashMap.get(id);
|
||||||
if (item && item.status) {
|
if (item && item.status) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { ChatPanelSplitView } from './chat-panel/split-view';
|
|||||||
import { ArtifactSkeleton } from './components/ai-artifact-skeleton';
|
import { ArtifactSkeleton } from './components/ai-artifact-skeleton';
|
||||||
import { AIChatAddContext } from './components/ai-chat-add-context';
|
import { AIChatAddContext } from './components/ai-chat-add-context';
|
||||||
import { ChatPanelAddPopover } from './components/ai-chat-chips/add-popover';
|
import { ChatPanelAddPopover } from './components/ai-chat-chips/add-popover';
|
||||||
|
import { ChatPanelAttachmentChip } from './components/ai-chat-chips/attachment-chip';
|
||||||
import { ChatPanelCandidatesPopover } from './components/ai-chat-chips/candidates-popover';
|
import { ChatPanelCandidatesPopover } from './components/ai-chat-chips/candidates-popover';
|
||||||
import { ChatPanelChips } from './components/ai-chat-chips/chat-panel-chips';
|
import { ChatPanelChips } from './components/ai-chat-chips/chat-panel-chips';
|
||||||
import { ChatPanelChip } from './components/ai-chat-chips/chip';
|
import { ChatPanelChip } from './components/ai-chat-chips/chip';
|
||||||
@@ -166,6 +167,7 @@ export function registerAIEffects() {
|
|||||||
customElements.define('chat-panel-tag-chip', ChatPanelTagChip);
|
customElements.define('chat-panel-tag-chip', ChatPanelTagChip);
|
||||||
customElements.define('chat-panel-collection-chip', ChatPanelCollectionChip);
|
customElements.define('chat-panel-collection-chip', ChatPanelCollectionChip);
|
||||||
customElements.define('chat-panel-selected-chip', ChatPanelSelectedChip);
|
customElements.define('chat-panel-selected-chip', ChatPanelSelectedChip);
|
||||||
|
customElements.define('chat-panel-attachment-chip', ChatPanelAttachmentChip);
|
||||||
customElements.define('chat-panel-chip', ChatPanelChip);
|
customElements.define('chat-panel-chip', ChatPanelChip);
|
||||||
customElements.define('ai-error-wrapper', AIErrorWrapper);
|
customElements.define('ai-error-wrapper', AIErrorWrapper);
|
||||||
customElements.define('ai-slides-renderer', AISlidesRenderer);
|
customElements.define('ai-slides-renderer', AISlidesRenderer);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export function edgelessToolbarAIEntryConfig(): ToolbarModuleConfig {
|
|||||||
aiPanel.hide();
|
aiPanel.hide();
|
||||||
extractSelectedContent(host)
|
extractSelectedContent(host)
|
||||||
.then(context => {
|
.then(context => {
|
||||||
if (context?.attachments?.length) {
|
if (context?.attachments?.length || context?.docs?.length) {
|
||||||
AIProvider.slots.requestOpenWithChat.next({
|
AIProvider.slots.requestOpenWithChat.next({
|
||||||
input,
|
input,
|
||||||
host,
|
host,
|
||||||
|
|||||||
@@ -748,31 +748,20 @@ Could you make a new website based on these notes and send back just the html fi
|
|||||||
) => {
|
) => {
|
||||||
return client.applyDocUpdates(workspaceId, docId, op, updates);
|
return client.applyDocUpdates(workspaceId, docId, op, updates);
|
||||||
},
|
},
|
||||||
addContextBlobs: async (options: {
|
addContextBlob: async (options: { blobId: string; contextId: string }) => {
|
||||||
blobIds: string[];
|
return client.addContextBlob({
|
||||||
contextId: string;
|
contextId: options.contextId,
|
||||||
}) => {
|
blobId: options.blobId,
|
||||||
return Promise.all(
|
});
|
||||||
options.blobIds.map(blobId =>
|
|
||||||
client.addContextBlob({
|
|
||||||
contextId: options.contextId,
|
|
||||||
blobId,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
removeContextBlobs: async (options: {
|
removeContextBlob: async (options: {
|
||||||
blobIds: string[];
|
blobId: string;
|
||||||
contextId: string;
|
contextId: string;
|
||||||
}) => {
|
}) => {
|
||||||
return Promise.all(
|
return client.removeContextBlob({
|
||||||
options.blobIds.map(blobId =>
|
contextId: options.contextId,
|
||||||
client.removeContextBlob({
|
blobId: options.blobId,
|
||||||
contextId: options.contextId,
|
});
|
||||||
blobId,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).then(results => results.every(Boolean));
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user