import './open-ai.js'; import './fal.js'; import './llama2.js'; import { ShadowlessElement, WithDisposable } from '@cbi-blocksuite/block-std'; import { nanoid } from '@cbi-blocksuite/store'; import { computePosition } from '@floating-ui/dom'; import { css, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; import { stopPropagation } from '../utils/selection-utils.js'; import { copilotConfig, type VendorConfig } from './copilot-config.js'; import { falVendor } from './fal.js'; import { llama2Vendor } from './llama2.js'; import { openaiVendor } from './open-ai.js'; import { allKindService, type AllServiceKind, type ServiceImpl, type Vendor, } from './service-base.js'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const allVendor: Vendor[] = [openaiVendor, falVendor, llama2Vendor]; @customElement('create-new-service') export class CreateNewService extends WithDisposable(ShadowlessElement) { @property({ attribute: false }) type!: string; @property({ attribute: false }) onSave!: (config: VendorConfig) => void; @state() key = ''; @state() name = ''; @state() data?: unknown; changeKeyByEvent(e: Event) { const select = e.target as HTMLSelectElement; this.changeKey(select.value); } get serviceKind() { return allKindService.find(v => v.type === this.type); } changeKey(key: string) { this.key = key; this.data = allVendor.find(v => v.key === key)?.initData(); } changeName(e: Event) { const input = e.target as HTMLInputElement; this.name = input.value; } save() { if (!this.data) { return; } this.onSave({ id: nanoid(), vendorKey: this.key, name: this.name, data: this.data, }); } close() { this.remove(); } list() { const set = new Set>(); allKindService .find(v => v.type === this.type) ?.implList.forEach(v => { set.add(v.vendor); }); return [...set]; } protected override render(): unknown { const list = this.list(); if (!list) { requestAnimationFrame(() => { this.remove(); }); return; } const current = allVendor.find(v => v.key === this.key); if (!current) { if (!list[0]) { return html`
no vendor
`; } this.changeKey(list[0].key); requestAnimationFrame(() => { this.requestUpdate(); }); return; } return html`
${current.renderConfigEditor(this.data, () => this.requestUpdate())}
`; } } @customElement('vendor-service-select') export class VendorServiceSelect extends WithDisposable(ShadowlessElement) { static override styles = css` .vendor-service-select { display: flex; align-items: center; justify-content: center; border-radius: 4px; padding: 2px 4px; font-size: 12px; color: white; width: max-content; cursor: pointer; } `; @property({ attribute: false }) featureKey!: string; @property({ attribute: false }) service!: AllServiceKind; changeService(e: Event) { const options = new VendorServiceOptions(); options.featureKey = this.featureKey; options.service = this.service; options.close = () => { this.requestUpdate(); }; const target = e.target as HTMLElement; document.body.append(options); computePosition(target, options) .then(pos => { options.style.left = `${pos.x}px`; options.style.top = `${pos.y}px`; }) .catch(() => { options.remove(); }); } protected override render(): unknown { const list = copilotConfig.getVendorsByService(this.service); if (!list) { return html`
no service
`; } const current = copilotConfig.getVendor(this.featureKey, this.service); if (!current) { return html`
no vendor
`; } const style = styleMap({ border: '1px solid', borderColor: current.impl.vendor.color, color: current.impl.vendor.color, }); return html`
${current.vendor.name} ${current.impl.vendor.key} ${current.impl.name}
`; } } @customElement('vendor-service-options') export class VendorServiceOptions extends WithDisposable(ShadowlessElement) { static override styles = css` vendor-service-options { position: fixed; font-family: var(--affine-font-family); } .vendor-service-option { display: flex; align-items: center; justify-content: center; border-radius: 4px; padding: 2px 4px; font-size: 12px; color: white; width: max-content; cursor: pointer; } `; @property({ attribute: false }) featureKey!: string; @property({ attribute: false }) service!: AllServiceKind; @property({ attribute: false }) close!: () => void; select(vendor: VendorConfig, impl: ServiceImpl) { copilotConfig.changeService( this.featureKey, this.service.type, vendor.id, impl.name ); this.remove(); this.close(); } protected override render(): unknown { const list = copilotConfig.getVendorsByService(this.service); return html`
${repeat(list, item => { const style = styleMap({ backgroundColor: item.impl.vendor.color, }); const select = () => { this.select(item.vendor, item.impl); }; return html`
${item.vendor.name} ${item.impl.vendor.key} ${item.impl.name}
`; })}
`; } }