66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import type { Attachment, AttachmentAdapter, CompleteAttachment, PendingAttachment } from "@assistant-ui/react";
|
|
|
|
type AttachmentApi = {
|
|
uploadAttachment(file: File): Promise<{ attachment: { attachmentId: string } }>;
|
|
deleteAttachment(attachmentId: string): Promise<unknown>;
|
|
};
|
|
|
|
export class HarnessAttachmentAdapter implements AttachmentAdapter {
|
|
public readonly accept = "image/jpeg,image/png,image/webp";
|
|
readonly #previews = new Map<string, string>();
|
|
|
|
public constructor(private readonly api: AttachmentApi) {}
|
|
|
|
public async add({ file }: { file: File }): Promise<PendingAttachment> {
|
|
if (!this.accept.split(",").includes(file.type)) throw new Error("仅支持 JPEG、PNG 和 WebP 图片");
|
|
const preview = URL.createObjectURL(file);
|
|
try {
|
|
const response = await this.api.uploadAttachment(file);
|
|
this.#previews.set(response.attachment.attachmentId, preview);
|
|
return {
|
|
id: response.attachment.attachmentId,
|
|
type: "image",
|
|
name: file.name,
|
|
contentType: file.type,
|
|
file,
|
|
status: { type: "requires-action", reason: "composer-send" },
|
|
};
|
|
} catch (error) {
|
|
URL.revokeObjectURL(preview);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
public async remove(attachment: Attachment): Promise<void> {
|
|
if (attachment.id.startsWith("att_")) await this.api.deleteAttachment(attachment.id);
|
|
this.#revoke(attachment.id);
|
|
}
|
|
|
|
public send(attachment: PendingAttachment): Promise<CompleteAttachment> {
|
|
this.#revoke(attachment.id);
|
|
return Promise.resolve({
|
|
id: attachment.id,
|
|
type: "image",
|
|
name: attachment.name,
|
|
contentType: attachment.contentType,
|
|
status: { type: "complete" },
|
|
content: [],
|
|
});
|
|
}
|
|
|
|
public previewUrl(attachmentId: string): string | undefined {
|
|
return this.#previews.get(attachmentId);
|
|
}
|
|
|
|
public dispose(): void {
|
|
for (const url of this.#previews.values()) URL.revokeObjectURL(url);
|
|
this.#previews.clear();
|
|
}
|
|
|
|
#revoke(attachmentId: string): void {
|
|
const preview = this.#previews.get(attachmentId);
|
|
if (preview !== undefined) URL.revokeObjectURL(preview);
|
|
this.#previews.delete(attachmentId);
|
|
}
|
|
}
|