From 6695c4bc74fda588c6eef9f7ae182cd91114dfff Mon Sep 17 00:00:00 2001 From: arvinxx Date: Thu, 9 May 2024 21:50:05 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20fix=20Perplexity=20duplic?= =?UTF-8?q?ate=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/chat/agentRuntime.ts | 7 +- src/config/server/provider.ts | 2 + .../agent-runtime/perplexity/index.test.ts | 4 +- src/libs/agent-runtime/perplexity/index.ts | 102 ++++-------------- 4 files changed, 32 insertions(+), 83 deletions(-) diff --git a/src/app/api/chat/agentRuntime.ts b/src/app/api/chat/agentRuntime.ts index 7ff149d766b0..57649b764c1a 100644 --- a/src/app/api/chat/agentRuntime.ts +++ b/src/app/api/chat/agentRuntime.ts @@ -93,9 +93,12 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => { return { baseURL }; } case ModelProvider.Perplexity: { - const { PERPLEXITY_API_KEY } = getServerConfig(); + const { PERPLEXITY_API_KEY, PERPLEXITY_PROXY_URL } = getServerConfig(); + const apiKey = apiKeyManager.pick(payload?.apiKey || PERPLEXITY_API_KEY); - return { apiKey }; + const baseURL = payload?.endpoint || PERPLEXITY_PROXY_URL; + + return { apiKey, baseURL }; } case ModelProvider.Anthropic: { const { ANTHROPIC_API_KEY, ANTHROPIC_PROXY_URL } = getServerConfig(); diff --git a/src/config/server/provider.ts b/src/config/server/provider.ts index f4b1657e0758..d1d497dab4a4 100644 --- a/src/config/server/provider.ts +++ b/src/config/server/provider.ts @@ -37,6 +37,7 @@ declare global { // Perplexity Provider ENABLED_PERPLEXITY?: string; PERPLEXITY_API_KEY?: string; + PERPLEXITY_PROXY_URL?: string; // Anthropic Provider ENABLED_ANTHROPIC?: string; @@ -173,6 +174,7 @@ export const getProviderConfig = () => { ENABLED_PERPLEXITY: !!PERPLEXITY_API_KEY, PERPLEXITY_API_KEY, + PERPLEXITY_PROXY_URL: process.env.PERPLEXITY_PROXY_URL, ENABLED_ANTHROPIC: !!ANTHROPIC_API_KEY, ANTHROPIC_API_KEY, diff --git a/src/libs/agent-runtime/perplexity/index.test.ts b/src/libs/agent-runtime/perplexity/index.test.ts index 21ed19654bd3..07e29fa5eaa3 100644 --- a/src/libs/agent-runtime/perplexity/index.test.ts +++ b/src/libs/agent-runtime/perplexity/index.test.ts @@ -2,7 +2,7 @@ import OpenAI from 'openai'; import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { ChatStreamCallbacks } from '@/libs/agent-runtime'; +import { ChatStreamCallbacks, LobeOpenAICompatibleRuntime } from '@/libs/agent-runtime'; import * as debugStreamModule from '../utils/debugStream'; import { LobePerplexityAI } from './index'; @@ -15,7 +15,7 @@ const invalidErrorType = 'InvalidPerplexityAPIKey'; // Mock the console.error to avoid polluting test output vi.spyOn(console, 'error').mockImplementation(() => {}); -let instance: LobePerplexityAI; +let instance: LobeOpenAICompatibleRuntime; beforeEach(() => { instance = new LobePerplexityAI({ apiKey: 'test' }); diff --git a/src/libs/agent-runtime/perplexity/index.ts b/src/libs/agent-runtime/perplexity/index.ts index 391f41d86596..061c2a5a6e7f 100644 --- a/src/libs/agent-runtime/perplexity/index.ts +++ b/src/libs/agent-runtime/perplexity/index.ts @@ -1,85 +1,29 @@ -import { OpenAIStream, StreamingTextResponse } from 'ai'; -import OpenAI, { ClientOptions } from 'openai'; +import OpenAI from 'openai'; -import { LobeRuntimeAI } from '../BaseAI'; import { AgentRuntimeErrorType } from '../error'; -import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types'; -import { AgentRuntimeError } from '../utils/createError'; -import { debugStream } from '../utils/debugStream'; -import { desensitizeUrl } from '../utils/desensitizeUrl'; -import { handleOpenAIError } from '../utils/handleOpenAIError'; +import { ChatStreamPayload, ModelProvider } from '../types'; +import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory'; -const DEFAULT_BASE_URL = 'https://api.perplexity.ai'; - -export class LobePerplexityAI implements LobeRuntimeAI { - private client: OpenAI; - - baseURL: string; - - constructor({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions) { - if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidPerplexityAPIKey); - - this.client = new OpenAI({ apiKey, baseURL, ...res }); - this.baseURL = this.client.baseURL; - } - - async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) { - try { +export const LobePerplexityAI = LobeOpenAICompatibleFactory({ + baseURL: 'https://api.perplexity.ai', + chatCompletion: { + handlePayload: (payload: ChatStreamPayload) => { // Set a default frequency penalty value greater than 0 - const defaultFrequencyPenalty = 0.1; - const chatPayload = { + const defaultFrequencyPenalty = 1; + + return { ...payload, frequency_penalty: payload.frequency_penalty || defaultFrequencyPenalty, - }; - const response = await this.client.chat.completions.create( - chatPayload as unknown as OpenAI.ChatCompletionCreateParamsStreaming, - { signal: options?.signal }, - ); - const [prod, debug] = response.tee(); - - if (process.env.DEBUG_PERPLEXITY_CHAT_COMPLETION === '1') { - debugStream(debug.toReadableStream()).catch(console.error); - } - - return new StreamingTextResponse(OpenAIStream(prod, options?.callback), { - headers: options?.headers, - }); - } catch (error) { - let desensitizedEndpoint = this.baseURL; - - if (this.baseURL !== DEFAULT_BASE_URL) { - desensitizedEndpoint = desensitizeUrl(this.baseURL); - } - - if ('status' in (error as any)) { - switch ((error as Response).status) { - case 401: { - throw AgentRuntimeError.chat({ - endpoint: desensitizedEndpoint, - error: error as any, - errorType: AgentRuntimeErrorType.InvalidPerplexityAPIKey, - provider: ModelProvider.Perplexity, - }); - } - - default: { - break; - } - } - } - - const { errorResult, RuntimeError } = handleOpenAIError(error); - - const errorType = RuntimeError || AgentRuntimeErrorType.PerplexityBizError; - - throw AgentRuntimeError.chat({ - endpoint: desensitizedEndpoint, - error: errorResult, - errorType, - provider: ModelProvider.Perplexity, - }); - } - } -} - -export default LobePerplexityAI; + stream: true, + } as OpenAI.ChatCompletionCreateParamsStreaming; + }, + }, + debug: { + chatCompletion: () => process.env.DEBUG_PERPLEXITY_CHAT_COMPLETION === '1', + }, + errorType: { + bizError: AgentRuntimeErrorType.PerplexityBizError, + invalidAPIKey: AgentRuntimeErrorType.InvalidPerplexityAPIKey, + }, + provider: ModelProvider.Perplexity, +});