mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 16:23:41 +08:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
			feat/markd
			...
			9b4b57748f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9b4b57748f | ||
| 
						 | 
					705dffc664 | ||
| 
						 | 
					02f7e6de98 | ||
| 
						 | 
					3809375694 | ||
| 
						 | 
					1b0de25986 | ||
| 
						 | 
					865c45dd29 | ||
| 
						 | 
					1f5d8e6d9c | ||
| 
						 | 
					c9ef6d58ed | ||
| 
						 | 
					2d7229d2b8 | ||
| 
						 | 
					11b37c15bd | ||
| 
						 | 
					1d0038f17d | ||
| 
						 | 
					619fa519c0 | ||
| 
						 | 
					c3b50a9c93 | ||
| 
						 | 
					ab4bf3ba67 | ||
| 
						 | 
					67192a7946 | ||
| 
						 | 
					bcd50b89c8 | 
@@ -22,7 +22,7 @@ English / [简体中文](./README_CN.md)
 | 
				
			|||||||
[![MacOS][MacOS-image]][download-url]
 | 
					[![MacOS][MacOS-image]][download-url]
 | 
				
			||||||
[![Linux][Linux-image]][download-url]
 | 
					[![Linux][Linux-image]][download-url]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[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)
 | 
					[NextChatAI](https://nextchat.club?utm_source=readme) / [iOS APP](https://apps.apple.com/us/app/nextchat-ai/id6743085599) / [Web App Demo](https://app.nextchat.dev) / [Desktop App](https://github.com/Yidadaa/ChatGPT-Next-Web/releases) / [Enterprise Edition](#enterprise-edition) 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[saas-url]: https://nextchat.club?utm_source=readme
 | 
					[saas-url]: https://nextchat.club?utm_source=readme
 | 
				
			||||||
@@ -40,11 +40,12 @@ English / [简体中文](./README_CN.md)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 🥳 Cheer for DeepSeek, China's AI star!
 | 
					## 🥳 Cheer for NextChat iOS Version Online!
 | 
				
			||||||
 > Purpose-Built UI for DeepSeek Reasoner Model
 | 
					> [👉 Click Here to Install Now](https://apps.apple.com/us/app/nextchat-ai/id6743085599)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<img src="https://github.com/user-attachments/assets/f3952210-3af1-4dc0-9b81-40eaa4847d9a"/>
 | 
					> [❤️ Source Code Coming Soon](https://github.com/ChatGPTNextWeb/NextChat-iOS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
## 🫣 NextChat Support MCP  ! 
 | 
					## 🫣 NextChat Support MCP  ! 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -198,7 +198,8 @@ export class ChatGPTApi implements LLMApi {
 | 
				
			|||||||
    const isDalle3 = _isDalle3(options.config.model);
 | 
					    const isDalle3 = _isDalle3(options.config.model);
 | 
				
			||||||
    const isO1OrO3 =
 | 
					    const isO1OrO3 =
 | 
				
			||||||
      options.config.model.startsWith("o1") ||
 | 
					      options.config.model.startsWith("o1") ||
 | 
				
			||||||
      options.config.model.startsWith("o3");
 | 
					      options.config.model.startsWith("o3") ||
 | 
				
			||||||
 | 
					      options.config.model.startsWith("o4-mini");
 | 
				
			||||||
    if (isDalle3) {
 | 
					    if (isDalle3) {
 | 
				
			||||||
      const prompt = getMessageTextContent(
 | 
					      const prompt = getMessageTextContent(
 | 
				
			||||||
        options.messages.slice(-1)?.pop() as any,
 | 
					        options.messages.slice(-1)?.pop() as any,
 | 
				
			||||||
@@ -243,7 +244,7 @@ export class ChatGPTApi implements LLMApi {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // add max_tokens to vision model
 | 
					      // add max_tokens to vision model
 | 
				
			||||||
      if (visionModel) {
 | 
					      if (visionModel && !isO1OrO3) {
 | 
				
			||||||
        requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
 | 
					        requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,76 @@
 | 
				
			|||||||
import { TTSConfig, TTSConfigValidator } from "../store";
 | 
					import { TTSConfig, TTSConfigValidator } from "../store";
 | 
				
			||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Locale from "../locales";
 | 
					import Locale from "../locales";
 | 
				
			||||||
import { ListItem, Select } from "./ui-lib";
 | 
					import { ListItem, Select } from "./ui-lib";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  ModelProvider,
 | 
				
			||||||
  DEFAULT_TTS_ENGINE,
 | 
					  DEFAULT_TTS_ENGINE,
 | 
				
			||||||
  DEFAULT_TTS_ENGINES,
 | 
					  DEFAULT_TTS_ENGINES,
 | 
				
			||||||
  DEFAULT_TTS_MODELS,
 | 
					  DEFAULT_TTS_MODELS,
 | 
				
			||||||
  DEFAULT_TTS_VOICES,
 | 
					  DEFAULT_TTS_VOICES,
 | 
				
			||||||
} from "../constant";
 | 
					} from "../constant";
 | 
				
			||||||
import { InputRange } from "./input-range";
 | 
					import { InputRange } from "./input-range";
 | 
				
			||||||
 | 
					import { IconButton } from "./button";
 | 
				
			||||||
 | 
					import SpeakIcon from "../icons/speak.svg";
 | 
				
			||||||
 | 
					import SpeakStopIcon from "../icons/speak-stop.svg";
 | 
				
			||||||
 | 
					import { createTTSPlayer } from "../utils/audio";
 | 
				
			||||||
 | 
					import { useAppConfig } from "../store";
 | 
				
			||||||
 | 
					import { ClientApi } from "../client/api";
 | 
				
			||||||
 | 
					import { showToast } from "../components/ui-lib";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ttsPlayer = createTTSPlayer();
 | 
				
			||||||
export function TTSConfigList(props: {
 | 
					export function TTSConfigList(props: {
 | 
				
			||||||
  ttsConfig: TTSConfig;
 | 
					  ttsConfig: TTSConfig;
 | 
				
			||||||
  updateConfig: (updater: (config: TTSConfig) => void) => void;
 | 
					  updateConfig: (updater: (config: TTSConfig) => void) => void;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
 | 
					  const [speechLoading, setSpeechLoading] = useState(false);
 | 
				
			||||||
 | 
					  const [speechStatus, setSpeechStatus] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const config = useAppConfig.getState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function stopSpeech() {
 | 
				
			||||||
 | 
					    ttsPlayer.stop();
 | 
				
			||||||
 | 
					    setSpeechStatus(false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function playSpeech(text: string, ttsConfig: TTSConfig) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const api = new ClientApi(ModelProvider.GPT);
 | 
				
			||||||
 | 
					      setSpeechLoading(true);
 | 
				
			||||||
 | 
					      ttsPlayer.init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const audioBuffer = await api.llm.speech({
 | 
				
			||||||
 | 
					        model: ttsConfig.model,
 | 
				
			||||||
 | 
					        input: text,
 | 
				
			||||||
 | 
					        voice: ttsConfig.voice,
 | 
				
			||||||
 | 
					        speed: ttsConfig.speed,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setSpeechStatus(true);
 | 
				
			||||||
 | 
					      await ttsPlayer.play(audioBuffer, () => {
 | 
				
			||||||
 | 
					        setSpeechStatus(false);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error("[OpenAI Speech]", error);
 | 
				
			||||||
 | 
					      setSpeechStatus(false);
 | 
				
			||||||
 | 
					      // Implement user-facing error notification here
 | 
				
			||||||
 | 
					      if (typeof (error as Error).message === "string") {
 | 
				
			||||||
 | 
					        showToast((error as Error).message);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      setSpeechLoading(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function openaiSpeech(text: string) {
 | 
				
			||||||
 | 
					    if (speechStatus) {
 | 
				
			||||||
 | 
					      stopSpeech();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      await playSpeech(text, config.ttsConfig);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <ListItem
 | 
					      <ListItem
 | 
				
			||||||
@@ -88,23 +145,41 @@ export function TTSConfigList(props: {
 | 
				
			|||||||
            title={Locale.Settings.TTS.Voice.Title}
 | 
					            title={Locale.Settings.TTS.Voice.Title}
 | 
				
			||||||
            subTitle={Locale.Settings.TTS.Voice.SubTitle}
 | 
					            subTitle={Locale.Settings.TTS.Voice.SubTitle}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <Select
 | 
					            <div style={{ display: "flex", gap: "10px" }}>
 | 
				
			||||||
              value={props.ttsConfig.voice}
 | 
					              <IconButton
 | 
				
			||||||
              onChange={(e) => {
 | 
					                aria={Locale.Chat.Actions.Speech}
 | 
				
			||||||
                props.updateConfig(
 | 
					                icon={speechStatus ? <SpeakStopIcon /> : <SpeakIcon />}
 | 
				
			||||||
                  (config) =>
 | 
					                text={
 | 
				
			||||||
                    (config.voice = TTSConfigValidator.voice(
 | 
					                  speechLoading
 | 
				
			||||||
 | 
					                    ? "Loading..."
 | 
				
			||||||
 | 
					                    : speechStatus
 | 
				
			||||||
 | 
					                    ? Locale.Chat.Actions.Stop
 | 
				
			||||||
 | 
					                    : Locale.Chat.Actions.Speech
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                onClick={() => {
 | 
				
			||||||
 | 
					                  openaiSpeech(
 | 
				
			||||||
 | 
					                    "NextChat,Unleash your imagination, experience the future of AI conversation.",
 | 
				
			||||||
 | 
					                  );
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <Select
 | 
				
			||||||
 | 
					                value={props.ttsConfig.voice}
 | 
				
			||||||
 | 
					                onChange={(e) => {
 | 
				
			||||||
 | 
					                  props.updateConfig((config) => {
 | 
				
			||||||
 | 
					                    config.voice = TTSConfigValidator.voice(
 | 
				
			||||||
                      e.currentTarget.value,
 | 
					                      e.currentTarget.value,
 | 
				
			||||||
                    )),
 | 
					                    );
 | 
				
			||||||
                );
 | 
					                  });
 | 
				
			||||||
              }}
 | 
					                }}
 | 
				
			||||||
            >
 | 
					              >
 | 
				
			||||||
              {DEFAULT_TTS_VOICES.map((v, i) => (
 | 
					                {DEFAULT_TTS_VOICES.map((v, i) => (
 | 
				
			||||||
                <option value={v} key={i}>
 | 
					                  <option value={v} key={i}>
 | 
				
			||||||
                  {v}
 | 
					                    {v}
 | 
				
			||||||
                </option>
 | 
					                  </option>
 | 
				
			||||||
              ))}
 | 
					                ))}
 | 
				
			||||||
            </Select>
 | 
					              </Select>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
          </ListItem>
 | 
					          </ListItem>
 | 
				
			||||||
          <ListItem
 | 
					          <ListItem
 | 
				
			||||||
            title={Locale.Settings.TTS.Speed.Title}
 | 
					            title={Locale.Settings.TTS.Speed.Title}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -417,6 +417,14 @@ export const KnowledgeCutOffDate: Record<string, string> = {
 | 
				
			|||||||
  "gpt-4-turbo": "2023-12",
 | 
					  "gpt-4-turbo": "2023-12",
 | 
				
			||||||
  "gpt-4-turbo-2024-04-09": "2023-12",
 | 
					  "gpt-4-turbo-2024-04-09": "2023-12",
 | 
				
			||||||
  "gpt-4-turbo-preview": "2023-12",
 | 
					  "gpt-4-turbo-preview": "2023-12",
 | 
				
			||||||
 | 
					  "gpt-4.1": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.1-2025-04-14": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.1-mini": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.1-mini-2025-04-14": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.1-nano": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.1-nano-2025-04-14": "2024-06",
 | 
				
			||||||
 | 
					  "gpt-4.5-preview": "2023-10",
 | 
				
			||||||
 | 
					  "gpt-4.5-preview-2025-02-27": "2023-10",
 | 
				
			||||||
  "gpt-4o": "2023-10",
 | 
					  "gpt-4o": "2023-10",
 | 
				
			||||||
  "gpt-4o-2024-05-13": "2023-10",
 | 
					  "gpt-4o-2024-05-13": "2023-10",
 | 
				
			||||||
  "gpt-4o-2024-08-06": "2023-10",
 | 
					  "gpt-4o-2024-08-06": "2023-10",
 | 
				
			||||||
@@ -458,6 +466,7 @@ export const DEFAULT_TTS_VOICES = [
 | 
				
			|||||||
export const VISION_MODEL_REGEXES = [
 | 
					export const VISION_MODEL_REGEXES = [
 | 
				
			||||||
  /vision/,
 | 
					  /vision/,
 | 
				
			||||||
  /gpt-4o/,
 | 
					  /gpt-4o/,
 | 
				
			||||||
 | 
					  /gpt-4\.1/,
 | 
				
			||||||
  /claude-3/,
 | 
					  /claude-3/,
 | 
				
			||||||
  /gemini-1\.5/,
 | 
					  /gemini-1\.5/,
 | 
				
			||||||
  /gemini-exp/,
 | 
					  /gemini-exp/,
 | 
				
			||||||
@@ -469,6 +478,8 @@ export const VISION_MODEL_REGEXES = [
 | 
				
			|||||||
  /^dall-e-3$/, // Matches exactly "dall-e-3"
 | 
					  /^dall-e-3$/, // Matches exactly "dall-e-3"
 | 
				
			||||||
  /glm-4v/,
 | 
					  /glm-4v/,
 | 
				
			||||||
  /vl/i,
 | 
					  /vl/i,
 | 
				
			||||||
 | 
					  /o3/,
 | 
				
			||||||
 | 
					  /o4-mini/,
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
 | 
					export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
 | 
				
			||||||
@@ -485,6 +496,14 @@ const openaiModels = [
 | 
				
			|||||||
  "gpt-4-32k-0613",
 | 
					  "gpt-4-32k-0613",
 | 
				
			||||||
  "gpt-4-turbo",
 | 
					  "gpt-4-turbo",
 | 
				
			||||||
  "gpt-4-turbo-preview",
 | 
					  "gpt-4-turbo-preview",
 | 
				
			||||||
 | 
					  "gpt-4.1",
 | 
				
			||||||
 | 
					  "gpt-4.1-2025-04-14",
 | 
				
			||||||
 | 
					  "gpt-4.1-mini",
 | 
				
			||||||
 | 
					  "gpt-4.1-mini-2025-04-14",
 | 
				
			||||||
 | 
					  "gpt-4.1-nano",
 | 
				
			||||||
 | 
					  "gpt-4.1-nano-2025-04-14",
 | 
				
			||||||
 | 
					  "gpt-4.5-preview",
 | 
				
			||||||
 | 
					  "gpt-4.5-preview-2025-02-27",
 | 
				
			||||||
  "gpt-4o",
 | 
					  "gpt-4o",
 | 
				
			||||||
  "gpt-4o-2024-05-13",
 | 
					  "gpt-4o-2024-05-13",
 | 
				
			||||||
  "gpt-4o-2024-08-06",
 | 
					  "gpt-4o-2024-08-06",
 | 
				
			||||||
@@ -499,6 +518,8 @@ const openaiModels = [
 | 
				
			|||||||
  "o1-mini",
 | 
					  "o1-mini",
 | 
				
			||||||
  "o1-preview",
 | 
					  "o1-preview",
 | 
				
			||||||
  "o3-mini",
 | 
					  "o3-mini",
 | 
				
			||||||
 | 
					  "o3",
 | 
				
			||||||
 | 
					  "o4-mini",
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const googleModels = [
 | 
					const googleModels = [
 | 
				
			||||||
@@ -525,6 +546,7 @@ const googleModels = [
 | 
				
			|||||||
  "gemini-2.0-flash-thinking-exp-01-21",
 | 
					  "gemini-2.0-flash-thinking-exp-01-21",
 | 
				
			||||||
  "gemini-2.0-pro-exp",
 | 
					  "gemini-2.0-pro-exp",
 | 
				
			||||||
  "gemini-2.0-pro-exp-02-05",
 | 
					  "gemini-2.0-pro-exp-02-05",
 | 
				
			||||||
 | 
					  "gemini-2.5-pro-preview-06-05",
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const anthropicModels = [
 | 
					const anthropicModels = [
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user