-
Notifications
You must be signed in to change notification settings - Fork 61k
Qwen #6538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Qwen #6538
Changes from 6 commits
861d854
4aaa9db
e3fc9ee
cdeb278
b07760f
ee25e4a
8af4d7a
a043f03
4ec717f
972f957
b42c515
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
app/store/config.ts |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"use client"; | ||
import { useEffect } from "react"; | ||
import { useSyncStore } from "./store/sync"; | ||
|
||
export default function SyncOnFirstLoad() { | ||
const syncStore = useSyncStore(); | ||
|
||
useEffect(() => { | ||
// Parse cookies using the custom function | ||
// syncStore.sync(); | ||
}, []); | ||
|
||
return null; | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,22 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { getServerSideConfig } from "@/app/config/server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ALIBABA_BASE_URL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ApiPath, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ModelProvider, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ServiceProvider, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} from "@/app/constant"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ALIBABA_BASE_URL, ApiPath, ModelProvider } from "@/app/constant"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { prettyObject } from "@/app/utils/format"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { NextRequest, NextResponse } from "next/server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { auth } from "@/app/api/auth"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { isModelNotavailableInServer } from "@/app/utils/model"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const serverConfig = getServerSideConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export async function handle( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req: NextRequest, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ params }: { params: { path: string[] } }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("[Alibaba Route] params ", params); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// console.log("[Alibaba Route] params ", params); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (req.method === "OPTIONS") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ body: "OK" }, { status: 200 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -42,7 +36,9 @@ async function request(req: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const controller = new AbortController(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// alibaba use base url or just remove the path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let path = `${req.nextUrl.pathname}`.replaceAll(ApiPath.Alibaba, ""); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let path = `${req.nextUrl.pathname}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.replaceAll(ApiPath.Alibaba, "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.replace("/api", ""); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let baseUrl = serverConfig.alibabaUrl || ALIBABA_BASE_URL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -65,6 +61,9 @@ async function request(req: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const fetchUrl = `${baseUrl}${path}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("[Alibaba] fetchUrl", fetchUrl); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const fetchOptions: RequestInit = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
headers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Content-Type": "application/json", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -83,28 +82,77 @@ async function request(req: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (serverConfig.customModels && req.body) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const clonedBody = await req.text(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fetchOptions.body = clonedBody; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let jsonBody: any = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jsonBody = JSON.parse(clonedBody); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Move input.messages to messages at the root level if present | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (jsonBody.input && Array.isArray(jsonBody.input.messages)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jsonBody.messages = jsonBody.input.messages; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Remove input.messages to avoid duplication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
delete jsonBody.input; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jsonBody.stream = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+87
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix performance issue with delete operator. The Replace the delete operation with object destructuring: - // Move input.messages to messages at the root level if present
- if (jsonBody.input && Array.isArray(jsonBody.input.messages)) {
- jsonBody.messages = jsonBody.input.messages;
-
- // Remove input.messages to avoid duplication
- delete jsonBody.input;
-
- jsonBody.stream = true;
- }
+ // Move input.messages to messages at the root level if present
+ if (jsonBody.input && Array.isArray(jsonBody.input.messages)) {
+ const { input, ...bodyWithoutInput } = jsonBody;
+ jsonBody = {
+ ...bodyWithoutInput,
+ messages: input.messages,
+ stream: true
+ };
+ } 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 95-95: Avoid the delete operator which can impact performance. Unsafe fix: Use an undefined assignment instead. (lint/performance/noDelete) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const current_model = jsonBody?.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("[Alibaba] custom models", current_model); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//kiem tra xem model co phai la qwen-vl hay khong (vision model) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (current_model && current_model.startsWith("qwen-vl")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("[Alibaba] current model is qwen-vl"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log("xu ly hinh anh trong message"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Reformat image objects in messages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (Array.isArray(jsonBody.messages)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jsonBody.messages = jsonBody.messages.map((msg: any) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (Array.isArray(msg.content)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
msg.content = msg.content.map((item: any) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (item && typeof item === "object" && "image" in item) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: "image_url", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
image_url: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
url: item.image, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return item; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return msg; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+105
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor vision model processing and use English comments. The vision model processing logic has several maintainability issues:
Consider refactoring like this: - //kiem tra xem model co phai la qwen-vl hay khong (vision model)
- if (current_model && current_model.startsWith("qwen-vl")) {
- console.log("[Alibaba] current model is qwen-vl");
- console.log("xu ly hinh anh trong message");
-
- // Reformat image objects in messages
- if (Array.isArray(jsonBody.messages)) {
- jsonBody.messages = jsonBody.messages.map((msg: any) => {
- if (Array.isArray(msg.content)) {
- msg.content = msg.content.map((item: any) => {
- if (item && typeof item === "object" && "image" in item) {
- return {
- type: "image_url",
- image_url: {
- url: item.image,
- },
- };
- }
- return item;
- });
- }
- return msg;
- });
- }
- }
+ // Check if model is a qwen-vl vision model
+ if (current_model?.startsWith("qwen-vl")) {
+ console.log("[Alibaba] Processing vision model:", current_model);
+ jsonBody.messages = transformVisionMessages(jsonBody.messages);
+ } Add this helper function: function transformVisionMessages(messages: any[]): any[] {
if (!Array.isArray(messages)) return messages;
return messages.map((msg) => {
if (!Array.isArray(msg.content)) return msg;
return {
...msg,
content: msg.content.map((item) => {
if (item && typeof item === "object" && "image" in item) {
return {
type: "image_url",
image_url: { url: item.image },
};
}
return item;
}),
};
});
} 🧰 Tools🪛 Biome (1.9.4)[error] 106-106: Change to an optional chain. Unsafe fix: Change to an optional chain. (lint/complexity/useOptionalChain) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// console.log("[Alibaba] request body json", jsonBody); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fetchOptions.body = JSON.stringify(jsonBody); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fetchOptions.body = clonedBody; // fallback if not JSON | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const jsonBody = JSON.parse(clonedBody) as { model?: string }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// console.log("[Alibaba] request body", fetchOptions.body); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// not undefined and is false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
isModelNotavailableInServer( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
serverConfig.customModels, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jsonBody?.model as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ServiceProvider.Alibaba as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: `you are not allowed to use ${jsonBody?.model} model`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: 403, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// isModelNotavailableInServer( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// serverConfig.customModels, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// jsonBody?.model as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ServiceProvider.Alibaba as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// error: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// message: `you are not allowed to use ${jsonBody?.model} model`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// status: 403, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+141
to
+157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove commented model availability check code. This large block of commented code should either be removed entirely if no longer needed, or uncommented and fixed if the functionality is still required. If this functionality is no longer needed, remove the commented code: - // not undefined and is false
- // if (
- // isModelNotavailableInServer(
- // serverConfig.customModels,
- // jsonBody?.model as string,
- // ServiceProvider.Alibaba as string,
- // )
- // ) {
- // return NextResponse.json(
- // {
- // error: true,
- // message: `you are not allowed to use ${jsonBody?.model} model`,
- // },
- // {
- // status: 403,
- // },
- // );
- // } If this functionality should be retained, please uncomment and ensure the imports are available.
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.error(`[Alibaba] filter`, e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,14 +6,20 @@ import { getModelProvider, isModelNotavailableInServer } from "../utils/model"; | |
|
||
const serverConfig = getServerSideConfig(); | ||
|
||
// Hàm proxy request từ client tới OpenAI hoặc Azure OpenAI, xử lý xác thực, cấu hình endpoint, kiểm tra model, và trả về response phù hợp. | ||
export async function requestOpenai(req: NextRequest) { | ||
// Tạo controller để có thể hủy request khi timeout | ||
const controller = new AbortController(); | ||
|
||
// Kiểm tra xem request có phải tới Azure OpenAI không | ||
const isAzure = req.nextUrl.pathname.includes("azure/deployments"); | ||
|
||
// Biến lưu giá trị xác thực và tên header xác thực | ||
var authValue, | ||
authHeaderName = ""; | ||
|
||
if (isAzure) { | ||
// Nếu là Azure, lấy api-key từ header Authorization | ||
authValue = | ||
req.headers | ||
.get("Authorization") | ||
|
@@ -23,33 +29,43 @@ export async function requestOpenai(req: NextRequest) { | |
|
||
authHeaderName = "api-key"; | ||
} else { | ||
// Nếu là OpenAI thường, giữ nguyên header Authorization | ||
authValue = req.headers.get("Authorization") ?? ""; | ||
authHeaderName = "Authorization"; | ||
} | ||
|
||
// Xử lý lại đường dẫn endpoint cho phù hợp với OpenAI/Azure | ||
let path = `${req.nextUrl.pathname}`.replaceAll("/api/openai/", ""); | ||
|
||
console.log("[Proxy] mac dinh ", path); | ||
|
||
|
||
// Lấy baseUrl từ config, ưu tiên Azure nếu là request Azure | ||
let baseUrl = | ||
(isAzure ? serverConfig.azureUrl : serverConfig.baseUrl) || OPENAI_BASE_URL; | ||
|
||
// Đảm bảo baseUrl có tiền tố https | ||
if (!baseUrl.startsWith("http")) { | ||
baseUrl = `https://${baseUrl}`; | ||
} | ||
|
||
// Loại bỏ dấu "/" ở cuối baseUrl nếu có | ||
if (baseUrl.endsWith("/")) { | ||
baseUrl = baseUrl.slice(0, -1); | ||
} | ||
|
||
// In ra log để debug đường dẫn và baseUrl | ||
console.log("[Proxy] ", path); | ||
console.log("[Base Url]", baseUrl); | ||
|
||
// Thiết lập timeout cho request (10 phút), nếu quá sẽ abort | ||
const timeoutId = setTimeout( | ||
() => { | ||
controller.abort(); | ||
}, | ||
10 * 60 * 1000, | ||
); | ||
|
||
// Nếu là Azure, xử lý lại path và api-version cho đúng chuẩn Azure | ||
if (isAzure) { | ||
const azureApiVersion = | ||
req?.nextUrl?.searchParams?.get("api-version") || | ||
|
@@ -60,9 +76,7 @@ export async function requestOpenai(req: NextRequest) { | |
"", | ||
)}?api-version=${azureApiVersion}`; | ||
|
||
// Forward compatibility: | ||
// if display_name(deployment_name) not set, and '{deploy-id}' in AZURE_URL | ||
// then using default '{deploy-id}' | ||
// Nếu có customModels và azureUrl, kiểm tra và thay thế deployment id nếu cần | ||
if (serverConfig.customModels && serverConfig.azureUrl) { | ||
const modelName = path.split("/")[1]; | ||
let realDeployName = ""; | ||
|
@@ -88,8 +102,12 @@ export async function requestOpenai(req: NextRequest) { | |
} | ||
} | ||
|
||
// Tạo url cuối cùng để fetch, có thể qua Cloudflare Gateway nếu cấu hình | ||
const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}/${path}`); | ||
|
||
console.log("fetchUrl", fetchUrl); | ||
|
||
// Thiết lập các option cho fetch, bao gồm headers, method, body, v.v. | ||
const fetchOptions: RequestInit = { | ||
headers: { | ||
"Content-Type": "application/json", | ||
|
@@ -101,30 +119,30 @@ export async function requestOpenai(req: NextRequest) { | |
}, | ||
method: req.method, | ||
body: req.body, | ||
// to fix #2485: https://stackoverflow.com/questions/55920957/cloudflare-worker-typeerror-one-time-use-body | ||
// Fix lỗi body chỉ dùng được 1 lần trên Cloudflare Worker | ||
redirect: "manual", | ||
// @ts-ignore | ||
duplex: "half", | ||
signal: controller.signal, | ||
}; | ||
|
||
// #1815 try to refuse gpt4 request | ||
// Kiểm tra model có bị cấm sử dụng không (ví dụ: cấm GPT-4) | ||
if (serverConfig.customModels && req.body) { | ||
try { | ||
const clonedBody = await req.text(); | ||
fetchOptions.body = clonedBody; | ||
|
||
const jsonBody = JSON.parse(clonedBody) as { model?: string }; | ||
|
||
// not undefined and is false | ||
// Nếu model không được phép sử dụng, trả về lỗi 403 | ||
if ( | ||
isModelNotavailableInServer( | ||
serverConfig.customModels, | ||
jsonBody?.model as string, | ||
[ | ||
ServiceProvider.OpenAI, | ||
ServiceProvider.Azure, | ||
jsonBody?.model as string, // support provider-unspecified model | ||
jsonBody?.model as string, // hỗ trợ model không rõ provider | ||
], | ||
) | ||
) { | ||
|
@@ -144,43 +162,40 @@ export async function requestOpenai(req: NextRequest) { | |
} | ||
|
||
try { | ||
// Gửi request tới OpenAI/Azure và nhận response | ||
const res = await fetch(fetchUrl, fetchOptions); | ||
|
||
// Extract the OpenAI-Organization header from the response | ||
// Lấy header OpenAI-Organization từ response (nếu có) | ||
const openaiOrganizationHeader = res.headers.get("OpenAI-Organization"); | ||
|
||
// Check if serverConfig.openaiOrgId is defined and not an empty string | ||
// Nếu đã cấu hình openaiOrgId, log giá trị header này | ||
if (serverConfig.openaiOrgId && serverConfig.openaiOrgId.trim() !== "") { | ||
// If openaiOrganizationHeader is present, log it; otherwise, log that the header is not present | ||
console.log("[Org ID]", openaiOrganizationHeader); | ||
} else { | ||
console.log("[Org ID] is not set up."); | ||
} | ||
|
||
// to prevent browser prompt for credentials | ||
// Xử lý lại headers trả về cho client | ||
const newHeaders = new Headers(res.headers); | ||
newHeaders.delete("www-authenticate"); | ||
// to disable nginx buffering | ||
newHeaders.set("X-Accel-Buffering", "no"); | ||
newHeaders.delete("www-authenticate"); // Xóa header yêu cầu xác thực | ||
newHeaders.set("X-Accel-Buffering", "no"); // Tắt buffer của nginx | ||
|
||
// Conditionally delete the OpenAI-Organization header from the response if [Org ID] is undefined or empty (not setup in ENV) | ||
// Also, this is to prevent the header from being sent to the client | ||
// Nếu chưa cấu hình Org ID, xóa header này khỏi response | ||
if (!serverConfig.openaiOrgId || serverConfig.openaiOrgId.trim() === "") { | ||
newHeaders.delete("OpenAI-Organization"); | ||
} | ||
|
||
// The latest version of the OpenAI API forced the content-encoding to be "br" in json response | ||
// So if the streaming is disabled, we need to remove the content-encoding header | ||
// Because Vercel uses gzip to compress the response, if we don't remove the content-encoding header | ||
// The browser will try to decode the response with brotli and fail | ||
// Xóa header content-encoding để tránh lỗi giải nén trên trình duyệt | ||
newHeaders.delete("content-encoding"); | ||
|
||
// Trả về response cho client với các header đã xử lý | ||
return new Response(res.body, { | ||
status: res.status, | ||
statusText: res.statusText, | ||
headers: newHeaders, | ||
}); | ||
} finally { | ||
// Dù thành công hay lỗi đều clear timeout | ||
clearTimeout(timeoutId); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove commented console.log statements instead of leaving them commented out.
Commented-out debug logs should be removed entirely to keep the codebase clean, rather than left as commented code.
Also applies to: 30-30, 65-65, 81-81, 103-103, 131-131, 138-138, 159-159
🤖 Prompt for AI Agents