From 6c60863694c0b2c7f2eff4e2402219bdf1ea193a Mon Sep 17 00:00:00 2001 From: Logan Yang Date: Wed, 19 Jul 2023 18:17:08 -0700 Subject: [PATCH] Add support for 3rd party openai proxy (#113) --- manifest.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/aiState.ts | 12 ++++++++++-- src/constants.ts | 1 + src/langchainWrappers.ts | 18 ++++++++++++++++++ src/main.ts | 2 ++ src/settings.ts | 23 +++++++++++++++++++++++ versions.json | 3 ++- 9 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 src/langchainWrappers.ts diff --git a/manifest.json b/manifest.json index e50a0c29..eff1c5bc 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "copilot", "name": "Copilot", - "version": "2.3.5", + "version": "2.3.6", "minAppVersion": "0.15.0", "description": "A ChatGPT Copilot in Obsidian.", "author": "Logan Yang", diff --git a/package-lock.json b/package-lock.json index d834535a..2225d6d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-copilot", - "version": "2.3.5", + "version": "2.3.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-copilot", - "version": "2.3.5", + "version": "2.3.6", "license": "AGPL-3.0", "dependencies": { "@huggingface/inference": "^1.8.0", diff --git a/package.json b/package.json index f9e77435..b102b258 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-copilot", - "version": "2.3.5", + "version": "2.3.6", "description": "ChatGPT integration for Obsidian", "main": "main.js", "scripts": { diff --git a/src/aiState.ts b/src/aiState.ts index 6fcf117d..8f04340e 100644 --- a/src/aiState.ts +++ b/src/aiState.ts @@ -44,6 +44,7 @@ import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"; import { MemoryVectorStore } from "langchain/vectorstores/memory"; import { Notice } from 'obsidian'; import { useState } from 'react'; +import { ProxyChatOpenAI } from './langchainWrappers'; interface ModelConfig { @@ -59,6 +60,7 @@ interface ModelConfig { azureOpenAIApiInstanceName?: string, azureOpenAIApiDeploymentName?: string, azureOpenAIApiVersion?: string, + openAIProxyBaseUrl?: string, } export interface LangChainParams { @@ -80,6 +82,7 @@ export interface LangChainParams { embeddingProvider: string, chainType: ChainType, // Default ChainType is set in main.ts getAIStateParams options: SetChainOptions, + openAIProxyBaseUrl?: string, } export interface SetChainOptions { @@ -161,6 +164,7 @@ class AIState { model, temperature, maxTokens, + openAIProxyBaseUrl, } = this.langChainParams; // Create a base configuration that applies to all models @@ -169,7 +173,7 @@ class AIState { temperature: temperature, streaming: true, maxRetries: 3, - maxConcurrency: 3 + maxConcurrency: 3, }; switch(chatModelProvider) { @@ -178,6 +182,7 @@ class AIState { ...config, openAIApiKey, maxTokens, + openAIProxyBaseUrl, }; break; case ANTHROPIC: @@ -211,11 +216,14 @@ class AIState { } > = {}; + const OpenAIChatModel = this.langChainParams.openAIProxyBaseUrl + ? ProxyChatOpenAI : ChatOpenAI; + // Build modelMap for (const modelDisplayNameKey of OPENAI_MODELS) { modelMap[modelDisplayNameKey] = { hasApiKey: Boolean(this.langChainParams.openAIApiKey), - AIConstructor: ChatOpenAI, + AIConstructor: OpenAIChatModel, vendor: OPENAI, }; } diff --git a/src/constants.ts b/src/constants.ts index a5c75ed3..12594920 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -104,6 +104,7 @@ export const DEFAULT_SETTINGS: CopilotSettings = { contextTurns: 3, useNotesAsContext: false, userSystemPrompt: '', + openAIProxyBaseUrl: '', stream: true, embeddingProvider: OPENAI, debug: false, diff --git a/src/langchainWrappers.ts b/src/langchainWrappers.ts new file mode 100644 index 00000000..d112da5b --- /dev/null +++ b/src/langchainWrappers.ts @@ -0,0 +1,18 @@ +import { ChatOpenAI } from 'langchain/chat_models/openai'; +import { Configuration, OpenAIApi } from "openai"; + +export class ProxyChatOpenAI extends ChatOpenAI { + constructor( + fields?: any, + ) { + super(fields ?? {}); + + const clientConfig = new Configuration({ + ...this["clientConfig"], + basePath: fields.openAIProxyBaseUrl, + }); + + // Reinitialize the client with the updated clientConfig + this["client"] = new OpenAIApi(clientConfig); + } +} diff --git a/src/main.ts b/src/main.ts index 4738751b..0db34a4c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -32,6 +32,7 @@ export interface CopilotSettings { contextTurns: number; useNotesAsContext: boolean; userSystemPrompt: string; + openAIProxyBaseUrl: string; stream: boolean; embeddingProvider: string; debug: boolean; @@ -471,6 +472,7 @@ export default class CopilotPlugin extends Plugin { embeddingProvider: embeddingProvider, chainType: ChainType.LLM_CHAIN, // Set LLM_CHAIN as default ChainType options: { forceNewCreation: true } as SetChainOptions, + openAIProxyBaseUrl: this.settings.openAIProxyBaseUrl, }; } } diff --git a/src/settings.ts b/src/settings.ts index 737f6ec1..bdf50429 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -422,6 +422,29 @@ export class CopilotSettingTab extends PluginSettingTab { }); }); + new Setting(containerEl) + .setName("OpenAI Proxy Base URL (3rd-party providers)") + .setDesc( + createFragment((frag) => { + frag.createEl( + 'strong', + { text: "CAUTION: This will override the default OpenAI API URL! Use with discretion!" } + ); + frag.createEl('br'); + frag.appendText("Leave blank to use the official OpenAI API."); + }) + ) + .addText((text) => { + text.inputEl.style.width = "100%"; + text + .setPlaceholder("https://openai.example.com/v1") + .setValue(this.plugin.settings.openAIProxyBaseUrl) + .onChange(async (value) => { + this.plugin.settings.openAIProxyBaseUrl = value; + await this.plugin.saveSettings(); + }) + }); + containerEl.createEl('h4', { text: 'Development mode' }); new Setting(containerEl) diff --git a/versions.json b/versions.json index 19a77ba0..69436235 100644 --- a/versions.json +++ b/versions.json @@ -19,5 +19,6 @@ "2.3.2": "0.15.0", "2.3.3": "0.15.0", "2.3.4": "0.15.0", - "2.3.5": "0.15.0" + "2.3.5": "0.15.0", + "2.3.6": "0.15.0" } \ No newline at end of file