mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-12 13:03:43 +08:00
Compare commits
51 Commits
Leizhenpen
...
bff6a5f226
Author | SHA1 | Date | |
---|---|---|---|
|
bff6a5f226 | ||
|
f72aadc35d | ||
|
cd0366392a | ||
|
f682b1f4de | ||
|
3aae552167 | ||
|
9a865fd76f | ||
|
a5caf98db0 | ||
|
4093e4c500 | ||
|
04cbadb197 | ||
|
78e8cb31c2 | ||
|
fc9688a1f7 | ||
|
48469bd8ca | ||
|
5a5e887f2b | ||
|
b6f5d75656 | ||
|
0d41a17ef6 | ||
|
f7cde17919 | ||
|
570cbb34b6 | ||
|
7aa9ae0a3e | ||
|
2d4180f5be | ||
|
9f0182b55e | ||
|
ad6666eeaf | ||
|
a2c4e468a0 | ||
|
2167076652 | ||
|
e123076250 | ||
|
ebcb4db245 | ||
|
0a25a1a8cb | ||
|
f3154b20a5 | ||
|
b709ee3983 | ||
|
f5f3ce94f6 | ||
|
2b5f600308 | ||
|
b966107117 | ||
|
377480b448 | ||
|
8bd0d6a1a7 | ||
|
90827fc593 | ||
|
008e339b6d | ||
|
12863f5213 | ||
|
cf140d4228 | ||
|
476d946f96 | ||
|
9714258322 | ||
|
48cd4b11b5 | ||
|
77c78b230a | ||
|
b44686b887 | ||
|
34bdd4b945 | ||
|
b0758cccde | ||
|
98a11e56d2 | ||
|
86f86962fb | ||
|
2137aa65bf | ||
|
18fa2cc30d | ||
|
0bfc648085 | ||
|
9f91c2d05c | ||
|
a029b4330b |
@@ -57,7 +57,7 @@ DISABLE_FAST_LINK=
|
||||
# (optional)
|
||||
# Default: Empty
|
||||
# To control custom models, use + to add a custom model, use - to hide a model, use name=displayName to customize model name, separated by comma.
|
||||
CUSTOM_MODELS=
|
||||
CUSTOM_MODELS=-all,+gpt-4o-2024-11-20@openai=gpt-4o,+gpt-4o-mini@openai,+us.anthropic.claude-3-5-sonnet-20241022-v2:0@bedrock=sonnet
|
||||
|
||||
# (optional)
|
||||
# Default: Empty
|
||||
@@ -81,3 +81,22 @@ SILICONFLOW_API_KEY=
|
||||
|
||||
### siliconflow Api url (optional)
|
||||
SILICONFLOW_URL=
|
||||
|
||||
# --- AWS Bedrock Section ---
|
||||
# Ensure these lines for keys either have placeholder values like below,
|
||||
# are commented out entirely, or removed if they shouldn't be in the template.
|
||||
|
||||
# AWS Access Key for Bedrock API (Example: Use placeholder or comment out)
|
||||
# AWS_ACCESS_KEY_ID=
|
||||
|
||||
# AWS Secret Access Key for Bedrock API (Example: Use placeholder or comment out)
|
||||
# AWS_SECRET_ACCESS_KEY=
|
||||
|
||||
# AWS Region for Bedrock API (e.g. us-east-1, us-west-2)
|
||||
AWS_REGION=
|
||||
|
||||
# Enable AWS Bedrock models (set to "true" to enable)
|
||||
ENABLE_AWS_BEDROCK=
|
||||
|
||||
# Custom endpoint URL for AWS Bedrock (optional)
|
||||
AWS_BEDROCK_ENDPOINT=
|
||||
|
@@ -1,13 +1,13 @@
|
||||
<div align="center">
|
||||
|
||||
<a href='https://nextchat.dev/chat'>
|
||||
<a href='https://nextchat.club'>
|
||||
<img src="https://github.com/user-attachments/assets/83bdcc07-ae5e-4954-a53a-ac151ba6ccf3" width="1000" alt="icon"/>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
<h1 align="center">NextChat (ChatGPT Next Web)</h1>
|
||||
<h1 align="center">NextChat</h1>
|
||||
|
||||
English / [简体中文](./README_CN.md)
|
||||
|
||||
@@ -22,10 +22,10 @@ English / [简体中文](./README_CN.md)
|
||||
[![MacOS][MacOS-image]][download-url]
|
||||
[![Linux][Linux-image]][download-url]
|
||||
|
||||
[NextChatAI](https://nextchat.dev/chat?utm_source=readme) / [Web App Demo](https://app.nextchat.dev) / [Desktop App](https://github.com/Yidadaa/ChatGPT-Next-Web/releases)
|
||||
[NextChatAI](https://nextchat.club?utm_source=readme) / [Web App Demo](https://app.nextchat.dev) / [Desktop App](https://github.com/Yidadaa/ChatGPT-Next-Web/releases) / [Discord](https://discord.gg/YCkeafCafC) / [Enterprise Edition](#enterprise-edition) / [Twitter](https://twitter.com/NextChatDev)
|
||||
|
||||
|
||||
[saas-url]: https://nextchat.dev/chat?utm_source=readme
|
||||
[saas-url]: https://nextchat.club?utm_source=readme
|
||||
[saas-image]: https://img.shields.io/badge/NextChat-Saas-green?logo=microsoftedge
|
||||
[web-url]: https://app.nextchat.dev/
|
||||
[download-url]: https://github.com/Yidadaa/ChatGPT-Next-Web/releases
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
一键免费部署你的私人 ChatGPT 网页应用,支持 Claude, GPT4 & Gemini Pro 模型。
|
||||
|
||||
[NextChatAI](https://nextchat.dev/chat?utm_source=readme) / [企业版](#%E4%BC%81%E4%B8%9A%E7%89%88) / [演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 Discord](https://discord.gg/zrhvHCr79N)
|
||||
[NextChatAI](https://nextchat.club?utm_source=readme) / [企业版](#%E4%BC%81%E4%B8%9A%E7%89%88) / [演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 Discord](https://discord.gg/zrhvHCr79N)
|
||||
|
||||
[<img src="https://vercel.com/button" alt="Deploy on Zeabur" height="30">](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FChatGPTNextWeb%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=nextchat&repository-name=NextChat) [<img src="https://zeabur.com/button.svg" alt="Deploy on Zeabur" height="30">](https://zeabur.com/templates/ZBUEFA) [<img src="https://gitpod.io/button/open-in-gitpod.svg" alt="Open in Gitpod" height="30">](https://gitpod.io/#https://github.com/Yidadaa/ChatGPT-Next-Web)
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
ワンクリックで無料であなた専用の ChatGPT ウェブアプリをデプロイ。GPT3、GPT4 & Gemini Pro モデルをサポート。
|
||||
|
||||
[NextChatAI](https://nextchat.dev/chat?utm_source=readme) / [企業版](#企業版) / [デモ](https://chat-gpt-next-web.vercel.app/) / [フィードバック](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Discordに参加](https://discord.gg/zrhvHCr79N)
|
||||
[NextChatAI](https://nextchat.club?utm_source=readme) / [企業版](#企業版) / [デモ](https://chat-gpt-next-web.vercel.app/) / [フィードバック](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Discordに参加](https://discord.gg/zrhvHCr79N)
|
||||
|
||||
[<img src="https://vercel.com/button" alt="Zeaburでデプロイ" height="30">](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FChatGPTNextWeb%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=nextchat&repository-name=NextChat) [<img src="https://zeabur.com/button.svg" alt="Zeaburでデプロイ" height="30">](https://zeabur.com/templates/ZBUEFA) [<img src="https://gitpod.io/button/open-in-gitpod.svg" alt="Gitpodで開く" height="30">](https://gitpod.io/#https://github.com/Yidadaa/ChatGPT-Next-Web)
|
||||
|
||||
|
@@ -14,6 +14,7 @@ import { handle as deepseekHandler } from "../../deepseek";
|
||||
import { handle as siliconflowHandler } from "../../siliconflow";
|
||||
import { handle as xaiHandler } from "../../xai";
|
||||
import { handle as chatglmHandler } from "../../glm";
|
||||
import { handle as bedrockHandler } from "../../bedrock";
|
||||
import { handle as proxyHandler } from "../../proxy";
|
||||
|
||||
async function handle(
|
||||
@@ -50,6 +51,8 @@ async function handle(
|
||||
return chatglmHandler(req, { params });
|
||||
case ApiPath.SiliconFlow:
|
||||
return siliconflowHandler(req, { params });
|
||||
case ApiPath.Bedrock:
|
||||
return bedrockHandler(req, { params });
|
||||
case ApiPath.OpenAI:
|
||||
return openaiHandler(req, { params });
|
||||
default:
|
||||
|
@@ -56,14 +56,6 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
|
||||
// if user does not provide an api key, inject system api key
|
||||
if (!apiKey) {
|
||||
const serverConfig = getServerSideConfig();
|
||||
|
||||
// const systemApiKey =
|
||||
// modelProvider === ModelProvider.GeminiPro
|
||||
// ? serverConfig.googleApiKey
|
||||
// : serverConfig.isAzure
|
||||
// ? serverConfig.azureApiKey
|
||||
// : serverConfig.apiKey;
|
||||
|
||||
let systemApiKey: string | undefined;
|
||||
|
||||
switch (modelProvider) {
|
||||
@@ -104,6 +96,11 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
|
||||
case ModelProvider.SiliconFlow:
|
||||
systemApiKey = serverConfig.siliconFlowApiKey;
|
||||
break;
|
||||
case ModelProvider.Bedrock:
|
||||
console.log(
|
||||
"[Auth] Using AWS credentials for Bedrock, no API key override.",
|
||||
);
|
||||
return { error: false };
|
||||
case ModelProvider.GPT:
|
||||
default:
|
||||
if (req.nextUrl.pathname.includes("azure/deployments")) {
|
||||
@@ -117,7 +114,10 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
|
||||
console.log("[Auth] use system api key");
|
||||
req.headers.set("Authorization", `Bearer ${systemApiKey}`);
|
||||
} else {
|
||||
console.log("[Auth] admin did not provide an api key");
|
||||
console.log(
|
||||
"[Auth] admin did not provide an api key for provider:",
|
||||
modelProvider,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.log("[Auth] use user api key");
|
||||
|
637
app/api/bedrock/index.ts
Normal file
637
app/api/bedrock/index.ts
Normal file
@@ -0,0 +1,637 @@
|
||||
import { ModelProvider, Bedrock as BedrockConfig } from "@/app/constant";
|
||||
import { getServerSideConfig } from "@/app/config/server";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { auth } from "../auth";
|
||||
import {
|
||||
BedrockRuntimeClient,
|
||||
InvokeModelWithResponseStreamCommand,
|
||||
InvokeModelCommand,
|
||||
} from "@aws-sdk/client-bedrock-runtime";
|
||||
|
||||
const ALLOWED_PATH = new Set([BedrockConfig.ChatPath]);
|
||||
|
||||
// Helper to get AWS Credentials
|
||||
function getAwsCredentials() {
|
||||
const config = getServerSideConfig();
|
||||
if (!config.isBedrock) {
|
||||
throw new Error(
|
||||
"AWS Bedrock is not configured properly (ENABLE_AWS_BEDROCK is not true)",
|
||||
);
|
||||
}
|
||||
if (!config.bedrockAccessKeyId) {
|
||||
throw new Error("AWS Bedrock Access Key ID is missing or empty.");
|
||||
}
|
||||
if (!config.bedrockSecretAccessKey) {
|
||||
throw new Error("AWS Bedrock Secret Access Key is missing or empty.");
|
||||
}
|
||||
return {
|
||||
accessKeyId: config.bedrockAccessKeyId as string,
|
||||
secretAccessKey: config.bedrockSecretAccessKey as string,
|
||||
};
|
||||
}
|
||||
|
||||
export async function handle(
|
||||
req: NextRequest,
|
||||
{ params }: { params: { path: string[] } },
|
||||
) {
|
||||
console.log("[Bedrock Route] params ", params);
|
||||
|
||||
if (req.method === "OPTIONS") {
|
||||
return NextResponse.json({ body: "OK" }, { status: 200 });
|
||||
}
|
||||
|
||||
const subpath = params.path.join("/");
|
||||
|
||||
if (!ALLOWED_PATH.has(subpath)) {
|
||||
console.log("[Bedrock Route] forbidden path ", subpath);
|
||||
return NextResponse.json(
|
||||
{ error: true, msg: "you are not allowed to request " + subpath },
|
||||
{ status: 403 },
|
||||
);
|
||||
}
|
||||
|
||||
// Auth check specifically for Bedrock (might not need header API key)
|
||||
const authResult = auth(req, ModelProvider.Bedrock);
|
||||
if (authResult.error) {
|
||||
return NextResponse.json(authResult, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
const config = getServerSideConfig();
|
||||
|
||||
const bedrockRegion = config.bedrockRegion as string;
|
||||
const bedrockEndpoint = config.bedrockEndpoint;
|
||||
|
||||
const client = new BedrockRuntimeClient({
|
||||
region: bedrockRegion,
|
||||
credentials: getAwsCredentials(),
|
||||
endpoint: bedrockEndpoint || undefined,
|
||||
});
|
||||
|
||||
const body = await req.json();
|
||||
console.log(
|
||||
"[Bedrock] Request - Model:",
|
||||
body.model,
|
||||
"Stream:",
|
||||
body.stream,
|
||||
"Messages count:",
|
||||
body.messages?.length || 0,
|
||||
);
|
||||
|
||||
// Add detailed logging for debugging
|
||||
if (body.messages && body.messages.length > 0) {
|
||||
body.messages.forEach((msg: any, index: number) => {
|
||||
console.log(`[Bedrock] Message ${index}:`, {
|
||||
role: msg.role,
|
||||
contentType: typeof msg.content,
|
||||
isArray: Array.isArray(msg.content),
|
||||
contentLength: Array.isArray(msg.content)
|
||||
? msg.content.length
|
||||
: typeof msg.content === "string"
|
||||
? msg.content.length
|
||||
: "unknown",
|
||||
});
|
||||
|
||||
if (Array.isArray(msg.content)) {
|
||||
msg.content.forEach((item: any, itemIndex: number) => {
|
||||
console.log(`[Bedrock] Message ${index}, Item ${itemIndex}:`, {
|
||||
type: item.type,
|
||||
hasImageUrl: !!item.image_url?.url,
|
||||
urlPreview: item.image_url?.url
|
||||
? item.image_url.url.substring(0, 50) + "..."
|
||||
: null,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
messages,
|
||||
model,
|
||||
stream = false,
|
||||
temperature = 0.7,
|
||||
max_tokens,
|
||||
} = body;
|
||||
|
||||
// --- Input Validation ---
|
||||
if (!model || typeof model !== "string") {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: true,
|
||||
msg: "Model parameter is required and must be a string",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!Array.isArray(messages) || messages.length === 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: true,
|
||||
msg: "Messages parameter is required and must be a non-empty array",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// --- Payload formatting for Claude on Bedrock ---
|
||||
const isClaudeModel = model.includes("anthropic.claude");
|
||||
if (!isClaudeModel) {
|
||||
return NextResponse.json(
|
||||
{ error: true, msg: "Unsupported Bedrock model: " + model },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const systemPrompts = messages.filter((msg: any) => msg.role === "system");
|
||||
const userAssistantMessages = messages.filter(
|
||||
(msg: any) => msg.role !== "system",
|
||||
);
|
||||
|
||||
// Validate we have non-system messages
|
||||
if (userAssistantMessages.length === 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: true,
|
||||
msg: "At least one user or assistant message is required",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Process messages and handle image fetching
|
||||
const processedMessages = await Promise.all(
|
||||
userAssistantMessages.map(async (msg: any) => {
|
||||
let content;
|
||||
|
||||
if (Array.isArray(msg.content)) {
|
||||
const processedContent = await Promise.all(
|
||||
msg.content.map(async (item: any) => {
|
||||
if (item.type === "image_url") {
|
||||
console.log("[Bedrock] Processing image_url item:", item);
|
||||
// Adapt from OpenAI format to Bedrock's format
|
||||
const url = item.image_url?.url;
|
||||
if (!url) {
|
||||
console.warn(
|
||||
"[Bedrock] Image URL is missing in content item",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if it's a data URL or regular URL
|
||||
const dataUrlMatch = url.match(
|
||||
/^data:(image\/[^;]+);base64,(.+)$/,
|
||||
);
|
||||
if (dataUrlMatch) {
|
||||
// Handle data URL (base64)
|
||||
const mediaType = dataUrlMatch[1];
|
||||
const base64Data = dataUrlMatch[2];
|
||||
|
||||
if (!base64Data) {
|
||||
console.warn("[Bedrock] Empty base64 data in image URL");
|
||||
return null;
|
||||
}
|
||||
|
||||
const bedrockImageItem = {
|
||||
type: "image",
|
||||
source: {
|
||||
type: "base64",
|
||||
media_type: mediaType,
|
||||
data: base64Data,
|
||||
},
|
||||
};
|
||||
|
||||
console.log(
|
||||
"[Bedrock] Successfully converted data URL to Bedrock format:",
|
||||
{
|
||||
mediaType,
|
||||
dataLength: base64Data.length,
|
||||
},
|
||||
);
|
||||
|
||||
return bedrockImageItem;
|
||||
} else if (
|
||||
url.startsWith("http://") ||
|
||||
url.startsWith("https://")
|
||||
) {
|
||||
// Handle HTTP URL - fetch directly and convert to base64
|
||||
console.log(
|
||||
"[Bedrock] HTTP URL detected, fetching directly:",
|
||||
url.substring(0, 50) + "...",
|
||||
);
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
console.log(
|
||||
"[Bedrock] Fetch response status:",
|
||||
response.status,
|
||||
response.statusText,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to fetch image:",
|
||||
response.status,
|
||||
response.statusText,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
console.log("[Bedrock] Blob info:", {
|
||||
size: blob.size,
|
||||
type: blob.type,
|
||||
});
|
||||
|
||||
if (blob.size === 0) {
|
||||
console.error(
|
||||
"[Bedrock] Fetched blob is empty - cache endpoint may not be working",
|
||||
);
|
||||
console.log(
|
||||
"[Bedrock] This might be a service worker cache issue - image was uploaded but cache retrieval failed",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
console.log(
|
||||
"[Bedrock] ArrayBuffer size:",
|
||||
arrayBuffer.byteLength,
|
||||
);
|
||||
|
||||
if (arrayBuffer.byteLength === 0) {
|
||||
console.error("[Bedrock] ArrayBuffer is empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
const base64Data =
|
||||
Buffer.from(arrayBuffer).toString("base64");
|
||||
console.log("[Bedrock] Base64 conversion:", {
|
||||
originalSize: arrayBuffer.byteLength,
|
||||
base64Length: base64Data.length,
|
||||
isEmpty: !base64Data || base64Data.length === 0,
|
||||
firstChars: base64Data.substring(0, 20),
|
||||
});
|
||||
|
||||
if (!base64Data || base64Data.length === 0) {
|
||||
console.error(
|
||||
"[Bedrock] Base64 data is empty after conversion",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const mediaType = blob.type || "image/jpeg";
|
||||
|
||||
const bedrockImageItem = {
|
||||
type: "image",
|
||||
source: {
|
||||
type: "base64",
|
||||
media_type: mediaType,
|
||||
data: base64Data,
|
||||
},
|
||||
};
|
||||
|
||||
console.log(
|
||||
"[Bedrock] Successfully converted HTTP URL to Bedrock format:",
|
||||
{
|
||||
url: url.substring(0, 50) + "...",
|
||||
mediaType,
|
||||
dataLength: base64Data.length,
|
||||
hasValidData: !!base64Data && base64Data.length > 0,
|
||||
},
|
||||
);
|
||||
|
||||
return bedrockImageItem;
|
||||
} catch (error) {
|
||||
console.error("[Bedrock] Error fetching image:", error);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
"[Bedrock] Invalid URL format:",
|
||||
url.substring(0, 50) + "...",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// Handle text content
|
||||
return item;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Filter out nulls and ensure we have content
|
||||
content = processedContent.filter(Boolean);
|
||||
|
||||
// Additional validation: ensure no image objects have empty data
|
||||
content = content.filter((item: any) => {
|
||||
if (item.type === "image") {
|
||||
const hasValidData =
|
||||
item.source?.data && item.source.data.length > 0;
|
||||
if (!hasValidData) {
|
||||
console.error(
|
||||
"[Bedrock] Filtering out image with empty data:",
|
||||
{
|
||||
hasSource: !!item.source,
|
||||
hasData: !!item.source?.data,
|
||||
dataLength: item.source?.data?.length || 0,
|
||||
},
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (content.length === 0) {
|
||||
console.warn(
|
||||
"[Bedrock] All content items were filtered out, adding empty text",
|
||||
);
|
||||
content = [{ type: "text", text: "" }];
|
||||
}
|
||||
|
||||
console.log(
|
||||
"[Bedrock] Processed content for message:",
|
||||
content.length,
|
||||
"items",
|
||||
);
|
||||
} else if (typeof msg.content === "string") {
|
||||
content = [{ type: "text", text: msg.content }];
|
||||
} else {
|
||||
console.warn("[Bedrock] Unknown content type:", typeof msg.content);
|
||||
content = [{ type: "text", text: "" }];
|
||||
}
|
||||
|
||||
return {
|
||||
role: msg.role,
|
||||
content: content,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const payload = {
|
||||
anthropic_version: "bedrock-2023-05-31",
|
||||
max_tokens:
|
||||
typeof max_tokens === "number" && max_tokens > 0 ? max_tokens : 8000,
|
||||
temperature:
|
||||
typeof temperature === "number" && temperature >= 0 && temperature <= 1
|
||||
? temperature
|
||||
: 0.7, // Bedrock Claude accepts 0-1 range
|
||||
messages: processedMessages,
|
||||
...(systemPrompts.length > 0 && {
|
||||
system: systemPrompts
|
||||
.map((msg: any) => {
|
||||
if (typeof msg.content === "string") {
|
||||
return msg.content;
|
||||
} else if (Array.isArray(msg.content)) {
|
||||
// Handle multimodal system prompts by extracting text
|
||||
return msg.content
|
||||
.filter((item: any) => item.type === "text")
|
||||
.map((item: any) => item.text)
|
||||
.join(" ");
|
||||
}
|
||||
return String(msg.content); // Fallback conversion
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
}),
|
||||
};
|
||||
// --- End Payload Formatting ---
|
||||
|
||||
// Log the final payload structure (without base64 data to avoid huge logs)
|
||||
console.log("[Bedrock] Final payload structure:", {
|
||||
anthropic_version: payload.anthropic_version,
|
||||
max_tokens: payload.max_tokens,
|
||||
temperature: payload.temperature,
|
||||
messageCount: payload.messages.length,
|
||||
messages: payload.messages.map((msg: any, index: number) => ({
|
||||
index,
|
||||
role: msg.role,
|
||||
contentItems: msg.content.map((item: any) => ({
|
||||
type: item.type,
|
||||
hasData: item.type === "image" ? !!item.source?.data : !!item.text,
|
||||
mediaType: item.source?.media_type || null,
|
||||
textLength: item.text?.length || null,
|
||||
dataLength: item.source?.data?.length || null,
|
||||
})),
|
||||
})),
|
||||
hasSystem: !!(payload as any).system,
|
||||
});
|
||||
|
||||
// Final validation: check for any empty images
|
||||
const hasEmptyImages = payload.messages.some((msg: any) =>
|
||||
msg.content.some(
|
||||
(item: any) =>
|
||||
item.type === "image" &&
|
||||
(!item.source?.data || item.source.data.length === 0),
|
||||
),
|
||||
);
|
||||
|
||||
if (hasEmptyImages) {
|
||||
console.error(
|
||||
"[Bedrock] Payload contains empty images, this will cause Bedrock to fail",
|
||||
);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: true,
|
||||
msg: "Image processing failed: empty image data detected",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
const command = new InvokeModelWithResponseStreamCommand({
|
||||
modelId: model,
|
||||
contentType: "application/json",
|
||||
accept: "application/json",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const response = await client.send(command);
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error("Empty response stream from Bedrock");
|
||||
}
|
||||
const responseBody = response.body;
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
const readableStream = new ReadableStream({
|
||||
async start(controller) {
|
||||
try {
|
||||
for await (const event of responseBody) {
|
||||
if (event.chunk?.bytes) {
|
||||
let chunkData;
|
||||
try {
|
||||
chunkData = JSON.parse(decoder.decode(event.chunk.bytes));
|
||||
} catch (parseError) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to parse chunk JSON:",
|
||||
parseError,
|
||||
);
|
||||
continue; // Skip malformed chunks
|
||||
}
|
||||
|
||||
let responseText = "";
|
||||
let finishReason: string | null = null;
|
||||
|
||||
if (
|
||||
chunkData.type === "content_block_delta" &&
|
||||
chunkData.delta?.type === "text_delta"
|
||||
) {
|
||||
responseText = chunkData.delta.text || "";
|
||||
} else if (chunkData.type === "message_stop") {
|
||||
finishReason =
|
||||
chunkData["amazon-bedrock-invocationMetrics"]
|
||||
?.outputTokenCount > 0
|
||||
? "stop"
|
||||
: "length"; // Example logic
|
||||
}
|
||||
|
||||
// Only send non-empty responses or finish signals
|
||||
if (responseText || finishReason) {
|
||||
// Format as OpenAI SSE chunk
|
||||
const sseData = {
|
||||
id: `chatcmpl-${nanoid()}`,
|
||||
object: "chat.completion.chunk",
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
model: model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: { content: responseText },
|
||||
finish_reason: finishReason,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
try {
|
||||
controller.enqueue(
|
||||
encoder.encode(`data: ${JSON.stringify(sseData)}\n\n`),
|
||||
);
|
||||
} catch (enqueueError) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to enqueue data:",
|
||||
enqueueError,
|
||||
);
|
||||
break; // Stop processing if client disconnected
|
||||
}
|
||||
}
|
||||
|
||||
if (finishReason) {
|
||||
try {
|
||||
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
||||
} catch (enqueueError) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to enqueue [DONE]:",
|
||||
enqueueError,
|
||||
);
|
||||
}
|
||||
break; // Exit loop after stop message
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Bedrock] Streaming error:", error);
|
||||
try {
|
||||
controller.error(error);
|
||||
} catch (controllerError) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to signal controller error:",
|
||||
controllerError,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
controller.close();
|
||||
} catch (closeError) {
|
||||
console.error(
|
||||
"[Bedrock] Failed to close controller:",
|
||||
closeError,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return new NextResponse(readableStream, {
|
||||
headers: {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
Connection: "keep-alive",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// Non-streaming response
|
||||
const command = new InvokeModelCommand({
|
||||
modelId: model,
|
||||
contentType: "application/json",
|
||||
accept: "application/json",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const response = await client.send(command);
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error("Empty response body from Bedrock");
|
||||
}
|
||||
|
||||
let responseBody;
|
||||
try {
|
||||
responseBody = JSON.parse(new TextDecoder().decode(response.body));
|
||||
} catch (parseError) {
|
||||
console.error("[Bedrock] Failed to parse response JSON:", parseError);
|
||||
throw new Error("Invalid JSON response from Bedrock");
|
||||
}
|
||||
|
||||
// Validate response structure
|
||||
if (
|
||||
!responseBody.content ||
|
||||
!Array.isArray(responseBody.content) ||
|
||||
responseBody.content.length === 0
|
||||
) {
|
||||
console.error("[Bedrock] Invalid response structure:", responseBody);
|
||||
throw new Error("Invalid response structure from Bedrock");
|
||||
}
|
||||
|
||||
// Format response to match OpenAI
|
||||
const formattedResponse = {
|
||||
id: `chatcmpl-${nanoid()}`,
|
||||
object: "chat.completion",
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
model: model,
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: responseBody.content?.[0]?.text ?? "",
|
||||
},
|
||||
finish_reason: "stop", // Assuming stop for non-streamed
|
||||
},
|
||||
],
|
||||
usage: {
|
||||
prompt_tokens:
|
||||
responseBody["amazon-bedrock-invocationMetrics"]?.inputTokenCount ??
|
||||
-1,
|
||||
completion_tokens:
|
||||
responseBody["amazon-bedrock-invocationMetrics"]
|
||||
?.outputTokenCount ?? -1,
|
||||
total_tokens:
|
||||
(responseBody["amazon-bedrock-invocationMetrics"]
|
||||
?.inputTokenCount ?? 0) +
|
||||
(responseBody["amazon-bedrock-invocationMetrics"]
|
||||
?.outputTokenCount ?? 0) || -1,
|
||||
},
|
||||
};
|
||||
return NextResponse.json(formattedResponse);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Bedrock] API Handler Error:", e);
|
||||
return NextResponse.json(prettyObject(e), { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// Need nanoid for unique IDs
|
||||
import { nanoid } from "nanoid";
|
@@ -14,8 +14,12 @@ function getModels(remoteModelRes: OpenAIListModelResponse) {
|
||||
if (config.disableGPT4) {
|
||||
remoteModelRes.data = remoteModelRes.data.filter(
|
||||
(m) =>
|
||||
!(m.id.startsWith("gpt-4") || m.id.startsWith("chatgpt-4o") || m.id.startsWith("o1") || m.id.startsWith("o3")) ||
|
||||
m.id.startsWith("gpt-4o-mini"),
|
||||
!(
|
||||
m.id.startsWith("gpt-4") ||
|
||||
m.id.startsWith("chatgpt-4o") ||
|
||||
m.id.startsWith("o1") ||
|
||||
m.id.startsWith("o3")
|
||||
) || m.id.startsWith("gpt-4o-mini"),
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ import { DeepSeekApi } from "./platforms/deepseek";
|
||||
import { XAIApi } from "./platforms/xai";
|
||||
import { ChatGLMApi } from "./platforms/glm";
|
||||
import { SiliconflowApi } from "./platforms/siliconflow";
|
||||
import { BedrockApi } from "./platforms/bedrock";
|
||||
|
||||
export const ROLES = ["system", "user", "assistant"] as const;
|
||||
export type MessageRole = (typeof ROLES)[number];
|
||||
@@ -40,6 +41,11 @@ export interface MultimodalContent {
|
||||
};
|
||||
}
|
||||
|
||||
export interface MultimodalContentForAlibaba {
|
||||
text?: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export interface RequestMessage {
|
||||
role: MessageRole;
|
||||
content: string | MultimodalContent[];
|
||||
@@ -168,6 +174,9 @@ export class ClientApi {
|
||||
case ModelProvider.SiliconFlow:
|
||||
this.llm = new SiliconflowApi();
|
||||
break;
|
||||
case ModelProvider.Bedrock:
|
||||
this.llm = new BedrockApi();
|
||||
break;
|
||||
default:
|
||||
this.llm = new ChatGPTApi();
|
||||
}
|
||||
@@ -351,11 +360,74 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
export function getClientApi(provider: ServiceProvider): ClientApi {
|
||||
switch (provider) {
|
||||
export function getClientApi(provider: ServiceProvider | string): ClientApi {
|
||||
console.log(
|
||||
"[getClientApi] Received Provider (raw):",
|
||||
provider,
|
||||
"| Type:",
|
||||
typeof provider,
|
||||
"| Browser:",
|
||||
typeof navigator !== "undefined"
|
||||
? navigator.userAgent.includes("Edge")
|
||||
? "Edge"
|
||||
: navigator.userAgent.includes("Safari")
|
||||
? "Safari"
|
||||
: "Other"
|
||||
: "SSR",
|
||||
);
|
||||
|
||||
// Standardize the provider name to match Enum case (TitleCase)
|
||||
let standardizedProvider: ServiceProvider | string;
|
||||
if (typeof provider === "string") {
|
||||
console.log(
|
||||
"[getClientApi] Provider is string, attempting to standardize:",
|
||||
provider,
|
||||
);
|
||||
// Convert known lowercase versions to their Enum equivalent
|
||||
switch (provider.toLowerCase()) {
|
||||
case "bedrock":
|
||||
standardizedProvider = ServiceProvider.Bedrock;
|
||||
console.log(
|
||||
"[getClientApi] Converted 'bedrock' string to ServiceProvider.Bedrock",
|
||||
);
|
||||
break;
|
||||
case "openai":
|
||||
standardizedProvider = ServiceProvider.OpenAI;
|
||||
console.log(
|
||||
"[getClientApi] Converted 'openai' string to ServiceProvider.OpenAI",
|
||||
);
|
||||
break;
|
||||
case "google":
|
||||
standardizedProvider = ServiceProvider.Google;
|
||||
break;
|
||||
// Add other potential lowercase strings if needed
|
||||
default:
|
||||
console.log(
|
||||
"[getClientApi] Unknown string provider, keeping as-is:",
|
||||
provider,
|
||||
);
|
||||
standardizedProvider = provider; // Keep unknown strings as is
|
||||
}
|
||||
} else {
|
||||
console.log("[getClientApi] Provider is already enum value:", provider);
|
||||
standardizedProvider = provider; // Already an Enum value
|
||||
}
|
||||
|
||||
console.log(
|
||||
"[getClientApi] Final Standardized Provider:",
|
||||
standardizedProvider,
|
||||
"| Enum check:",
|
||||
standardizedProvider === ServiceProvider.Bedrock,
|
||||
);
|
||||
|
||||
switch (standardizedProvider) {
|
||||
case ServiceProvider.Google:
|
||||
console.log(
|
||||
"[getClientApi] Returning ClientApi(ModelProvider.GeminiPro)",
|
||||
);
|
||||
return new ClientApi(ModelProvider.GeminiPro);
|
||||
case ServiceProvider.Anthropic:
|
||||
console.log("[getClientApi] Returning ClientApi(ModelProvider.Claude)");
|
||||
return new ClientApi(ModelProvider.Claude);
|
||||
case ServiceProvider.Baidu:
|
||||
return new ClientApi(ModelProvider.Ernie);
|
||||
@@ -377,7 +449,28 @@ export function getClientApi(provider: ServiceProvider): ClientApi {
|
||||
return new ClientApi(ModelProvider.ChatGLM);
|
||||
case ServiceProvider.SiliconFlow:
|
||||
return new ClientApi(ModelProvider.SiliconFlow);
|
||||
case ServiceProvider.Bedrock:
|
||||
console.log(
|
||||
"[getClientApi] Returning ClientApi(ModelProvider.Bedrock) for",
|
||||
standardizedProvider,
|
||||
);
|
||||
return new ClientApi(ModelProvider.Bedrock);
|
||||
default:
|
||||
console.log(
|
||||
`[getClientApi] Provider '${provider}' (Standardized: '${standardizedProvider}') not matched, returning default GPT.`,
|
||||
);
|
||||
|
||||
// Edge browser fallback: check if this is a Bedrock model by name
|
||||
if (
|
||||
typeof provider === "string" &&
|
||||
provider.includes("anthropic.claude")
|
||||
) {
|
||||
console.log(
|
||||
"[getClientApi] Edge fallback: Detected Bedrock model by name, routing to Bedrock",
|
||||
);
|
||||
return new ClientApi(ModelProvider.Bedrock);
|
||||
}
|
||||
|
||||
return new ClientApi(ModelProvider.GPT);
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,16 @@
|
||||
"use client";
|
||||
import { ApiPath, Alibaba, ALIBABA_BASE_URL } from "@/app/constant";
|
||||
import {
|
||||
ApiPath,
|
||||
Alibaba,
|
||||
ALIBABA_BASE_URL,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
} from "@/app/constant";
|
||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||
|
||||
useAccessStore,
|
||||
useAppConfig,
|
||||
useChatStore,
|
||||
ChatMessageTool,
|
||||
usePluginStore,
|
||||
} from "@/app/store";
|
||||
import {
|
||||
preProcessImageContentForAlibabaDashScope,
|
||||
streamWithThink,
|
||||
} from "@/app/utils/chat";
|
||||
import {
|
||||
ChatOptions,
|
||||
getHeaders,
|
||||
@@ -14,15 +18,15 @@ import {
|
||||
LLMModel,
|
||||
SpeechOptions,
|
||||
MultimodalContent,
|
||||
MultimodalContentForAlibaba,
|
||||
} from "../api";
|
||||
import Locale from "../../locales";
|
||||
import {
|
||||
EventStreamContentType,
|
||||
fetchEventSource,
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { getMessageTextContent } from "@/app/utils";
|
||||
import {
|
||||
getMessageTextContent,
|
||||
getMessageTextContentWithoutThinking,
|
||||
getTimeoutMSByModel,
|
||||
isVisionModel,
|
||||
} from "@/app/utils";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
|
||||
export interface OpenAIListModelResponse {
|
||||
@@ -90,11 +94,6 @@ export class QwenApi implements LLMApi {
|
||||
}
|
||||
|
||||
async chat(options: ChatOptions) {
|
||||
const messages = options.messages.map((v) => ({
|
||||
role: v.role,
|
||||
content: getMessageTextContent(v),
|
||||
}));
|
||||
|
||||
const modelConfig = {
|
||||
...useAppConfig.getState().modelConfig,
|
||||
...useChatStore.getState().currentSession().mask.modelConfig,
|
||||
@@ -103,6 +102,21 @@ export class QwenApi implements LLMApi {
|
||||
},
|
||||
};
|
||||
|
||||
const visionModel = isVisionModel(options.config.model);
|
||||
|
||||
const messages: ChatOptions["messages"] = [];
|
||||
for (const v of options.messages) {
|
||||
const content = (
|
||||
visionModel
|
||||
? await preProcessImageContentForAlibabaDashScope(v.content)
|
||||
: v.role === "assistant"
|
||||
? getMessageTextContentWithoutThinking(v)
|
||||
: getMessageTextContent(v)
|
||||
) as any;
|
||||
|
||||
messages.push({ role: v.role, content });
|
||||
}
|
||||
|
||||
const shouldStream = !!options.config.stream;
|
||||
const requestPayload: RequestPayload = {
|
||||
model: modelConfig.model,
|
||||
@@ -122,134 +136,120 @@ export class QwenApi implements LLMApi {
|
||||
options.onController?.(controller);
|
||||
|
||||
try {
|
||||
const chatPath = this.path(Alibaba.ChatPath);
|
||||
const headers = {
|
||||
...getHeaders(),
|
||||
"X-DashScope-SSE": shouldStream ? "enable" : "disable",
|
||||
};
|
||||
|
||||
const chatPath = this.path(Alibaba.ChatPath(modelConfig.model));
|
||||
const chatPayload = {
|
||||
method: "POST",
|
||||
body: JSON.stringify(requestPayload),
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
...getHeaders(),
|
||||
"X-DashScope-SSE": shouldStream ? "enable" : "disable",
|
||||
},
|
||||
headers: headers,
|
||||
};
|
||||
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
let responseText = "";
|
||||
let remainText = "";
|
||||
let finished = false;
|
||||
let responseRes: Response;
|
||||
const [tools, funcs] = usePluginStore
|
||||
.getState()
|
||||
.getAsTools(
|
||||
useChatStore.getState().currentSession().mask?.plugin || [],
|
||||
);
|
||||
return streamWithThink(
|
||||
chatPath,
|
||||
requestPayload,
|
||||
headers,
|
||||
tools as any,
|
||||
funcs,
|
||||
controller,
|
||||
// parseSSE
|
||||
(text: string, runTools: ChatMessageTool[]) => {
|
||||
// console.log("parseSSE", text, runTools);
|
||||
const json = JSON.parse(text);
|
||||
const choices = json.output.choices as Array<{
|
||||
message: {
|
||||
content: string | null | MultimodalContentForAlibaba[];
|
||||
tool_calls: ChatMessageTool[];
|
||||
reasoning_content: string | null;
|
||||
};
|
||||
}>;
|
||||
|
||||
// animate response to make it looks smooth
|
||||
function animateResponseText() {
|
||||
if (finished || controller.signal.aborted) {
|
||||
responseText += remainText;
|
||||
console.log("[Response Animation] finished");
|
||||
if (responseText?.length === 0) {
|
||||
options.onError?.(new Error("empty response from server"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!choices?.length) return { isThinking: false, content: "" };
|
||||
|
||||
if (remainText.length > 0) {
|
||||
const fetchCount = Math.max(1, Math.round(remainText.length / 60));
|
||||
const fetchText = remainText.slice(0, fetchCount);
|
||||
responseText += fetchText;
|
||||
remainText = remainText.slice(fetchCount);
|
||||
options.onUpdate?.(responseText, fetchText);
|
||||
}
|
||||
|
||||
requestAnimationFrame(animateResponseText);
|
||||
}
|
||||
|
||||
// start animaion
|
||||
animateResponseText();
|
||||
|
||||
const finish = () => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
options.onFinish(responseText + remainText, responseRes);
|
||||
}
|
||||
};
|
||||
|
||||
controller.signal.onabort = finish;
|
||||
|
||||
fetchEventSource(chatPath, {
|
||||
fetch: fetch as any,
|
||||
...chatPayload,
|
||||
async onopen(res) {
|
||||
clearTimeout(requestTimeoutId);
|
||||
const contentType = res.headers.get("content-type");
|
||||
console.log(
|
||||
"[Alibaba] request response content type: ",
|
||||
contentType,
|
||||
);
|
||||
responseRes = res;
|
||||
|
||||
if (contentType?.startsWith("text/plain")) {
|
||||
responseText = await res.clone().text();
|
||||
return finish();
|
||||
const tool_calls = choices[0]?.message?.tool_calls;
|
||||
if (tool_calls?.length > 0) {
|
||||
const index = tool_calls[0]?.index;
|
||||
const id = tool_calls[0]?.id;
|
||||
const args = tool_calls[0]?.function?.arguments;
|
||||
if (id) {
|
||||
runTools.push({
|
||||
id,
|
||||
type: tool_calls[0]?.type,
|
||||
function: {
|
||||
name: tool_calls[0]?.function?.name as string,
|
||||
arguments: args,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// @ts-ignore
|
||||
runTools[index]["function"]["arguments"] += args;
|
||||
}
|
||||
}
|
||||
|
||||
const reasoning = choices[0]?.message?.reasoning_content;
|
||||
const content = choices[0]?.message?.content;
|
||||
|
||||
// Skip if both content and reasoning_content are empty or null
|
||||
if (
|
||||
!res.ok ||
|
||||
!res.headers
|
||||
.get("content-type")
|
||||
?.startsWith(EventStreamContentType) ||
|
||||
res.status !== 200
|
||||
(!reasoning || reasoning.length === 0) &&
|
||||
(!content || content.length === 0)
|
||||
) {
|
||||
const responseTexts = [responseText];
|
||||
let extraInfo = await res.clone().text();
|
||||
try {
|
||||
const resJson = await res.clone().json();
|
||||
extraInfo = prettyObject(resJson);
|
||||
} catch {}
|
||||
|
||||
if (res.status === 401) {
|
||||
responseTexts.push(Locale.Error.Unauthorized);
|
||||
}
|
||||
|
||||
if (extraInfo) {
|
||||
responseTexts.push(extraInfo);
|
||||
}
|
||||
|
||||
responseText = responseTexts.join("\n\n");
|
||||
|
||||
return finish();
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
}
|
||||
},
|
||||
onmessage(msg) {
|
||||
if (msg.data === "[DONE]" || finished) {
|
||||
return finish();
|
||||
}
|
||||
const text = msg.data;
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
const choices = json.output.choices as Array<{
|
||||
message: { content: string };
|
||||
}>;
|
||||
const delta = choices[0]?.message?.content;
|
||||
if (delta) {
|
||||
remainText += delta;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Request] parse error", text, msg);
|
||||
|
||||
if (reasoning && reasoning.length > 0) {
|
||||
return {
|
||||
isThinking: true,
|
||||
content: reasoning,
|
||||
};
|
||||
} else if (content && content.length > 0) {
|
||||
return {
|
||||
isThinking: false,
|
||||
content: Array.isArray(content)
|
||||
? content.map((item) => item.text).join(",")
|
||||
: content,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
},
|
||||
onclose() {
|
||||
finish();
|
||||
// processToolMessage, include tool_calls message and tool call results
|
||||
(
|
||||
requestPayload: RequestPayload,
|
||||
toolCallMessage: any,
|
||||
toolCallResult: any[],
|
||||
) => {
|
||||
requestPayload?.input?.messages?.splice(
|
||||
requestPayload?.input?.messages?.length,
|
||||
0,
|
||||
toolCallMessage,
|
||||
...toolCallResult,
|
||||
);
|
||||
},
|
||||
onerror(e) {
|
||||
options.onError?.(e);
|
||||
throw e;
|
||||
},
|
||||
openWhenHidden: true,
|
||||
});
|
||||
options,
|
||||
);
|
||||
} else {
|
||||
const res = await fetch(chatPath, chatPayload);
|
||||
clearTimeout(requestTimeoutId);
|
||||
|
@@ -1,10 +1,5 @@
|
||||
"use client";
|
||||
import {
|
||||
ApiPath,
|
||||
Baidu,
|
||||
BAIDU_BASE_URL,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
} from "@/app/constant";
|
||||
import { ApiPath, Baidu, BAIDU_BASE_URL } from "@/app/constant";
|
||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||
import { getAccessToken } from "@/app/utils/baidu";
|
||||
|
||||
@@ -23,7 +18,7 @@ import {
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { getMessageTextContent } from "@/app/utils";
|
||||
import { getMessageTextContent, getTimeoutMSByModel } from "@/app/utils";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
|
||||
export interface OpenAIListModelResponse {
|
||||
@@ -155,7 +150,7 @@ export class ErnieApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
|
140
app/client/platforms/bedrock.ts
Normal file
140
app/client/platforms/bedrock.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
"use client";
|
||||
|
||||
import { ApiPath, Bedrock } from "@/app/constant";
|
||||
import { LLMApi, ChatOptions, LLMModel, LLMUsage, SpeechOptions } from "../api";
|
||||
import { getHeaders } from "../api";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
|
||||
export class BedrockApi implements LLMApi {
|
||||
path(path: string): string {
|
||||
// Route requests to our backend handler
|
||||
const apiPath = `${ApiPath.Bedrock}/${path}`;
|
||||
console.log("[BedrockApi] Constructed API path:", apiPath);
|
||||
return apiPath;
|
||||
}
|
||||
|
||||
async chat(options: ChatOptions) {
|
||||
const messages = options.messages;
|
||||
const modelConfig = options.config;
|
||||
|
||||
const controller = new AbortController();
|
||||
options.onController?.(controller);
|
||||
|
||||
try {
|
||||
const chatPath = this.path(Bedrock.ChatPath);
|
||||
console.log("[BedrockApi] Requesting path:", chatPath);
|
||||
|
||||
const chatPayload = {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
model: modelConfig.model,
|
||||
messages,
|
||||
temperature: modelConfig.temperature,
|
||||
stream: !!modelConfig.stream,
|
||||
max_tokens: (modelConfig as any).max_tokens || 8000, // Cast to access max_tokens from ModelConfig
|
||||
}),
|
||||
signal: controller.signal,
|
||||
headers: getHeaders(), // getHeaders should handle Bedrock (no auth needed)
|
||||
};
|
||||
console.log("[BedrockApi] Request payload (excluding messages):", {
|
||||
model: modelConfig.model,
|
||||
temperature: modelConfig.temperature,
|
||||
stream: !!modelConfig.stream,
|
||||
});
|
||||
|
||||
// Handle stream response
|
||||
if (modelConfig.stream) {
|
||||
const response = await fetch(chatPath, chatPayload);
|
||||
const reader = response.body?.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let messageBuffer = "";
|
||||
|
||||
if (!reader) {
|
||||
throw new Error("Response body reader is not available");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// Loop until stream is done
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const text = decoder.decode(value, { stream: true }); // Decode chunk
|
||||
const lines = text.split("\n");
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith("data:")) continue;
|
||||
const jsonData = line.substring("data:".length).trim();
|
||||
if (jsonData === "[DONE]") break; // End of stream
|
||||
if (!jsonData) continue;
|
||||
|
||||
try {
|
||||
const data = JSON.parse(jsonData);
|
||||
const content = data.choices?.[0]?.delta?.content ?? "";
|
||||
const finishReason = data.choices?.[0]?.finish_reason;
|
||||
|
||||
if (content) {
|
||||
messageBuffer += content;
|
||||
options.onUpdate?.(messageBuffer, content);
|
||||
}
|
||||
if (finishReason) {
|
||||
// Potentially handle finish reason if needed
|
||||
console.log(
|
||||
"[BedrockApi] Stream finished with reason:",
|
||||
finishReason,
|
||||
);
|
||||
break; // Exit inner loop on finish signal within a chunk
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[BedrockApi] Error parsing stream chunk:",
|
||||
jsonData,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.releaseLock(); // Release reader lock
|
||||
options.onFinish(messageBuffer, response);
|
||||
} else {
|
||||
// Handle non-streaming response
|
||||
const response = await fetch(chatPath, chatPayload);
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
console.error(
|
||||
"[BedrockApi] Non-stream error response:",
|
||||
response.status,
|
||||
errorBody,
|
||||
);
|
||||
throw new Error(
|
||||
`Request failed with status ${response.status}: ${errorBody}`,
|
||||
);
|
||||
}
|
||||
const responseJson = await response.json();
|
||||
const content = responseJson.choices?.[0]?.message?.content ?? "";
|
||||
options.onFinish(content, response);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[BedrockApi] Chat request failed:", e);
|
||||
options.onError?.(e as Error);
|
||||
}
|
||||
}
|
||||
|
||||
async usage(): Promise<LLMUsage> {
|
||||
// Bedrock usage reporting might require separate implementation if available
|
||||
return {
|
||||
used: 0,
|
||||
total: Number.MAX_SAFE_INTEGER, // Indicate no limit or unknown
|
||||
};
|
||||
}
|
||||
|
||||
async models(): Promise<LLMModel[]> {
|
||||
// Fetching models dynamically from Bedrock is complex and usually not needed
|
||||
// Rely on the hardcoded models in constant.ts
|
||||
return [];
|
||||
}
|
||||
|
||||
async speech(options: SpeechOptions): Promise<ArrayBuffer> {
|
||||
// Implement if Bedrock TTS is needed
|
||||
throw new Error("Speech synthesis not supported for Bedrock yet");
|
||||
}
|
||||
}
|
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
import { ApiPath, ByteDance, BYTEDANCE_BASE_URL } from "@/app/constant";
|
||||
import {
|
||||
ApiPath,
|
||||
ByteDance,
|
||||
BYTEDANCE_BASE_URL,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
} from "@/app/constant";
|
||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||
useAccessStore,
|
||||
useAppConfig,
|
||||
useChatStore,
|
||||
ChatMessageTool,
|
||||
usePluginStore,
|
||||
} from "@/app/store";
|
||||
|
||||
import {
|
||||
ChatOptions,
|
||||
@@ -15,14 +16,14 @@ import {
|
||||
MultimodalContent,
|
||||
SpeechOptions,
|
||||
} from "../api";
|
||||
import Locale from "../../locales";
|
||||
import {
|
||||
EventStreamContentType,
|
||||
fetchEventSource,
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
|
||||
import { streamWithThink } from "@/app/utils/chat";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { preProcessImageContent } from "@/app/utils/chat";
|
||||
import {
|
||||
getMessageTextContentWithoutThinking,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
|
||||
export interface OpenAIListModelResponse {
|
||||
@@ -34,7 +35,7 @@ export interface OpenAIListModelResponse {
|
||||
}>;
|
||||
}
|
||||
|
||||
interface RequestPayload {
|
||||
interface RequestPayloadForByteDance {
|
||||
messages: {
|
||||
role: "system" | "user" | "assistant";
|
||||
content: string | MultimodalContent[];
|
||||
@@ -86,7 +87,10 @@ export class DoubaoApi implements LLMApi {
|
||||
async chat(options: ChatOptions) {
|
||||
const messages: ChatOptions["messages"] = [];
|
||||
for (const v of options.messages) {
|
||||
const content = await preProcessImageContent(v.content);
|
||||
const content =
|
||||
v.role === "assistant"
|
||||
? getMessageTextContentWithoutThinking(v)
|
||||
: await preProcessImageContent(v.content);
|
||||
messages.push({ role: v.role, content });
|
||||
}
|
||||
|
||||
@@ -99,7 +103,7 @@ export class DoubaoApi implements LLMApi {
|
||||
};
|
||||
|
||||
const shouldStream = !!options.config.stream;
|
||||
const requestPayload: RequestPayload = {
|
||||
const requestPayload: RequestPayloadForByteDance = {
|
||||
messages,
|
||||
stream: shouldStream,
|
||||
model: modelConfig.model,
|
||||
@@ -124,119 +128,101 @@ export class DoubaoApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
let responseText = "";
|
||||
let remainText = "";
|
||||
let finished = false;
|
||||
let responseRes: Response;
|
||||
const [tools, funcs] = usePluginStore
|
||||
.getState()
|
||||
.getAsTools(
|
||||
useChatStore.getState().currentSession().mask?.plugin || [],
|
||||
);
|
||||
return streamWithThink(
|
||||
chatPath,
|
||||
requestPayload,
|
||||
getHeaders(),
|
||||
tools as any,
|
||||
funcs,
|
||||
controller,
|
||||
// parseSSE
|
||||
(text: string, runTools: ChatMessageTool[]) => {
|
||||
// console.log("parseSSE", text, runTools);
|
||||
const json = JSON.parse(text);
|
||||
const choices = json.choices as Array<{
|
||||
delta: {
|
||||
content: string | null;
|
||||
tool_calls: ChatMessageTool[];
|
||||
reasoning_content: string | null;
|
||||
};
|
||||
}>;
|
||||
|
||||
// animate response to make it looks smooth
|
||||
function animateResponseText() {
|
||||
if (finished || controller.signal.aborted) {
|
||||
responseText += remainText;
|
||||
console.log("[Response Animation] finished");
|
||||
if (responseText?.length === 0) {
|
||||
options.onError?.(new Error("empty response from server"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (remainText.length > 0) {
|
||||
const fetchCount = Math.max(1, Math.round(remainText.length / 60));
|
||||
const fetchText = remainText.slice(0, fetchCount);
|
||||
responseText += fetchText;
|
||||
remainText = remainText.slice(fetchCount);
|
||||
options.onUpdate?.(responseText, fetchText);
|
||||
}
|
||||
|
||||
requestAnimationFrame(animateResponseText);
|
||||
}
|
||||
|
||||
// start animaion
|
||||
animateResponseText();
|
||||
|
||||
const finish = () => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
options.onFinish(responseText + remainText, responseRes);
|
||||
}
|
||||
};
|
||||
|
||||
controller.signal.onabort = finish;
|
||||
|
||||
fetchEventSource(chatPath, {
|
||||
fetch: fetch as any,
|
||||
...chatPayload,
|
||||
async onopen(res) {
|
||||
clearTimeout(requestTimeoutId);
|
||||
const contentType = res.headers.get("content-type");
|
||||
console.log(
|
||||
"[ByteDance] request response content type: ",
|
||||
contentType,
|
||||
);
|
||||
responseRes = res;
|
||||
if (contentType?.startsWith("text/plain")) {
|
||||
responseText = await res.clone().text();
|
||||
return finish();
|
||||
if (!choices?.length) return { isThinking: false, content: "" };
|
||||
|
||||
const tool_calls = choices[0]?.delta?.tool_calls;
|
||||
if (tool_calls?.length > 0) {
|
||||
const index = tool_calls[0]?.index;
|
||||
const id = tool_calls[0]?.id;
|
||||
const args = tool_calls[0]?.function?.arguments;
|
||||
if (id) {
|
||||
runTools.push({
|
||||
id,
|
||||
type: tool_calls[0]?.type,
|
||||
function: {
|
||||
name: tool_calls[0]?.function?.name as string,
|
||||
arguments: args,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// @ts-ignore
|
||||
runTools[index]["function"]["arguments"] += args;
|
||||
}
|
||||
}
|
||||
const reasoning = choices[0]?.delta?.reasoning_content;
|
||||
const content = choices[0]?.delta?.content;
|
||||
|
||||
// Skip if both content and reasoning_content are empty or null
|
||||
if (
|
||||
!res.ok ||
|
||||
!res.headers
|
||||
.get("content-type")
|
||||
?.startsWith(EventStreamContentType) ||
|
||||
res.status !== 200
|
||||
(!reasoning || reasoning.length === 0) &&
|
||||
(!content || content.length === 0)
|
||||
) {
|
||||
const responseTexts = [responseText];
|
||||
let extraInfo = await res.clone().text();
|
||||
try {
|
||||
const resJson = await res.clone().json();
|
||||
extraInfo = prettyObject(resJson);
|
||||
} catch {}
|
||||
|
||||
if (res.status === 401) {
|
||||
responseTexts.push(Locale.Error.Unauthorized);
|
||||
}
|
||||
|
||||
if (extraInfo) {
|
||||
responseTexts.push(extraInfo);
|
||||
}
|
||||
|
||||
responseText = responseTexts.join("\n\n");
|
||||
|
||||
return finish();
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
}
|
||||
},
|
||||
onmessage(msg) {
|
||||
if (msg.data === "[DONE]" || finished) {
|
||||
return finish();
|
||||
}
|
||||
const text = msg.data;
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
const choices = json.choices as Array<{
|
||||
delta: { content: string };
|
||||
}>;
|
||||
const delta = choices[0]?.delta?.content;
|
||||
if (delta) {
|
||||
remainText += delta;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Request] parse error", text, msg);
|
||||
|
||||
if (reasoning && reasoning.length > 0) {
|
||||
return {
|
||||
isThinking: true,
|
||||
content: reasoning,
|
||||
};
|
||||
} else if (content && content.length > 0) {
|
||||
return {
|
||||
isThinking: false,
|
||||
content: content,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
},
|
||||
onclose() {
|
||||
finish();
|
||||
// processToolMessage, include tool_calls message and tool call results
|
||||
(
|
||||
requestPayload: RequestPayloadForByteDance,
|
||||
toolCallMessage: any,
|
||||
toolCallResult: any[],
|
||||
) => {
|
||||
requestPayload?.messages?.splice(
|
||||
requestPayload?.messages?.length,
|
||||
0,
|
||||
toolCallMessage,
|
||||
...toolCallResult,
|
||||
);
|
||||
},
|
||||
onerror(e) {
|
||||
options.onError?.(e);
|
||||
throw e;
|
||||
},
|
||||
openWhenHidden: true,
|
||||
});
|
||||
options,
|
||||
);
|
||||
} else {
|
||||
const res = await fetch(chatPath, chatPayload);
|
||||
clearTimeout(requestTimeoutId);
|
||||
|
@@ -1,12 +1,6 @@
|
||||
"use client";
|
||||
// azure and openai, using same models. so using same LLMApi.
|
||||
import {
|
||||
ApiPath,
|
||||
DEEPSEEK_BASE_URL,
|
||||
DeepSeek,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
} from "@/app/constant";
|
||||
import { ApiPath, DEEPSEEK_BASE_URL, DeepSeek } from "@/app/constant";
|
||||
import {
|
||||
useAccessStore,
|
||||
useAppConfig,
|
||||
@@ -26,6 +20,7 @@ import { getClientConfig } from "@/app/config/client";
|
||||
import {
|
||||
getMessageTextContent,
|
||||
getMessageTextContentWithoutThinking,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { RequestPayload } from "./openai";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
@@ -80,6 +75,25 @@ export class DeepSeekApi implements LLMApi {
|
||||
}
|
||||
}
|
||||
|
||||
// 检测并修复消息顺序,确保除system外的第一个消息是user
|
||||
const filteredMessages: ChatOptions["messages"] = [];
|
||||
let hasFoundFirstUser = false;
|
||||
|
||||
for (const msg of messages) {
|
||||
if (msg.role === "system") {
|
||||
// Keep all system messages
|
||||
filteredMessages.push(msg);
|
||||
} else if (msg.role === "user") {
|
||||
// User message directly added
|
||||
filteredMessages.push(msg);
|
||||
hasFoundFirstUser = true;
|
||||
} else if (hasFoundFirstUser) {
|
||||
// After finding the first user message, all subsequent non-system messages are retained.
|
||||
filteredMessages.push(msg);
|
||||
}
|
||||
// If hasFoundFirstUser is false and it is not a system message, it will be skipped.
|
||||
}
|
||||
|
||||
const modelConfig = {
|
||||
...useAppConfig.getState().modelConfig,
|
||||
...useChatStore.getState().currentSession().mask.modelConfig,
|
||||
@@ -90,7 +104,7 @@ export class DeepSeekApi implements LLMApi {
|
||||
};
|
||||
|
||||
const requestPayload: RequestPayload = {
|
||||
messages,
|
||||
messages: filteredMessages,
|
||||
stream: options.config.stream,
|
||||
model: modelConfig.model,
|
||||
temperature: modelConfig.temperature,
|
||||
@@ -116,16 +130,10 @@ export class DeepSeekApi implements LLMApi {
|
||||
headers: getHeaders(),
|
||||
};
|
||||
|
||||
// console.log(chatPayload);
|
||||
|
||||
const isR1 =
|
||||
options.config.model.endsWith("-reasoner") ||
|
||||
options.config.model.endsWith("-r1");
|
||||
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
isR1 ? REQUEST_TIMEOUT_MS_FOR_THINKING : REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
@@ -176,8 +184,8 @@ export class DeepSeekApi implements LLMApi {
|
||||
|
||||
// Skip if both content and reasoning_content are empty or null
|
||||
if (
|
||||
(!reasoning || reasoning.trim().length === 0) &&
|
||||
(!content || content.trim().length === 0)
|
||||
(!reasoning || reasoning.length === 0) &&
|
||||
(!content || content.length === 0)
|
||||
) {
|
||||
return {
|
||||
isThinking: false,
|
||||
@@ -185,12 +193,12 @@ export class DeepSeekApi implements LLMApi {
|
||||
};
|
||||
}
|
||||
|
||||
if (reasoning && reasoning.trim().length > 0) {
|
||||
if (reasoning && reasoning.length > 0) {
|
||||
return {
|
||||
isThinking: true,
|
||||
content: reasoning,
|
||||
};
|
||||
} else if (content && content.trim().length > 0) {
|
||||
} else if (content && content.length > 0) {
|
||||
return {
|
||||
isThinking: false,
|
||||
content: content,
|
||||
|
@@ -1,10 +1,5 @@
|
||||
"use client";
|
||||
import {
|
||||
ApiPath,
|
||||
CHATGLM_BASE_URL,
|
||||
ChatGLM,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
} from "@/app/constant";
|
||||
import { ApiPath, CHATGLM_BASE_URL, ChatGLM } from "@/app/constant";
|
||||
import {
|
||||
useAccessStore,
|
||||
useAppConfig,
|
||||
@@ -21,7 +16,11 @@ import {
|
||||
SpeechOptions,
|
||||
} from "../api";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { getMessageTextContent, isVisionModel } from "@/app/utils";
|
||||
import {
|
||||
getMessageTextContent,
|
||||
isVisionModel,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { RequestPayload } from "./openai";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
import { preProcessImageContent } from "@/app/utils/chat";
|
||||
@@ -191,7 +190,7 @@ export class ChatGLMApi implements LLMApi {
|
||||
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (modelType === "image" || modelType === "video") {
|
||||
|
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
ApiPath,
|
||||
Google,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
} from "@/app/constant";
|
||||
import { ApiPath, Google } from "@/app/constant";
|
||||
import {
|
||||
ChatOptions,
|
||||
getHeaders,
|
||||
@@ -27,6 +22,7 @@ import {
|
||||
getMessageTextContent,
|
||||
getMessageImages,
|
||||
isVisionModel,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { preProcessImageContent } from "@/app/utils/chat";
|
||||
import { nanoid } from "nanoid";
|
||||
@@ -206,7 +202,7 @@ export class GeminiProApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
isThinking ? REQUEST_TIMEOUT_MS_FOR_THINKING : REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
Azure,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
ServiceProvider,
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
} from "@/app/constant";
|
||||
import {
|
||||
ChatMessageTool,
|
||||
@@ -22,7 +21,7 @@ import {
|
||||
preProcessImageContent,
|
||||
uploadImage,
|
||||
base64Image2Blob,
|
||||
stream,
|
||||
streamWithThink,
|
||||
} from "@/app/utils/chat";
|
||||
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
|
||||
import { ModelSize, DalleQuality, DalleStyle } from "@/app/typing";
|
||||
@@ -42,6 +41,7 @@ import {
|
||||
getMessageTextContent,
|
||||
isVisionModel,
|
||||
isDalle3 as _isDalle3,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
|
||||
@@ -244,7 +244,7 @@ export class ChatGPTApi implements LLMApi {
|
||||
|
||||
// add max_tokens to vision model
|
||||
if (visionModel) {
|
||||
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
|
||||
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 8000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ export class ChatGPTApi implements LLMApi {
|
||||
useChatStore.getState().currentSession().mask?.plugin || [],
|
||||
);
|
||||
// console.log("getAsTools", tools, funcs);
|
||||
stream(
|
||||
streamWithThink(
|
||||
chatPath,
|
||||
requestPayload,
|
||||
getHeaders(),
|
||||
@@ -309,8 +309,12 @@ export class ChatGPTApi implements LLMApi {
|
||||
delta: {
|
||||
content: string;
|
||||
tool_calls: ChatMessageTool[];
|
||||
reasoning_content: string | null;
|
||||
};
|
||||
}>;
|
||||
|
||||
if (!choices?.length) return { isThinking: false, content: "" };
|
||||
|
||||
const tool_calls = choices[0]?.delta?.tool_calls;
|
||||
if (tool_calls?.length > 0) {
|
||||
const id = tool_calls[0]?.id;
|
||||
@@ -330,7 +334,37 @@ export class ChatGPTApi implements LLMApi {
|
||||
runTools[index]["function"]["arguments"] += args;
|
||||
}
|
||||
}
|
||||
return choices[0]?.delta?.content;
|
||||
|
||||
const reasoning = choices[0]?.delta?.reasoning_content;
|
||||
const content = choices[0]?.delta?.content;
|
||||
|
||||
// Skip if both content and reasoning_content are empty or null
|
||||
if (
|
||||
(!reasoning || reasoning.length === 0) &&
|
||||
(!content || content.length === 0)
|
||||
) {
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
}
|
||||
|
||||
if (reasoning && reasoning.length > 0) {
|
||||
return {
|
||||
isThinking: true,
|
||||
content: reasoning,
|
||||
};
|
||||
} else if (content && content.length > 0) {
|
||||
return {
|
||||
isThinking: false,
|
||||
content: content,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isThinking: false,
|
||||
content: "",
|
||||
};
|
||||
},
|
||||
// processToolMessage, include tool_calls message and tool call results
|
||||
(
|
||||
@@ -362,9 +396,7 @@ export class ChatGPTApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
isDalle3 || isO1OrO3
|
||||
? REQUEST_TIMEOUT_MS_FOR_THINKING
|
||||
: REQUEST_TIMEOUT_MS, // dalle3 using b64_json is slow.
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
const res = await fetch(chatPath, chatPayload);
|
||||
|
@@ -4,7 +4,7 @@ import {
|
||||
ApiPath,
|
||||
SILICONFLOW_BASE_URL,
|
||||
SiliconFlow,
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
DEFAULT_MODELS,
|
||||
} from "@/app/constant";
|
||||
import {
|
||||
useAccessStore,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ChatMessageTool,
|
||||
usePluginStore,
|
||||
} from "@/app/store";
|
||||
import { streamWithThink } from "@/app/utils/chat";
|
||||
import { preProcessImageContent, streamWithThink } from "@/app/utils/chat";
|
||||
import {
|
||||
ChatOptions,
|
||||
getHeaders,
|
||||
@@ -25,12 +25,23 @@ import { getClientConfig } from "@/app/config/client";
|
||||
import {
|
||||
getMessageTextContent,
|
||||
getMessageTextContentWithoutThinking,
|
||||
isVisionModel,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import { RequestPayload } from "./openai";
|
||||
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
export interface SiliconFlowListModelResponse {
|
||||
object: string;
|
||||
data: Array<{
|
||||
id: string;
|
||||
object: string;
|
||||
root: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export class SiliconflowApi implements LLMApi {
|
||||
private disableListModels = true;
|
||||
private disableListModels = false;
|
||||
|
||||
path(path: string): string {
|
||||
const accessStore = useAccessStore.getState();
|
||||
@@ -71,13 +82,16 @@ export class SiliconflowApi implements LLMApi {
|
||||
}
|
||||
|
||||
async chat(options: ChatOptions) {
|
||||
const visionModel = isVisionModel(options.config.model);
|
||||
const messages: ChatOptions["messages"] = [];
|
||||
for (const v of options.messages) {
|
||||
if (v.role === "assistant") {
|
||||
const content = getMessageTextContentWithoutThinking(v);
|
||||
messages.push({ role: v.role, content });
|
||||
} else {
|
||||
const content = getMessageTextContent(v);
|
||||
const content = visionModel
|
||||
? await preProcessImageContent(v.content)
|
||||
: getMessageTextContent(v);
|
||||
messages.push({ role: v.role, content });
|
||||
}
|
||||
}
|
||||
@@ -123,7 +137,7 @@ export class SiliconflowApi implements LLMApi {
|
||||
// Use extended timeout for thinking models as they typically require more processing time
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
@@ -238,6 +252,36 @@ export class SiliconflowApi implements LLMApi {
|
||||
}
|
||||
|
||||
async models(): Promise<LLMModel[]> {
|
||||
return [];
|
||||
if (this.disableListModels) {
|
||||
return DEFAULT_MODELS.slice();
|
||||
}
|
||||
|
||||
const res = await fetch(this.path(SiliconFlow.ListModelPath), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
...getHeaders(),
|
||||
},
|
||||
});
|
||||
|
||||
const resJson = (await res.json()) as SiliconFlowListModelResponse;
|
||||
const chatModels = resJson.data;
|
||||
console.log("[Models]", chatModels);
|
||||
|
||||
if (!chatModels) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let seq = 1000; //同 Constant.ts 中的排序保持一致
|
||||
return chatModels.map((m) => ({
|
||||
name: m.id,
|
||||
available: true,
|
||||
sorted: seq++,
|
||||
provider: {
|
||||
id: "siliconflow",
|
||||
providerName: "SiliconFlow",
|
||||
providerType: "siliconflow",
|
||||
sorted: 14,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { ApiPath, TENCENT_BASE_URL, REQUEST_TIMEOUT_MS } from "@/app/constant";
|
||||
import { ApiPath, TENCENT_BASE_URL } from "@/app/constant";
|
||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||
|
||||
import {
|
||||
@@ -17,7 +17,11 @@ import {
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { getMessageTextContent, isVisionModel } from "@/app/utils";
|
||||
import {
|
||||
getMessageTextContent,
|
||||
isVisionModel,
|
||||
getTimeoutMSByModel,
|
||||
} from "@/app/utils";
|
||||
import mapKeys from "lodash-es/mapKeys";
|
||||
import mapValues from "lodash-es/mapValues";
|
||||
import isArray from "lodash-es/isArray";
|
||||
@@ -135,7 +139,7 @@ export class HunyuanApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
// azure and openai, using same models. so using same LLMApi.
|
||||
import { ApiPath, XAI_BASE_URL, XAI, REQUEST_TIMEOUT_MS } from "@/app/constant";
|
||||
import { ApiPath, XAI_BASE_URL, XAI } from "@/app/constant";
|
||||
import {
|
||||
useAccessStore,
|
||||
useAppConfig,
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
SpeechOptions,
|
||||
} from "../api";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import { getTimeoutMSByModel } from "@/app/utils";
|
||||
import { preProcessImageContent } from "@/app/utils/chat";
|
||||
import { RequestPayload } from "./openai";
|
||||
import { fetch } from "@/app/utils/stream";
|
||||
@@ -103,7 +104,7 @@ export class XAIApi implements LLMApi {
|
||||
// make a fetch request
|
||||
const requestTimeoutId = setTimeout(
|
||||
() => controller.abort(),
|
||||
REQUEST_TIMEOUT_MS,
|
||||
getTimeoutMSByModel(options.config.model),
|
||||
);
|
||||
|
||||
if (shouldStream) {
|
||||
|
@@ -77,8 +77,6 @@ import {
|
||||
showPlugins,
|
||||
} from "../utils";
|
||||
|
||||
import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { ChatControllerPool } from "../client/controller";
|
||||
@@ -693,22 +691,71 @@ export function ChatActions(props: {
|
||||
onClose={() => setShowModelSelector(false)}
|
||||
onSelection={(s) => {
|
||||
if (s.length === 0) return;
|
||||
const [model, providerName] = getModelProvider(s[0]);
|
||||
chatStore.updateTargetSession(session, (session) => {
|
||||
session.mask.modelConfig.model = model as ModelType;
|
||||
session.mask.modelConfig.providerName =
|
||||
providerName as ServiceProvider;
|
||||
session.mask.syncGlobalConfig = false;
|
||||
});
|
||||
if (providerName == "ByteDance") {
|
||||
const selectedModel = models.find(
|
||||
(m) =>
|
||||
m.name == model &&
|
||||
m?.provider?.providerName == providerName,
|
||||
);
|
||||
showToast(selectedModel?.displayName ?? "");
|
||||
const selectedValue = s[0];
|
||||
console.log(
|
||||
"[ChatActions] Model selected raw value:",
|
||||
selectedValue,
|
||||
);
|
||||
// providerId here will be lowercase, e.g., "bedrock"
|
||||
const [model, providerId] = getModelProvider(selectedValue);
|
||||
console.log(
|
||||
"[ChatActions] Parsed model:",
|
||||
model,
|
||||
"Provider ID:",
|
||||
providerId,
|
||||
);
|
||||
|
||||
// Convert lowercase providerId to TitleCase ServiceProvider enum value
|
||||
let targetProvider: ServiceProvider | undefined;
|
||||
if (providerId) {
|
||||
const upperProvider =
|
||||
providerId.charAt(0).toUpperCase() + providerId.slice(1);
|
||||
if (
|
||||
Object.values(ServiceProvider).includes(
|
||||
upperProvider as ServiceProvider,
|
||||
)
|
||||
) {
|
||||
targetProvider = upperProvider as ServiceProvider;
|
||||
} else {
|
||||
console.error(
|
||||
`[ChatActions] Unknown provider ID: ${providerId}. Falling back to OpenAI.`,
|
||||
);
|
||||
// Handle error or fallback if needed
|
||||
targetProvider = ServiceProvider.OpenAI; // Fallback for unrecognized provider
|
||||
}
|
||||
} else {
|
||||
showToast(model);
|
||||
// Handle case where providerId is missing, maybe default to OpenAI?
|
||||
targetProvider = ServiceProvider.OpenAI;
|
||||
console.warn(
|
||||
`[ChatActions] Provider ID missing in ${selectedValue}, defaulting to OpenAI.`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
"[ChatActions] Target ServiceProvider Enum:",
|
||||
targetProvider,
|
||||
);
|
||||
|
||||
if (targetProvider) {
|
||||
// Only update if we found a valid provider
|
||||
chatStore.updateTargetSession(session, (session) => {
|
||||
session.mask.modelConfig.model = model as ModelType;
|
||||
session.mask.modelConfig.providerName = targetProvider!; // Use the Enum value (Assert non-null)
|
||||
session.mask.syncGlobalConfig = false;
|
||||
console.log(
|
||||
"[ChatActions] Updated session modelConfig:",
|
||||
session.mask.modelConfig,
|
||||
);
|
||||
});
|
||||
// Display toast based on provider
|
||||
const toastMessage =
|
||||
targetProvider === ServiceProvider.ByteDance
|
||||
? models.find(
|
||||
(m) =>
|
||||
m.name === model && m?.provider?.id === providerId,
|
||||
)?.displayName ?? model
|
||||
: model;
|
||||
showToast(toastMessage);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -920,7 +967,9 @@ export function DeleteImageButton(props: { deleteImage: () => void }) {
|
||||
}
|
||||
|
||||
export function ShortcutKeyModal(props: { onClose: () => void }) {
|
||||
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
||||
const isMac =
|
||||
typeof navigator !== "undefined" &&
|
||||
navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
||||
const shortcuts = [
|
||||
{
|
||||
title: Locale.Chat.ShortcutKey.newChat,
|
||||
@@ -1104,6 +1153,15 @@ function _Chat() {
|
||||
|
||||
const doSubmit = (userInput: string) => {
|
||||
if (userInput.trim() === "" && isEmpty(attachImages)) return;
|
||||
|
||||
console.log("[doSubmit] Called with:", {
|
||||
userInput: userInput?.substring(0, 50) + "...",
|
||||
hasAttachImages: !!attachImages,
|
||||
attachImagesCount: attachImages?.length || 0,
|
||||
attachImagesPreview:
|
||||
attachImages?.map((img) => img?.substring(0, 50) + "...") || [],
|
||||
});
|
||||
|
||||
const matchCommand = chatCommands.match(userInput);
|
||||
if (matchCommand.matched) {
|
||||
setUserInput("");
|
||||
@@ -1527,13 +1585,27 @@ function _Chat() {
|
||||
...(await new Promise<string[]>((res, rej) => {
|
||||
setUploading(true);
|
||||
const imagesData: string[] = [];
|
||||
uploadImageRemote(file)
|
||||
// Use compressImage directly to bypass cache issues
|
||||
import("@/app/utils/chat")
|
||||
.then(({ compressImage }) => compressImage(file, 256 * 1024))
|
||||
.then((dataUrl) => {
|
||||
console.log("[uploadImage] Compressed image:", {
|
||||
fileSize: file.size,
|
||||
fileName: file.name,
|
||||
dataUrlLength: dataUrl.length,
|
||||
isDataUrl: dataUrl.startsWith("data:"),
|
||||
});
|
||||
imagesData.push(dataUrl);
|
||||
setUploading(false);
|
||||
res(imagesData);
|
||||
if (
|
||||
imagesData.length === 3 ||
|
||||
imagesData.length === 1 // Only one file in this context
|
||||
) {
|
||||
setUploading(false);
|
||||
res(imagesData);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("[uploadImage] Compression failed:", e);
|
||||
setUploading(false);
|
||||
rej(e);
|
||||
});
|
||||
@@ -1569,8 +1641,16 @@ function _Chat() {
|
||||
const imagesData: string[] = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = event.target.files[i];
|
||||
uploadImageRemote(file)
|
||||
// Use compressImage directly to bypass cache issues
|
||||
import("@/app/utils/chat")
|
||||
.then(({ compressImage }) => compressImage(file, 256 * 1024))
|
||||
.then((dataUrl) => {
|
||||
console.log("[uploadImage] Compressed image:", {
|
||||
fileSize: file.size,
|
||||
fileName: file.name,
|
||||
dataUrlLength: dataUrl.length,
|
||||
isDataUrl: dataUrl.startsWith("data:"),
|
||||
});
|
||||
imagesData.push(dataUrl);
|
||||
if (
|
||||
imagesData.length === 3 ||
|
||||
@@ -1581,6 +1661,7 @@ function _Chat() {
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("[uploadImage] Compression failed:", e);
|
||||
setUploading(false);
|
||||
rej(e);
|
||||
});
|
||||
|
@@ -66,11 +66,11 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
|
||||
LlmIcon = BotIconGemma;
|
||||
} else if (modelName.startsWith("claude")) {
|
||||
LlmIcon = BotIconClaude;
|
||||
} else if (modelName.startsWith("llama")) {
|
||||
} else if (modelName.includes("llama")) {
|
||||
LlmIcon = BotIconMeta;
|
||||
} else if (modelName.startsWith("mixtral")) {
|
||||
} else if (modelName.startsWith("mixtral") || modelName.startsWith("codestral")) {
|
||||
LlmIcon = BotIconMistral;
|
||||
} else if (modelName.startsWith("deepseek")) {
|
||||
} else if (modelName.includes("deepseek")) {
|
||||
LlmIcon = BotIconDeepseek;
|
||||
} else if (modelName.startsWith("moonshot")) {
|
||||
LlmIcon = BotIconMoonshot;
|
||||
@@ -85,7 +85,7 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
|
||||
} else if (modelName.startsWith("doubao") || modelName.startsWith("ep-")) {
|
||||
LlmIcon = BotIconDoubao;
|
||||
} else if (
|
||||
modelName.startsWith("glm") ||
|
||||
modelName.includes("glm") ||
|
||||
modelName.startsWith("cogview-") ||
|
||||
modelName.startsWith("cogvideox-")
|
||||
) {
|
||||
|
@@ -23,7 +23,6 @@ import CopyIcon from "../icons/copy.svg";
|
||||
import LoadingIcon from "../icons/three-dots.svg";
|
||||
import ChatGptIcon from "../icons/chatgpt.png";
|
||||
import ShareIcon from "../icons/share.svg";
|
||||
import BotIcon from "../icons/bot.png";
|
||||
|
||||
import DownloadIcon from "../icons/download.svg";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -33,13 +32,13 @@ import dynamic from "next/dynamic";
|
||||
import NextImage from "next/image";
|
||||
|
||||
import { toBlob, toPng } from "html-to-image";
|
||||
import { DEFAULT_MASK_AVATAR } from "../store/mask";
|
||||
|
||||
import { prettyObject } from "../utils/format";
|
||||
import { EXPORT_MESSAGE_CLASS_NAME } from "../constant";
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { type ClientApi, getClientApi } from "../client/api";
|
||||
import { getMessageTextContent } from "../utils";
|
||||
import { MaskAvatar } from "./mask";
|
||||
import clsx from "clsx";
|
||||
|
||||
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
||||
@@ -407,22 +406,6 @@ export function PreviewActions(props: {
|
||||
);
|
||||
}
|
||||
|
||||
function ExportAvatar(props: { avatar: string }) {
|
||||
if (props.avatar === DEFAULT_MASK_AVATAR) {
|
||||
return (
|
||||
<img
|
||||
src={BotIcon.src}
|
||||
width={30}
|
||||
height={30}
|
||||
alt="bot"
|
||||
className="user-avatar"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <Avatar avatar={props.avatar} />;
|
||||
}
|
||||
|
||||
export function ImagePreviewer(props: {
|
||||
messages: ChatMessage[];
|
||||
topic: string;
|
||||
@@ -546,9 +529,12 @@ export function ImagePreviewer(props: {
|
||||
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
|
||||
</div>
|
||||
<div className={styles["icons"]}>
|
||||
<ExportAvatar avatar={config.avatar} />
|
||||
<MaskAvatar avatar={config.avatar} />
|
||||
<span className={styles["icon-space"]}>&</span>
|
||||
<ExportAvatar avatar={mask.avatar} />
|
||||
<MaskAvatar
|
||||
avatar={mask.avatar}
|
||||
model={session.mask.modelConfig.model}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -576,9 +562,14 @@ export function ImagePreviewer(props: {
|
||||
key={i}
|
||||
>
|
||||
<div className={styles["avatar"]}>
|
||||
<ExportAvatar
|
||||
avatar={m.role === "user" ? config.avatar : mask.avatar}
|
||||
/>
|
||||
{m.role === "user" ? (
|
||||
<Avatar avatar={config.avatar}></Avatar>
|
||||
) : (
|
||||
<MaskAvatar
|
||||
avatar={session.mask.avatar}
|
||||
model={m.model || session.mask.modelConfig.model}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles["body"]}>
|
||||
|
@@ -218,7 +218,7 @@ export function ModelConfigList(props: {
|
||||
aria-label={Locale.Settings.CompressThreshold.Title}
|
||||
type="number"
|
||||
min={500}
|
||||
max={4000}
|
||||
max={8000}
|
||||
value={props.modelConfig.compressMessageLengthThreshold}
|
||||
onChange={(e) =>
|
||||
props.updateConfig(
|
||||
|
@@ -163,19 +163,18 @@ export const getServerSideConfig = () => {
|
||||
const isXAI = !!process.env.XAI_API_KEY;
|
||||
const isChatGLM = !!process.env.CHATGLM_API_KEY;
|
||||
const isSiliconFlow = !!process.env.SILICONFLOW_API_KEY;
|
||||
// const apiKeyEnvVar = process.env.OPENAI_API_KEY ?? "";
|
||||
// const apiKeys = apiKeyEnvVar.split(",").map((v) => v.trim());
|
||||
// const randomIndex = Math.floor(Math.random() * apiKeys.length);
|
||||
// const apiKey = apiKeys[randomIndex];
|
||||
// console.log(
|
||||
// `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`,
|
||||
// );
|
||||
|
||||
const isBedrock =
|
||||
process.env.ENABLE_AWS_BEDROCK === "true" &&
|
||||
!!process.env.AWS_ACCESS_KEY_ID &&
|
||||
!!process.env.AWS_SECRET_ACCESS_KEY &&
|
||||
!!process.env.AWS_REGION;
|
||||
|
||||
const allowedWebDavEndpoints = (
|
||||
process.env.WHITE_WEBDAV_ENDPOINTS ?? ""
|
||||
).split(",");
|
||||
|
||||
return {
|
||||
const config = {
|
||||
baseUrl: process.env.BASE_URL,
|
||||
apiKey: getApiKey(process.env.OPENAI_API_KEY),
|
||||
openaiOrgId: process.env.OPENAI_ORG_ID,
|
||||
@@ -246,6 +245,12 @@ export const getServerSideConfig = () => {
|
||||
siliconFlowUrl: process.env.SILICONFLOW_URL,
|
||||
siliconFlowApiKey: getApiKey(process.env.SILICONFLOW_API_KEY),
|
||||
|
||||
isBedrock,
|
||||
bedrockRegion: process.env.AWS_REGION,
|
||||
bedrockAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||
bedrockSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
bedrockEndpoint: process.env.AWS_BEDROCK_ENDPOINT,
|
||||
|
||||
gtmId: process.env.GTM_ID,
|
||||
gaId: process.env.GA_ID || DEFAULT_GA_ID,
|
||||
|
||||
@@ -266,4 +271,5 @@ export const getServerSideConfig = () => {
|
||||
allowedWebDavEndpoints,
|
||||
enableMcp: process.env.ENABLE_MCP === "true",
|
||||
};
|
||||
return config;
|
||||
};
|
||||
|
@@ -72,6 +72,7 @@ export enum ApiPath {
|
||||
ChatGLM = "/api/chatglm",
|
||||
DeepSeek = "/api/deepseek",
|
||||
SiliconFlow = "/api/siliconflow",
|
||||
Bedrock = "/api/bedrock",
|
||||
}
|
||||
|
||||
export enum SlotID {
|
||||
@@ -130,6 +131,7 @@ export enum ServiceProvider {
|
||||
ChatGLM = "ChatGLM",
|
||||
DeepSeek = "DeepSeek",
|
||||
SiliconFlow = "SiliconFlow",
|
||||
Bedrock = "Bedrock",
|
||||
}
|
||||
|
||||
// Google API safety settings, see https://ai.google.dev/gemini-api/docs/safety-settings
|
||||
@@ -156,6 +158,7 @@ export enum ModelProvider {
|
||||
ChatGLM = "ChatGLM",
|
||||
DeepSeek = "DeepSeek",
|
||||
SiliconFlow = "SiliconFlow",
|
||||
Bedrock = "Bedrock",
|
||||
}
|
||||
|
||||
export const Stability = {
|
||||
@@ -221,7 +224,12 @@ export const ByteDance = {
|
||||
|
||||
export const Alibaba = {
|
||||
ExampleEndpoint: ALIBABA_BASE_URL,
|
||||
ChatPath: "v1/services/aigc/text-generation/generation",
|
||||
ChatPath: (modelName: string) => {
|
||||
if (modelName.includes("vl") || modelName.includes("omni")) {
|
||||
return "v1/services/aigc/multimodal-generation/generation";
|
||||
}
|
||||
return `v1/services/aigc/text-generation/generation`;
|
||||
},
|
||||
};
|
||||
|
||||
export const Tencent = {
|
||||
@@ -258,6 +266,11 @@ export const ChatGLM = {
|
||||
export const SiliconFlow = {
|
||||
ExampleEndpoint: SILICONFLOW_BASE_URL,
|
||||
ChatPath: "v1/chat/completions",
|
||||
ListModelPath: "v1/models?&sub_type=chat",
|
||||
};
|
||||
|
||||
export const Bedrock = {
|
||||
ChatPath: "v1/chat/completions",
|
||||
};
|
||||
|
||||
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
|
||||
@@ -453,6 +466,7 @@ export const VISION_MODEL_REGEXES = [
|
||||
/vision/,
|
||||
/gpt-4o/,
|
||||
/claude-3/,
|
||||
/anthropic\.claude-3/,
|
||||
/gemini-1\.5/,
|
||||
/gemini-exp/,
|
||||
/gemini-2\.0/,
|
||||
@@ -462,6 +476,7 @@ export const VISION_MODEL_REGEXES = [
|
||||
/gpt-4-turbo(?!.*preview)/, // Matches "gpt-4-turbo" but not "gpt-4-turbo-preview"
|
||||
/^dall-e-3$/, // Matches exactly "dall-e-3"
|
||||
/glm-4v/,
|
||||
/vl/i,
|
||||
];
|
||||
|
||||
export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
|
||||
@@ -533,6 +548,8 @@ const anthropicModels = [
|
||||
"claude-3-5-sonnet-20240620",
|
||||
"claude-3-5-sonnet-20241022",
|
||||
"claude-3-5-sonnet-latest",
|
||||
"claude-3-7-sonnet-20250219",
|
||||
"claude-3-7-sonnet-latest",
|
||||
];
|
||||
|
||||
const baiduModels = [
|
||||
@@ -566,6 +583,9 @@ const alibabaModes = [
|
||||
"qwen-max-0403",
|
||||
"qwen-max-0107",
|
||||
"qwen-max-longcontext",
|
||||
"qwen-omni-turbo",
|
||||
"qwen-vl-plus",
|
||||
"qwen-vl-max",
|
||||
];
|
||||
|
||||
const tencentModels = [
|
||||
@@ -638,6 +658,24 @@ const siliconflowModels = [
|
||||
"Pro/deepseek-ai/DeepSeek-V3",
|
||||
];
|
||||
|
||||
const bedrockModels = [
|
||||
"anthropic.claude-3-opus-20240229-v1:0",
|
||||
"anthropic.claude-3-sonnet-20240229-v1:0",
|
||||
"anthropic.claude-3-haiku-20240307-v1:0",
|
||||
"anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
"anthropic.claude-3-5-sonnet-20241022-v1:0",
|
||||
"anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
"anthropic.claude-instant-v1",
|
||||
"amazon.titan-text-express-v1",
|
||||
"amazon.titan-text-lite-v1",
|
||||
"cohere.command-text-v14",
|
||||
"cohere.command-light-text-v14",
|
||||
"ai21.j2-ultra-v1",
|
||||
"ai21.j2-mid-v1",
|
||||
"meta.llama2-13b-chat-v1",
|
||||
"meta.llama2-70b-chat-v1",
|
||||
];
|
||||
|
||||
let seq = 1000; // 内置的模型序号生成器从1000开始
|
||||
export const DEFAULT_MODELS = [
|
||||
...openaiModels.map((name) => ({
|
||||
@@ -794,6 +832,17 @@ export const DEFAULT_MODELS = [
|
||||
sorted: 14,
|
||||
},
|
||||
})),
|
||||
...bedrockModels.map((name) => ({
|
||||
name,
|
||||
available: true,
|
||||
sorted: seq++,
|
||||
provider: {
|
||||
id: "bedrock",
|
||||
providerName: "Bedrock",
|
||||
providerType: "bedrock",
|
||||
sorted: 15,
|
||||
},
|
||||
})),
|
||||
] as const;
|
||||
|
||||
export const CHAT_PAGE_SIZE = 15;
|
||||
@@ -814,5 +863,5 @@ export const internalAllowedWebDavEndpoints = [
|
||||
|
||||
export const DEFAULT_GA_ID = "G-89WN60ZK2E";
|
||||
|
||||
export const SAAS_CHAT_URL = "https://nextchat.dev/chat";
|
||||
export const SAAS_CHAT_UTM_URL = "https://nextchat.dev/chat?utm=github";
|
||||
export const SAAS_CHAT_URL = "https://nextchat.club";
|
||||
export const SAAS_CHAT_UTM_URL = "https://nextchat.club?utm=github";
|
||||
|
832
app/locales/da.ts
Normal file
832
app/locales/da.ts
Normal file
@@ -0,0 +1,832 @@
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { SubmitKey } from "../store/config";
|
||||
import { SAAS_CHAT_UTM_URL } from "@/app/constant";
|
||||
import { PartialLocaleType } from "./index";
|
||||
|
||||
const isApp = !!getClientConfig()?.isApp;
|
||||
const da: PartialLocaleType = {
|
||||
WIP: "Der kommer snart mere...",
|
||||
Error: {
|
||||
Unauthorized: isApp
|
||||
? `Hov, der skete en fejl. Sådan kan du komme videre:
|
||||
\\ 1️⃣ Er du ny her? [Tryk for at starte nu 🚀](${SAAS_CHAT_UTM_URL})
|
||||
\\ 2️⃣ Vil du bruge dine egne OpenAI-nøgler? [Tryk her](/#/settings) for at ændre indstillinger ⚙️`
|
||||
: `Hov, der skete en fejl. Lad os løse det:
|
||||
\\ 1️⃣ Er du ny her? [Tryk for at starte nu 🚀](${SAAS_CHAT_UTM_URL})
|
||||
\\ 2️⃣ Bruger du en privat opsætning? [Tryk her](/#/auth) for at taste din nøgle 🔑
|
||||
\\ 3️⃣ Vil du bruge dine egne OpenAI-nøgler? [Tryk her](/#/settings) for at ændre indstillinger ⚙️
|
||||
`,
|
||||
},
|
||||
Auth: {
|
||||
Return: "Tilbage",
|
||||
Title: "Adgangskode",
|
||||
Tips: "Skriv venligst koden herunder",
|
||||
SubTips: "Eller brug din egen OpenAI- eller Google-nøgle",
|
||||
Input: "Adgangskode",
|
||||
Confirm: "OK",
|
||||
Later: "Senere",
|
||||
SaasTips: "Hvis det er for svært, kan du starte nu",
|
||||
},
|
||||
ChatItem: {
|
||||
ChatItemCount: (count: number) => `${count} beskeder`,
|
||||
},
|
||||
Chat: {
|
||||
SubTitle: (count: number) => `${count} beskeder`,
|
||||
EditMessage: {
|
||||
Title: "Rediger beskeder",
|
||||
Topic: {
|
||||
Title: "Emne",
|
||||
SubTitle: "Skift emne for denne chat",
|
||||
},
|
||||
},
|
||||
Actions: {
|
||||
ChatList: "Gå til chatliste",
|
||||
CompressedHistory: "Komprimeret historie",
|
||||
Export: "Eksporter alle beskeder som Markdown",
|
||||
Copy: "Kopiér",
|
||||
Stop: "Stop",
|
||||
Retry: "Prøv igen",
|
||||
Pin: "Fastgør",
|
||||
PinToastContent: "1 besked er nu fastgjort",
|
||||
PinToastAction: "Se",
|
||||
Delete: "Slet",
|
||||
Edit: "Rediger",
|
||||
FullScreen: "Fuld skærm",
|
||||
RefreshTitle: "Opdatér titel",
|
||||
RefreshToast: "Anmodning om ny titel sendt",
|
||||
Speech: "Afspil",
|
||||
StopSpeech: "Stop",
|
||||
},
|
||||
Commands: {
|
||||
new: "Ny chat",
|
||||
newm: "Ny chat med persona",
|
||||
next: "Næste chat",
|
||||
prev: "Forrige chat",
|
||||
clear: "Ryd alt før",
|
||||
fork: "Kopiér chat",
|
||||
del: "Slet chat",
|
||||
},
|
||||
InputActions: {
|
||||
Stop: "Stop",
|
||||
ToBottom: "Ned til nyeste",
|
||||
Theme: {
|
||||
auto: "Automatisk",
|
||||
light: "Lyst tema",
|
||||
dark: "Mørkt tema",
|
||||
},
|
||||
Prompt: "Prompts",
|
||||
Masks: "Personaer",
|
||||
Clear: "Ryd kontekst",
|
||||
Settings: "Indstillinger",
|
||||
UploadImage: "Upload billeder",
|
||||
},
|
||||
Rename: "Omdøb chat",
|
||||
Typing: "Skriver…",
|
||||
Input: (submitKey: string) => {
|
||||
let inputHints = `${submitKey} for at sende`;
|
||||
if (submitKey === String(SubmitKey.Enter)) {
|
||||
inputHints += ", Shift + Enter for ny linje";
|
||||
}
|
||||
return (
|
||||
inputHints + ", / for at søge i prompts, : for at bruge kommandoer"
|
||||
);
|
||||
},
|
||||
Send: "Send",
|
||||
StartSpeak: "Start oplæsning",
|
||||
StopSpeak: "Stop oplæsning",
|
||||
Config: {
|
||||
Reset: "Nulstil til standard",
|
||||
SaveAs: "Gem som persona",
|
||||
},
|
||||
IsContext: "Ekstra prompt til baggrund",
|
||||
ShortcutKey: {
|
||||
Title: "Hurtigtaster",
|
||||
newChat: "Åbn ny chat",
|
||||
focusInput: "Fokus på tekstfeltet",
|
||||
copyLastMessage: "Kopiér sidste svar",
|
||||
copyLastCode: "Kopiér sidste kodeblok",
|
||||
showShortcutKey: "Vis hurtigtaster",
|
||||
clearContext: "Ryd kontekst",
|
||||
},
|
||||
},
|
||||
Export: {
|
||||
Title: "Eksportér beskeder",
|
||||
Copy: "Kopiér alt",
|
||||
Download: "Download",
|
||||
MessageFromYou: "Fra dig",
|
||||
MessageFromChatGPT: "Fra ChatGPT",
|
||||
Share: "Del til ShareGPT",
|
||||
Format: {
|
||||
Title: "Filformat",
|
||||
SubTitle: "Vælg enten Markdown eller PNG-billede",
|
||||
},
|
||||
IncludeContext: {
|
||||
Title: "Tag baggrund med",
|
||||
SubTitle: "Skal ekstra baggrund (persona) med i eksporten?",
|
||||
},
|
||||
Steps: {
|
||||
Select: "Vælg",
|
||||
Preview: "Forhåndsvis",
|
||||
},
|
||||
Image: {
|
||||
Toast: "Laver billede...",
|
||||
Modal: "Tryk længe eller højreklik for at gemme",
|
||||
},
|
||||
Artifacts: {
|
||||
Title: "Del side",
|
||||
Error: "Fejl ved deling",
|
||||
},
|
||||
},
|
||||
Select: {
|
||||
Search: "Søg",
|
||||
All: "Vælg alle",
|
||||
Latest: "Vælg nyeste",
|
||||
Clear: "Ryd alt",
|
||||
},
|
||||
Memory: {
|
||||
Title: "Huskesætning",
|
||||
EmptyContent: "Ingenting lige nu.",
|
||||
Send: "Send huskesætning",
|
||||
Copy: "Kopiér huskesætning",
|
||||
Reset: "Nulstil chat",
|
||||
ResetConfirm:
|
||||
"Dette sletter nuværende samtale og hukommelse. Er du sikker?",
|
||||
},
|
||||
Home: {
|
||||
NewChat: "Ny Chat",
|
||||
DeleteChat: "Vil du slette den valgte chat?",
|
||||
DeleteToast: "Chat slettet",
|
||||
Revert: "Fortryd",
|
||||
},
|
||||
Settings: {
|
||||
Title: "Indstillinger",
|
||||
SubTitle: "Alle indstillinger",
|
||||
ShowPassword: "Vis kodeord",
|
||||
Danger: {
|
||||
Reset: {
|
||||
Title: "Nulstil alle indstillinger",
|
||||
SubTitle: "Gendan alt til standard",
|
||||
Action: "Nulstil",
|
||||
Confirm: "Vil du virkelig nulstille alt?",
|
||||
},
|
||||
Clear: {
|
||||
Title: "Slet alle data",
|
||||
SubTitle: "Sletter alt om beskeder og indstillinger",
|
||||
Action: "Slet",
|
||||
Confirm: "Er du sikker på, at du vil slette alt?",
|
||||
},
|
||||
},
|
||||
Lang: {
|
||||
Name: "Language",
|
||||
All: "Alle sprog",
|
||||
},
|
||||
Avatar: "Avatar",
|
||||
FontSize: {
|
||||
Title: "Skriftstørrelse",
|
||||
SubTitle: "Vælg, hvor stor teksten skal være",
|
||||
},
|
||||
FontFamily: {
|
||||
Title: "Skrifttype",
|
||||
SubTitle: "Hvis tom, bruger den standard skrifttype",
|
||||
Placeholder: "Skrifttype-navn",
|
||||
},
|
||||
InjectSystemPrompts: {
|
||||
Title: "Tilføj system-prompt",
|
||||
SubTitle: "Læg altid en ekstra prompt først i anmodninger",
|
||||
},
|
||||
InputTemplate: {
|
||||
Title: "Tekstskabelon",
|
||||
SubTitle: "Den seneste besked placeres i denne skabelon",
|
||||
},
|
||||
Update: {
|
||||
Version: (x: string) => `Version: ${x}`,
|
||||
IsLatest: "Du har nyeste version",
|
||||
CheckUpdate: "Tjek efter opdatering",
|
||||
IsChecking: "Tjekker...",
|
||||
FoundUpdate: (x: string) => `Ny version fundet: ${x}`,
|
||||
GoToUpdate: "Opdatér",
|
||||
Success: "Opdatering lykkedes.",
|
||||
Failed: "Opdatering mislykkedes.",
|
||||
},
|
||||
SendKey: "Tast for send",
|
||||
Theme: "Tema",
|
||||
TightBorder: "Stram kant",
|
||||
SendPreviewBubble: {
|
||||
Title: "Forhåndsvisnings-boble",
|
||||
SubTitle: "Vis tekst, før den sendes",
|
||||
},
|
||||
AutoGenerateTitle: {
|
||||
Title: "Lav titel automatisk",
|
||||
SubTitle: "Foreslå en titel ud fra chatten",
|
||||
},
|
||||
Sync: {
|
||||
CloudState: "Seneste opdatering",
|
||||
NotSyncYet: "Endnu ikke synkroniseret",
|
||||
Success: "Synkronisering lykkedes",
|
||||
Fail: "Synkronisering mislykkedes",
|
||||
Config: {
|
||||
Modal: {
|
||||
Title: "Indstil synk",
|
||||
Check: "Tjek forbindelse",
|
||||
},
|
||||
SyncType: {
|
||||
Title: "Synk-type",
|
||||
SubTitle: "Vælg en synk-tjeneste",
|
||||
},
|
||||
Proxy: {
|
||||
Title: "Aktivér proxy",
|
||||
SubTitle: "Brug proxy for at undgå netværksproblemer",
|
||||
},
|
||||
ProxyUrl: {
|
||||
Title: "Proxy-adresse",
|
||||
SubTitle: "Bruges kun til projektets egen proxy",
|
||||
},
|
||||
WebDav: {
|
||||
Endpoint: "WebDAV-adresse",
|
||||
UserName: "Brugernavn",
|
||||
Password: "Kodeord",
|
||||
},
|
||||
UpStash: {
|
||||
Endpoint: "UpStash Redis REST URL",
|
||||
UserName: "Backup-navn",
|
||||
Password: "UpStash Redis REST Token",
|
||||
},
|
||||
},
|
||||
LocalState: "Lokale data",
|
||||
Overview: (overview: any) =>
|
||||
`${overview.chat} chats, ${overview.message} beskeder, ${overview.prompt} prompts, ${overview.mask} personaer`,
|
||||
ImportFailed: "Import mislykkedes",
|
||||
},
|
||||
Mask: {
|
||||
Splash: {
|
||||
Title: "Persona-forside",
|
||||
SubTitle: "Vis denne side, når du opretter ny chat",
|
||||
},
|
||||
Builtin: {
|
||||
Title: "Skjul indbyggede personaer",
|
||||
SubTitle: "Vis ikke de indbyggede personaer i listen",
|
||||
},
|
||||
},
|
||||
Prompt: {
|
||||
Disable: {
|
||||
Title: "Slå auto-forslag fra",
|
||||
SubTitle: "Tast / for at få forslag",
|
||||
},
|
||||
List: "Prompt-liste",
|
||||
ListCount: (builtin: number, custom: number) =>
|
||||
`${builtin} indbygget, ${custom} brugerdefineret`,
|
||||
Edit: "Rediger",
|
||||
Modal: {
|
||||
Title: "Prompt-liste",
|
||||
Add: "Tilføj",
|
||||
Search: "Søg prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Rediger prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Antal beskeder, der følger med",
|
||||
SubTitle: "Hvor mange af de tidligere beskeder, der sendes hver gang",
|
||||
},
|
||||
CompressThreshold: {
|
||||
Title: "Komprimeringsgrænse",
|
||||
SubTitle:
|
||||
"Hvis chatten bliver for lang, vil den komprimeres efter dette antal tegn",
|
||||
},
|
||||
Usage: {
|
||||
Title: "Brug og saldo",
|
||||
SubTitle(used: any, total: any) {
|
||||
return `Du har brugt $${used} i denne måned, og din grænse er $${total}.`;
|
||||
},
|
||||
IsChecking: "Tjekker...",
|
||||
Check: "Tjek igen",
|
||||
NoAccess: "Indtast API-nøgle for at se forbrug",
|
||||
},
|
||||
Access: {
|
||||
AccessCode: {
|
||||
Title: "Adgangskode",
|
||||
SubTitle: "Adgangskontrol er slået til",
|
||||
Placeholder: "Skriv kode her",
|
||||
},
|
||||
CustomEndpoint: {
|
||||
Title: "Brugerdefineret adresse",
|
||||
SubTitle: "Brug Azure eller OpenAI fra egen server",
|
||||
},
|
||||
Provider: {
|
||||
Title: "Model-udbyder",
|
||||
SubTitle: "Vælg Azure eller OpenAI",
|
||||
},
|
||||
OpenAI: {
|
||||
ApiKey: {
|
||||
Title: "OpenAI API-nøgle",
|
||||
SubTitle: "Brug din egen nøgle",
|
||||
Placeholder: "sk-xxx",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "OpenAI Endpoint",
|
||||
SubTitle: "Skal starte med http(s):// eller /api/openai som standard",
|
||||
},
|
||||
},
|
||||
Azure: {
|
||||
ApiKey: {
|
||||
Title: "Azure Api Key",
|
||||
SubTitle: "Hent din nøgle fra Azure-portalen",
|
||||
Placeholder: "Azure Api Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Azure Endpoint",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
ApiVerion: {
|
||||
Title: "Azure Api Version",
|
||||
SubTitle: "Hentet fra Azure-portalen",
|
||||
},
|
||||
},
|
||||
Anthropic: {
|
||||
ApiKey: {
|
||||
Title: "Anthropic API-nøgle",
|
||||
SubTitle: "Brug din egen Anthropic-nøgle",
|
||||
Placeholder: "Anthropic API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Endpoint-adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
ApiVerion: {
|
||||
Title: "API-version (Claude)",
|
||||
SubTitle: "Vælg den ønskede version",
|
||||
},
|
||||
},
|
||||
Baidu: {
|
||||
ApiKey: {
|
||||
Title: "Baidu-nøgle",
|
||||
SubTitle: "Din egen Baidu-nøgle",
|
||||
Placeholder: "Baidu API Key",
|
||||
},
|
||||
SecretKey: {
|
||||
Title: "Baidu hemmelig nøgle",
|
||||
SubTitle: "Din egen hemmelige nøgle fra Baidu",
|
||||
Placeholder: "Baidu Secret Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "Kan ikke ændres, se .env",
|
||||
},
|
||||
},
|
||||
Tencent: {
|
||||
ApiKey: {
|
||||
Title: "Tencent-nøgle",
|
||||
SubTitle: "Din egen nøgle fra Tencent",
|
||||
Placeholder: "Tencent API Key",
|
||||
},
|
||||
SecretKey: {
|
||||
Title: "Tencent hemmelig nøgle",
|
||||
SubTitle: "Din egen hemmelige nøgle fra Tencent",
|
||||
Placeholder: "Tencent Secret Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "Kan ikke ændres, se .env",
|
||||
},
|
||||
},
|
||||
ByteDance: {
|
||||
ApiKey: {
|
||||
Title: "ByteDance-nøgle",
|
||||
SubTitle: "Din egen nøgle til ByteDance",
|
||||
Placeholder: "ByteDance API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
Alibaba: {
|
||||
ApiKey: {
|
||||
Title: "Alibaba-nøgle",
|
||||
SubTitle: "Din egen Alibaba Cloud-nøgle",
|
||||
Placeholder: "Alibaba Cloud API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
Moonshot: {
|
||||
ApiKey: {
|
||||
Title: "Moonshot-nøgle",
|
||||
SubTitle: "Din egen Moonshot-nøgle",
|
||||
Placeholder: "Moonshot API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
DeepSeek: {
|
||||
ApiKey: {
|
||||
Title: "DeepSeek-nøgle",
|
||||
SubTitle: "Din egen DeepSeek-nøgle",
|
||||
Placeholder: "DeepSeek API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
XAI: {
|
||||
ApiKey: {
|
||||
Title: "XAI-nøgle",
|
||||
SubTitle: "Din egen XAI-nøgle",
|
||||
Placeholder: "XAI API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
ChatGLM: {
|
||||
ApiKey: {
|
||||
Title: "ChatGLM-nøgle",
|
||||
SubTitle: "Din egen ChatGLM-nøgle",
|
||||
Placeholder: "ChatGLM API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
SiliconFlow: {
|
||||
ApiKey: {
|
||||
Title: "SiliconFlow-nøgle",
|
||||
SubTitle: "Din egen SiliconFlow-nøgle",
|
||||
Placeholder: "SiliconFlow API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
Stability: {
|
||||
ApiKey: {
|
||||
Title: "Stability-nøgle",
|
||||
SubTitle: "Din egen Stability-nøgle",
|
||||
Placeholder: "Stability API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
Iflytek: {
|
||||
ApiKey: {
|
||||
Title: "Iflytek API Key",
|
||||
SubTitle: "Nøgle fra Iflytek",
|
||||
Placeholder: "Iflytek API Key",
|
||||
},
|
||||
ApiSecret: {
|
||||
Title: "Iflytek hemmelig nøgle",
|
||||
SubTitle: "Hentet fra Iflytek",
|
||||
Placeholder: "Iflytek API Secret",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
},
|
||||
CustomModel: {
|
||||
Title: "Egne modelnavne",
|
||||
SubTitle: "Skriv komma-adskilte navne",
|
||||
},
|
||||
Google: {
|
||||
ApiKey: {
|
||||
Title: "Google-nøgle",
|
||||
SubTitle: "Få din nøgle hos Google AI",
|
||||
Placeholder: "Google AI API Key",
|
||||
},
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "F.eks.: ",
|
||||
},
|
||||
ApiVersion: {
|
||||
Title: "API-version (til gemini-pro)",
|
||||
SubTitle: "Vælg en bestemt version",
|
||||
},
|
||||
GoogleSafetySettings: {
|
||||
Title: "Google sikkerhedsindstillinger",
|
||||
SubTitle: "Vælg et niveau for indholdskontrol",
|
||||
},
|
||||
},
|
||||
},
|
||||
Model: "Model",
|
||||
CompressModel: {
|
||||
Title: "Opsummeringsmodel",
|
||||
SubTitle: "Bruges til at korte historik ned og lave titel",
|
||||
},
|
||||
Temperature: {
|
||||
Title: "Temperatur",
|
||||
SubTitle: "Jo højere tal, jo mere kreativt svar",
|
||||
},
|
||||
TopP: {
|
||||
Title: "Top P",
|
||||
SubTitle: "Skal ikke ændres sammen med temperatur",
|
||||
},
|
||||
MaxTokens: {
|
||||
Title: "Maks. længde",
|
||||
SubTitle: "Hvor mange tokens (ord/stykker tekst) der kan bruges",
|
||||
},
|
||||
PresencePenalty: {
|
||||
Title: "Nye emner",
|
||||
SubTitle: "Jo højere tal, jo mere nyt indhold",
|
||||
},
|
||||
FrequencyPenalty: {
|
||||
Title: "Gentagelsesstraf",
|
||||
SubTitle: "Jo højere tal, jo mindre gentagelse",
|
||||
},
|
||||
TTS: {
|
||||
Enable: {
|
||||
Title: "Tænd for oplæsning (TTS)",
|
||||
SubTitle: "Slå tekst-til-tale til",
|
||||
},
|
||||
Autoplay: {
|
||||
Title: "Automatisk oplæsning",
|
||||
SubTitle: "Laver lyd automatisk, hvis TTS er slået til",
|
||||
},
|
||||
Model: "Model",
|
||||
Voice: {
|
||||
Title: "Stemme",
|
||||
SubTitle: "Hvilken stemme der bruges til lyd",
|
||||
},
|
||||
Speed: {
|
||||
Title: "Hastighed",
|
||||
SubTitle: "Hvor hurtigt der oplæses",
|
||||
},
|
||||
Engine: "TTS-motor",
|
||||
},
|
||||
Realtime: {
|
||||
Enable: {
|
||||
Title: "Live-chat",
|
||||
SubTitle: "Slå live-svar til",
|
||||
},
|
||||
Provider: {
|
||||
Title: "Modeludbyder",
|
||||
SubTitle: "Vælg forskellig udbyder",
|
||||
},
|
||||
Model: {
|
||||
Title: "Model",
|
||||
SubTitle: "Vælg en model",
|
||||
},
|
||||
ApiKey: {
|
||||
Title: "API-nøgle",
|
||||
SubTitle: "Din nøgle",
|
||||
Placeholder: "API-nøgle",
|
||||
},
|
||||
Azure: {
|
||||
Endpoint: {
|
||||
Title: "Adresse",
|
||||
SubTitle: "Endpoint til Azure",
|
||||
},
|
||||
Deployment: {
|
||||
Title: "Udrulningsnavn",
|
||||
SubTitle: "Navn for dit Azure-setup",
|
||||
},
|
||||
},
|
||||
Temperature: {
|
||||
Title: "Temperatur",
|
||||
SubTitle: "Højere tal = mere varierede svar",
|
||||
},
|
||||
},
|
||||
},
|
||||
Store: {
|
||||
DefaultTopic: "Ny samtale",
|
||||
BotHello: "Hej! Hvordan kan jeg hjælpe dig i dag?",
|
||||
Error: "Noget gik galt. Prøv igen senere.",
|
||||
Prompt: {
|
||||
History: (content: string) =>
|
||||
"Her er et kort resume af, hvad vi har snakket om: " + content,
|
||||
Topic:
|
||||
"Find en kort overskrift med 4-5 ord om emnet. Ingen tegnsætning eller anførselstegn.",
|
||||
Summarize:
|
||||
"Skriv et kort resumé (under 200 ord) af vores samtale til senere brug.",
|
||||
},
|
||||
},
|
||||
Copy: {
|
||||
Success: "Kopieret",
|
||||
Failed: "Kunne ikke kopiere. Giv adgang til udklipsholder.",
|
||||
},
|
||||
Download: {
|
||||
Success: "Filen er downloadet.",
|
||||
Failed: "Download fejlede.",
|
||||
},
|
||||
Context: {
|
||||
Toast: (x: any) => `Inkluderer ${x} ekstra prompts`,
|
||||
Edit: "Chatindstillinger",
|
||||
Add: "Tilføj prompt",
|
||||
Clear: "Kontekst ryddet",
|
||||
Revert: "Fortryd",
|
||||
},
|
||||
Discovery: {
|
||||
Name: "Søgning og plugins",
|
||||
},
|
||||
Mcp: {
|
||||
Name: "MCP",
|
||||
},
|
||||
FineTuned: {
|
||||
Sysmessage: "Du er en hjælper, der skal...",
|
||||
},
|
||||
SearchChat: {
|
||||
Name: "Søg",
|
||||
Page: {
|
||||
Title: "Søg i tidligere chats",
|
||||
Search: "Skriv her for at søge",
|
||||
NoResult: "Ingen resultater",
|
||||
NoData: "Ingen data",
|
||||
Loading: "Henter...",
|
||||
SubTitle: (count: number) => `Fandt ${count} resultater`,
|
||||
},
|
||||
Item: {
|
||||
View: "Vis",
|
||||
},
|
||||
},
|
||||
Plugin: {
|
||||
Name: "Plugin",
|
||||
Page: {
|
||||
Title: "Plugins",
|
||||
SubTitle: (count: number) => `${count} plugins`,
|
||||
Search: "Søg plugin",
|
||||
Create: "Opret nyt",
|
||||
Find: "Du kan finde flere plugins på GitHub: ",
|
||||
},
|
||||
Item: {
|
||||
Info: (count: number) => `${count} metode`,
|
||||
View: "Vis",
|
||||
Edit: "Rediger",
|
||||
Delete: "Slet",
|
||||
DeleteConfirm: "Vil du slette?",
|
||||
},
|
||||
Auth: {
|
||||
None: "Ingen",
|
||||
Basic: "Basic",
|
||||
Bearer: "Bearer",
|
||||
Custom: "Tilpasset",
|
||||
CustomHeader: "Parameternavn",
|
||||
Token: "Token",
|
||||
Proxy: "Brug Proxy",
|
||||
ProxyDescription: "Løs CORS-problemer med Proxy",
|
||||
Location: "Sted",
|
||||
LocationHeader: "Header",
|
||||
LocationQuery: "Query",
|
||||
LocationBody: "Body",
|
||||
},
|
||||
EditModal: {
|
||||
Title: (readonly: boolean) =>
|
||||
`Rediger Plugin ${readonly ? "(skrivebeskyttet)" : ""}`,
|
||||
Download: "Download",
|
||||
Auth: "Godkendelsestype",
|
||||
Content: "OpenAPI Schema",
|
||||
Load: "Hent fra URL",
|
||||
Method: "Metode",
|
||||
Error: "Fejl i OpenAPI Schema",
|
||||
},
|
||||
},
|
||||
Mask: {
|
||||
Name: "Persona",
|
||||
Page: {
|
||||
Title: "Prompts som personaer",
|
||||
SubTitle: (count: number) => `${count} skabeloner`,
|
||||
Search: "Søg skabeloner",
|
||||
Create: "Opret ny",
|
||||
},
|
||||
Item: {
|
||||
Info: (count: number) => `${count} prompts`,
|
||||
Chat: "Chat",
|
||||
View: "Vis",
|
||||
Edit: "Rediger",
|
||||
Delete: "Slet",
|
||||
DeleteConfirm: "Vil du slette?",
|
||||
},
|
||||
EditModal: {
|
||||
Title: (readonly: boolean) =>
|
||||
`Rediger skabelon ${readonly ? "(skrivebeskyttet)" : ""}`,
|
||||
Download: "Download",
|
||||
Clone: "Klon",
|
||||
},
|
||||
Config: {
|
||||
Avatar: "Chat-avatar",
|
||||
Name: "Chat-navn",
|
||||
Sync: {
|
||||
Title: "Brug globale indstillinger",
|
||||
SubTitle: "Gældende for denne chat",
|
||||
Confirm: "Erstat nuværende indstillinger med globale?",
|
||||
},
|
||||
HideContext: {
|
||||
Title: "Skjul ekstra prompts",
|
||||
SubTitle: "Vis dem ikke på chat-skærmen",
|
||||
},
|
||||
Artifacts: {
|
||||
Title: "Brug Artefakter",
|
||||
SubTitle: "Gør det muligt at vise HTML-sider",
|
||||
},
|
||||
CodeFold: {
|
||||
Title: "Fold kode sammen",
|
||||
SubTitle: "Luk/åbn lange kodestykker automatisk",
|
||||
},
|
||||
Share: {
|
||||
Title: "Del denne persona",
|
||||
SubTitle: "Få et link til denne skabelon",
|
||||
Action: "Kopiér link",
|
||||
},
|
||||
},
|
||||
},
|
||||
NewChat: {
|
||||
Return: "Tilbage",
|
||||
Skip: "Start straks",
|
||||
Title: "Vælg en persona",
|
||||
SubTitle: "Chat med den persona, du vælger",
|
||||
More: "Se flere",
|
||||
NotShow: "Vis ikke igen",
|
||||
ConfirmNoShow:
|
||||
"Er du sikker på, at du ikke vil se det igen? Du kan altid slå det til under indstillinger.",
|
||||
},
|
||||
UI: {
|
||||
Confirm: "OK",
|
||||
Cancel: "Fortryd",
|
||||
Close: "Luk",
|
||||
Create: "Opret",
|
||||
Edit: "Rediger",
|
||||
Export: "Eksporter",
|
||||
Import: "Importér",
|
||||
Sync: "Synk",
|
||||
Config: "Konfigurer",
|
||||
},
|
||||
Exporter: {
|
||||
Description: {
|
||||
Title: "Kun beskeder efter sidste rydning vises",
|
||||
},
|
||||
Model: "Model",
|
||||
Messages: "Beskeder",
|
||||
Topic: "Emne",
|
||||
Time: "Tid",
|
||||
},
|
||||
URLCommand: {
|
||||
Code: "Så ud til, at der var en kode i linket. Vil du bruge den?",
|
||||
Settings: "Så ud til, at der var indstillinger i linket. Vil du bruge dem?",
|
||||
},
|
||||
SdPanel: {
|
||||
Prompt: "Prompt",
|
||||
NegativePrompt: "Negativ prompt",
|
||||
PleaseInput: (name: string) => `Indtast: ${name}`,
|
||||
AspectRatio: "Billedformat",
|
||||
ImageStyle: "Stil",
|
||||
OutFormat: "Uddataformat",
|
||||
AIModel: "AI-model",
|
||||
ModelVersion: "Version",
|
||||
Submit: "Send",
|
||||
ParamIsRequired: (name: string) => `${name} er krævet`,
|
||||
Styles: {
|
||||
D3Model: "3d-model",
|
||||
AnalogFilm: "analog-film",
|
||||
Anime: "anime",
|
||||
Cinematic: "cinematisk",
|
||||
ComicBook: "tegneserie",
|
||||
DigitalArt: "digital-art",
|
||||
Enhance: "enhance",
|
||||
FantasyArt: "fantasy-art",
|
||||
Isometric: "isometric",
|
||||
LineArt: "line-art",
|
||||
LowPoly: "low-poly",
|
||||
ModelingCompound: "modeling-compound",
|
||||
NeonPunk: "neon-punk",
|
||||
Origami: "origami",
|
||||
Photographic: "fotografisk",
|
||||
PixelArt: "pixel-art",
|
||||
TileTexture: "tile-texture",
|
||||
},
|
||||
},
|
||||
Sd: {
|
||||
SubTitle: (count: number) => `${count} billeder`,
|
||||
Actions: {
|
||||
Params: "Se indstillinger",
|
||||
Copy: "Kopiér prompt",
|
||||
Delete: "Slet",
|
||||
Retry: "Prøv igen",
|
||||
ReturnHome: "Til forsiden",
|
||||
History: "Historik",
|
||||
},
|
||||
EmptyRecord: "Ingen billeder endnu",
|
||||
Status: {
|
||||
Name: "Status",
|
||||
Success: "Ok",
|
||||
Error: "Fejl",
|
||||
Wait: "Venter",
|
||||
Running: "I gang",
|
||||
},
|
||||
Danger: {
|
||||
Delete: "Vil du slette?",
|
||||
},
|
||||
GenerateParams: "Genereringsvalg",
|
||||
Detail: "Detaljer",
|
||||
},
|
||||
};
|
||||
|
||||
export default da;
|
@@ -2,6 +2,7 @@ import cn from "./cn";
|
||||
import en from "./en";
|
||||
import pt from "./pt";
|
||||
import tw from "./tw";
|
||||
import da from "./da";
|
||||
import id from "./id";
|
||||
import fr from "./fr";
|
||||
import es from "./es";
|
||||
@@ -30,6 +31,7 @@ const ALL_LANGS = {
|
||||
en,
|
||||
tw,
|
||||
pt,
|
||||
da,
|
||||
jp,
|
||||
ko,
|
||||
id,
|
||||
@@ -56,6 +58,7 @@ export const ALL_LANG_OPTIONS: Record<Lang, string> = {
|
||||
en: "English",
|
||||
pt: "Português",
|
||||
tw: "繁體中文",
|
||||
da: "Dansk",
|
||||
jp: "日本語",
|
||||
ko: "한국어",
|
||||
id: "Indonesia",
|
||||
@@ -94,6 +97,9 @@ function setItem(key: string, value: string) {
|
||||
|
||||
function getLanguage() {
|
||||
try {
|
||||
if (typeof navigator === "undefined") {
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
const locale = new Intl.Locale(navigator.language).maximize();
|
||||
const region = locale?.region?.toLowerCase();
|
||||
// 1. check region code in ALL_LANGS
|
||||
@@ -141,6 +147,7 @@ export const STT_LANG_MAP: Record<Lang, string> = {
|
||||
en: "en-US",
|
||||
pt: "pt-BR",
|
||||
tw: "zh-TW",
|
||||
da: "da-DK",
|
||||
jp: "ja-JP",
|
||||
ko: "ko-KR",
|
||||
id: "id-ID",
|
||||
|
@@ -1,6 +1,13 @@
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import { Home } from "./components/home";
|
||||
import { getServerSideConfig } from "./config/server";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const Home = dynamic(
|
||||
() => import("./components/home").then((mod) => ({ default: mod.Home })),
|
||||
{
|
||||
ssr: false,
|
||||
},
|
||||
);
|
||||
|
||||
const serverConfig = getServerSideConfig();
|
||||
|
||||
|
@@ -412,12 +412,24 @@ export const useChatStore = createPersistStore(
|
||||
const session = get().currentSession();
|
||||
const modelConfig = session.mask.modelConfig;
|
||||
|
||||
console.log("[onUserInput] Starting with:", {
|
||||
content: content?.substring(0, 50) + "...",
|
||||
hasAttachImages: !!attachImages,
|
||||
attachImagesCount: attachImages?.length || 0,
|
||||
isMcpResponse,
|
||||
});
|
||||
|
||||
// MCP Response no need to fill template
|
||||
let mContent: string | MultimodalContent[] = isMcpResponse
|
||||
? content
|
||||
: fillTemplateWith(content, modelConfig);
|
||||
|
||||
if (!isMcpResponse && attachImages && attachImages.length > 0) {
|
||||
console.log("[onUserInput] Processing attached images:", {
|
||||
imageCount: attachImages.length,
|
||||
firstImagePreview: attachImages[0]?.substring(0, 50) + "...",
|
||||
});
|
||||
|
||||
mContent = [
|
||||
...(content ? [{ type: "text" as const, text: content }] : []),
|
||||
...attachImages.map((url) => ({
|
||||
@@ -425,6 +437,14 @@ export const useChatStore = createPersistStore(
|
||||
image_url: { url },
|
||||
})),
|
||||
];
|
||||
|
||||
console.log("[onUserInput] Created multimodal content:", {
|
||||
isArray: Array.isArray(mContent),
|
||||
contentLength: Array.isArray(mContent) ? mContent.length : "N/A",
|
||||
contentTypes: Array.isArray(mContent)
|
||||
? mContent.map((item) => item.type)
|
||||
: "N/A",
|
||||
});
|
||||
}
|
||||
|
||||
let userMessage: ChatMessage = createMessage({
|
||||
@@ -456,7 +476,123 @@ export const useChatStore = createPersistStore(
|
||||
]);
|
||||
});
|
||||
|
||||
const api: ClientApi = getClientApi(modelConfig.providerName);
|
||||
// --- 详细日志 (修正版) ---
|
||||
const providerNameFromConfig = modelConfig.providerName;
|
||||
console.log(
|
||||
"[onUserInput] Preparing API call. Provider from config:",
|
||||
providerNameFromConfig,
|
||||
"| Type:",
|
||||
typeof providerNameFromConfig,
|
||||
"| Is Enum value (Bedrock)?:",
|
||||
providerNameFromConfig === ServiceProvider.Bedrock, // 与枚举比较
|
||||
"| Is 'Bedrock' string?:",
|
||||
providerNameFromConfig === "Bedrock", // 与字符串比较
|
||||
"| Model:",
|
||||
modelConfig.model,
|
||||
);
|
||||
|
||||
// Add detailed browser and session logging
|
||||
console.log(
|
||||
"[onUserInput] Browser:",
|
||||
typeof navigator !== "undefined" ? navigator.userAgent : "SSR",
|
||||
);
|
||||
console.log(
|
||||
"[onUserInput] Full modelConfig:",
|
||||
JSON.stringify(modelConfig, null, 2),
|
||||
);
|
||||
console.log(
|
||||
"[onUserInput] Session mask:",
|
||||
JSON.stringify(session.mask, null, 2),
|
||||
);
|
||||
|
||||
// --- 日志结束 ---
|
||||
|
||||
// 使用从配置中获取的 providerName,并提供默认值
|
||||
const api: ClientApi = getClientApi(
|
||||
providerNameFromConfig ?? ServiceProvider.OpenAI,
|
||||
);
|
||||
|
||||
// Edge browser workaround: if we're using a Bedrock model but got wrong API, force Bedrock
|
||||
if (
|
||||
modelConfig.model?.includes("anthropic.claude") &&
|
||||
!api.llm.constructor.name.includes("Bedrock")
|
||||
) {
|
||||
console.warn(
|
||||
"[onUserInput] Edge workaround: Detected Bedrock model but wrong API class:",
|
||||
api.llm.constructor.name,
|
||||
"- forcing Bedrock",
|
||||
);
|
||||
const bedrockApi = getClientApi(ServiceProvider.Bedrock);
|
||||
bedrockApi.llm.chat({
|
||||
messages: sendMessages,
|
||||
config: { ...modelConfig, stream: true },
|
||||
onUpdate(message) {
|
||||
botMessage.streaming = true;
|
||||
if (message) {
|
||||
botMessage.content = message;
|
||||
}
|
||||
get().updateTargetSession(session, (session) => {
|
||||
session.messages = session.messages.concat();
|
||||
});
|
||||
},
|
||||
async onFinish(message) {
|
||||
botMessage.streaming = false;
|
||||
if (message) {
|
||||
botMessage.content = message;
|
||||
botMessage.date = new Date().toLocaleString();
|
||||
get().onNewMessage(botMessage, session);
|
||||
}
|
||||
ChatControllerPool.remove(session.id, botMessage.id);
|
||||
},
|
||||
onBeforeTool(tool: ChatMessageTool) {
|
||||
(botMessage.tools = botMessage?.tools || []).push(tool);
|
||||
get().updateTargetSession(session, (session) => {
|
||||
session.messages = session.messages.concat();
|
||||
});
|
||||
},
|
||||
onAfterTool(tool: ChatMessageTool) {
|
||||
botMessage?.tools?.forEach((t, i, tools) => {
|
||||
if (tool.id == t.id) {
|
||||
tools[i] = { ...tool };
|
||||
}
|
||||
});
|
||||
get().updateTargetSession(session, (session) => {
|
||||
session.messages = session.messages.concat();
|
||||
});
|
||||
},
|
||||
onError(error) {
|
||||
const isAborted = error.message?.includes?.("aborted");
|
||||
botMessage.content +=
|
||||
"\n\n" +
|
||||
prettyObject({
|
||||
error: true,
|
||||
message: error.message,
|
||||
});
|
||||
botMessage.streaming = false;
|
||||
userMessage.isError = !isAborted;
|
||||
botMessage.isError = !isAborted;
|
||||
get().updateTargetSession(session, (session) => {
|
||||
session.messages = session.messages.concat();
|
||||
});
|
||||
ChatControllerPool.remove(
|
||||
session.id,
|
||||
botMessage.id ?? messageIndex,
|
||||
);
|
||||
|
||||
console.error("[Chat] failed ", error);
|
||||
},
|
||||
onController(controller) {
|
||||
// collect controller for stop/retry
|
||||
ChatControllerPool.addController(
|
||||
session.id,
|
||||
botMessage.id ?? messageIndex,
|
||||
controller,
|
||||
);
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// make request
|
||||
api.llm.chat({
|
||||
messages: sendMessages,
|
||||
@@ -734,7 +870,7 @@ export const useChatStore = createPersistStore(
|
||||
|
||||
const historyMsgLength = countMessages(toBeSummarizedMsgs);
|
||||
|
||||
if (historyMsgLength > (modelConfig?.max_tokens || 4000)) {
|
||||
if (historyMsgLength > (modelConfig?.max_tokens || 8000)) {
|
||||
const n = toBeSummarizedMsgs.length;
|
||||
toBeSummarizedMsgs = toBeSummarizedMsgs.slice(
|
||||
Math.max(0, n - modelConfig.historyMessageCount),
|
||||
|
@@ -68,7 +68,7 @@ export const DEFAULT_CONFIG = {
|
||||
providerName: "OpenAI" as ServiceProvider,
|
||||
temperature: 0.5,
|
||||
top_p: 1,
|
||||
max_tokens: 4000,
|
||||
max_tokens: 8000,
|
||||
presence_penalty: 0,
|
||||
frequency_penalty: 0,
|
||||
sendMemory: true,
|
||||
|
27
app/utils.ts
27
app/utils.ts
@@ -2,7 +2,11 @@ import { useEffect, useState } from "react";
|
||||
import { showToast } from "./components/ui-lib";
|
||||
import Locale from "./locales";
|
||||
import { RequestMessage } from "./client/api";
|
||||
import { ServiceProvider } from "./constant";
|
||||
import {
|
||||
REQUEST_TIMEOUT_MS,
|
||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||
ServiceProvider,
|
||||
} from "./constant";
|
||||
// import { fetch as tauriFetch, ResponseType } from "@tauri-apps/api/http";
|
||||
import { fetch as tauriStreamFetch } from "./utils/stream";
|
||||
import { VISION_MODEL_REGEXES, EXCLUDE_VISION_MODEL_REGEXES } from "./constant";
|
||||
@@ -16,8 +20,8 @@ export function trimTopic(topic: string) {
|
||||
return (
|
||||
topic
|
||||
// fix for gemini
|
||||
.replace(/^["“”*]+|["“”*]+$/g, "")
|
||||
.replace(/[,。!?”“"、,.!?*]*$/, "")
|
||||
.replace(/^["""*]+|["""*]+$/g, "")
|
||||
.replace(/[,。!?""""、,.!?*]*$/, "")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,6 +114,9 @@ export function readFromFile() {
|
||||
}
|
||||
|
||||
export function isIOS() {
|
||||
if (typeof navigator === "undefined") {
|
||||
return false;
|
||||
}
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
return /iphone|ipad|ipod/.test(userAgent);
|
||||
}
|
||||
@@ -292,6 +299,20 @@ export function isDalle3(model: string) {
|
||||
return "dall-e-3" === model;
|
||||
}
|
||||
|
||||
export function getTimeoutMSByModel(model: string) {
|
||||
model = model.toLowerCase();
|
||||
if (
|
||||
model.startsWith("dall-e") ||
|
||||
model.startsWith("dalle") ||
|
||||
model.startsWith("o1") ||
|
||||
model.startsWith("o3") ||
|
||||
model.includes("deepseek-r") ||
|
||||
model.includes("-thinking")
|
||||
)
|
||||
return REQUEST_TIMEOUT_MS_FOR_THINKING;
|
||||
return REQUEST_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
export function getModelSizes(model: string): ModelSize[] {
|
||||
if (isDalle3(model)) {
|
||||
return ["1024x1024", "1792x1024", "1024x1792"];
|
||||
|
@@ -3,7 +3,7 @@ import {
|
||||
UPLOAD_URL,
|
||||
REQUEST_TIMEOUT_MS,
|
||||
} from "@/app/constant";
|
||||
import { RequestMessage } from "@/app/client/api";
|
||||
import { MultimodalContent, RequestMessage } from "@/app/client/api";
|
||||
import Locale from "@/app/locales";
|
||||
import {
|
||||
EventStreamContentType,
|
||||
@@ -70,8 +70,9 @@ export function compressImage(file: Blob, maxSize: number): Promise<string> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function preProcessImageContent(
|
||||
export async function preProcessImageContentBase(
|
||||
content: RequestMessage["content"],
|
||||
transformImageUrl: (url: string) => Promise<{ [key: string]: any }>,
|
||||
) {
|
||||
if (typeof content === "string") {
|
||||
return content;
|
||||
@@ -81,7 +82,7 @@ export async function preProcessImageContent(
|
||||
if (part?.type == "image_url" && part?.image_url?.url) {
|
||||
try {
|
||||
const url = await cacheImageToBase64Image(part?.image_url?.url);
|
||||
result.push({ type: part.type, image_url: { url } });
|
||||
result.push(await transformImageUrl(url));
|
||||
} catch (error) {
|
||||
console.error("Error processing image URL:", error);
|
||||
}
|
||||
@@ -92,6 +93,23 @@ export async function preProcessImageContent(
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function preProcessImageContent(
|
||||
content: RequestMessage["content"],
|
||||
) {
|
||||
return preProcessImageContentBase(content, async (url) => ({
|
||||
type: "image_url",
|
||||
image_url: { url },
|
||||
})) as Promise<MultimodalContent[] | string>;
|
||||
}
|
||||
|
||||
export async function preProcessImageContentForAlibabaDashScope(
|
||||
content: RequestMessage["content"],
|
||||
) {
|
||||
return preProcessImageContentBase(content, async (url) => ({
|
||||
image: url,
|
||||
}));
|
||||
}
|
||||
|
||||
const imageCaches: Record<string, string> = {};
|
||||
export function cacheImageToBase64Image(imageUrl: string) {
|
||||
if (imageUrl.includes(CACHE_URL_PREFIX)) {
|
||||
@@ -400,6 +418,7 @@ export function streamWithThink(
|
||||
let responseRes: Response;
|
||||
let isInThinkingMode = false;
|
||||
let lastIsThinking = false;
|
||||
let lastIsThinkingTagged = false; //between <think> and </think> tags
|
||||
|
||||
// animate response to make it looks smooth
|
||||
function animateResponseText() {
|
||||
@@ -579,6 +598,23 @@ export function streamWithThink(
|
||||
if (!chunk?.content || chunk.content.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// deal with <think> and </think> tags start
|
||||
if (!chunk.isThinking) {
|
||||
if (chunk.content.startsWith("<think>")) {
|
||||
chunk.isThinking = true;
|
||||
chunk.content = chunk.content.slice(7).trim();
|
||||
lastIsThinkingTagged = true;
|
||||
} else if (chunk.content.endsWith("</think>")) {
|
||||
chunk.isThinking = false;
|
||||
chunk.content = chunk.content.slice(0, -8).trim();
|
||||
lastIsThinkingTagged = false;
|
||||
} else if (lastIsThinkingTagged) {
|
||||
chunk.isThinking = true;
|
||||
}
|
||||
}
|
||||
// deal with <think> and </think> tags start
|
||||
|
||||
// Check if thinking mode changed
|
||||
const isThinkingChanged = lastIsThinking !== chunk.isThinking;
|
||||
lastIsThinking = chunk.isThinking;
|
||||
|
@@ -69,7 +69,8 @@ export function fetch(url: string, options?: RequestInit): Promise<Response> {
|
||||
const headers: Record<string, string> = {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
|
||||
"User-Agent": navigator.userAgent,
|
||||
"User-Agent":
|
||||
typeof navigator !== "undefined" ? navigator.userAgent : "NextChat",
|
||||
};
|
||||
for (const item of new Headers(_headers || {})) {
|
||||
headers[item[0]] = item[1];
|
||||
|
@@ -15,6 +15,8 @@ const config: Config = {
|
||||
moduleNameMapper: {
|
||||
"^@/(.*)$": "<rootDir>/$1",
|
||||
},
|
||||
extensionsToTreatAsEsm: [".ts", ".tsx"],
|
||||
injectGlobals: true,
|
||||
};
|
||||
|
||||
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
|
||||
|
@@ -1,24 +1,22 @@
|
||||
// Learn more: https://github.com/testing-library/jest-dom
|
||||
import "@testing-library/jest-dom";
|
||||
import { jest } from "@jest/globals";
|
||||
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: () => Promise.resolve({}),
|
||||
json: () => Promise.resolve([]),
|
||||
headers: new Headers(),
|
||||
redirected: false,
|
||||
statusText: "OK",
|
||||
type: "basic",
|
||||
url: "",
|
||||
clone: function () {
|
||||
return this;
|
||||
},
|
||||
body: null,
|
||||
bodyUsed: false,
|
||||
arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)),
|
||||
blob: () => Promise.resolve(new Blob()),
|
||||
formData: () => Promise.resolve(new FormData()),
|
||||
text: () => Promise.resolve(""),
|
||||
}),
|
||||
} as Response),
|
||||
);
|
||||
|
@@ -17,10 +17,11 @@
|
||||
"prompts": "node ./scripts/fetch-prompts.mjs",
|
||||
"prepare": "husky install",
|
||||
"proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev",
|
||||
"test": "jest --watch",
|
||||
"test:ci": "jest --ci"
|
||||
"test": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --watch",
|
||||
"test:ci": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --ci"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.782.0",
|
||||
"@fortaine/fetch-event-source": "^3.0.6",
|
||||
"@hello-pangea/dnd": "^16.5.0",
|
||||
"@modelcontextprotocol/sdk": "^1.0.4",
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { jest } from "@jest/globals";
|
||||
import { isVisionModel } from "../app/utils";
|
||||
|
||||
describe("isVisionModel", () => {
|
||||
@@ -50,7 +51,7 @@ describe("isVisionModel", () => {
|
||||
|
||||
test("should identify models from VISION_MODELS env var", () => {
|
||||
process.env.VISION_MODELS = "custom-vision-model,another-vision-model";
|
||||
|
||||
|
||||
expect(isVisionModel("custom-vision-model")).toBe(true);
|
||||
expect(isVisionModel("another-vision-model")).toBe(true);
|
||||
expect(isVisionModel("unrelated-model")).toBe(false);
|
||||
@@ -64,4 +65,4 @@ describe("isVisionModel", () => {
|
||||
expect(isVisionModel("unrelated-model")).toBe(false);
|
||||
expect(isVisionModel("gpt-4-vision")).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
882
yarn.lock
882
yarn.lock
@@ -20,6 +20,423 @@
|
||||
"@jridgewell/gen-mapping" "^0.1.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@aws-crypto/crc32@5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1"
|
||||
integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==
|
||||
dependencies:
|
||||
"@aws-crypto/util" "^5.2.0"
|
||||
"@aws-sdk/types" "^3.222.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-crypto/sha256-browser@5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e"
|
||||
integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==
|
||||
dependencies:
|
||||
"@aws-crypto/sha256-js" "^5.2.0"
|
||||
"@aws-crypto/supports-web-crypto" "^5.2.0"
|
||||
"@aws-crypto/util" "^5.2.0"
|
||||
"@aws-sdk/types" "^3.222.0"
|
||||
"@aws-sdk/util-locate-window" "^3.0.0"
|
||||
"@smithy/util-utf8" "^2.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042"
|
||||
integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==
|
||||
dependencies:
|
||||
"@aws-crypto/util" "^5.2.0"
|
||||
"@aws-sdk/types" "^3.222.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-crypto/supports-web-crypto@^5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz#a1e399af29269be08e695109aa15da0a07b5b5fb"
|
||||
integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-crypto/util@^5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da"
|
||||
integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "^3.222.0"
|
||||
"@smithy/util-utf8" "^2.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/client-bedrock-runtime@^3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.782.0.tgz#ec9bf07d2b65ccd8598fa90420d763ff3c487a41"
|
||||
integrity sha512-jG6xHoTpAMlmqEXnW2exBsc9Av/5UpD5R22x1LuwfUZVOMD/F15XuJr/JfzZVG3FJ48H8j9p6hAMY8S4aYdL1A==
|
||||
dependencies:
|
||||
"@aws-crypto/sha256-browser" "5.2.0"
|
||||
"@aws-crypto/sha256-js" "5.2.0"
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/credential-provider-node" "3.782.0"
|
||||
"@aws-sdk/middleware-host-header" "3.775.0"
|
||||
"@aws-sdk/middleware-logger" "3.775.0"
|
||||
"@aws-sdk/middleware-recursion-detection" "3.775.0"
|
||||
"@aws-sdk/middleware-user-agent" "3.782.0"
|
||||
"@aws-sdk/region-config-resolver" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@aws-sdk/util-endpoints" "3.782.0"
|
||||
"@aws-sdk/util-user-agent-browser" "3.775.0"
|
||||
"@aws-sdk/util-user-agent-node" "3.782.0"
|
||||
"@smithy/config-resolver" "^4.1.0"
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/eventstream-serde-browser" "^4.0.2"
|
||||
"@smithy/eventstream-serde-config-resolver" "^4.1.0"
|
||||
"@smithy/eventstream-serde-node" "^4.0.2"
|
||||
"@smithy/fetch-http-handler" "^5.0.2"
|
||||
"@smithy/hash-node" "^4.0.2"
|
||||
"@smithy/invalid-dependency" "^4.0.2"
|
||||
"@smithy/middleware-content-length" "^4.0.2"
|
||||
"@smithy/middleware-endpoint" "^4.1.0"
|
||||
"@smithy/middleware-retry" "^4.1.0"
|
||||
"@smithy/middleware-serde" "^4.0.3"
|
||||
"@smithy/middleware-stack" "^4.0.2"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/node-http-handler" "^4.0.4"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/url-parser" "^4.0.2"
|
||||
"@smithy/util-base64" "^4.0.0"
|
||||
"@smithy/util-body-length-browser" "^4.0.0"
|
||||
"@smithy/util-body-length-node" "^4.0.0"
|
||||
"@smithy/util-defaults-mode-browser" "^4.0.8"
|
||||
"@smithy/util-defaults-mode-node" "^4.0.8"
|
||||
"@smithy/util-endpoints" "^3.0.2"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-retry" "^4.0.2"
|
||||
"@smithy/util-stream" "^4.2.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
"@types/uuid" "^9.0.1"
|
||||
tslib "^2.6.2"
|
||||
uuid "^9.0.1"
|
||||
|
||||
"@aws-sdk/client-sso@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz#072cbb23a90ec6fd53145ff75bef8329a857f362"
|
||||
integrity sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==
|
||||
dependencies:
|
||||
"@aws-crypto/sha256-browser" "5.2.0"
|
||||
"@aws-crypto/sha256-js" "5.2.0"
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/middleware-host-header" "3.775.0"
|
||||
"@aws-sdk/middleware-logger" "3.775.0"
|
||||
"@aws-sdk/middleware-recursion-detection" "3.775.0"
|
||||
"@aws-sdk/middleware-user-agent" "3.782.0"
|
||||
"@aws-sdk/region-config-resolver" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@aws-sdk/util-endpoints" "3.782.0"
|
||||
"@aws-sdk/util-user-agent-browser" "3.775.0"
|
||||
"@aws-sdk/util-user-agent-node" "3.782.0"
|
||||
"@smithy/config-resolver" "^4.1.0"
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/fetch-http-handler" "^5.0.2"
|
||||
"@smithy/hash-node" "^4.0.2"
|
||||
"@smithy/invalid-dependency" "^4.0.2"
|
||||
"@smithy/middleware-content-length" "^4.0.2"
|
||||
"@smithy/middleware-endpoint" "^4.1.0"
|
||||
"@smithy/middleware-retry" "^4.1.0"
|
||||
"@smithy/middleware-serde" "^4.0.3"
|
||||
"@smithy/middleware-stack" "^4.0.2"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/node-http-handler" "^4.0.4"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/url-parser" "^4.0.2"
|
||||
"@smithy/util-base64" "^4.0.0"
|
||||
"@smithy/util-body-length-browser" "^4.0.0"
|
||||
"@smithy/util-body-length-node" "^4.0.0"
|
||||
"@smithy/util-defaults-mode-browser" "^4.0.8"
|
||||
"@smithy/util-defaults-mode-node" "^4.0.8"
|
||||
"@smithy/util-endpoints" "^3.0.2"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-retry" "^4.0.2"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/core@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.775.0.tgz#5d22ba78f07c07b48fb4d5b18172b9a896c0cbd0"
|
||||
integrity sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/signature-v4" "^5.0.2"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
fast-xml-parser "4.4.1"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-env@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz#b8c81818f4c62d89b5f04dc410ab9b48e954f22c"
|
||||
integrity sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-http@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz#0fbc7f4e6cada37fc9b647de0d7c12a42a44bcc6"
|
||||
integrity sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/fetch-http-handler" "^5.0.2"
|
||||
"@smithy/node-http-handler" "^4.0.4"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-stream" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-ini@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz#4ffd90f6b3b6b34d1dabcba875e5d00fc5da23f1"
|
||||
integrity sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/credential-provider-env" "3.775.0"
|
||||
"@aws-sdk/credential-provider-http" "3.775.0"
|
||||
"@aws-sdk/credential-provider-process" "3.775.0"
|
||||
"@aws-sdk/credential-provider-sso" "3.782.0"
|
||||
"@aws-sdk/credential-provider-web-identity" "3.782.0"
|
||||
"@aws-sdk/nested-clients" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/credential-provider-imds" "^4.0.2"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-node@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz#81a798710d0567b26cd20a105790b49586e68d40"
|
||||
integrity sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==
|
||||
dependencies:
|
||||
"@aws-sdk/credential-provider-env" "3.775.0"
|
||||
"@aws-sdk/credential-provider-http" "3.775.0"
|
||||
"@aws-sdk/credential-provider-ini" "3.782.0"
|
||||
"@aws-sdk/credential-provider-process" "3.775.0"
|
||||
"@aws-sdk/credential-provider-sso" "3.782.0"
|
||||
"@aws-sdk/credential-provider-web-identity" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/credential-provider-imds" "^4.0.2"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-process@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz#7ab90383f12461c5d20546e933924e654660542b"
|
||||
integrity sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-sso@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz#f644884cae368204f750c35d8a61a04d77c02674"
|
||||
integrity sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==
|
||||
dependencies:
|
||||
"@aws-sdk/client-sso" "3.782.0"
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/token-providers" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/credential-provider-web-identity@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz#5dbab53a7b49dcf8390d71415855e78b911a4742"
|
||||
integrity sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/nested-clients" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/middleware-host-header@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz#1bf8160b8f4f96ba30c19f9baa030a6c9bd5f94d"
|
||||
integrity sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/middleware-logger@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz#df1909d441cd4bade8d6c7d24c41532808db0e81"
|
||||
integrity sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/middleware-recursion-detection@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz#36a40f467754d7c86424d12ef45c05e96ce3475b"
|
||||
integrity sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/middleware-user-agent@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz#60e47e365a39cfa64aa81c3c881896face74da45"
|
||||
integrity sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==
|
||||
dependencies:
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@aws-sdk/util-endpoints" "3.782.0"
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/nested-clients@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz#73f56fc4d22e1be342e00b7eba9de4d192521a05"
|
||||
integrity sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==
|
||||
dependencies:
|
||||
"@aws-crypto/sha256-browser" "5.2.0"
|
||||
"@aws-crypto/sha256-js" "5.2.0"
|
||||
"@aws-sdk/core" "3.775.0"
|
||||
"@aws-sdk/middleware-host-header" "3.775.0"
|
||||
"@aws-sdk/middleware-logger" "3.775.0"
|
||||
"@aws-sdk/middleware-recursion-detection" "3.775.0"
|
||||
"@aws-sdk/middleware-user-agent" "3.782.0"
|
||||
"@aws-sdk/region-config-resolver" "3.775.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@aws-sdk/util-endpoints" "3.782.0"
|
||||
"@aws-sdk/util-user-agent-browser" "3.775.0"
|
||||
"@aws-sdk/util-user-agent-node" "3.782.0"
|
||||
"@smithy/config-resolver" "^4.1.0"
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/fetch-http-handler" "^5.0.2"
|
||||
"@smithy/hash-node" "^4.0.2"
|
||||
"@smithy/invalid-dependency" "^4.0.2"
|
||||
"@smithy/middleware-content-length" "^4.0.2"
|
||||
"@smithy/middleware-endpoint" "^4.1.0"
|
||||
"@smithy/middleware-retry" "^4.1.0"
|
||||
"@smithy/middleware-serde" "^4.0.3"
|
||||
"@smithy/middleware-stack" "^4.0.2"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/node-http-handler" "^4.0.4"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/url-parser" "^4.0.2"
|
||||
"@smithy/util-base64" "^4.0.0"
|
||||
"@smithy/util-body-length-browser" "^4.0.0"
|
||||
"@smithy/util-body-length-node" "^4.0.0"
|
||||
"@smithy/util-defaults-mode-browser" "^4.0.8"
|
||||
"@smithy/util-defaults-mode-node" "^4.0.8"
|
||||
"@smithy/util-endpoints" "^3.0.2"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-retry" "^4.0.2"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/region-config-resolver@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz#592b52498e68501fe46480be3dfb185e949d1eab"
|
||||
integrity sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-config-provider" "^4.0.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/token-providers@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz#a6a12f9358f8897f5d1af311da60f90a7d384eac"
|
||||
integrity sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==
|
||||
dependencies:
|
||||
"@aws-sdk/nested-clients" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/types@3.775.0", "@aws-sdk/types@^3.222.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.775.0.tgz#09863a9e68c080947db7c3d226d1c56b8f0f5150"
|
||||
integrity sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/util-endpoints@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz#3b8de42c5fe951337d070432d4a5eba166c07bb7"
|
||||
integrity sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-endpoints" "^3.0.2"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/util-locate-window@^3.0.0":
|
||||
version "3.723.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.723.0.tgz#174551bfdd2eb36d3c16e7023fd7e7ee96ad0fa9"
|
||||
integrity sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/util-user-agent-browser@3.775.0":
|
||||
version "3.775.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz#b69a1a5548ccc6db1acb3ec115967593ece927a1"
|
||||
integrity sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==
|
||||
dependencies:
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
bowser "^2.11.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@aws-sdk/util-user-agent-node@3.782.0":
|
||||
version "3.782.0"
|
||||
resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz#795f2c22882f1ddbbe83bd324f0ceac1c4b07c89"
|
||||
integrity sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==
|
||||
dependencies:
|
||||
"@aws-sdk/middleware-user-agent" "3.782.0"
|
||||
"@aws-sdk/types" "3.775.0"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
|
||||
@@ -1925,6 +2342,444 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^3.0.0"
|
||||
|
||||
"@smithy/abort-controller@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-4.0.2.tgz#36a23e8cc65fc03cacb6afa35dfbfd319c560c6b"
|
||||
integrity sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/config-resolver@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.1.0.tgz#de1043cbd75f05d99798b0fbcfdaf4b89b0f2f41"
|
||||
integrity sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==
|
||||
dependencies:
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-config-provider" "^4.0.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/core@^3.2.0":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.2.0.tgz#613b15f76eab9a6be396b1d5453b6bc8f22ba99c"
|
||||
integrity sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==
|
||||
dependencies:
|
||||
"@smithy/middleware-serde" "^4.0.3"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-body-length-browser" "^4.0.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-stream" "^4.2.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/credential-provider-imds@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz#1ec34a04842fa69996b151a695b027f0486c69a8"
|
||||
integrity sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==
|
||||
dependencies:
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/url-parser" "^4.0.2"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/eventstream-codec@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz#d4d77699308a3dfeea1b2e87683845f5d8440bdb"
|
||||
integrity sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==
|
||||
dependencies:
|
||||
"@aws-crypto/crc32" "5.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-hex-encoding" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/eventstream-serde-browser@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz#876f05491373ab217801c47b802601b8c09388d4"
|
||||
integrity sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==
|
||||
dependencies:
|
||||
"@smithy/eventstream-serde-universal" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/eventstream-serde-config-resolver@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz#4ab7a2575e9041a2df2179bce64619a4e632e4d3"
|
||||
integrity sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/eventstream-serde-node@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz#390306ff79edb0c607705f639d8c5a76caad4bf7"
|
||||
integrity sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==
|
||||
dependencies:
|
||||
"@smithy/eventstream-serde-universal" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/eventstream-serde-universal@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz#9f45472fc4fe5fe5f7c22c33d90ec6fc0230d0ae"
|
||||
integrity sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==
|
||||
dependencies:
|
||||
"@smithy/eventstream-codec" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/fetch-http-handler@^5.0.2":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz#9d3cacf044aa9573ab933f445ab95cddb284813d"
|
||||
integrity sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==
|
||||
dependencies:
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/querystring-builder" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-base64" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/hash-node@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-4.0.2.tgz#a34fe5a33b067d754ca63302b9791778f003e437"
|
||||
integrity sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-buffer-from" "^4.0.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/invalid-dependency@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz#e9b1c5e407d795f10a03afba90e37bccdc3e38f7"
|
||||
integrity sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/is-array-buffer@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111"
|
||||
integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/is-array-buffer@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz#55a939029321fec462bcc574890075cd63e94206"
|
||||
integrity sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/middleware-content-length@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz#ff78658e8047ad7038f58478cf8713ee2f6ef647"
|
||||
integrity sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==
|
||||
dependencies:
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/middleware-endpoint@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz#cbfe47c5632942c960dbcf71fb02fd0d9985444d"
|
||||
integrity sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==
|
||||
dependencies:
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/middleware-serde" "^4.0.3"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/url-parser" "^4.0.2"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/middleware-retry@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz#338ac1e025bbc6fd7b008152c4efa8bc0591acc9"
|
||||
integrity sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==
|
||||
dependencies:
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/service-error-classification" "^4.0.2"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-retry" "^4.0.2"
|
||||
tslib "^2.6.2"
|
||||
uuid "^9.0.1"
|
||||
|
||||
"@smithy/middleware-serde@^4.0.3":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz#b90ef1065ad9dc0b54c561fae73c8a5792d145e3"
|
||||
integrity sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/middleware-stack@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz#ca7bc3eedc7c1349e2cf94e0dc92a68d681bef18"
|
||||
integrity sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/node-config-provider@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz#017ba626828bced0fa588e795246e5468632f3ef"
|
||||
integrity sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==
|
||||
dependencies:
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/shared-ini-file-loader" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/node-http-handler@^4.0.4":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz#aa583d201c1ee968170b65a07f06d633c214b7a1"
|
||||
integrity sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==
|
||||
dependencies:
|
||||
"@smithy/abort-controller" "^4.0.2"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/querystring-builder" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/property-provider@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-4.0.2.tgz#4572c10415c9d4215f3df1530ba61b0319b17b55"
|
||||
integrity sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/protocol-http@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-5.1.0.tgz#ad34e336a95944785185234bebe2ec8dbe266936"
|
||||
integrity sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/querystring-builder@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz#834cea95bf413ab417bf9c166d60fd80d2cb3016"
|
||||
integrity sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-uri-escape" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/querystring-parser@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz#d80c5afb740e12ad8b4d4f58415e402c69712479"
|
||||
integrity sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/service-error-classification@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz#96740ed8be7ac5ad7d6f296d4ddf3f66444b8dcc"
|
||||
integrity sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
|
||||
"@smithy/shared-ini-file-loader@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz#15043f0516fe09ff4b22982bc5f644dc701ebae5"
|
||||
integrity sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/signature-v4@^5.0.2":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.0.2.tgz#363854e946fbc5bc206ff82e79ada5d5c14be640"
|
||||
integrity sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==
|
||||
dependencies:
|
||||
"@smithy/is-array-buffer" "^4.0.0"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-hex-encoding" "^4.0.0"
|
||||
"@smithy/util-middleware" "^4.0.2"
|
||||
"@smithy/util-uri-escape" "^4.0.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/smithy-client@^4.2.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.2.0.tgz#0c64cae4fb5bb4f26386e9b2c33fc9a3c24c9df3"
|
||||
integrity sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==
|
||||
dependencies:
|
||||
"@smithy/core" "^3.2.0"
|
||||
"@smithy/middleware-endpoint" "^4.1.0"
|
||||
"@smithy/middleware-stack" "^4.0.2"
|
||||
"@smithy/protocol-http" "^5.1.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-stream" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/types@^4.2.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.2.0.tgz#e7998984cc54b1acbc32e6d4cf982c712e3d26b6"
|
||||
integrity sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/url-parser@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-4.0.2.tgz#a316f7d8593ffab796348bc5df96237833880713"
|
||||
integrity sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==
|
||||
dependencies:
|
||||
"@smithy/querystring-parser" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-base64@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-4.0.0.tgz#8345f1b837e5f636e5f8470c4d1706ae0c6d0358"
|
||||
integrity sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==
|
||||
dependencies:
|
||||
"@smithy/util-buffer-from" "^4.0.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-body-length-browser@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz#965d19109a4b1e5fe7a43f813522cce718036ded"
|
||||
integrity sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-body-length-node@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz#3db245f6844a9b1e218e30c93305bfe2ffa473b3"
|
||||
integrity sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-buffer-from@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b"
|
||||
integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==
|
||||
dependencies:
|
||||
"@smithy/is-array-buffer" "^2.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-buffer-from@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz#b23b7deb4f3923e84ef50c8b2c5863d0dbf6c0b9"
|
||||
integrity sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==
|
||||
dependencies:
|
||||
"@smithy/is-array-buffer" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-config-provider@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz#e0c7c8124c7fba0b696f78f0bd0ccb060997d45e"
|
||||
integrity sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-defaults-mode-browser@^4.0.8":
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz#77bc4590cdc928901b80f3482e79607a2cbcb150"
|
||||
integrity sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==
|
||||
dependencies:
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
bowser "^2.11.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-defaults-mode-node@^4.0.8":
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz#123b517efe6434977139b341d1f64b5f1e743aac"
|
||||
integrity sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==
|
||||
dependencies:
|
||||
"@smithy/config-resolver" "^4.1.0"
|
||||
"@smithy/credential-provider-imds" "^4.0.2"
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/property-provider" "^4.0.2"
|
||||
"@smithy/smithy-client" "^4.2.0"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-endpoints@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz#6933a0d6d4a349523ef71ca9540c9c0b222b559e"
|
||||
integrity sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==
|
||||
dependencies:
|
||||
"@smithy/node-config-provider" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-hex-encoding@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz#dd449a6452cffb37c5b1807ec2525bb4be551e8d"
|
||||
integrity sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-middleware@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-4.0.2.tgz#272f1249664e27068ef0d5f967a233bf7b77962c"
|
||||
integrity sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==
|
||||
dependencies:
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-retry@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.0.2.tgz#9b64cf460d63555884e641721d19e3c0abff8ee6"
|
||||
integrity sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==
|
||||
dependencies:
|
||||
"@smithy/service-error-classification" "^4.0.2"
|
||||
"@smithy/types" "^4.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-stream@^4.2.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.2.0.tgz#85f85516b0042726162bf619caa3358332195652"
|
||||
integrity sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==
|
||||
dependencies:
|
||||
"@smithy/fetch-http-handler" "^5.0.2"
|
||||
"@smithy/node-http-handler" "^4.0.4"
|
||||
"@smithy/types" "^4.2.0"
|
||||
"@smithy/util-base64" "^4.0.0"
|
||||
"@smithy/util-buffer-from" "^4.0.0"
|
||||
"@smithy/util-hex-encoding" "^4.0.0"
|
||||
"@smithy/util-utf8" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-uri-escape@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz#a96c160c76f3552458a44d8081fade519d214737"
|
||||
integrity sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==
|
||||
dependencies:
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-utf8@^2.0.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5"
|
||||
integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==
|
||||
dependencies:
|
||||
"@smithy/util-buffer-from" "^2.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@smithy/util-utf8@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-4.0.0.tgz#09ca2d9965e5849e72e347c130f2a29d5c0c863c"
|
||||
integrity sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==
|
||||
dependencies:
|
||||
"@smithy/util-buffer-from" "^4.0.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
"@svgr/babel-plugin-add-jsx-attribute@^6.5.1":
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz#74a5d648bd0347bda99d82409d87b8ca80b9a1ba"
|
||||
@@ -2433,6 +3288,11 @@
|
||||
resolved "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
|
||||
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
|
||||
|
||||
"@types/uuid@^9.0.1":
|
||||
version "9.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba"
|
||||
integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "21.0.3"
|
||||
resolved "https://registry.npmmirror.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15"
|
||||
@@ -2984,6 +3844,11 @@ boolbase@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
|
||||
|
||||
bowser@^2.11.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
|
||||
integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@@ -4545,6 +5410,13 @@ fast-levenshtein@^2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
|
||||
|
||||
fast-xml-parser@4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f"
|
||||
integrity sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==
|
||||
dependencies:
|
||||
strnum "^1.0.5"
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
|
||||
@@ -7879,6 +8751,11 @@ strip-json-comments@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
strnum@^1.0.5:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.1.2.tgz#57bca4fbaa6f271081715dbc9ed7cee5493e28e4"
|
||||
integrity sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==
|
||||
|
||||
style-to-object@^0.4.0:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37"
|
||||
@@ -8338,6 +9215,11 @@ uuid@^9.0.0:
|
||||
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
|
||||
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
|
||||
|
||||
uuid@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||
|
||||
uvu@^0.5.0:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
|
||||
|
Reference in New Issue
Block a user