save tts audio

This commit is contained in:
2023-11-30 11:47:29 +08:00
parent 647098ef83
commit 97a75ce35f
4 changed files with 29 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ export interface ChatStoreMessage extends Message {
hide: boolean; hide: boolean;
token: number; token: number;
example: boolean; example: boolean;
audio: Blob | null;
} }
export interface TemplateAPI { export interface TemplateAPI {

View File

@@ -151,6 +151,7 @@ export default function ChatBOX(props: {
hide: false, hide: false,
token: responseTokenCount, token: responseTokenCount,
example: false, example: false,
audio: null,
}; };
if (allChunkTool.length > 0) newMsg.tool_calls = allChunkTool; if (allChunkTool.length > 0) newMsg.tool_calls = allChunkTool;
@@ -205,6 +206,7 @@ export default function ChatBOX(props: {
token: token:
data.usage.completion_tokens ?? calculate_token_length(msg.content), data.usage.completion_tokens ?? calculate_token_length(msg.content),
example: false, example: false,
audio: null,
}); });
setShowGenerating(false); setShowGenerating(false);
}; };
@@ -300,6 +302,7 @@ export default function ChatBOX(props: {
hide: false, hide: false,
token: calculate_token_length(inputMsg.trim()), token: calculate_token_length(inputMsg.trim()),
example: false, example: false,
audio: null,
}); });
// manually calculate token length // manually calculate token length
@@ -975,6 +978,7 @@ export default function ChatBOX(props: {
calculate_token_length(images), calculate_token_length(images),
hide: false, hide: false,
example: false, example: false,
audio: null,
}); });
update_total_tokens(); update_total_tokens();
setInputMsg(""); setInputMsg("");
@@ -1068,6 +1072,7 @@ export default function ChatBOX(props: {
token: calculate_token_length(newToolContent), token: calculate_token_length(newToolContent),
hide: false, hide: false,
example: false, example: false,
audio: null,
}); });
update_total_tokens(); update_total_tokens();
setChatStore({ ...chatStore }); setChatStore({ ...chatStore });

View File

@@ -3,7 +3,7 @@ import { useState, useEffect, StateUpdater } from "preact/hooks";
import { ChatStore, ChatStoreMessage } from "./app"; import { ChatStore, ChatStoreMessage } from "./app";
import { calculate_token_length, getMessageText } from "./chatgpt"; import { calculate_token_length, getMessageText } from "./chatgpt";
import Markdown from "preact-markdown"; import Markdown from "preact-markdown";
import TTSButton from "./tts"; import TTSButton, { TTSPlay } from "./tts";
import { MessageHide } from "./messageHide"; import { MessageHide } from "./messageHide";
import { MessageDetail } from "./messageDetail"; import { MessageDetail } from "./messageDetail";
import { MessageToolCall } from "./messageToolCall"; import { MessageToolCall } from "./messageToolCall";
@@ -130,13 +130,18 @@ export default function Message(props: Props) {
</div> </div>
)} )}
<hr className="mt-2" /> <hr className="mt-2" />
<TTSPlay
chat={chat}
chatStore={chatStore}
setChatStore={setChatStore}
/>
<div className="w-full flex justify-between"> <div className="w-full flex justify-between">
<DeleteIcon /> <DeleteIcon />
<button onClick={() => setShowEdit(true)}>🖋</button> <button onClick={() => setShowEdit(true)}>🖋</button>
{chatStore.tts_api && chatStore.tts_key && ( {chatStore.tts_api && chatStore.tts_key && (
<TTSButton <TTSButton
chatStore={chatStore} chatStore={chatStore}
text={getMessageText(chat)} chat={chat}
setChatStore={setChatStore} setChatStore={setChatStore}
/> />
)} )}

View File

@@ -1,10 +1,18 @@
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { ChatStore, addTotalCost } from "./app"; import { ChatStore, ChatStoreMessage, addTotalCost } from "./app";
import { Message, getMessageText } from "./chatgpt";
interface TTSProps { interface TTSProps {
chatStore: ChatStore; chatStore: ChatStore;
chat: ChatStoreMessage;
setChatStore: (cs: ChatStore) => void; setChatStore: (cs: ChatStore) => void;
text: string; }
export function TTSPlay(props: TTSProps) {
if (props.chat.audio instanceof Blob) {
const url = URL.createObjectURL(props.chat.audio);
return <audio src={url} controls />;
}
return <></>;
} }
export default function TTSButton(props: TTSProps) { export default function TTSButton(props: TTSProps) {
const [generating, setGenerating] = useState(false); const [generating, setGenerating] = useState(false);
@@ -14,7 +22,7 @@ export default function TTSButton(props: TTSProps) {
const api = props.chatStore.tts_api; const api = props.chatStore.tts_api;
const api_key = props.chatStore.tts_key; const api_key = props.chatStore.tts_key;
const model = "tts-1"; const model = "tts-1";
const input = props.text; const input = getMessageText(props.chat);
const voice = props.chatStore.tts_voice; const voice = props.chatStore.tts_voice;
const body: Record<string, any> = { const body: Record<string, any> = {
@@ -40,11 +48,15 @@ export default function TTSButton(props: TTSProps) {
.then((response) => response.blob()) .then((response) => response.blob())
.then((blob) => { .then((blob) => {
// update price // update price
const cost = (props.text.length * 0.015) / 1000; const cost = (input.length * 0.015) / 1000;
props.chatStore.cost += cost; props.chatStore.cost += cost;
addTotalCost(cost); addTotalCost(cost);
props.setChatStore({ ...props.chatStore }); props.setChatStore({ ...props.chatStore });
// save blob
props.chat.audio = blob;
props.setChatStore({ ...props.chatStore });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const audio = new Audio(url); const audio = new Audio(url);
audio.play(); audio.play();