Skip to content

Commit

Permalink
Update API key button onClick parameter
Browse files Browse the repository at this point in the history
Add TTSOutputNode component
Add AudioPlayer component
Refactor SttOutputNode component
  • Loading branch information
felri committed Dec 17, 2023
1 parent 4568986 commit 2bb3304
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 85 deletions.
28 changes: 28 additions & 0 deletions src/components/Common/audioPlayer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useEffect, useRef } from "react";
import PropTypes from "prop-types";

const AudioPlayer = ({ file }) => {
const audioRef = useRef(null);

useEffect(() => {
if (audioRef.current) {
audioRef.current.load();
}
}, [file]);

return (
<div className="flex items-center justify-center w-full">
<audio ref={audioRef} controls className="w-full h-10">
<source src={file?.data} type="audio/mp3" />
</audio>
</div>
);
};

AudioPlayer.propTypes = {
file: PropTypes.shape({
data: PropTypes.string,
}),
};

export default AudioPlayer;
2 changes: 1 addition & 1 deletion src/components/FlowComponents/apiKey.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function ApiKeyNode({ id }) {
icon={button.icon}
label={button.label}
onClick={() =>
onChooseType(id, button.type, 320)
onChooseType(id, button.type, 290)
}
/>
))}
Expand Down
2 changes: 2 additions & 0 deletions src/components/FlowComponents/scene.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import TTSInput from "./ttsInput";
import SttOutputNode from "./sttOutput";
import SystemMessageInput from "./systemInput";
import DropFilesNode from "./dropFiles";
import TTSOutputNode from "./ttsOutput";
import Controls from "./controls";
import EditorNode from "./mediaEditor";
import ChatOutputNode from "./chatOutput";
Expand Down Expand Up @@ -47,6 +48,7 @@ const nodeTypes = {
ffmpeg: FFMpegNode,
sttOutput: SttOutputNode,
tts: TTSInput,
ttsOutput: TTSOutputNode,
};

function Flow() {
Expand Down
45 changes: 4 additions & 41 deletions src/components/FlowComponents/sttOutput.jsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,16 @@
import { useEffect, useState, useCallback, useRef, useMemo } from "react";
import { useState, useCallback, useRef, useMemo } from "react";
import { storeManager, useConfigStore, useFileStore } from "../../store";
import { Handle, Position } from "reactflow";
import Container from "../Common/container";
import TextArea from "../Common/textarea";
import { HiOutlineTrash } from "react-icons/hi2";
import hljs from "highlight.js";
import { IoIosAdd } from "react-icons/io";
import PropTypes from "prop-types";
import { IoStopCircleOutline } from "react-icons/io5";
import { FaSave } from "react-icons/fa";
import { IoIosRefresh } from "react-icons/io";
import { CiEdit } from "react-icons/ci";
import { uploadAudio } from "../../api/stt";
import Dropdown from "../Common/dropdown";
import { responseFormatSTT, languages } from "../../store/constants";
import Loading from "../Common/loading";
import "highlight.js/styles/github-dark.css"; // Or any other style you prefer
import Tooltip from "../Common/tooltip";

const AudioPlayer = ({ file }) => {
const [isPlaying, setIsPlaying] = useState(false);
const audioRef = useRef(null);

useEffect(() => {
if (audioRef.current) {
audioRef.current.load();
}
}, [file]);

return (
<div className="flex items-center justify-center w-full">
<audio
ref={audioRef}
controls
className="w-full h-10"
onPlay={() => setIsPlaying(true)}
onPause={() => setIsPlaying(false)}
>
<source src={file?.data} type="audio/mp3" />
</audio>
</div>
);
};

AudioPlayer.propTypes = {
file: PropTypes.shape({
data: PropTypes.string,
}),
};
import AudioPlayer from "../Common/audioPlayer";

function SttOutputNode({ id, data }) {
const containerRef = useRef(null);
Expand Down Expand Up @@ -124,7 +87,7 @@ function SttOutputNode({ id, data }) {
<AudioPlayer file={file} />

<div className="flex items-center justify-between w-full pt-4">
<div>
<div className="flex items-center justify-between space-x-4">
<Dropdown
label="Translate to"
name="language"
Expand All @@ -147,7 +110,7 @@ function SttOutputNode({ id, data }) {
<div className="flex items-start justify-between space-x-4">
<div>
<Tooltip
position="top-full"
position="bottom-full"
text="The transcriptions API takes as input the audio file you want to transcribe and the desired output file format for the transcription of the audio."
>
<button
Expand Down
77 changes: 38 additions & 39 deletions src/components/FlowComponents/ttsInput.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useCallback, useState, useRef, useEffect } from "react";
import { useCallback, useState, useRef } from "react";
import { storeManager, useConfigStore } from "../../store";
import { Handle, Position } from "reactflow";
import Container from "../Common/container";
import TextArea from "../Common/textarea";
import { IoMdSend } from "react-icons/io";
import Tooltip from "../Common/tooltip";
import PropTypes from "prop-types";
import { voices, languages } from "../../store/constants";
import Dropdown from "../Common/dropdown";
Expand All @@ -12,15 +12,16 @@ import TextInput from "../Common/text";
function TTSInput({ id, data }) {
const nodeRef = useRef(null);
const store = storeManager.getSelectedStore();
const { openAIInstance, voice, updateStore, language, speed } = useConfigStore(
({ openAIInstance, voice, updateStore, language, speed }) => ({
openAIInstance,
voice,
updateStore,
speed,
language,
})
);
const { openAIInstance, voice, updateStore, language, speed } =
useConfigStore(
({ openAIInstance, voice, updateStore, language, speed }) => ({
openAIInstance,
voice,
updateStore,
speed,
language,
})
);
const { onDataTextUpdate, onUserInputSend } = store(
useCallback(({ onDataTextUpdate, onUserInputSend }) => {
return {
Expand All @@ -31,25 +32,12 @@ function TTSInput({ id, data }) {
);

const [text, setText] = useState(data.text);
const [wordCount, setWordCount] = useState(0);

const onChange = (e) => {
setText(e.target.value);
onDataTextUpdate(e.target.value, id);
};

function countWords(text) {
return text.trim().split(/\s+/).length;
}

useEffect(() => {
if (!data?.text?.length) {
setWordCount(0);
return;
}
setWordCount(countWords(data.text));
}, [data.text]);

const onEnter = (e) => {
if (
e.key === "Enter" &&
Expand All @@ -59,12 +47,20 @@ function TTSInput({ id, data }) {
) {
// get the width and height via bounding client rect
const height = nodeRef.current.getBoundingClientRect().height;
onUserInputSend(id, height);
onUserInputSend(id, height, "ttsOutput", "tts");
}
};

const onSend = () => {
if (openAIInstance && text.trim().length > 0) {
// get the width and height via bounding client rect
const height = nodeRef.current.getBoundingClientRect().height;
onUserInputSend(id, height, "ttsOutput", "tts");
}
};

const placeHolderText = openAIInstance
? `The text to be spoken`
? `The text to be spoken, Enter to send, Shift + Enter new line`
: "Please add an API key";

return (
Expand Down Expand Up @@ -141,19 +137,22 @@ function TTSInput({ id, data }) {
<Handle type="source" position={Position.Bottom} />
<Handle type="target" position={Position.Top} />

<div className="flex items-center justify-center w-full">
<div className="flex w-full justify-end pt-4 items-center space-x-2">
<p className="text-gray-500 text-sm mr-2">Word Count: {wordCount}</p>

<IoMdSend
className="text-2xl text-gray-500 cursor-pointer"
onClick={() =>
onUserInputSend(
id,
nodeRef?.current?.getBoundingClientRect().width
)
}
/>
<div className="flex items-start justify-end space-x-4">
<div>
<Tooltip
position="bottom-full"
text="The transcriptions API takes as input the audio file you want to transcribe and the desired output file format for the transcription of the audio."
>
<button
disabled={!openAIInstance}
className={`border-2 border-gray-500 rounded-md whitespace-nowrap ${
!openAIInstance ? "opacity-50" : ""
}`}
onClick={onSend}
>
<span>Speak</span>
</button>
</Tooltip>
</div>
</div>
</Container>
Expand Down
114 changes: 114 additions & 0 deletions src/components/FlowComponents/ttsOutput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useState, useCallback, useRef, useEffect, useMemo } from "react";
import { storeManager, useConfigStore, useFileStore } from "../../store";
import { Handle, Position } from "reactflow";
import Container from "../Common/container";
import PropTypes from "prop-types";
import { uploadAudio } from "../../api/stt";
import Dropdown from "../Common/dropdown";
import { responseFormatSTT, languages } from "../../store/constants";
import Loading from "../Common/loading";
import Tooltip from "../Common/tooltip";
import AudioPlayer from "../Common/audioPlayer";
import "highlight.js/styles/github-dark.css";

function TTSOutputNode({ id }) {
const containerRef = useRef(null);
const [loading, setLoading] = useState(false);
const [regenerate, setRegenerate] = useState(false);
const [audio, setAudio] = useState(null);

const store = storeManager.getSelectedStore();
const { findParentNodeByType, findChildNodeByType } = store(
({ findParentNodeByType, findChildNodeByType }) => ({
findParentNodeByType,
findChildNodeByType,
})
);

const text = useMemo(() => {
const parent = findParentNodeByType(id, "tts");
if (parent) {
return parent.data.text;
}
return "";
}, [findParentNodeByType, id]);

const childNode = useMemo(() => {
const child = findChildNodeByType(id, "tts");
if (child) {
return child;
}
return null;
}, [findChildNodeByType, id]);

const { TTSModel, openAIInstance, voice, language, speed } = useConfigStore(
({ TTSModel, openAIInstance, voice, language, speed }) => ({
TTSModel,
openAIInstance,
voice,
language,
speed,
})
);

const sendText = useCallback(async () => {
setLoading(true);
if (openAIInstance && text.trim().length > 0 && !audio) {
setRegenerate(false);
const mp3 = await openAIInstance.audio.speech.create({
model: TTSModel,
input: text,
voice,
speed,
language,
});
const blob = new Blob([await mp3.arrayBuffer()], { type: "audio/mp3" });
const audioUrl = URL.createObjectURL(blob);
setAudio({ data: audioUrl });
}
setLoading(false);
}, [openAIInstance, text, audio, TTSModel, voice, speed, language]);

useEffect(() => {
// this is to stop the request if this is a reloading of the page
// as everything runs again when the page reloads and if there is a lot of audios
// it will take make a lot of requests to the api
if (childNode?.data?.text?.trim().length > 0) {
setLoading(false);
setRegenerate(true);
return;
}
sendText();
}, []);

return (
<Container
innerRef={containerRef}
title="Output"
className="w-[500px] min-h-[150px] overflow-y-scroll flex items-center justify-center overflow-hidden pb-10 relative"
id={id}
>
<div className="flex flex-col items-center justify-center w-full">
<Handle type="source" position={Position.Bottom} />
<Handle type="target" position={Position.Top} />
{loading && <Loading />}
{audio && <AudioPlayer file={audio} />}
{regenerate && (
<button className="p-2 border border-gray-300 rounded-md duration-200 ease-in-out" onClick={sendText}>
Regenerate
</button>
)}
</div>
</Container>
);
}

TTSOutputNode.propTypes = {
id: PropTypes.string,
data: PropTypes.shape({
text: PropTypes.string,
id: PropTypes.string,
}),
};

export default TTSOutputNode;
Loading

0 comments on commit 2bb3304

Please sign in to comment.