From f9929ebd61feec9d2fdf01ef4a42e0b171fcf678 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Thu, 27 Jul 2023 17:28:21 -0700 Subject: [PATCH] fix: copilot not working (#3425) --- apps/core/src/bootstrap/register-plugins.ts | 40 +++++- .../general-setting/plugins/index.tsx | 40 +++++- packages/cli/src/bin/dev-plugin.ts | 2 +- packages/plugin-infra/src/atom.ts | 6 + packages/plugin-infra/src/entry.ts | 10 +- plugins/copilot/package.json | 2 +- plugins/copilot/src/UI/debug-content.tsx | 57 +++------ .../src/core/langchain/vector-store.ts | 118 ------------------ plugins/copilot/src/index.ts | 15 +++ plugins/hello-world/src/index.ts | 8 ++ yarn.lock | 48 ++++--- 11 files changed, 165 insertions(+), 181 deletions(-) delete mode 100644 plugins/copilot/src/core/langchain/vector-store.ts diff --git a/apps/core/src/bootstrap/register-plugins.ts b/apps/core/src/bootstrap/register-plugins.ts index ed6be96c49..c3cdaf3b28 100644 --- a/apps/core/src/bootstrap/register-plugins.ts +++ b/apps/core/src/bootstrap/register-plugins.ts @@ -2,6 +2,7 @@ import 'ses'; import * as AFFiNEComponent from '@affine/component'; +import { FormatQuickBar } from '@blocksuite/blocks'; import * as BlockSuiteBlocksStd from '@blocksuite/blocks/std'; import { DisposableGroup } from '@blocksuite/global/utils'; import * as BlockSuiteGlobalUtils from '@blocksuite/global/utils'; @@ -12,6 +13,7 @@ import { headerItemsAtom, registeredPluginAtom, rootStore, + settingItemsAtom, windowItemsAtom, } from '@toeverything/plugin-infra/atom'; import type { @@ -96,8 +98,28 @@ const createGlobalThis = () => { document, navigator, userAgent: navigator.userAgent, - // todo: permission control - fetch: globalThis.fetch, + // todo(himself65): permission control + fetch: function (input: RequestInfo, init?: RequestInit) { + return globalThis.fetch(input, init); + }, + setTimeout: function (callback: () => void, timeout: number) { + return globalThis.setTimeout(callback, timeout); + }, + clearTimeout: function (id: number) { + return globalThis.clearTimeout(id); + }, + // copilot uses these + crypto: globalThis.crypto, + CustomEvent: globalThis.CustomEvent, + Date: globalThis.Date, + Math: globalThis.Math, + URL: globalThis.URL, + URLSearchParams: globalThis.URLSearchParams, + Headers: globalThis.Headers, + TextEncoder: globalThis.TextEncoder, + TextDecoder: globalThis.TextDecoder, + Request: globalThis.Request, + Error: globalThis.Error, // fixme: use our own db api indexedDB: globalThis.indexedDB, @@ -177,6 +199,20 @@ await Promise.all( ...items, [plugin]: callback as CallbackMap['window'], })); + } else if (part === 'setting') { + console.log('setting'); + rootStore.set(settingItemsAtom, items => ({ + ...items, + [plugin]: callback as CallbackMap['setting'], + })); + } else if (part === 'formatBar') { + console.log('1'); + FormatQuickBar.customElements.push((page, getBlockRange) => { + console.log('2'); + const div = document.createElement('div'); + (callback as CallbackMap['formatBar'])(div, page, getBlockRange); + return div; + }); } else { throw new Error(`Unknown part: ${part}`); } diff --git a/apps/core/src/components/affine/setting-modal/general-setting/plugins/index.tsx b/apps/core/src/components/affine/setting-modal/general-setting/plugins/index.tsx index e803fc5ed3..bcbc2cc90c 100644 --- a/apps/core/src/components/affine/setting-modal/general-setting/plugins/index.tsx +++ b/apps/core/src/components/affine/setting-modal/general-setting/plugins/index.tsx @@ -1,10 +1,38 @@ -import { - SettingHeader, - SettingWrapper, -} from '@affine/component/setting-components'; +import { SettingHeader } from '@affine/component/setting-components'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; -import { registeredPluginAtom } from '@toeverything/plugin-infra/atom'; +import { + registeredPluginAtom, + settingItemsAtom, +} from '@toeverything/plugin-infra/atom'; import { useAtomValue } from 'jotai'; +import type { FC, ReactNode } from 'react'; +import { useRef } from 'react'; + +const PluginSettingWrapper: FC<{ + id: string; + title?: ReactNode; +}> = ({ title, id }) => { + const Setting = useAtomValue(settingItemsAtom)[id]; + const disposeRef = useRef<(() => void) | null>(null); + return ( +
+ {title ?
{title}
: null} +
{ + if (ref && Setting) { + setTimeout(() => { + disposeRef.current = Setting(ref); + }); + } else if (ref === null) { + setTimeout(() => { + disposeRef.current?.(); + }); + } + }} + /> +
+ ); +}; export const Plugins = () => { const t = useAFFiNEI18N(); @@ -17,7 +45,7 @@ export const Plugins = () => { data-testid="plugins-title" /> {allowedPlugins.map(plugin => ( - + ))} ); diff --git a/packages/cli/src/bin/dev-plugin.ts b/packages/cli/src/bin/dev-plugin.ts index f71cfe060d..ec1938ec51 100644 --- a/packages/cli/src/bin/dev-plugin.ts +++ b/packages/cli/src/bin/dev-plugin.ts @@ -167,7 +167,7 @@ await build({ if (!existsSync(outDir)) { await mkdir(outDir, { recursive: true }); } - const file = await open(pluginListJsonPath, 'w+', 0o777); + const file = await open(pluginListJsonPath, 'as+', 0o777); const txt = await file.readFile({ encoding: 'utf-8', }); diff --git a/packages/plugin-infra/src/atom.ts b/packages/plugin-infra/src/atom.ts index d1bc3ab9c9..bda15b9ff5 100644 --- a/packages/plugin-infra/src/atom.ts +++ b/packages/plugin-infra/src/atom.ts @@ -16,6 +16,12 @@ export const headerItemsAtom = atom>( export const editorItemsAtom = atom>({}); export const registeredPluginAtom = atom([]); export const windowItemsAtom = atom>({}); +export const settingItemsAtom = atom>( + {} +); +export const formatBarItemsAtom = atom< + Record +>({}); export const currentWorkspaceIdAtom = atom(null); export const currentPageIdAtom = atom(null); diff --git a/packages/plugin-infra/src/entry.ts b/packages/plugin-infra/src/entry.ts index c7454925d5..337f7e5129 100644 --- a/packages/plugin-infra/src/entry.ts +++ b/packages/plugin-infra/src/entry.ts @@ -1,12 +1,20 @@ +import type { getCurrentBlockRange } from '@blocksuite/blocks'; import type { EditorContainer } from '@blocksuite/editor'; +import type { Page } from '@blocksuite/store'; import type { FC } from 'react'; -export type Part = 'headerItem' | 'editor' | 'window'; +export type Part = 'headerItem' | 'editor' | 'window' | 'setting' | 'formatBar'; export type CallbackMap = { headerItem: (root: HTMLElement) => () => void; window: (root: HTMLElement) => () => void; editor: (root: HTMLElement, editor: EditorContainer) => () => void; + setting: (root: HTMLElement) => () => void; + formatBar: ( + root: HTMLElement, + page: Page, + getBlockRange: () => ReturnType + ) => () => void; }; export interface PluginContext { diff --git a/plugins/copilot/package.json b/plugins/copilot/package.json index efed8d5c8b..c65f3c0cf7 100644 --- a/plugins/copilot/package.json +++ b/plugins/copilot/package.json @@ -11,7 +11,7 @@ "@affine/component": "workspace:*", "@toeverything/plugin-infra": "workspace:*", "idb": "^7.1.1", - "langchain": "^0.0.107", + "langchain": "^0.0.118", "marked": "^5.1.1", "marked-gfm-heading-id": "^3.0.4", "marked-mangle": "^1.1.0", diff --git a/plugins/copilot/src/UI/debug-content.tsx b/plugins/copilot/src/UI/debug-content.tsx index 2bc178ad9f..a5a3e80d7e 100644 --- a/plugins/copilot/src/UI/debug-content.tsx +++ b/plugins/copilot/src/UI/debug-content.tsx @@ -1,6 +1,4 @@ import { Button, FlexWrapper, Input } from '@affine/component'; -import { SettingRow } from '@affine/component/setting-components'; -import { SettingWrapper } from '@affine/component/setting-components'; import { useAtom } from 'jotai'; import { type ReactElement, useCallback } from 'react'; @@ -9,43 +7,28 @@ import { conversationHistoryDBName } from '../core/langchain/message-history'; export const DebugContent = (): ReactElement => { const [key, setKey] = useAtom(openAIApiKeyAtom); - const desc = ( - <> - You can get your API key from - - here. - - - ); return (
- - - - { - setKey(newValue); - }, - [setKey] - )} - /> - - - + + { + setKey(newValue); + }, + [setKey] + )} + /> + +
); }; diff --git a/plugins/copilot/src/core/langchain/vector-store.ts b/plugins/copilot/src/core/langchain/vector-store.ts deleted file mode 100644 index 239684be71..0000000000 --- a/plugins/copilot/src/core/langchain/vector-store.ts +++ /dev/null @@ -1,118 +0,0 @@ -// fixme: vector store has not finished -import type { DBSchema } from 'idb'; -import { Document } from 'langchain/document'; -import { Embeddings } from 'langchain/embeddings'; -import { VectorStore } from 'langchain/vectorstores'; -import { similarity as ml_distance_similarity } from 'ml-distance'; - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -interface VectorDBV1 extends DBSchema { - vector: { - key: string; - value: Vector; - }; -} - -interface Vector { - id: string; - - content: string; - embedding: number[]; - metadata: Record; -} - -export interface MemoryVectorStoreArgs { - similarity?: typeof ml_distance_similarity.cosine; -} - -export class IndexedDBVectorStore extends VectorStore { - memoryVectors: any[] = []; - - similarity: typeof ml_distance_similarity.cosine; - - constructor( - embeddings: Embeddings, - { similarity, ...rest }: MemoryVectorStoreArgs = {} - ) { - super(embeddings, rest); - - this.similarity = similarity ?? ml_distance_similarity.cosine; - } - - async addDocuments(documents: Document[]): Promise { - const texts = documents.map(({ pageContent }) => pageContent); - return this.addVectors( - await this.embeddings.embedDocuments(texts), - documents - ); - } - - async addVectors(vectors: number[][], documents: Document[]): Promise { - const memoryVectors = vectors.map((embedding, idx) => ({ - content: documents[idx].pageContent, - embedding, - metadata: documents[idx].metadata, - })); - - this.memoryVectors = this.memoryVectors.concat(memoryVectors); - } - - async similaritySearchVectorWithScore( - query: number[], - k: number - ): Promise<[Document, number][]> { - const searches = this.memoryVectors - .map((vector, index) => ({ - similarity: this.similarity(query, vector.embedding), - index, - })) - .sort((a, b) => (a.similarity > b.similarity ? -1 : 0)) - .slice(0, k); - - const result: [Document, number][] = searches.map(search => [ - new Document({ - metadata: this.memoryVectors[search.index].metadata, - pageContent: this.memoryVectors[search.index].content, - }), - search.similarity, - ]); - - return result; - } - - static override async fromTexts( - texts: string[], - metadatas: object[] | object, - embeddings: Embeddings, - dbConfig?: MemoryVectorStoreArgs - ): Promise { - const docs: Document[] = []; - for (let i = 0; i < texts.length; i += 1) { - const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas; - const newDoc = new Document({ - pageContent: texts[i], - metadata, - }); - docs.push(newDoc); - } - return IndexedDBVectorStore.fromDocuments(docs, embeddings, dbConfig); - } - - static override async fromDocuments( - docs: Document[], - embeddings: Embeddings, - dbConfig?: MemoryVectorStoreArgs - ): Promise { - const instance = new this(embeddings, dbConfig); - await instance.addDocuments(docs); - return instance; - } - - static async fromExistingIndex( - embeddings: Embeddings, - dbConfig?: MemoryVectorStoreArgs - ): Promise { - const instance = new this(embeddings, dbConfig); - return instance; - } -} diff --git a/plugins/copilot/src/index.ts b/plugins/copilot/src/index.ts index 2206474fa3..4fc9bcc485 100644 --- a/plugins/copilot/src/index.ts +++ b/plugins/copilot/src/index.ts @@ -2,6 +2,7 @@ import type { PluginContext } from '@toeverything/plugin-infra/entry'; import { createElement } from 'react'; import { createRoot } from 'react-dom/client'; +import { DebugContent } from './UI/debug-content'; import { DetailContent } from './UI/detail-content'; import { HeaderItem } from './UI/header-item'; @@ -29,5 +30,19 @@ export const entry = (context: PluginContext) => { root.unmount(); }; }); + + context.register('setting', div => { + const root = createRoot(div); + root.render( + createElement( + context.utils.PluginProvider, + {}, + createElement(DebugContent) + ) + ); + return () => { + root.unmount(); + }; + }); return () => {}; }; diff --git a/plugins/hello-world/src/index.ts b/plugins/hello-world/src/index.ts index abcc6cd4d5..0b2165cbea 100644 --- a/plugins/hello-world/src/index.ts +++ b/plugins/hello-world/src/index.ts @@ -20,6 +20,14 @@ export const entry = (context: PluginContext) => { }; }); + context.register('formatBar', div => { + const root = createRoot(div); + root.render(createElement(HeaderItem)); + return () => { + root.unmount(); + }; + }); + return () => { console.log('unregister'); }; diff --git a/yarn.lock b/yarn.lock index ce44febf8e..c1dcde67b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,7 +164,7 @@ __metadata: "@types/marked": ^5.0.1 idb: ^7.1.1 jotai: ^2.2.2 - langchain: ^0.0.107 + langchain: ^0.0.118 marked: ^5.1.1 marked-gfm-heading-id: ^3.0.4 marked-mangle: ^1.1.0 @@ -657,7 +657,7 @@ __metadata: languageName: node linkType: hard -"@anthropic-ai/sdk@npm:^0.5.3": +"@anthropic-ai/sdk@npm:^0.5.7": version: 0.5.8 resolution: "@anthropic-ai/sdk@npm:0.5.8" dependencies: @@ -22258,11 +22258,11 @@ __metadata: languageName: node linkType: hard -"langchain@npm:^0.0.107": - version: 0.0.107 - resolution: "langchain@npm:0.0.107" +"langchain@npm:^0.0.118": + version: 0.0.118 + resolution: "langchain@npm:0.0.118" dependencies: - "@anthropic-ai/sdk": ^0.5.3 + "@anthropic-ai/sdk": ^0.5.7 ansi-styles: ^5.0.0 binary-extensions: ^2.2.0 camelcase: 6 @@ -22272,7 +22272,7 @@ __metadata: js-tiktoken: ^1.0.7 js-yaml: ^4.1.0 jsonpointer: ^5.0.1 - langchainplus-sdk: ^0.0.19 + langsmith: ~0.0.11 ml-distance: ^4.0.0 object-hash: ^3.0.0 openai: ^3.3.0 @@ -22285,6 +22285,7 @@ __metadata: zod-to-json-schema: ^3.20.4 peerDependencies: "@aws-sdk/client-dynamodb": ^3.310.0 + "@aws-sdk/client-kendra": ^3.352.0 "@aws-sdk/client-lambda": ^3.310.0 "@aws-sdk/client-s3": ^3.310.0 "@aws-sdk/client-sagemaker-runtime": ^3.310.0 @@ -22294,11 +22295,13 @@ __metadata: "@getmetal/metal-sdk": "*" "@getzep/zep-js": ^0.4.1 "@gomomento/sdk": ^1.23.0 + "@google-ai/generativelanguage": ^0.2.1 "@google-cloud/storage": ^6.10.1 "@huggingface/inference": ^1.5.1 "@notionhq/client": ^2.2.5 "@opensearch-project/opensearch": "*" "@pinecone-database/pinecone": "*" + "@planetscale/database": ^1.8.0 "@qdrant/js-client-rest": ^1.2.0 "@supabase/postgrest-js": ^1.1.1 "@supabase/supabase-js": ^2.10.0 @@ -22316,10 +22319,12 @@ __metadata: d3-dsv: ^2.0.0 epub2: ^3.0.1 faiss-node: ^0.2.1 - google-auth-library: ^8.8.0 + firebase-admin: ^11.9.0 + google-auth-library: ^8.9.0 hnswlib-node: ^1.4.2 html-to-text: ^9.0.5 ignore: ^5.2.0 + ioredis: ^5.3.2 mammoth: "*" mongodb: ^5.2.0 mysql2: ^3.3.3 @@ -22327,11 +22332,12 @@ __metadata: pdf-parse: 1.1.1 peggy: ^3.0.2 pg: ^8.11.0 + pg-copy-streams: ^6.0.5 pickleparser: ^0.1.0 playwright: ^1.32.1 puppeteer: ^19.7.2 redis: ^4.6.4 - replicate: ^0.9.0 + replicate: ^0.12.3 sonix-speech-recognition: ^2.1.1 srt-parser-2: ^1.2.2 typeorm: ^0.3.12 @@ -22341,6 +22347,8 @@ __metadata: peerDependenciesMeta: "@aws-sdk/client-dynamodb": optional: true + "@aws-sdk/client-kendra": + optional: true "@aws-sdk/client-lambda": optional: true "@aws-sdk/client-s3": @@ -22359,6 +22367,8 @@ __metadata: optional: true "@gomomento/sdk": optional: true + "@google-ai/generativelanguage": + optional: true "@google-cloud/storage": optional: true "@huggingface/inference": @@ -22369,6 +22379,8 @@ __metadata: optional: true "@pinecone-database/pinecone": optional: true + "@planetscale/database": + optional: true "@qdrant/js-client-rest": optional: true "@supabase/postgrest-js": @@ -22403,6 +22415,8 @@ __metadata: optional: true faiss-node: optional: true + firebase-admin: + optional: true google-auth-library: optional: true hnswlib-node: @@ -22411,6 +22425,8 @@ __metadata: optional: true ignore: optional: true + ioredis: + optional: true mammoth: optional: true mongodb: @@ -22425,6 +22441,8 @@ __metadata: optional: true pg: optional: true + pg-copy-streams: + optional: true pickleparser: optional: true playwright: @@ -22447,13 +22465,13 @@ __metadata: optional: true weaviate-ts-client: optional: true - checksum: d1f01321db83aebae5b619ade2060b2416459e1b55723793c0e3244a9ec8fe57775f8c159f406b85eb58b66761a59705e17e9a2efb522876e81e881056711227 + checksum: 080e56911adf4e869d30ad92228356468d21ebcfb2b67e88d1625faa2fc9c9b267b0fd5c0776a5de704794b7db5ae255d3a8204b52c09b5798d233ee226b7288 languageName: node linkType: hard -"langchainplus-sdk@npm:^0.0.19": - version: 0.0.19 - resolution: "langchainplus-sdk@npm:0.0.19" +"langsmith@npm:~0.0.11": + version: 0.0.15 + resolution: "langsmith@npm:0.0.15" dependencies: "@types/uuid": ^9.0.1 commander: ^10.0.1 @@ -22461,8 +22479,8 @@ __metadata: p-retry: 4 uuid: ^9.0.0 bin: - langchain: dist/cli/main.cjs - checksum: f0174c1e248e4bc5034a7dd182f703b895a485b6408aa518c91ff12b3f015febd5546eeb7f821c82b63a9d2b67a7ea903a1a57ad196049743f0934ff1c524ae8 + langsmith: dist/cli/main.cjs + checksum: d23111aa0e65d5c28ebe08dd846b12fd788cc08a9de068c76f4ba362a0e5009939380efd7662d154375809d549eaba3a6658890f2676fea9b94b95de36ce62f1 languageName: node linkType: hard