mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 16:23:41 +08:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			dependabot
			...
			868bfca161
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					868bfca161 | ||
| 
						 | 
					c3b50a9c93 | ||
| 
						 | 
					ab4bf3ba67 | ||
| 
						 | 
					67192a7946 | ||
| 
						 | 
					bcd50b89c8 | 
@@ -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}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user