mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
retrieving list of voices from server
This commit is contained in:
1 parent
a0d9637719
commit
59b03fc0b1
3 files changed
+131
-39
No files matched your search
@@ -5,10 +5,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
|
||||
interface ListDropdownProps {
|
||||
list: {[key: string] : string}[];
|
||||
listDisplayKey?: string;
|
||||
onSelect: (val:string)=>void
|
||||
}
|
||||
export const ListSearchDropdown = ({
|
||||
list, onSelect
|
||||
list, listDisplayKey, onSelect
|
||||
}:ListDropdownProps) => {
|
||||
const [selected, setSelected] = useState(list[0])
|
||||
const [query, setQuery] = useState('')
|
||||
@@ -26,13 +27,17 @@ export const ListSearchDropdown = ({
|
||||
useEffect(()=>{
|
||||
onSelect(Object.values(selected)[0]);
|
||||
}, [selected]);
|
||||
|
||||
return (
|
||||
<Combobox value={selected} onChange={setSelected}>
|
||||
<div className="relative mt-1">
|
||||
<div className="relative w-full cursor-default overflow-hidden rounded-md text-left shadow-md sm:text-sm">
|
||||
<div className="relative w-full cursor-default rounded-md text-left shadow-md sm:text-sm">
|
||||
<Combobox.Input
|
||||
className="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 bg-brand-secondary text-white outline-none outline-offset-0 transition-all duration-150 ease-in-out focus:outline-brand-primary"
|
||||
displayValue={(item: {[key: string] : string}) => Object.values(item)[0]}
|
||||
className="w-full border-none rounded-md py-2 pl-3 pr-10 text-sm leading-5 bg-brand-secondary text-white outline-none outline-offset-0 transition-all duration-150 ease-in-out focus:outline-brand-primary"
|
||||
displayValue={(item: {[key: string] : string}) => {
|
||||
if(listDisplayKey) return item[listDisplayKey];
|
||||
else return Object.values(item)[0]
|
||||
}}
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
/>
|
||||
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
@@ -52,38 +57,43 @@ export const ListSearchDropdown = ({
|
||||
Nothing found.
|
||||
</div>
|
||||
) : (
|
||||
filteredList.map((item, itemIdx) => (
|
||||
<Combobox.Option
|
||||
key={itemIdx}
|
||||
className={({ active }) =>
|
||||
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${
|
||||
active ? 'text-white' : 'text-gray-400'
|
||||
}`
|
||||
}
|
||||
value={item}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? 'font-medium' : 'font-normal'
|
||||
}`}
|
||||
>
|
||||
{Object.values(item)[0]}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span
|
||||
className={`absolute inset-y-0 left-0 flex items-center pl-3 ${
|
||||
active ? 'text-white' : 'text-teal-600'
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCheck} aria-hidden="true"/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Combobox.Option>
|
||||
))
|
||||
filteredList.map((item, itemIdx) => {
|
||||
if(itemIdx <= 10)
|
||||
return (
|
||||
<Combobox.Option
|
||||
key={itemIdx}
|
||||
className={({ active }) =>
|
||||
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${
|
||||
active ? 'text-white' : 'text-gray-400'
|
||||
}`
|
||||
}
|
||||
value={item}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? 'font-medium' : 'font-normal'
|
||||
}`}
|
||||
>
|
||||
{!listDisplayKey && Object.values(item)[0]}
|
||||
{listDisplayKey && item[listDisplayKey]}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span
|
||||
className={`absolute inset-y-0 left-0 flex items-center pl-3 ${
|
||||
active ? 'text-white' : 'text-teal-600'
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCheck} aria-hidden="true"/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Combobox.Option>
|
||||
);
|
||||
return null;
|
||||
})
|
||||
)}
|
||||
</Combobox.Options>
|
||||
</Transition>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { faVolume, faShuffle, faPlay } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { AppUiContext } from "../../contexts/AppUiContext";
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
TransitionDialogue,
|
||||
Textarea
|
||||
} from "~/components";
|
||||
import { ListTtsModels, TtsModelListItem } from "./utilities";
|
||||
|
||||
const testdata = [
|
||||
{ name: 'Wade Cooper' },
|
||||
@@ -33,6 +34,28 @@ export const DialogueTTS = ()=>{
|
||||
hasAudio:false
|
||||
});
|
||||
|
||||
const [ttsModels, setTtsModels] = useState<Array<TtsModelListItem>>([]);
|
||||
|
||||
|
||||
const listModels = useCallback(async () => {
|
||||
const ttsModelsLoaded = ttsModels.length > 0;
|
||||
if (ttsModelsLoaded) {
|
||||
return; // Already queried.
|
||||
}
|
||||
const models = await ListTtsModels();
|
||||
if (models) {
|
||||
setTtsModels(models);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
listModels();
|
||||
}, [listModels]);
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log(ttsModels);
|
||||
// }, [ttsModels]);
|
||||
|
||||
const handleClose = ()=> {
|
||||
dispatchAppUiState({
|
||||
type: APPUI_ACTION_TYPES.CLOSE_DIALOGUE_TTS
|
||||
@@ -69,8 +92,12 @@ export const DialogueTTS = ()=>{
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1">Select a Voice</Label>
|
||||
<ListSearchDropdown list={testdata} onSelect={handleOnSelect}/>
|
||||
|
||||
{/* <ListSearchDropdown list={testdata} onSelect={handleOnSelect}/> */}
|
||||
<ListSearchDropdown
|
||||
list={ttsModels}
|
||||
listDisplayKey="title"
|
||||
onSelect={handleOnSelect}
|
||||
/>
|
||||
<div className="flex w-full justify-between mt-4">
|
||||
<Label>What would you like to say?</Label>
|
||||
<div className="flex gap-2 items-center">
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// https://api.fakeyou.com/tts/list
|
||||
|
||||
interface TtsModelListResponsePayload {
|
||||
success: boolean,
|
||||
models: Array<TtsModelListItem>,
|
||||
}
|
||||
|
||||
export interface UserRatings {
|
||||
positive_count: number,
|
||||
negative_count: number,
|
||||
// Total count does not take into account "neutral" ratings.
|
||||
total_count: number,
|
||||
}
|
||||
|
||||
export interface TtsModelListItem {
|
||||
model_token: string,
|
||||
tts_model_type: string,
|
||||
creator_user_token: string,
|
||||
creator_username: string,
|
||||
creator_display_name: string,
|
||||
creator_gravatar_hash: string,
|
||||
ietf_language_tag: string,
|
||||
ietf_primary_language_subtag: string,
|
||||
updatable_slug: string,
|
||||
title: string,
|
||||
is_front_page_featured: boolean,
|
||||
is_twitch_featured: boolean,
|
||||
user_ratings: UserRatings,
|
||||
category_tokens: string[],
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
}
|
||||
|
||||
export async function ListTtsModels() : Promise<Array<TtsModelListItem>| undefined> {
|
||||
const endpoint = 'https://api.fakeyou.com/tts/list';
|
||||
|
||||
return await fetch(endpoint, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const response : TtsModelListResponsePayload = res;
|
||||
if (!response.success) {
|
||||
return;
|
||||
}
|
||||
return response?.models;
|
||||
})
|
||||
.catch(e => {
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user