mirror of
https://github.com/Yanyutin753/ChatGPT-Next-Web-LangChain-Gpt-4-All.git
synced 2025-10-16 08:00:22 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6b95e7cdea | ||
![]() |
bf161371bc | ||
![]() |
f19a7bc242 | ||
![]() |
4fee67240c | ||
![]() |
8fe047641f | ||
![]() |
afacb3c427 | ||
![]() |
9fd0d19217 |
@@ -19,6 +19,7 @@ ENV OPENAI_API_KEY=""
|
|||||||
ENV GOOGLE_API_KEY=""
|
ENV GOOGLE_API_KEY=""
|
||||||
ENV CODE=""
|
ENV CODE=""
|
||||||
ENV NEXT_PUBLIC_ENABLE_NODEJS_PLUGIN=1
|
ENV NEXT_PUBLIC_ENABLE_NODEJS_PLUGIN=1
|
||||||
|
ENV NEXT_PUBLIC_ENABLE_BASE64=0
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
@@ -35,6 +36,7 @@ ENV PROXY_URL=""
|
|||||||
ENV OPENAI_API_KEY=""
|
ENV OPENAI_API_KEY=""
|
||||||
ENV GOOGLE_API_KEY=""
|
ENV GOOGLE_API_KEY=""
|
||||||
ENV CODE=""
|
ENV CODE=""
|
||||||
|
ENV NEXT_PUBLIC_ENABLE_BASE64=0
|
||||||
|
|
||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
|
@@ -2,72 +2,7 @@ import { getServerSideConfig } from "@/app/config/server";
|
|||||||
import LocalFileStorage from "@/app/utils/local_file_storage";
|
import LocalFileStorage from "@/app/utils/local_file_storage";
|
||||||
import S3FileStorage from "@/app/utils/s3_file_storage";
|
import S3FileStorage from "@/app/utils/s3_file_storage";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import mime from 'mime';
|
||||||
|
|
||||||
interface MimeTypeMap {
|
|
||||||
[extension: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建一个文件扩展名到MIME类型的映射
|
|
||||||
const mimeTypeMap: MimeTypeMap = {
|
|
||||||
'png': 'image/png',
|
|
||||||
'jpg': 'image/jpeg',
|
|
||||||
'webp': 'image/webp',
|
|
||||||
'gif': 'image/gif',
|
|
||||||
'bmp': 'image/bmp',
|
|
||||||
'svg': 'image/svg+xml',
|
|
||||||
'txt': 'text/plain',
|
|
||||||
'pdf': 'application/pdf',
|
|
||||||
'doc': 'application/msword',
|
|
||||||
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
||||||
'xls': 'application/vnd.ms-excel',
|
|
||||||
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
'ppt': 'application/vnd.ms-powerpoint',
|
|
||||||
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
||||||
'zip': 'application/zip',
|
|
||||||
'rar': 'application/x-rar-compressed',
|
|
||||||
'bin': 'application/octet-stream',
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
'mp3': 'audio/mpeg',
|
|
||||||
'wav': 'audio/wav',
|
|
||||||
'ogg': 'audio/ogg',
|
|
||||||
'flac': 'audio/flac',
|
|
||||||
'aac': 'audio/aac',
|
|
||||||
'weba': 'audio/webm',
|
|
||||||
'midi': 'audio/midi',
|
|
||||||
|
|
||||||
// Video
|
|
||||||
'mp4': 'video/mp4',
|
|
||||||
'webm': 'video/webm',
|
|
||||||
'avi': 'video/x-msvideo',
|
|
||||||
'wmv': 'video/x-ms-wmv',
|
|
||||||
'flv': 'video/x-flv',
|
|
||||||
'3gp': 'video/3gpp',
|
|
||||||
'mkv': 'video/x-matroska',
|
|
||||||
|
|
||||||
//编程
|
|
||||||
'js': 'application/javascript',
|
|
||||||
'json': 'application/json',
|
|
||||||
'html': 'text/html',
|
|
||||||
'css': 'text/css',
|
|
||||||
'xml': 'application/xml',
|
|
||||||
'csv': 'text/csv',
|
|
||||||
'ts': 'text/typescript',
|
|
||||||
'java': 'text/x-java-source',
|
|
||||||
'py': 'text/x-python',
|
|
||||||
'c': 'text/x-csrc',
|
|
||||||
'cpp': 'text/x-c++src',
|
|
||||||
'h': 'text/x-chdr',
|
|
||||||
'hpp': 'text/x-c++hdr',
|
|
||||||
'php': 'application/x-httpd-php',
|
|
||||||
'rb': 'text/x-ruby',
|
|
||||||
'go': 'text/x-go',
|
|
||||||
'rs': 'text/rust',
|
|
||||||
'swift': 'text/x-swift',
|
|
||||||
'kt': 'text/x-kotlin',
|
|
||||||
'scala': 'text/x-scala',
|
|
||||||
};
|
|
||||||
|
|
||||||
function getMimeType(filePath: string): string {
|
function getMimeType(filePath: string): string {
|
||||||
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
||||||
@@ -75,11 +10,11 @@ function getMimeType(filePath: string): string {
|
|||||||
}
|
}
|
||||||
const extension = filePath.split('.').pop();
|
const extension = filePath.split('.').pop();
|
||||||
if (extension) {
|
if (extension) {
|
||||||
return mimeTypeMap[extension] || 'application/octet-stream';
|
const mimeType = mime.getType(extension);
|
||||||
|
return mimeType || 'application/octet-stream';
|
||||||
} else {
|
} else {
|
||||||
return 'application/octet-stream';
|
return 'application/octet-stream';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handle(
|
async function handle(
|
||||||
@@ -121,4 +56,3 @@ export const GET = handle;
|
|||||||
|
|
||||||
export const runtime = "nodejs";
|
export const runtime = "nodejs";
|
||||||
export const revalidate = 0;
|
export const revalidate = 0;
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ export class GeminiProApi implements LLMApi {
|
|||||||
}
|
}
|
||||||
async chat(options: ChatOptions): Promise<void> {
|
async chat(options: ChatOptions): Promise<void> {
|
||||||
const messages: any[] = [];
|
const messages: any[] = [];
|
||||||
if (options.config.model.includes("vision")) {
|
if (options.config.model.includes("vision") || options.config.model.includes("gizmo")) {
|
||||||
for (const v of options.messages) {
|
for (const v of options.messages) {
|
||||||
let message: any = {
|
let message: any = {
|
||||||
role: v.role.replace("assistant", "model").replace("system", "user"),
|
role: v.role.replace("assistant", "model").replace("system", "user"),
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
"use client";
|
|
||||||
import {
|
import {
|
||||||
ApiPath,
|
ApiPath,
|
||||||
DEFAULT_API_HOST,
|
DEFAULT_API_HOST,
|
||||||
@@ -26,6 +25,7 @@ import { prettyObject } from "@/app/utils/format";
|
|||||||
import { getClientConfig } from "@/app/config/client";
|
import { getClientConfig } from "@/app/config/client";
|
||||||
import { makeAzurePath } from "@/app/azure";
|
import { makeAzurePath } from "@/app/azure";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import mime from 'mime';
|
||||||
|
|
||||||
export interface OpenAIListModelResponse {
|
export interface OpenAIListModelResponse {
|
||||||
object: string;
|
object: string;
|
||||||
@@ -40,6 +40,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
private disableListModels = true;
|
private disableListModels = true;
|
||||||
|
|
||||||
path(path: string, model?: string): string {
|
path(path: string, model?: string): string {
|
||||||
|
|
||||||
const accessStore = useAccessStore.getState();
|
const accessStore = useAccessStore.getState();
|
||||||
|
|
||||||
const isAzure = accessStore.provider === ServiceProvider.Azure;
|
const isAzure = accessStore.provider === ServiceProvider.Azure;
|
||||||
@@ -54,9 +55,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
|
|
||||||
if (baseUrl.length === 0) {
|
if (baseUrl.length === 0) {
|
||||||
const isApp = !!getClientConfig()?.isApp;
|
const isApp = !!getClientConfig()?.isApp;
|
||||||
baseUrl = isApp
|
baseUrl = isApp ? DEFAULT_API_HOST : ApiPath.OpenAI;
|
||||||
? DEFAULT_API_HOST + "/proxy" + ApiPath.OpenAI
|
|
||||||
: ApiPath.OpenAI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseUrl.endsWith("/")) {
|
if (baseUrl.endsWith("/")) {
|
||||||
@@ -71,8 +70,6 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
return [baseUrl, model, path].join("/");
|
return [baseUrl, model, path].join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[Proxy Endpoint] ", baseUrl, path);
|
|
||||||
|
|
||||||
return [baseUrl, path].join("/");
|
return [baseUrl, path].join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +85,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
const base64 = Buffer.from(response.data, "binary").toString("base64");
|
const base64 = Buffer.from(response.data, "binary").toString("base64");
|
||||||
return base64;
|
return base64;
|
||||||
};
|
};
|
||||||
if (options.config.model.includes("vision")) {
|
if (options.config.model.includes("vision") || options.config.model.includes("gizmo")) {
|
||||||
for (const v of options.messages) {
|
for (const v of options.messages) {
|
||||||
let message: {
|
let message: {
|
||||||
role: string;
|
role: string;
|
||||||
@@ -107,79 +104,15 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
});
|
});
|
||||||
if (v.image_url) {
|
if (v.image_url) {
|
||||||
let image_url_data = "";
|
let image_url_data = "";
|
||||||
if (process.env.NEXT_PUBLIC_ENABLE_BASE64 == '1') {
|
if (process.env.NEXT_PUBLIC_ENABLE_BASE64) {
|
||||||
var base64Data = await getImageBase64Data(v.image_url);
|
var base64Data = await getImageBase64Data(v.image_url);
|
||||||
interface MIMEMap {
|
let mimeType: string | null;
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const extensionToMIME: MIMEMap = {
|
|
||||||
'png': 'image/png',
|
|
||||||
'jpg': 'image/jpeg',
|
|
||||||
'webp': 'image/webp',
|
|
||||||
'gif': 'image/gif',
|
|
||||||
'bmp': 'image/bmp',
|
|
||||||
'svg': 'image/svg+xml',
|
|
||||||
'txt': 'text/plain',
|
|
||||||
'pdf': 'application/pdf',
|
|
||||||
'doc': 'application/msword',
|
|
||||||
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
||||||
'xls': 'application/vnd.ms-excel',
|
|
||||||
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
'ppt': 'application/vnd.ms-powerpoint',
|
|
||||||
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
||||||
'zip': 'application/zip',
|
|
||||||
'rar': 'application/x-rar-compressed',
|
|
||||||
'bin': 'application/octet-stream',
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
'mp3': 'audio/mpeg',
|
|
||||||
'wav': 'audio/wav',
|
|
||||||
'ogg': 'audio/ogg',
|
|
||||||
'flac': 'audio/flac',
|
|
||||||
'aac': 'audio/aac',
|
|
||||||
'weba': 'audio/webm',
|
|
||||||
'midi': 'audio/midi',
|
|
||||||
|
|
||||||
// Video
|
|
||||||
'mp4': 'video/mp4',
|
|
||||||
'webm': 'video/webm',
|
|
||||||
'avi': 'video/x-msvideo',
|
|
||||||
'wmv': 'video/x-ms-wmv',
|
|
||||||
'flv': 'video/x-flv',
|
|
||||||
'3gp': 'video/3gpp',
|
|
||||||
'mkv': 'video/x-matroska',
|
|
||||||
|
|
||||||
//编程
|
|
||||||
'js': 'application/javascript',
|
|
||||||
'json': 'application/json',
|
|
||||||
'html': 'text/html',
|
|
||||||
'css': 'text/css',
|
|
||||||
'xml': 'application/xml',
|
|
||||||
'csv': 'text/csv',
|
|
||||||
'ts': 'text/typescript',
|
|
||||||
'java': 'text/x-java-source',
|
|
||||||
'py': 'text/x-python',
|
|
||||||
'c': 'text/x-csrc',
|
|
||||||
'cpp': 'text/x-c++src',
|
|
||||||
'h': 'text/x-chdr',
|
|
||||||
'hpp': 'text/x-c++hdr',
|
|
||||||
'php': 'application/x-httpd-php',
|
|
||||||
'rb': 'text/x-ruby',
|
|
||||||
'go': 'text/x-go',
|
|
||||||
'rs': 'text/rust',
|
|
||||||
'swift': 'text/x-swift',
|
|
||||||
'kt': 'text/x-kotlin',
|
|
||||||
'scala': 'text/x-scala',
|
|
||||||
};
|
|
||||||
|
|
||||||
let mimeType: string | undefined;
|
|
||||||
try {
|
try {
|
||||||
// 使用正则表达式获取文件后缀
|
// 使用正则表达式获取文件后缀
|
||||||
const match = v.image_url.match(/\.(\w+)$/);
|
const match = v.image_url.match(/\.(\w+)$/);
|
||||||
if (match) {
|
if (match && match[1]) {
|
||||||
const fileExtension = match[1].toLowerCase();
|
const fileExtension = match[1].toLowerCase();
|
||||||
mimeType = extensionToMIME[fileExtension];
|
mimeType = mime.getType(fileExtension);
|
||||||
if (!mimeType) {
|
if (!mimeType) {
|
||||||
throw new Error('Unknown file extension: ' + fileExtension);
|
throw new Error('Unknown file extension: ' + fileExtension);
|
||||||
}
|
}
|
||||||
@@ -193,6 +126,11 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
image_url_data = `data:${mimeType};base64,${base64Data}`
|
image_url_data = `data:${mimeType};base64,${base64Data}`
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const match = v.image_url.match(/\.(\w+)$/);
|
||||||
|
if (match && match[1]) {
|
||||||
|
const fileExtension = match[1].toLowerCase();
|
||||||
|
v.image_url = v.image_url.replace(/\.\w+$/, '.' + fileExtension);
|
||||||
|
}
|
||||||
var port = window.location.port ? ':' + window.location.port : '';
|
var port = window.location.port ? ':' + window.location.port : '';
|
||||||
var url = window.location.protocol + "//" + window.location.hostname + port;
|
var url = window.location.protocol + "//" + window.location.hostname + port;
|
||||||
image_url_data = encodeURI(`${url}${v.image_url}`)
|
image_url_data = encodeURI(`${url}${v.image_url}`)
|
||||||
@@ -214,6 +152,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const modelConfig = {
|
const modelConfig = {
|
||||||
...useAppConfig.getState().modelConfig,
|
...useAppConfig.getState().modelConfig,
|
||||||
...useChatStore.getState().currentSession().mask.modelConfig,
|
...useChatStore.getState().currentSession().mask.modelConfig,
|
||||||
@@ -230,7 +169,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
frequency_penalty: modelConfig.frequency_penalty,
|
frequency_penalty: modelConfig.frequency_penalty,
|
||||||
top_p: modelConfig.top_p,
|
top_p: modelConfig.top_p,
|
||||||
max_tokens:
|
max_tokens:
|
||||||
modelConfig.model.includes("vision")
|
modelConfig.model.includes("vision") || modelConfig.model.includes("gizmo")
|
||||||
? modelConfig.max_tokens
|
? modelConfig.max_tokens
|
||||||
: null,
|
: null,
|
||||||
// max_tokens: Math.max(modelConfig.max_tokens, 1024),
|
// max_tokens: Math.max(modelConfig.max_tokens, 1024),
|
||||||
|
@@ -538,7 +538,7 @@ export function ChatActions(props: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (currentModel.includes("vision")) {
|
if (currentModel.includes("vision") || currentModel.includes("gizmo")) {
|
||||||
window.addEventListener("paste", onPaste);
|
window.addEventListener("paste", onPaste);
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("paste", onPaste);
|
window.removeEventListener("paste", onPaste);
|
||||||
@@ -609,7 +609,7 @@ export function ChatActions(props: {
|
|||||||
|
|
||||||
{config.pluginConfig.enable &&
|
{config.pluginConfig.enable &&
|
||||||
/^gpt(?!.*03\d{2}$).*$/.test(currentModel) &&
|
/^gpt(?!.*03\d{2}$).*$/.test(currentModel) &&
|
||||||
currentModel != "gpt-4-vision-preview" && (
|
(!currentModel.includes("vision") && !currentModel.includes("gizmo")) && (
|
||||||
<ChatAction
|
<ChatAction
|
||||||
onClick={switchUsePlugins}
|
onClick={switchUsePlugins}
|
||||||
text={
|
text={
|
||||||
@@ -620,7 +620,7 @@ export function ChatActions(props: {
|
|||||||
icon={usePlugins ? <EnablePluginIcon /> : <DisablePluginIcon />}
|
icon={usePlugins ? <EnablePluginIcon /> : <DisablePluginIcon />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{currentModel.includes("vision") && (
|
{(currentModel.includes("vision") || currentModel.includes("gizmo")) && (
|
||||||
<ChatAction
|
<ChatAction
|
||||||
onClick={selectImage}
|
onClick={selectImage}
|
||||||
text="选择图片"
|
text="选择图片"
|
||||||
@@ -1412,7 +1412,7 @@ function _Chat() {
|
|||||||
defaultShow={i >= messages.length - 6}
|
defaultShow={i >= messages.length - 6}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!isUser && message.model?.includes("vision") && (
|
{!isUser && (message.model?.includes("vision") || message.model?.includes("gizmo")) && (
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
styles["chat-message-actions"],
|
styles["chat-message-actions"],
|
||||||
|
@@ -7,6 +7,7 @@ import { type Metadata } from "next";
|
|||||||
import { SpeedInsights } from "@vercel/speed-insights/next";
|
import { SpeedInsights } from "@vercel/speed-insights/next";
|
||||||
import { getServerSideConfig } from "./config/server";
|
import { getServerSideConfig } from "./config/server";
|
||||||
import { GoogleTagManager } from "@next/third-parties/google";
|
import { GoogleTagManager } from "@next/third-parties/google";
|
||||||
|
import { Analytics } from "@vercel/analytics/react"
|
||||||
const serverConfig = getServerSideConfig();
|
const serverConfig = getServerSideConfig();
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
|
@@ -340,7 +340,7 @@ export const useChatStore = createPersistStore(
|
|||||||
session.mask.usePlugins &&
|
session.mask.usePlugins &&
|
||||||
allPlugins.length > 0 &&
|
allPlugins.length > 0 &&
|
||||||
modelConfig.model.startsWith("gpt") &&
|
modelConfig.model.startsWith("gpt") &&
|
||||||
modelConfig.model != "gpt-4-vision-preview"
|
(!modelConfig.model.includes("vision") && !modelConfig.model.includes("gizmo"))
|
||||||
) {
|
) {
|
||||||
console.log("[ToolAgent] start");
|
console.log("[ToolAgent] start");
|
||||||
const pluginToolNames = allPlugins.map((m) => m.toolName);
|
const pluginToolNames = allPlugins.map((m) => m.toolName);
|
||||||
|
13711
package-lock.json
generated
Normal file
13711
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@
|
|||||||
"@aws-sdk/s3-request-presigner": "^3.414.0",
|
"@aws-sdk/s3-request-presigner": "^3.414.0",
|
||||||
"@fortaine/fetch-event-source": "^3.0.6",
|
"@fortaine/fetch-event-source": "^3.0.6",
|
||||||
"@hello-pangea/dnd": "^16.5.0",
|
"@hello-pangea/dnd": "^16.5.0",
|
||||||
"langchain": "0.1.20",
|
|
||||||
"@langchain/community": "0.0.30",
|
"@langchain/community": "0.0.30",
|
||||||
"@langchain/openai": "0.0.14",
|
"@langchain/openai": "0.0.14",
|
||||||
"@next/third-parties": "^14.1.0",
|
"@next/third-parties": "^14.1.0",
|
||||||
@@ -37,7 +36,9 @@
|
|||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
"https-proxy-agent": "^7.0.2",
|
"https-proxy-agent": "^7.0.2",
|
||||||
|
"langchain": "0.1.20",
|
||||||
"mermaid": "^10.6.1",
|
"mermaid": "^10.6.1",
|
||||||
|
"mime": "^4.0.1",
|
||||||
"nanoid": "^5.0.3",
|
"nanoid": "^5.0.3",
|
||||||
"next": "^13.4.9",
|
"next": "^13.4.9",
|
||||||
"node-fetch": "^3.3.1",
|
"node-fetch": "^3.3.1",
|
||||||
|
Reference in New Issue
Block a user