mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-09-27 05:36:39 +08:00
cap nhat giao dien
This commit is contained in:
parent
b07760fbc9
commit
ee25e4ac82
@ -6,16 +6,8 @@ export default function SyncOnFirstLoad() {
|
||||
const syncStore = useSyncStore();
|
||||
|
||||
useEffect(() => {
|
||||
// if (syncStore.lastSyncTime === 0) {
|
||||
// // If this is the first time syncing, call sync()
|
||||
// alert("[SyncOnFirstLoad] Dong bo hoa du lieu lan dau tien");
|
||||
|
||||
console.log("[SyncOnFirstLoad] Dong bo hoa du lieu lan dau tien");
|
||||
|
||||
console.log("Thoi gian dong bo lan cuoi: ", syncStore.lastSyncTime);
|
||||
|
||||
syncStore.sync();
|
||||
// }
|
||||
// Parse cookies using the custom function
|
||||
// syncStore.sync();
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
|
@ -15,6 +15,7 @@ import { handle as siliconflowHandler } from "../../siliconflow";
|
||||
import { handle as xaiHandler } from "../../xai";
|
||||
import { handle as chatglmHandler } from "../../glm";
|
||||
import { handle as proxyHandler } from "../../proxy";
|
||||
import { handle as supabaseHandler } from "../../supabase";
|
||||
|
||||
async function handle(
|
||||
req: NextRequest,
|
||||
@ -27,6 +28,9 @@ async function handle(
|
||||
|
||||
console.log(`[${params.provider} Route] params `, params);
|
||||
switch (apiPath) {
|
||||
case ApiPath.Supabase:
|
||||
console.log("[Supabase Route] params ", params);
|
||||
return supabaseHandler(req, { params });
|
||||
case ApiPath.Azure:
|
||||
return azureHandler(req, { params });
|
||||
case ApiPath.Google:
|
||||
|
51
app/api/supabase.ts
Normal file
51
app/api/supabase.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import cookie from "cookie";
|
||||
|
||||
const SUPABASE_URL = process.env.SUPABASE_URL!;
|
||||
const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY!;
|
||||
const AUTHEN_PAGE = process.env.AUTHEN_PAGE!;
|
||||
|
||||
export async function handle(
|
||||
req: NextRequest,
|
||||
{ params }: { params: { path: string[] } },
|
||||
) {
|
||||
// Parse cookies using the 'cookie' library
|
||||
const cookies = cookie.parse(req.headers.get("cookie") || "");
|
||||
const authToken = cookies["sb-zzgkylsbdgwoohcbompi-auth-token"];
|
||||
|
||||
console.log("[Supabase] authToken", authToken);
|
||||
|
||||
if (!authToken) {
|
||||
return NextResponse.redirect(AUTHEN_PAGE, 302);
|
||||
}
|
||||
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase.auth.getUser();
|
||||
|
||||
console.log("[Supabase] user", data?.user);
|
||||
|
||||
if (error || !data?.user) {
|
||||
return NextResponse.json(
|
||||
{ error: error?.message || "Error fetching user data" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ user: data.user }, { status: 200 });
|
||||
} catch (err) {
|
||||
console.error("Error fetching user data from Supabase:", err);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
@ -132,10 +132,16 @@ interface ChatProvider {
|
||||
usage: () => void;
|
||||
}
|
||||
|
||||
// Khởi tạo API client dựa trên nhà cung cấp mô hình được chỉ định
|
||||
export class ClientApi {
|
||||
public llm: LLMApi;
|
||||
|
||||
// Hàm khởi tạo nhận vào một provider (nhà cung cấp mô hình AI)
|
||||
// Mặc định là ModelProvider.GPT nếu không được chỉ định
|
||||
constructor(provider: ModelProvider = ModelProvider.GPT) {
|
||||
console.log("[ClientApi] provider ", provider);
|
||||
|
||||
// Sử dụng switch để khởi tạo instance tương ứng với provider được chọn
|
||||
switch (provider) {
|
||||
case ModelProvider.GeminiPro:
|
||||
this.llm = new GeminiProApi();
|
||||
@ -178,13 +184,18 @@ export class ClientApi {
|
||||
}
|
||||
}
|
||||
|
||||
// Hàm cấu hình (chưa triển khai chi tiết)
|
||||
config() {}
|
||||
|
||||
// Hàm lấy prompts (chưa triển khai chi tiết)
|
||||
prompts() {}
|
||||
|
||||
// Hàm lấy masks (chưa triển khai chi tiết)
|
||||
masks() {}
|
||||
|
||||
// Hàm chia sẻ cuộc trò chuyện
|
||||
async share(messages: ChatMessage[], avatarUrl: string | null = null) {
|
||||
// Chuẩn bị dữ liệu tin nhắn để chia sẻ
|
||||
const msgs = messages
|
||||
.map((m) => ({
|
||||
from: m.role === "user" ? "human" : "gpt",
|
||||
@ -197,14 +208,20 @@ export class ClientApi {
|
||||
"Share from [NextChat]: https://github.com/Yidadaa/ChatGPT-Next-Web",
|
||||
},
|
||||
]);
|
||||
// 敬告二开开发者们,为了开源大模型的发展,请不要修改上述消息,此消息用于后续数据清洗使用
|
||||
// Lưu ý: Không nên sửa đổi dòng thông báo cuối cùng này vì nó dùng cho việc làm sạch dữ liệu sau này
|
||||
// Please do not modify this message
|
||||
|
||||
console.log("[Share]", messages, msgs);
|
||||
|
||||
// Lấy cấu hình client
|
||||
const clientConfig = getClientConfig();
|
||||
|
||||
// Xác định URL để chia sẻ dựa trên môi trường (app hay web)
|
||||
const proxyUrl = "/sharegpt";
|
||||
const rawUrl = "https://sharegpt.com/api/conversations";
|
||||
const shareUrl = clientConfig?.isApp ? rawUrl : proxyUrl;
|
||||
|
||||
// Gửi yêu cầu POST để chia sẻ cuộc trò chuyện
|
||||
const res = await fetch(shareUrl, {
|
||||
body: JSON.stringify({
|
||||
avatarUrl,
|
||||
@ -216,6 +233,7 @@ export class ClientApi {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
// Xử lý phản hồi và trả về link chia sẻ
|
||||
const resJson = await res.json();
|
||||
console.log("[Share]", resJson);
|
||||
if (resJson.id) {
|
||||
@ -224,6 +242,7 @@ export class ClientApi {
|
||||
}
|
||||
}
|
||||
|
||||
// Hàm tạo token xác thực Bearer
|
||||
export function getBearerToken(
|
||||
apiKey: string,
|
||||
noBearer: boolean = false,
|
||||
@ -233,14 +252,21 @@ export function getBearerToken(
|
||||
: "";
|
||||
}
|
||||
|
||||
// Hàm kiểm tra chuỗi có hợp lệ không (có độ dài > 0)
|
||||
export function validString(x: string): boolean {
|
||||
return x?.length > 0;
|
||||
}
|
||||
|
||||
// Hàm lấy các header cần thiết cho yêu cầu API
|
||||
export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
// Lấy store để truy cập các trạng thái liên quan đến quyền truy cập và chat
|
||||
const accessStore = useAccessStore.getState();
|
||||
const chatStore = useChatStore.getState();
|
||||
|
||||
// Khởi tạo đối tượng headers rỗng
|
||||
let headers: Record<string, string> = {};
|
||||
|
||||
// Nếu không bỏ qua headers thì thêm các header mặc định
|
||||
if (!ignoreHeaders) {
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
@ -248,10 +274,15 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
};
|
||||
}
|
||||
|
||||
// Lấy cấu hình client
|
||||
const clientConfig = getClientConfig();
|
||||
|
||||
// Hàm getConfig sẽ xác định nhà cung cấp hiện tại và API key tương ứng
|
||||
function getConfig() {
|
||||
// Lấy cấu hình mô hình từ session hiện tại
|
||||
const modelConfig = chatStore.currentSession().mask.modelConfig;
|
||||
|
||||
// Kiểm tra loại nhà cung cấp đang được sử dụng
|
||||
const isGoogle = modelConfig.providerName === ServiceProvider.Google;
|
||||
const isAzure = modelConfig.providerName === ServiceProvider.Azure;
|
||||
const isAnthropic = modelConfig.providerName === ServiceProvider.Anthropic;
|
||||
@ -265,7 +296,11 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
const isChatGLM = modelConfig.providerName === ServiceProvider.ChatGLM;
|
||||
const isSiliconFlow =
|
||||
modelConfig.providerName === ServiceProvider.SiliconFlow;
|
||||
|
||||
// Kiểm tra xem có bật kiểm soát truy cập không
|
||||
const isEnabledAccessControl = accessStore.enabledAccessControl();
|
||||
|
||||
// Xác định API key dựa trên nhà cung cấp đang được sử dụng
|
||||
const apiKey = isGoogle
|
||||
? accessStore.googleApiKey
|
||||
: isAzure
|
||||
@ -309,6 +344,7 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
};
|
||||
}
|
||||
|
||||
// Hàm xác định header nào sẽ được sử dụng để xác thực
|
||||
function getAuthHeader(): string {
|
||||
return isAzure
|
||||
? "api-key"
|
||||
@ -319,6 +355,7 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
: "Authorization";
|
||||
}
|
||||
|
||||
// Lấy các giá trị đã được xác định trong getConfig
|
||||
const {
|
||||
isGoogle,
|
||||
isAzure,
|
||||
@ -335,19 +372,24 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
apiKey,
|
||||
isEnabledAccessControl,
|
||||
} = getConfig();
|
||||
// when using baidu api in app, not set auth header
|
||||
|
||||
// Khi sử dụng API của Baidu trong ứng dụng, không đặt header xác thực
|
||||
if (isBaidu && clientConfig?.isApp) return headers;
|
||||
|
||||
// Xác định tên header xác thực
|
||||
const authHeader = getAuthHeader();
|
||||
|
||||
// Tạo token xác thực
|
||||
const bearerToken = getBearerToken(
|
||||
apiKey,
|
||||
isAzure || isAnthropic || isGoogle,
|
||||
);
|
||||
|
||||
// Nếu có bearer token thì thêm vào headers
|
||||
if (bearerToken) {
|
||||
headers[authHeader] = bearerToken;
|
||||
} else if (isEnabledAccessControl && validString(accessStore.accessCode)) {
|
||||
// Nếu có mã truy cập thì sử dụng nó để tạo bearer token
|
||||
headers["Authorization"] = getBearerToken(
|
||||
ACCESS_CODE_PREFIX + accessStore.accessCode,
|
||||
);
|
||||
@ -356,6 +398,7 @@ export function getHeaders(ignoreHeaders: boolean = false) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Hàm tạo instance của ClientApi dựa trên nhà cung cấp dịch vụ
|
||||
export function getClientApi(provider: ServiceProvider): ClientApi {
|
||||
switch (provider) {
|
||||
case ServiceProvider.Google:
|
||||
|
@ -1813,7 +1813,7 @@ function _Chat() {
|
||||
const shouldShowClearContextDivider =
|
||||
i === clearContextIndex - 1;
|
||||
|
||||
console.log(message.role);
|
||||
// console.log(message.role);
|
||||
|
||||
return (
|
||||
<Fragment key={message.id}>
|
||||
@ -1868,9 +1868,9 @@ function _Chat() {
|
||||
}}
|
||||
></IconButton>
|
||||
</div>
|
||||
{isUser ? (
|
||||
<Avatar avatar={config.avatar} />
|
||||
) : (
|
||||
|
||||
{/* Neu la user thi khong hien thi avatar */}
|
||||
{isUser ? null : (
|
||||
<>
|
||||
{["system"].includes(message.role) ? (
|
||||
<Avatar avatar="2699-fe0f" />
|
||||
|
@ -5,7 +5,8 @@ require("../polyfill");
|
||||
import { useEffect, useState } from "react";
|
||||
import styles from "./home.module.scss";
|
||||
|
||||
import BotIcon from "../icons/bot.svg";
|
||||
//icon chebichat logo
|
||||
import BotIcon from "../icons/chebichat.svg";
|
||||
import LoadingIcon from "../icons/three-dots.svg";
|
||||
|
||||
import { getCSSVar, useMobileScreen } from "../utils";
|
||||
@ -14,7 +15,7 @@ import dynamic from "next/dynamic";
|
||||
import { Path, SlotID } from "../constant";
|
||||
import { ErrorBoundary } from "./error";
|
||||
|
||||
import { getISOLang, getLang } from "../locales";
|
||||
import { getISOLang } from "../locales";
|
||||
|
||||
import {
|
||||
HashRouter as Router,
|
||||
@ -212,7 +213,7 @@ function Screen() {
|
||||
<div
|
||||
className={clsx(styles.container, {
|
||||
[styles["tight-container"]]: shouldTightBorder,
|
||||
[styles["rtl-screen"]]: getLang() === "ar",
|
||||
// [styles["rtl-screen"]]: getLang() === "ar", // Removed because "ar" is not a possible return value
|
||||
})}
|
||||
>
|
||||
{renderContent()}
|
||||
|
@ -61,6 +61,7 @@ export enum Path {
|
||||
|
||||
export enum ApiPath {
|
||||
Cors = "",
|
||||
Supabase = "/api/supabase",
|
||||
Azure = "/api/azure",
|
||||
OpenAI = "/api/alibaba", // Use Alibaba path for OpenAI API
|
||||
Anthropic = "/api/anthropic",
|
||||
|
17622
package-lock.json
generated
Normal file
17622
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -25,22 +25,28 @@
|
||||
"@hello-pangea/dnd": "^16.5.0",
|
||||
"@modelcontextprotocol/sdk": "^1.0.4",
|
||||
"@next/third-parties": "^14.1.0",
|
||||
"@supabase/auth-helpers-nextjs": "^0.10.0",
|
||||
"@supabase/ssr": "^0.6.1",
|
||||
"@supabase/supabase-js": "^2.50.1",
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"@vercel/analytics": "^0.1.11",
|
||||
"@vercel/speed-insights": "^1.0.2",
|
||||
"axios": "^1.7.5",
|
||||
"clsx": "^2.1.1",
|
||||
"cookie": "^1.0.2",
|
||||
"emoji-picker-react": "^4.9.2",
|
||||
"fuse.js": "^7.0.0",
|
||||
"heic2any": "^0.0.4",
|
||||
"html-to-image": "^1.11.11",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"install": "^0.13.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"markdown-to-txt": "^2.0.1",
|
||||
"mermaid": "^10.6.1",
|
||||
"nanoid": "^5.0.3",
|
||||
"next": "^14.1.1",
|
||||
"node-fetch": "^3.3.1",
|
||||
"npm": "^11.4.2",
|
||||
"openapi-client-axios": "^7.5.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -54,6 +60,7 @@
|
||||
"rt-client": "https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz",
|
||||
"sass": "^1.59.2",
|
||||
"spark-md5": "^3.0.2",
|
||||
"supabase": "^2.26.9",
|
||||
"use-debounce": "^9.0.4",
|
||||
"zod": "^3.24.1",
|
||||
"zustand": "^4.3.8"
|
||||
|
Loading…
Reference in New Issue
Block a user