mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix: copilot not working (#3425)
This commit is contained in:
@@ -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 = (
|
||||
<>
|
||||
<span>You can get your API key from </span>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://beta.openai.com/account/api-keys"
|
||||
>
|
||||
here.
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<SettingWrapper title={'Ai Copilot'}>
|
||||
<SettingRow name={'openAI API key'} desc={desc}></SettingRow>
|
||||
<FlexWrapper justifyContent="space-between">
|
||||
<Input
|
||||
defaultValue={key ?? undefined}
|
||||
onChange={useCallback(
|
||||
(newValue: string) => {
|
||||
setKey(newValue);
|
||||
},
|
||||
[setKey]
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
size="large"
|
||||
onClick={() => {
|
||||
indexedDB.deleteDatabase(conversationHistoryDBName);
|
||||
location.reload();
|
||||
}}
|
||||
>
|
||||
{'Clean conversations'}
|
||||
</Button>
|
||||
</FlexWrapper>
|
||||
</SettingWrapper>
|
||||
<FlexWrapper justifyContent="space-between">
|
||||
<Input
|
||||
defaultValue={key ?? undefined}
|
||||
onChange={useCallback(
|
||||
(newValue: string) => {
|
||||
setKey(newValue);
|
||||
},
|
||||
[setKey]
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
size="large"
|
||||
onClick={() => {
|
||||
indexedDB.deleteDatabase(conversationHistoryDBName);
|
||||
location.reload();
|
||||
}}
|
||||
>
|
||||
{'Clean conversations'}
|
||||
</Button>
|
||||
</FlexWrapper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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<string, unknown>;
|
||||
}
|
||||
|
||||
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<void> {
|
||||
const texts = documents.map(({ pageContent }) => pageContent);
|
||||
return this.addVectors(
|
||||
await this.embeddings.embedDocuments(texts),
|
||||
documents
|
||||
);
|
||||
}
|
||||
|
||||
async addVectors(vectors: number[][], documents: Document[]): Promise<void> {
|
||||
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<IndexedDBVectorStore> {
|
||||
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<IndexedDBVectorStore> {
|
||||
const instance = new this(embeddings, dbConfig);
|
||||
await instance.addDocuments(docs);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static async fromExistingIndex(
|
||||
embeddings: Embeddings,
|
||||
dbConfig?: MemoryVectorStoreArgs
|
||||
): Promise<IndexedDBVectorStore> {
|
||||
const instance = new this(embeddings, dbConfig);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -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 () => {};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user