mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-19 20:20:16 +09:00
Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web
This commit is contained in:
commit
9c00ca8b1c
@ -5,6 +5,7 @@ import {
|
|||||||
SILICONFLOW_BASE_URL,
|
SILICONFLOW_BASE_URL,
|
||||||
SiliconFlow,
|
SiliconFlow,
|
||||||
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
REQUEST_TIMEOUT_MS_FOR_THINKING,
|
||||||
|
DEFAULT_MODELS,
|
||||||
} from "@/app/constant";
|
} from "@/app/constant";
|
||||||
import {
|
import {
|
||||||
useAccessStore,
|
useAccessStore,
|
||||||
@ -13,7 +14,7 @@ import {
|
|||||||
ChatMessageTool,
|
ChatMessageTool,
|
||||||
usePluginStore,
|
usePluginStore,
|
||||||
} from "@/app/store";
|
} from "@/app/store";
|
||||||
import { streamWithThink } from "@/app/utils/chat";
|
import { preProcessImageContent, streamWithThink } from "@/app/utils/chat";
|
||||||
import {
|
import {
|
||||||
ChatOptions,
|
ChatOptions,
|
||||||
getHeaders,
|
getHeaders,
|
||||||
@ -25,12 +26,22 @@ import { getClientConfig } from "@/app/config/client";
|
|||||||
import {
|
import {
|
||||||
getMessageTextContent,
|
getMessageTextContent,
|
||||||
getMessageTextContentWithoutThinking,
|
getMessageTextContentWithoutThinking,
|
||||||
|
isVisionModel,
|
||||||
} from "@/app/utils";
|
} from "@/app/utils";
|
||||||
import { RequestPayload } from "./openai";
|
import { RequestPayload } from "./openai";
|
||||||
|
|
||||||
import { fetch } from "@/app/utils/stream";
|
import { fetch } from "@/app/utils/stream";
|
||||||
|
export interface SiliconFlowListModelResponse {
|
||||||
|
object: string;
|
||||||
|
data: Array<{
|
||||||
|
id: string;
|
||||||
|
object: string;
|
||||||
|
root: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
export class SiliconflowApi implements LLMApi {
|
export class SiliconflowApi implements LLMApi {
|
||||||
private disableListModels = true;
|
private disableListModels = false;
|
||||||
|
|
||||||
path(path: string): string {
|
path(path: string): string {
|
||||||
const accessStore = useAccessStore.getState();
|
const accessStore = useAccessStore.getState();
|
||||||
@ -71,13 +82,16 @@ export class SiliconflowApi implements LLMApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async chat(options: ChatOptions) {
|
async chat(options: ChatOptions) {
|
||||||
|
const visionModel = isVisionModel(options.config.model);
|
||||||
const messages: ChatOptions["messages"] = [];
|
const messages: ChatOptions["messages"] = [];
|
||||||
for (const v of options.messages) {
|
for (const v of options.messages) {
|
||||||
if (v.role === "assistant") {
|
if (v.role === "assistant") {
|
||||||
const content = getMessageTextContentWithoutThinking(v);
|
const content = getMessageTextContentWithoutThinking(v);
|
||||||
messages.push({ role: v.role, content });
|
messages.push({ role: v.role, content });
|
||||||
} else {
|
} else {
|
||||||
const content = getMessageTextContent(v);
|
const content = visionModel
|
||||||
|
? await preProcessImageContent(v.content)
|
||||||
|
: getMessageTextContent(v);
|
||||||
messages.push({ role: v.role, content });
|
messages.push({ role: v.role, content });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,6 +252,36 @@ export class SiliconflowApi implements LLMApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async models(): Promise<LLMModel[]> {
|
async models(): Promise<LLMModel[]> {
|
||||||
|
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 [];
|
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,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,11 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
|
|||||||
LlmIcon = BotIconGemma;
|
LlmIcon = BotIconGemma;
|
||||||
} else if (modelName.startsWith("claude")) {
|
} else if (modelName.startsWith("claude")) {
|
||||||
LlmIcon = BotIconClaude;
|
LlmIcon = BotIconClaude;
|
||||||
} else if (modelName.startsWith("llama")) {
|
} else if (modelName.toLowerCase().includes("llama")) {
|
||||||
LlmIcon = BotIconMeta;
|
LlmIcon = BotIconMeta;
|
||||||
} else if (modelName.startsWith("mixtral")) {
|
} else if (modelName.startsWith("mixtral")) {
|
||||||
LlmIcon = BotIconMistral;
|
LlmIcon = BotIconMistral;
|
||||||
} else if (modelName.startsWith("deepseek")) {
|
} else if (modelName.toLowerCase().includes("deepseek")) {
|
||||||
LlmIcon = BotIconDeepseek;
|
LlmIcon = BotIconDeepseek;
|
||||||
} else if (modelName.startsWith("moonshot")) {
|
} else if (modelName.startsWith("moonshot")) {
|
||||||
LlmIcon = BotIconMoonshot;
|
LlmIcon = BotIconMoonshot;
|
||||||
@ -85,7 +85,7 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
|
|||||||
} else if (modelName.startsWith("doubao") || modelName.startsWith("ep-")) {
|
} else if (modelName.startsWith("doubao") || modelName.startsWith("ep-")) {
|
||||||
LlmIcon = BotIconDoubao;
|
LlmIcon = BotIconDoubao;
|
||||||
} else if (
|
} else if (
|
||||||
modelName.startsWith("glm") ||
|
modelName.toLowerCase().includes("glm") ||
|
||||||
modelName.startsWith("cogview-") ||
|
modelName.startsWith("cogview-") ||
|
||||||
modelName.startsWith("cogvideox-")
|
modelName.startsWith("cogvideox-")
|
||||||
) {
|
) {
|
||||||
|
@ -23,7 +23,6 @@ import CopyIcon from "../icons/copy.svg";
|
|||||||
import LoadingIcon from "../icons/three-dots.svg";
|
import LoadingIcon from "../icons/three-dots.svg";
|
||||||
import ChatGptIcon from "../icons/chatgpt.png";
|
import ChatGptIcon from "../icons/chatgpt.png";
|
||||||
import ShareIcon from "../icons/share.svg";
|
import ShareIcon from "../icons/share.svg";
|
||||||
import BotIcon from "../icons/bot.png";
|
|
||||||
|
|
||||||
import DownloadIcon from "../icons/download.svg";
|
import DownloadIcon from "../icons/download.svg";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
@ -33,13 +32,13 @@ import dynamic from "next/dynamic";
|
|||||||
import NextImage from "next/image";
|
import NextImage from "next/image";
|
||||||
|
|
||||||
import { toBlob, toPng } from "html-to-image";
|
import { toBlob, toPng } from "html-to-image";
|
||||||
import { DEFAULT_MASK_AVATAR } from "../store/mask";
|
|
||||||
|
|
||||||
import { prettyObject } from "../utils/format";
|
import { prettyObject } from "../utils/format";
|
||||||
import { EXPORT_MESSAGE_CLASS_NAME } from "../constant";
|
import { EXPORT_MESSAGE_CLASS_NAME } from "../constant";
|
||||||
import { getClientConfig } from "../config/client";
|
import { getClientConfig } from "../config/client";
|
||||||
import { type ClientApi, getClientApi } from "../client/api";
|
import { type ClientApi, getClientApi } from "../client/api";
|
||||||
import { getMessageTextContent } from "../utils";
|
import { getMessageTextContent } from "../utils";
|
||||||
|
import { MaskAvatar } from "./mask";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
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: {
|
export function ImagePreviewer(props: {
|
||||||
messages: ChatMessage[];
|
messages: ChatMessage[];
|
||||||
topic: string;
|
topic: string;
|
||||||
@ -546,9 +529,12 @@ export function ImagePreviewer(props: {
|
|||||||
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
|
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
|
||||||
</div>
|
</div>
|
||||||
<div className={styles["icons"]}>
|
<div className={styles["icons"]}>
|
||||||
<ExportAvatar avatar={config.avatar} />
|
<MaskAvatar avatar={config.avatar} />
|
||||||
<span className={styles["icon-space"]}>&</span>
|
<span className={styles["icon-space"]}>&</span>
|
||||||
<ExportAvatar avatar={mask.avatar} />
|
<MaskAvatar
|
||||||
|
avatar={mask.avatar}
|
||||||
|
model={session.mask.modelConfig.model}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -576,9 +562,14 @@ export function ImagePreviewer(props: {
|
|||||||
key={i}
|
key={i}
|
||||||
>
|
>
|
||||||
<div className={styles["avatar"]}>
|
<div className={styles["avatar"]}>
|
||||||
<ExportAvatar
|
{m.role === "user" ? (
|
||||||
avatar={m.role === "user" ? config.avatar : mask.avatar}
|
<Avatar avatar={config.avatar}></Avatar>
|
||||||
|
) : (
|
||||||
|
<MaskAvatar
|
||||||
|
avatar={session.mask.avatar}
|
||||||
|
model={m.model || session.mask.modelConfig.model}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles["body"]}>
|
<div className={styles["body"]}>
|
||||||
|
@ -258,6 +258,7 @@ export const ChatGLM = {
|
|||||||
export const SiliconFlow = {
|
export const SiliconFlow = {
|
||||||
ExampleEndpoint: SILICONFLOW_BASE_URL,
|
ExampleEndpoint: SILICONFLOW_BASE_URL,
|
||||||
ChatPath: "v1/chat/completions",
|
ChatPath: "v1/chat/completions",
|
||||||
|
ListModelPath: "v1/models?&sub_type=chat",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
|
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
|
||||||
@ -462,6 +463,7 @@ export const VISION_MODEL_REGEXES = [
|
|||||||
/gpt-4-turbo(?!.*preview)/, // Matches "gpt-4-turbo" but not "gpt-4-turbo-preview"
|
/gpt-4-turbo(?!.*preview)/, // Matches "gpt-4-turbo" but not "gpt-4-turbo-preview"
|
||||||
/^dall-e-3$/, // Matches exactly "dall-e-3"
|
/^dall-e-3$/, // Matches exactly "dall-e-3"
|
||||||
/glm-4v/,
|
/glm-4v/,
|
||||||
|
/vl/i,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
|
export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
|
||||||
|
Loading…
Reference in New Issue
Block a user