mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Edit TTS models
This commit is contained in:
1 parent
07c3e0be61
commit
139d1f1c17
6 files changed
+238
-162
No files matched your search
@@ -64,8 +64,12 @@ class ApiConfig {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/tts/model/${modelToken}/delete`;
|
||||
}
|
||||
|
||||
getTtsModelUseCount(modelSlug: string) : string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/tts/model/${modelSlug}/count`;
|
||||
editTtsModel(modelToken: string) : string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/tts/model/${modelToken}/edit`;
|
||||
}
|
||||
|
||||
getTtsModelUseCount(modelToken: string) : string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/tts/model/${modelToken}/count`;
|
||||
}
|
||||
|
||||
viewTtsInferenceResult(token: string) : string {
|
||||
|
||||
@@ -51,6 +51,10 @@ export class SessionWrapper {
|
||||
return this.canEditOtherUsersProfiles();
|
||||
}
|
||||
|
||||
public canEditTtsModelByUserToken(userToken: MaybeString) : boolean {
|
||||
return this.canEditOtherUsersTtsModels() || this.verifyUserTokenMatch(userToken);
|
||||
}
|
||||
|
||||
public canDeleteTtsModelByUserToken(userToken: MaybeString) : boolean {
|
||||
return this.canDeleteOtherUsersTtsModels() || this.verifyUserTokenMatch(userToken);
|
||||
}
|
||||
@@ -95,6 +99,10 @@ export class SessionWrapper {
|
||||
return this.sessionStateResponse?.user?.can_edit_other_users_profiles || false;
|
||||
}
|
||||
|
||||
public canEditOtherUsersTtsModels() : boolean {
|
||||
return this.sessionStateResponse?.user?.can_edit_other_users_tts_models || false;
|
||||
}
|
||||
|
||||
public canDeleteOtherUsersTtsModels() : boolean {
|
||||
return this.sessionStateResponse?.user?.can_delete_other_users_tts_models || false;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import { W2lTemplateViewFc } from './w2l/w2l_template_view/W2lTemplateViewFc';
|
||||
import { ModerationViewIpBanFc } from './moderation/moderation_view_ip_ban/ModerationViewIpBanFc';
|
||||
import { AboutFc } from './about/about_page/AboutFc';
|
||||
import { TermsFc } from './about/terms_page/TermsFc';
|
||||
import { TtsModelEditFc } from './tts/tts_model_edit/TtsModelEditFc';
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper,
|
||||
@@ -114,6 +115,14 @@ class NewVocodesContainer extends React.Component<Props, State> {
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/tts/:token/edit">
|
||||
<TtsModelEditFc
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
enqueueTtsJob={this.props.enqueueTtsJob}
|
||||
ttsInferenceJobs={this.props.ttsInferenceJobs}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/tts/:token">
|
||||
<TtsModelViewFc
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
//import axios from 'axios';
|
||||
import { ApiConfig } from '../../../common/ApiConfig';
|
||||
import { SessionWrapper } from '../../../session/SessionWrapper';
|
||||
import { TtsInferenceJob } from '../../../App';
|
||||
import { useParams, Link, useHistory } from 'react-router-dom';
|
||||
|
||||
interface TtsModelViewResponsePayload {
|
||||
success: boolean,
|
||||
model: TtsModel,
|
||||
}
|
||||
|
||||
interface TtsModel {
|
||||
model_token: string,
|
||||
title: string,
|
||||
tts_model_type: string,
|
||||
text_preprocessing_algorithm: string,
|
||||
creator_user_token: string,
|
||||
creator_username: string,
|
||||
creator_display_name: string,
|
||||
description_markdown: string,
|
||||
description_rendered_html: string,
|
||||
updatable_slug: string,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
maybe_moderator_fields: TtsModelModeratorFields | null | undefined,
|
||||
}
|
||||
|
||||
interface TtsModelModeratorFields {
|
||||
creator_ip_address_creation: string,
|
||||
creator_ip_address_last_update: string,
|
||||
mod_deleted_at: string | undefined | null,
|
||||
user_deleted_at: string | undefined | null,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper,
|
||||
enqueueTtsJob: (jobToken: string) => void,
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>,
|
||||
}
|
||||
|
||||
function TtsModelEditFc(props: Props) {
|
||||
let { token } = useParams() as { token : string };
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
const [ttsModel, setTtsModel] = useState<TtsModel|undefined>(undefined);
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [descriptionMarkdown, setDescriptionMarkdown] = useState<string>("");
|
||||
|
||||
const getModel = useCallback((token) => {
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.viewTtsModel(token);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const modelsResponse : TtsModelViewResponsePayload = res;
|
||||
if (!modelsResponse.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTitle(modelsResponse.model.title || "")
|
||||
setDescriptionMarkdown(modelsResponse.model.description_markdown || "")
|
||||
setTtsModel(modelsResponse.model);
|
||||
})
|
||||
.catch(e => {});
|
||||
}, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getModel(token);
|
||||
}, [token, getModel]);
|
||||
|
||||
const handleTitleChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
ev.preventDefault();
|
||||
const textValue = (ev.target as HTMLInputElement).value;
|
||||
setTitle(textValue);
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleDescriptionMarkdownChange = (ev: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
ev.preventDefault();
|
||||
const textValue = (ev.target as HTMLTextAreaElement).value;
|
||||
setDescriptionMarkdown(textValue);
|
||||
return false;
|
||||
};
|
||||
|
||||
const modelLink = `/tts/${token}`;
|
||||
|
||||
const handleFormSubmit = (ev: React.FormEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
|
||||
if (ttsModel === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (title.trim() === "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const modelToken = ttsModel!.model_token;
|
||||
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.editTtsModel(modelToken);
|
||||
|
||||
const request = {
|
||||
title: title,
|
||||
description_markdown: descriptionMarkdown,
|
||||
}
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res === undefined ||
|
||||
!res.success) {
|
||||
return; // Endpoint error?
|
||||
}
|
||||
|
||||
history.push(modelLink);
|
||||
})
|
||||
.catch(e => {
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
let isDisabled = ttsModel === undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="title is-1"> Edit Model </h1>
|
||||
|
||||
<Link to={modelLink}>Back to model</Link>
|
||||
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
|
||||
<div className="field">
|
||||
<label className="label">Model Title</label>
|
||||
<div className="control has-icons-left has-icons-right">
|
||||
<input
|
||||
onChange={handleTitleChange}
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="Model Title"
|
||||
value={title}
|
||||
/>
|
||||
<span className="icon is-small is-left">
|
||||
<i className="fas fa-envelope"></i>
|
||||
</span>
|
||||
<span className="icon is-small is-right">
|
||||
<i className="fas fa-exclamation-triangle"></i>
|
||||
</span>
|
||||
</div>
|
||||
{/*<p className="help">{invalidReason}</p>*/}
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="label">Description (supports Markdown)</label>
|
||||
<div className="control">
|
||||
<textarea
|
||||
onChange={handleDescriptionMarkdownChange}
|
||||
className="textarea is-large"
|
||||
placeholder="Model description (ie. source of data, training duration, etc)"
|
||||
value={descriptionMarkdown}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<button className="button is-link is-large is-fullwidth">Update</button>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { TtsModelEditFc };
|
||||
@@ -1,160 +0,0 @@
|
||||
import React from 'react';
|
||||
import { ApiConfig } from '../../../common/ApiConfig';
|
||||
import { Mode } from '../../../AppMode';
|
||||
import { SessionWrapper } from '../../../session/SessionWrapper';
|
||||
|
||||
enum FieldTriState {
|
||||
EMPTY_FALSE,
|
||||
FALSE,
|
||||
TRUE,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper,
|
||||
querySessionCallback : () => void,
|
||||
switchModeCallback?: (mode: Mode) => void,
|
||||
}
|
||||
|
||||
interface State {
|
||||
usernameOrEmail: string,
|
||||
usernameOrEmailValid: FieldTriState,
|
||||
usernameOrEmailInvalidReason: string,
|
||||
|
||||
password: string,
|
||||
passwordValid: FieldTriState,
|
||||
passwordInvalidReason: string,
|
||||
}
|
||||
|
||||
class TtsModelViewComponent extends React.Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
usernameOrEmail: "",
|
||||
usernameOrEmailValid: FieldTriState.EMPTY_FALSE,
|
||||
usernameOrEmailInvalidReason: "",
|
||||
|
||||
password: "",
|
||||
passwordValid: FieldTriState.EMPTY_FALSE,
|
||||
passwordInvalidReason: "",
|
||||
};
|
||||
}
|
||||
|
||||
handleUsernameOrEmailChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
ev.preventDefault();
|
||||
|
||||
const usernameOrEmail = (ev.target as HTMLInputElement).value;
|
||||
|
||||
this.setState({
|
||||
usernameOrEmail: usernameOrEmail,
|
||||
})
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
handlePasswordChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
ev.preventDefault();
|
||||
|
||||
const password = (ev.target as HTMLInputElement).value;
|
||||
|
||||
this.setState({
|
||||
password: password,
|
||||
})
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
handleFormSubmit = (ev: React.FormEvent<HTMLFormElement>) : boolean => {
|
||||
ev.preventDefault();
|
||||
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.login();
|
||||
|
||||
const request = {
|
||||
username_or_email: this.state.usernameOrEmail,
|
||||
password: this.state.password,
|
||||
}
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
console.log('login response', res)
|
||||
if (res.success) {
|
||||
console.log('querying new session');
|
||||
this.props.querySessionCallback();
|
||||
|
||||
if (this.props.switchModeCallback !== undefined) {
|
||||
this.props.switchModeCallback(Mode.SPEAK_MODE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
//this.props.onSpeakErrorCallback();
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public render() {
|
||||
if (this.props.sessionWrapper.isLoggedIn()) {
|
||||
return <div>Invalid view for logged in users.</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="title is-1"> Login </h1>
|
||||
|
||||
<p></p>
|
||||
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<div className="field">
|
||||
<label className="label">Username or Email</label>
|
||||
<div className="control has-icons-left has-icons-right">
|
||||
<input className="input" type="text" placeholder="Username or Email" value={this.state.usernameOrEmail} onChange={this.handleUsernameOrEmailChange} />
|
||||
<span className="icon is-small is-left">
|
||||
<i className="fas fa-user"></i>
|
||||
</span>
|
||||
<span className="icon is-small is-right">
|
||||
<i className="fas fa-check"></i>
|
||||
</span>
|
||||
</div>
|
||||
{/*<p className="help"></p>*/}
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="label">Password</label>
|
||||
<div className="control has-icons-left has-icons-right">
|
||||
<input className="input" type="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} />
|
||||
<span className="icon is-small is-left">
|
||||
<i className="fas fa-envelope"></i>
|
||||
</span>
|
||||
<span className="icon is-small is-right">
|
||||
<i className="fas fa-exclamation-triangle"></i>
|
||||
</span>
|
||||
</div>
|
||||
{/*<p className="help"></p>*/}
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<button className="button is-link is-large">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export { TtsModelViewComponent };
|
||||
@@ -27,6 +27,8 @@ interface TtsModel {
|
||||
creator_user_token: string,
|
||||
creator_username: string,
|
||||
creator_display_name: string,
|
||||
description_markdown: string,
|
||||
description_rendered_html: string,
|
||||
updatable_slug: string,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
@@ -198,9 +200,24 @@ function TtsModelViewFc(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
let editModelButton = <span />
|
||||
|
||||
if (!!ttsModel?.creator_user_token) {
|
||||
if (props.sessionWrapper.canEditTtsModelByUserToken(ttsModel.creator_user_token)) {
|
||||
let editLinkUrl = `/tts/${token}/edit`;
|
||||
editModelButton = (
|
||||
<Link
|
||||
className={"button is-medium is-info"}
|
||||
to={editLinkUrl}>Edit</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="title is-1"> {title} </h1>
|
||||
|
||||
{editModelButton}
|
||||
|
||||
<table className="table">
|
||||
<thead>
|
||||
|
||||
Reference in new issue
Block a user