feat: add support for OpenAI-compatible embedding API (#776)

# PR Checklist
- [x] Have you checked if it works normally in all models? *Ignore this
if it doesn't use models.*
- [x] Have you checked if it works normally in all web, local, and node
hosted versions? If it doesn't, have you blocked it in those versions?
- [ ] Have you added type definitions?

# Preview

![preview](https://github.com/user-attachments/assets/ce0130ae-e340-465e-8b06-9a680e229b63)

# Description
This PR introduces support for OpenAI-compatible embedding API
This commit is contained in:
kwaroran
2025-03-05 05:37:32 +09:00
committed by GitHub
3 changed files with 34 additions and 9 deletions

View File

@@ -594,6 +594,7 @@
<OptionInput value="openai3small">OpenAI text-embedding-3-small</OptionInput> <OptionInput value="openai3small">OpenAI text-embedding-3-small</OptionInput>
<OptionInput value="openai3large">OpenAI text-embedding-3-large</OptionInput> <OptionInput value="openai3large">OpenAI text-embedding-3-large</OptionInput>
<OptionInput value="ada">OpenAI Ada</OptionInput> <OptionInput value="ada">OpenAI Ada</OptionInput>
<OptionInput value="custom">Custom (OpenAI-compatible)</OptionInput>
</SelectInput> </SelectInput>
{#if DBState.db.hypaModel === 'openai3small' || DBState.db.hypaModel === 'openai3large' || DBState.db.hypaModel === 'ada'} {#if DBState.db.hypaModel === 'openai3small' || DBState.db.hypaModel === 'openai3large' || DBState.db.hypaModel === 'ada'}
@@ -601,5 +602,14 @@
<TextInput size="sm" marginBottom bind:value={DBState.db.supaMemoryKey}/> <TextInput size="sm" marginBottom bind:value={DBState.db.supaMemoryKey}/>
{/if} {/if}
{#if DBState.db.hypaModel === 'custom'}
<span class="text-textcolor">URL</span>
<TextInput size="sm" marginBottom bind:value={DBState.db.hypaCustomSettings.url}/>
<span class="text-textcolor">Key/Password</span>
<TextInput size="sm" marginBottom bind:value={DBState.db.hypaCustomSettings.key}/>
<span class="text-textcolor">Request Model</span>
<TextInput size="sm" marginBottom bind:value={DBState.db.hypaCustomSettings.model}/>
{/if}
</Arcodion> </Arcodion>
{/if} {/if}

View File

@@ -37,14 +37,14 @@ export class HypaProcesser{
name: "hypaVector" name: "hypaVector"
}) })
this.vectors = [] this.vectors = []
if(model === 'auto'){
const db = getDatabase() const db = getDatabase()
if(model === 'auto'){
this.model = db.hypaModel || 'MiniLM' this.model = db.hypaModel || 'MiniLM'
} }
else{ else{
this.model = model this.model = model
} }
this.customEmbeddingUrl = customEmbeddingUrl this.customEmbeddingUrl = customEmbeddingUrl || db.hypaCustomSettings.url
} }
async embedDocuments(texts: string[]): Promise<VectorArray[]> { async embedDocuments(texts: string[]): Promise<VectorArray[]> {
@@ -78,11 +78,16 @@ export class HypaProcesser{
const {customEmbeddingUrl} = this const {customEmbeddingUrl} = this
const replaceUrl = customEmbeddingUrl.endsWith('/embeddings')?customEmbeddingUrl:appendLastPath(customEmbeddingUrl,'embeddings') const replaceUrl = customEmbeddingUrl.endsWith('/embeddings')?customEmbeddingUrl:appendLastPath(customEmbeddingUrl,'embeddings')
gf = await globalFetch(replaceUrl.toString(), { const db = getDatabase()
const fetchArgs = {
...(db.hypaCustomSettings.key ? {headers: {"Authorization": "Bearer " + db.hypaCustomSettings.key}} : {}),
body: { body: {
"input": input "input": input,
}, ...(db.hypaCustomSettings.model ? {"model": db.hypaCustomSettings.model} : {})
}) }
};
gf = await globalFetch(replaceUrl.toString(), fetchArgs)
} }
if(this.model === 'ada' || this.model === 'openai3small' || this.model === 'openai3large'){ if(this.model === 'ada' || this.model === 'openai3small' || this.model === 'openai3large'){
const db = getDatabase() const db = getDatabase()

View File

@@ -489,6 +489,11 @@ export function setDatabase(data:Database){
data.antiClaudeOverload = false data.antiClaudeOverload = false
data.antiServerOverloads = true data.antiServerOverloads = true
} }
data.hypaCustomSettings = {
url: data.hypaCustomSettings?.url ?? "",
key: data.hypaCustomSettings?.key ?? "",
model: data.hypaCustomSettings?.model ?? "",
}
changeLanguage(data.language) changeLanguage(data.language)
setDatabaseLite(data) setDatabaseLite(data)
} }
@@ -902,7 +907,7 @@ export interface Database{
preserveOrphanedMemory: boolean preserveOrphanedMemory: boolean
processRegexScript: boolean processRegexScript: boolean
doNotSummarizeUserMessage: boolean doNotSummarizeUserMessage: boolean
}, }
OaiCompAPIKeys: {[key:string]:string} OaiCompAPIKeys: {[key:string]:string}
inlayErrorResponse:boolean inlayErrorResponse:boolean
reasoningEffort:number reasoningEffort:number
@@ -913,6 +918,11 @@ export interface Database{
useExperimentalGoogleTranslator:boolean useExperimentalGoogleTranslator:boolean
thinkingTokens: number thinkingTokens: number
antiServerOverloads: boolean antiServerOverloads: boolean
hypaCustomSettings: {
url: string,
key: string,
model: string,
}
} }
interface SeparateParameters{ interface SeparateParameters{