diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index ca4cf422..7b350017 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -185,7 +185,7 @@ const Chat: React.FC = ({ const content = await getFileContent(file, app.vault); const tags = await getTagsFromNote(file, app.vault); if (content) { - notes.push({ name: getFileName(file), content, tags}); + notes.push({ name: getFileName(file), content, tags }); } } @@ -456,6 +456,7 @@ const Chat: React.FC = ({ addMessage={addMessage} vault={app.vault} vault_qa_strategy={plugin.settings.indexVaultToVectorStore} + proxyServer={plugin.proxyServer} /> void; vault: Vault; vault_qa_strategy: string; + proxyServer: ProxyServer; } const ChatIcons: React.FC = ({ @@ -52,9 +52,9 @@ const ChatIcons: React.FC = ({ addMessage, vault, vault_qa_strategy, + proxyServer, }) => { const [selectedChain, setSelectedChain] = useState(currentChain); - const proxyServer = new ProxyServer(PROXY_SERVER_PORT); const handleModelChange = async (event: React.ChangeEvent) => { const selectedModel = event.target.value; @@ -69,6 +69,23 @@ const ChatIcons: React.FC = ({ } }; + useEffect(() => { + // If Claude is the default, start the proxy server + const startProxyServerForClaude = async () => { + if (currentModel === ChatModelDisplayNames.CLAUDE) { + await proxyServer.startProxyServer('https://api.anthropic.com/'); + } + }; + + // Call the function on component mount + startProxyServerForClaude(); + + // Cleanup function to stop the proxy server when the component unmounts + return () => { + proxyServer.stopProxyServer().catch(console.error); + }; + }, [currentModel, proxyServer]); + const handleChainChange = async ( event: React.ChangeEvent ) => { diff --git a/src/main.ts b/src/main.ts index ea735b07..cd4d6001 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,10 +12,12 @@ import { CHAT_VIEWTYPE, DEFAULT_SETTINGS, DEFAULT_SYSTEM_PROMPT, + PROXY_SERVER_PORT, VAULT_VECTOR_STORE_STRATEGY, } from "@/constants"; import { CustomPrompt } from "@/customPromptProcessor"; import EncryptionService from "@/encryptionService"; +import { ProxyServer } from "@/proxyServer"; import { CopilotSettingTab, CopilotSettings } from "@/settings/SettingsPage"; import SharedState from "@/sharedState"; import { @@ -25,7 +27,6 @@ import { } from "@/utils"; import VectorDBManager, { VectorStoreDocument } from "@/vectorDBManager"; import { MD5 } from "crypto-js"; -import { Server } from "http"; import { Editor, Notice, Plugin, TFile, WorkspaceLeaf } from "obsidian"; import PouchDB from "pouchdb"; @@ -41,12 +42,13 @@ export default class CopilotPlugin extends Plugin { dbVectorStores: PouchDB.Database; embeddingsManager: EmbeddingsManager; encryptionService: EncryptionService; - server: Server | null = null; + proxyServer: ProxyServer; isChatVisible = () => this.chatIsVisible; async onload(): Promise { await this.loadSettings(); + this.proxyServer = new ProxyServer(PROXY_SERVER_PORT); this.addSettingTab(new CopilotSettingTab(this.app, this)); // Always have one instance of sharedState and chainManager in the plugin this.sharedState = new SharedState(); diff --git a/src/proxyServer.ts b/src/proxyServer.ts index e3d11e5c..69c071e3 100644 --- a/src/proxyServer.ts +++ b/src/proxyServer.ts @@ -1,7 +1,7 @@ -import cors from '@koa/cors'; -import Koa from 'koa'; -import proxy from 'koa-proxies'; -import net from 'net'; +import cors from "@koa/cors"; +import Koa from "koa"; +import proxy from "koa-proxies"; +import net from "net"; export class ProxyServer { private port: number; @@ -12,29 +12,25 @@ export class ProxyServer { } async startProxyServer(proxyBaseUrl: string) { - console.log('loading plugin'); - // check if the port is already in use - const inUse = await this.checkPortInUse(this.port); + console.log("Attempting to start proxy server..."); - if (!inUse) { - // Create a new Koa application - const app = new Koa(); + const app = new Koa(); + app.use(cors()); + app.use(proxy("/", { target: proxyBaseUrl, changeOrigin: true })); - app.use(cors()); + // Create the server and attach error handling for "EADDRINUSE" + this.server = app.listen(this.port); + this.server.on("error", (err: NodeJS.ErrnoException) => { + if (err.code === "EADDRINUSE") { + console.error(`Proxy server port ${this.port} is already in use.`); + } else { + console.error(`Failed to start proxy server: ${err.message}`); + } + }); - // Create and apply the proxy middleware - app.use(proxy('/', { - // your target API, e.g. https://api.anthropic.com/ - target: proxyBaseUrl, - changeOrigin: true, - })); - - // Start the server on the specified port - this.server = app.listen(this.port); + this.server.on("listening", () => { console.log(`Proxy server running on http://localhost:${this.port}`); - } else { - console.error(`Port ${this.port} is in use`); - } + }); } async stopProxyServer() { @@ -42,24 +38,4 @@ export class ProxyServer { this.server.close(); } } - - checkPortInUse(port: number) { - return new Promise((resolve, reject) => { - const server = net.createServer() - .once('error', (err: NodeJS.ErrnoException) => { - if (err.code === 'EADDRINUSE') { - resolve(true); // Port is in use - } else { - reject(err); - } - }) - .once('listening', () => { - server.once('close', () => { - resolve(false); // Port is not in use - }) - .close(); - }) - .listen(port); - }); - } -} \ No newline at end of file +}