mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-14 05:42:32 +00:00
moderation job status page
This commit is contained in:
1 parent
80cbf79811
commit
6e5443244d
8 files changed
+226
-16
No files matched your search
@@ -258,6 +258,14 @@ class ApiConfig {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/user/list`;
|
||||
}
|
||||
|
||||
getTtsInferenceStats() : string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/jobs/tts_inference_queue_stats`;
|
||||
}
|
||||
|
||||
getW2lInferenceStats() : string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/moderation/jobs/w2l_inference_queue_stats`;
|
||||
}
|
||||
|
||||
private getScheme() : string {
|
||||
return this.isLocalDev ? "http" : "https";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { ApiConfig } from "../../../common/ApiConfig";
|
||||
|
||||
export interface TtsInferenceStats {
|
||||
success: boolean,
|
||||
pending_count: number,
|
||||
}
|
||||
|
||||
export enum TtsInferenceStatsError {
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
FrontendError,
|
||||
}
|
||||
|
||||
export type GetTtsInferenceStatsResponse = TtsInferenceStats | TtsInferenceStatsError;
|
||||
|
||||
export function GetTtsInferenceStatsIsOk(response: GetTtsInferenceStatsResponse): response is TtsInferenceStats {
|
||||
return response.hasOwnProperty('pending_count');
|
||||
}
|
||||
|
||||
export function GetTtsInferenceStatsIsErr(response: GetTtsInferenceStatsResponse): response is TtsInferenceStatsError {
|
||||
return !response.hasOwnProperty('pending_count');
|
||||
}
|
||||
|
||||
interface TtsInferenceStatsResponsePayload {
|
||||
success: boolean,
|
||||
error_reason?: string,
|
||||
pending_count?: number,
|
||||
}
|
||||
|
||||
|
||||
export async function GetTtsInferenceStats() : Promise<GetTtsInferenceStatsResponse>
|
||||
{
|
||||
const endpoint = new ApiConfig().getTtsInferenceStats();
|
||||
|
||||
return await fetch(endpoint, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const response : TtsInferenceStatsResponsePayload = res;
|
||||
|
||||
if (response?.success) {
|
||||
return res as TtsInferenceStats; // TODO: This is not the way.
|
||||
}
|
||||
|
||||
if (response?.success === false) {
|
||||
if (response.error_reason?.includes("authorized")) {
|
||||
return TtsInferenceStatsError.NotAuthorized;
|
||||
} else {
|
||||
return TtsInferenceStatsError.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
return TtsInferenceStatsError.FrontendError;
|
||||
})
|
||||
.catch(e => {
|
||||
return TtsInferenceStatsError.FrontendError;
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
import { ApiConfig } from "../../../common/ApiConfig";
|
||||
|
||||
//export interface GetUserListRequest {
|
||||
//}
|
||||
|
||||
export interface GetUserListSuccessResponse {
|
||||
success: boolean,
|
||||
users: Array<UserForList>
|
||||
@@ -53,7 +50,7 @@ export async function GetUserList() : Promise<GetUserListResponse>
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (!res) {
|
||||
return { success : false };
|
||||
return { success : false }; // TODO: This loses error semantics and is deprecated
|
||||
}
|
||||
|
||||
if (res && 'success' in res) {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { ApiConfig } from "../../../common/ApiConfig";
|
||||
|
||||
export interface W2lInferenceStats {
|
||||
success: boolean,
|
||||
pending_count: number,
|
||||
}
|
||||
|
||||
export enum W2lInferenceStatsError {
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
FrontendError,
|
||||
}
|
||||
|
||||
export type GetW2lInferenceStatsResponse = W2lInferenceStats | W2lInferenceStatsError;
|
||||
|
||||
export function GetW2lInferenceStatsIsOk(response: GetW2lInferenceStatsResponse): response is W2lInferenceStats {
|
||||
return response.hasOwnProperty('pending_count');
|
||||
}
|
||||
|
||||
export function GetW2lInferenceStatsIsErr(response: GetW2lInferenceStatsResponse): response is W2lInferenceStatsError {
|
||||
return !response.hasOwnProperty('pending_count');
|
||||
}
|
||||
|
||||
interface W2lInferenceStatsResponsePayload {
|
||||
success: boolean,
|
||||
error_reason?: string,
|
||||
pending_count?: number,
|
||||
}
|
||||
|
||||
|
||||
export async function GetW2lInferenceStats() : Promise<GetW2lInferenceStatsResponse>
|
||||
{
|
||||
const endpoint = new ApiConfig().getW2lInferenceStats();
|
||||
|
||||
return await fetch(endpoint, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const response : W2lInferenceStatsResponsePayload = res;
|
||||
|
||||
if (response?.success) {
|
||||
return res as W2lInferenceStats; // TODO: This is not the way.
|
||||
}
|
||||
|
||||
if (response?.success === false) {
|
||||
if (response.error_reason?.includes("authorized")) {
|
||||
return W2lInferenceStatsError.NotAuthorized;
|
||||
} else {
|
||||
return W2lInferenceStatsError.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
return W2lInferenceStatsError.FrontendError;
|
||||
})
|
||||
.catch(e => {
|
||||
return W2lInferenceStatsError.FrontendError;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import { TtsModelListItem } from '../api/tts/ListTtsModels';
|
||||
import { ProfileBanFc } from './profile/profile_ban/ProfileBanFc';
|
||||
import { ModerationUserListFc } from './moderation/moderation_user_list/ModerationUserList';
|
||||
import { LeaderboardFc } from './leaderboard/LeaderboardFc';
|
||||
import { ModerationJobStatsFc } from './moderation/moderation_job_stats/ModerationJobStatsFc';
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper,
|
||||
@@ -278,6 +279,12 @@ class NewVocodesContainer extends React.Component<Props, State> {
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/moderation/job_stats">
|
||||
<ModerationJobStatsFc
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/moderation">
|
||||
<ModerationFc
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
|
||||
@@ -9,16 +9,6 @@ interface FirehoseEventListResponsePayload {
|
||||
events: Array<FirehoseEvent>,
|
||||
}
|
||||
|
||||
/*
|
||||
event_token "EV:YR8HA4VCVYX9JMH5AMDFHTNRGSYGD"
|
||||
event_type "w2l_template_upload_completed"
|
||||
maybe_target_user_token "U:WNZCXKV1AN7XD"
|
||||
maybe_target_username "brandon"
|
||||
maybe_target_display_name "brandon"
|
||||
maybe_target_entity_token "W2L_TPL:MJZ2SMCXX9DRNZ249VK70TWJ"
|
||||
created_at "2021-05-30T06:42:39Z"
|
||||
updated_at "2021-05-30T06:42:39Z"
|
||||
*/
|
||||
interface FirehoseEvent {
|
||||
event_token: string,
|
||||
event_type: string,
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { SessionWrapper } from '../../../../session/SessionWrapper';
|
||||
import { FrontendUrlConfig } from '../../../../common/FrontendUrlConfig';
|
||||
import { BackLink } from '../../_common/BackLink';
|
||||
import { GetTtsInferenceStats, GetTtsInferenceStatsIsOk } from '../../../api/moderation/GetTtsInferenceStats';
|
||||
import { GetW2lInferenceStats, GetW2lInferenceStatsIsOk } from '../../../api/moderation/GetW2lInferenceStats';
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper,
|
||||
}
|
||||
|
||||
function ModerationJobStatsFc(props: Props) {
|
||||
const [ttsPendingJobCount, setTtsPendingJobCount] = useState<number>(-1);
|
||||
const [w2lPendingJobCount, setW2lPendingJobCount] = useState<number>(-1);
|
||||
|
||||
const getTtsStats = useCallback(async () => {
|
||||
const response = await GetTtsInferenceStats();
|
||||
if (GetTtsInferenceStatsIsOk(response)) {
|
||||
setTtsPendingJobCount(response.pending_count);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getW2lStats = useCallback(async () => {
|
||||
const response = await GetW2lInferenceStats();
|
||||
if (GetW2lInferenceStatsIsOk(response)) {
|
||||
setW2lPendingJobCount(response.pending_count);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getTtsStats();
|
||||
getW2lStats();
|
||||
}, [getTtsStats, getW2lStats]);
|
||||
|
||||
|
||||
if (ttsPendingJobCount === -1 && w2lPendingJobCount === -1) {
|
||||
return <div />
|
||||
}
|
||||
|
||||
if (!props.sessionWrapper.canBanUsers()) {
|
||||
return <h1>Unauthorized</h1>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="title is-1"> Job Stats </h1>
|
||||
|
||||
<BackLink link={FrontendUrlConfig.moderationMain()} text="Back to moderation" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table className="table is-fullwidth">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
Pending TTS Inference Jobs
|
||||
</th>
|
||||
<td>{ttsPendingJobCount}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Pending W2L Inference Jobs
|
||||
</th>
|
||||
<td>{w2lPendingJobCount}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { ModerationJobStatsFc };
|
||||
@@ -18,18 +18,25 @@ function ModerationFc(props: Props) {
|
||||
|
||||
<Link
|
||||
to="/moderation/user/list"
|
||||
className="button is-link is-large is-fullwidth is-outlined"
|
||||
className="button is-link is-large is-fullwidth is-light"
|
||||
>User List</Link>
|
||||
|
||||
<br />
|
||||
|
||||
<Link
|
||||
to="/moderation/ip_bans"
|
||||
className="button is-link is-large is-fullwidth is-outlined"
|
||||
className="button is-link is-large is-fullwidth is-light"
|
||||
>IP Ban List</Link>
|
||||
|
||||
<br />
|
||||
|
||||
<Link
|
||||
to="/moderation/job_stats"
|
||||
className="button is-link is-large is-fullwidth is-light"
|
||||
>Job Stats</Link>
|
||||
|
||||
<br />
|
||||
|
||||
<p>
|
||||
More mod controls will be added in the future: user roles, activity tracking,
|
||||
timed bans, account bans, etc.
|
||||
|
||||
Reference in new issue
Block a user