Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/aritralegndery_lobe-chat.json
T

1 line
12 KiB
JSON

{"repo": "aritralegndery/lobe-chat", "files": {"Dockerfile": {"83bdb185238ce79006f4d32f5deb921dca6223ce": {"t": 1785746999.5288472, "n": 3570, "h": "246118d1e37c456c", "c": "## Base image for all the stages\nFROM node:20-alpine AS base\n\nRUN \\\n # Add user nextjs to run the app\n addgroup --system --gid 1001 nodejs \\\n && adduser --system --uid 1001 nextjs\n\n## Builder image, install all the dependencies and build the app\nFROM base AS builder\n\nARG USE_NPM_CN_MIRROR\n\nENV NEXT_PUBLIC_BASE_PATH=\"\"\n\n# Sentry\nENV NEXT_PUBLIC_SENTRY_DSN=\"\" \\\n SENTRY_ORG=\"\" \\\n SENTRY_PROJECT=\"\"\n\n# Posthog\nENV NEXT_PUBLIC_ANALYTICS_POSTHOG=\"\" \\\n NEXT_PUBLIC_POSTHOG_HOST=\"\" \\\n NEXT_PUBLIC_POSTHOG_KEY=\"\"\n\n# Umami\nENV NEXT_PUBLIC_ANALYTICS_UMAMI=\"\" \\\n NEXT_PUBLIC_UMAMI_SCRIPT_URL=\"\" \\\n NEXT_PUBLIC_UMAMI_WEBSITE_ID=\"\"\n\n# Node\nENV NODE_OPTIONS=\"--max-old-space-size=8192\"\n\nWORKDIR /app\n\nCOPY package.json ./\nCOPY .npmrc ./\n\nRUN \\\n # If you want to build docker in China, build with --build-arg USE_NPM_CN_MIRROR=true\n if [ \"${USE_NPM_CN_MIRROR:-false}\" = \"true\" ]; then \\\n export SENTRYCLI_CDNURL=\"https://npmmirror.com/mirrors/sentry-cli\"; \\\n npm config set registry \"https://registry.npmmirror.com/\"; \\\n fi \\\n # Set the registry for corepack\n && export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\\/$//') \\\n # Enable corepack\n && corepack enable \\\n # Use pnpm for corepack\n && corepack use pnpm \\\n # Install the dependencies\n && pnpm i \\\n # Add sharp dependencies\n && mkdir -p /sharp \\\n && pnpm add sharp --prefix /sharp\n\nCOPY . .\n\n# run build standalone for docker version\nRUN npm run build:docker\n\n## Application image, copy all the files for production\nFROM scratch AS app\n\nCOPY --from=builder /app/public /app/public\n\n# Automatically leverage output traces to reduce image size\n# https://nextjs.org/docs/advanced-features/output-file-tracing\nCOPY --from=builder /app/.next/standalone /app/\nCOPY --from=builder /app/.next/static /app/.next/static\nCOPY --from=builder /sharp/node_modules/.pnpm /app/node_modules/.pnpm\n\n## Production image, copy all the files and run next\nFROM base\n\n# Copy all the files from app, set the correct permission for prerender cache\nCOPY --from=app --chown=nextjs:nodejs /app /app\n\nENV NODE_ENV=\"production\"\n\n# set hostname to localhost\nENV HOSTNAME=\"0.0.0.0\" \\\n PORT=\"3210\"\n\n# General Variables\nENV ACCESS_CODE=\"\" \\\n API_KEY_SELECT_MODE=\"\" \\\n FEATURE_FLAGS=\"\"\n\n# Model Variables\nENV \\\n # Ai360\n AI360_API_KEY=\"\" \\\n # Anthropic\n ANTHROPIC_API_KEY=\"\" ANTHROPIC_PROXY_URL=\"\" \\\n # Amazon Bedrock\n AWS_ACCESS_KEY_ID=\"\" AWS_SECRET_ACCESS_KEY=\"\" AWS_REGION=\"\" \\\n # Azure OpenAI\n AZURE_API_KEY=\"\" AZURE_API_VERSION=\"\" AZURE_ENDPOINT=\"\" AZURE_MODEL_LIST=\"\" \\\n # Baichuan\n BAICHUAN_API_KEY=\"\" \\\n # DeepSeek\n DEEPSEEK_API_KEY=\"\" \\\n # Google\n GOOGLE_API_KEY=\"\" GOOGLE_PROXY_URL=\"\" \\\n # Groq\n GROQ_API_KEY=\"\" GROQ_PROXY_URL=\"\" \\\n # Minimax\n MINIMAX_API_KEY=\"\" \\\n # Mistral\n MISTRAL_API_KEY=\"\" \\\n # Moonshot\n MOONSHOT_API_KEY=\"\" MOONSHOT_PROXY_URL=\"\" \\\n # Novita\n NOVITA_API_KEY=\"\" \\\n # Ollama\n OLLAMA_MODEL_LIST=\"\" OLLAMA_PROXY_URL=\"\" \\\n # OpenAI\n OPENAI_API_KEY=\"\" OPENAI_MODEL_LIST=\"\" OPENAI_PROXY_URL=\"\" \\\n # OpenRouter\n OPENROUTER_API_KEY=\"\" OPENROUTER_MODEL_LIST=\"\" \\\n # Perplexity\n PERPLEXITY_API_KEY=\"\" PERPLEXITY_PROXY_URL=\"\" \\\n # Qwen\n QWEN_API_KEY=\"\" \\\n # Stepfun\n STEPFUN_API_KEY=\"\" \\\n # Taichu\n TAICHU_API_KEY=\"\" \\\n # TogetherAI\n TOGETHERAI_API_KEY=\"\" TOGETHERAI_MODEL_LIST=\"\" \\\n # 01.AI\n ZEROONE_API_KEY=\"\" \\\n # Zhipu\n ZHIPU_API_KEY=\"\"\n\nUSER nextjs\n\nEXPOSE 3210/tcp\n\nCMD [\"node\", \"/app/server.js\"]\n"}}, "src/libs/agent-runtime/ai360/index.test.ts": {"83bdb185238ce79006f4d32f5deb921dca6223ce": {"t": 1785809837.1725013, "n": 7744, "h": "0a90fc2c380d8604", "c": "// @vitest-environment node\nimport OpenAI from 'openai';\nimport { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n ChatStreamCallbacks,\n LobeOpenAICompatibleRuntime,\n ModelProvider,\n} from '@/libs/agent-runtime';\n\nimport * as debugStreamModule from '../utils/debugStream';\nimport { LobeAi360AI } from './index';\n\nconst provider = ModelProvider.Ai360;\nconst defaultBaseURL = 'https://ai.360.cn/v1';\n\nconst bizErrorType = 'ProviderBizError';\nconst invalidErrorType = 'InvalidProviderAPIKey';\n\n// Mock the console.error to avoid polluting test output\nvi.spyOn(console, 'error').mockImplementation(() => {});\n\nlet instance: LobeOpenAICompatibleRuntime;\n\nbeforeEach(() => {\n instance = new LobeAi360AI({ apiKey: 'test' });\n\n // 使用 vi.spyOn 来模拟 chat.completions.create 方法\n vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(\n new ReadableStream() as any,\n );\n});\n\nafterEach(() => {\n vi.clearAllMocks();\n});\n\ndescribe('LobeAi360AI', () => {\n describe('init', () => {\n it('should correctly initialize with an API key', async () => {\n const instance = new LobeAi360AI({ apiKey: 'test_api_key' });\n expect(instance).toBeInstanceOf(LobeAi360AI);\n expect(instance.baseURL).toEqual(defaultBaseURL);\n });\n });\n\n describe('chat', () => {\n describe('Error', () => {\n it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {\n // Arrange\n const apiError = new OpenAI.APIError(\n 400,\n {\n status: 400,\n error: {\n message: 'Bad Request',\n },\n },\n 'Error message',\n {},\n );\n\n vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);\n\n // Act\n try {\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n temperature: 0,\n });\n } catch (e) {\n expect(e).toEqual({\n endpoint: defaultBaseURL,\n error: {\n error: { message: 'Bad Request' },\n status: 400,\n },\n errorType: bizErrorType,\n provider,\n });\n }\n });\n\n it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {\n try {\n new LobeAi360AI({});\n } catch (e) {\n expect(e).toEqual({ errorType: invalidErrorType });\n }\n });\n\n it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {\n // Arrange\n const errorInfo = {\n stack: 'abc',\n cause: {\n message: 'api is undefined',\n },\n };\n const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});\n\n vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);\n\n // Act\n try {\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n temperature: 0,\n });\n } catch (e) {\n expect(e).toEqual({\n endpoint: defaultBaseURL,\n error: {\n cause: { message: 'api is undefined' },\n stack: 'abc',\n },\n errorType: bizErrorType,\n provider,\n });\n }\n });\n\n it('should return OpenAIBizError with an cause response with desensitize Url', async () => {\n // Arrange\n const errorInfo = {\n stack: 'abc',\n cause: { message: 'api is undefined' },\n };\n const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});\n\n instance = new LobeAi360AI({\n apiKey: 'test',\n\n baseURL: 'https://api.abc.com/v1',\n });\n\n vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);\n\n // Act\n try {\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n temperature: 0,\n });\n } catch (e) {\n expect(e).toEqual({\n endpoint: 'https://api.***.com/v1',\n error: {\n cause: { message: 'api is undefined' },\n stack: 'abc',\n },\n errorType: bizErrorType,\n provider,\n });\n }\n });\n\n it('should throw an InvalidAi360APIKey error type on 401 status code', async () => {\n // Mock the API call to simulate a 401 error\n const error = new Error('Unauthorized') as any;\n error.status = 401;\n vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);\n\n try {\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n temperature: 0,\n });\n } catch (e) {\n // Expect the chat method to throw an error with InvalidAi360APIKey\n expect(e).toEqual({\n endpoint: defaultBaseURL,\n error: new Error('Unauthorized'),\n errorType: invalidErrorType,\n provider,\n });\n }\n });\n\n it('should return AgentRuntimeError for non-OpenAI errors', async () => {\n // Arrange\n const genericError = new Error('Generic Error');\n\n vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);\n\n // Act\n try {\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n temperature: 0,\n });\n } catch (e) {\n expect(e).toEqual({\n endpoint: defaultBaseURL,\n errorType: 'AgentRuntimeError',\n provider,\n error: {\n name: genericError.name,\n cause: genericError.cause,\n message: genericError.message,\n stack: genericError.stack,\n },\n });\n }\n });\n });\n\n describe('DEBUG', () => {\n it('should call debugStream and return StreamingTextResponse when DEBUG_AI360_CHAT_COMPLETION is 1', async () => {\n // Arrange\n const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流\n const mockDebugStream = new ReadableStream({\n start(controller) {\n controller.enqueue('Debug stream content');\n controller.close();\n },\n }) as any;\n mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法\n\n // 模拟 chat.completions.create 返回值,包括模拟的 tee 方法\n (instance['client'].chat.completions.create as Mock).mockResolvedValue({\n tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }],\n });\n\n // 保存原始环境变量值\n const originalDebugValue = process.env.DEBUG_AI360_CHAT_COMPLETION;\n\n // 模拟环境变量\n process.env.DEBUG_AI360_CHAT_COMPLETION = '1';\n vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve());\n\n // 执行测试\n // 运行你的测试函数,确保它会在条件满足时调用 debugStream\n // 假设的测试函数调用,你可能需要根据实际情况调整\n await instance.chat({\n messages: [{ content: 'Hello', role: 'user' }],\n model: '360gpt-turbo',\n stream: true,\n temperature: 0,\n });\n\n // 验证 debugStream 被调用\n expect(debugStreamModule.debugStream).toHaveBeenCalled();\n\n // 恢复原始环境变量值\n process.env.DEBUG_AI360_CHAT_COMPLETION = originalDebugValue;\n });\n });\n });\n});\n"}}}}