mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Merge pull request #195 from storytold/bflat-fy-profile-feed
updated profile tts results
This commit is contained in:
5 files changed
+134
-60
No files matched your search
@@ -1017,6 +1017,14 @@ styles with important tags:
|
||||
font-size: 13px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.profile-model-title {
|
||||
color: $white !important;
|
||||
|
||||
&:hover {
|
||||
color: $primary !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import React, { useState, useCallback } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faPause, faPlay } from "@fortawesome/free-solid-svg-icons";
|
||||
import Wavesurfer from "react-wavesurfer.js";
|
||||
|
||||
interface Props {
|
||||
filename: string;
|
||||
}
|
||||
|
||||
function ProfileTtsAudioPlayer(props: Props) {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [position, setPosition] = useState(0);
|
||||
|
||||
const handleTogglePlay = useCallback(() => {
|
||||
if (!isPlaying) {
|
||||
setIsPlaying(true);
|
||||
} else {
|
||||
setIsPlaying(false);
|
||||
}
|
||||
}, [isPlaying]);
|
||||
|
||||
const handleFinish = useCallback(() => {
|
||||
setIsPlaying(false);
|
||||
setPosition(0);
|
||||
return [setIsPlaying, setPosition];
|
||||
}, []);
|
||||
|
||||
let playButtonText = <FontAwesomeIcon icon={faPlay} />;
|
||||
|
||||
if (isPlaying) {
|
||||
playButtonText = (
|
||||
<>
|
||||
<FontAwesomeIcon icon={faPause} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="d-flex w-100 align-items-center gap-3 zi-1">
|
||||
<button
|
||||
className="btn btn-primary btn-session-tts-play align-items-center justify-content-center"
|
||||
onClick={() => handleTogglePlay()}
|
||||
type="button"
|
||||
>
|
||||
{playButtonText}
|
||||
</button>
|
||||
<div className="w-100 h-100 overflow-hidden">
|
||||
<Wavesurfer
|
||||
onFinish={handleFinish}
|
||||
pos={position}
|
||||
src={props.filename}
|
||||
// barWidth={2}
|
||||
// barRadius={1}
|
||||
// barGap={2}
|
||||
// barMinHeight={1}
|
||||
// barHeight={2}
|
||||
height={50}
|
||||
progressColor="#fc8481"
|
||||
waveColor="#b09e9e"
|
||||
cursorColor="#fc8481"
|
||||
playing={isPlaying}
|
||||
responsive={true}
|
||||
normalize={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { ProfileTtsAudioPlayer };
|
||||
@@ -473,7 +473,7 @@ function ProfilePage(props: Props) {
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="tab-content p-3 p-lg-4" id="myTabContent">
|
||||
<div className="tab-content" id="myTabContent">
|
||||
<div
|
||||
className="tab-pane fade show active"
|
||||
id="ttsresults"
|
||||
@@ -483,7 +483,7 @@ function ProfilePage(props: Props) {
|
||||
<ProfileTtsInferenceResultsListFc username={userData.username} />
|
||||
</div>
|
||||
<div
|
||||
className="tab-pane fade"
|
||||
className="tab-pane fade p-3 p-lg-4"
|
||||
id="w2lresults"
|
||||
role="tabpanel"
|
||||
aria-labelledby="w2lresults-tab"
|
||||
@@ -491,7 +491,7 @@ function ProfilePage(props: Props) {
|
||||
<ProfileW2lInferenceResultsListFc username={userData.username} />
|
||||
</div>
|
||||
<div
|
||||
className="tab-pane fade"
|
||||
className="tab-pane fade p-3 p-lg-4"
|
||||
id="uploadedtts"
|
||||
role="tabpanel"
|
||||
aria-labelledby="uploadedtts-tab"
|
||||
@@ -499,7 +499,7 @@ function ProfilePage(props: Props) {
|
||||
<ProfileTtsModelListFc username={userData.username} />
|
||||
</div>
|
||||
<div
|
||||
className="tab-pane fade"
|
||||
className="tab-pane fade p-3 p-lg-4"
|
||||
id="uploadedw2l"
|
||||
role="tabpanel"
|
||||
aria-labelledby="uploadedw2l-tab"
|
||||
@@ -507,7 +507,7 @@ function ProfilePage(props: Props) {
|
||||
<ProfileW2lTemplateListFc username={userData.username} />
|
||||
</div>
|
||||
<div
|
||||
className="tab-pane fade"
|
||||
className="tab-pane fade p-3 p-lg-4"
|
||||
id="badges"
|
||||
role="tabpanel"
|
||||
aria-labelledby="badges-tab"
|
||||
|
||||
+48
-52
@@ -7,12 +7,14 @@ import { Link } from "react-router-dom";
|
||||
import { formatDistance } from "date-fns";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faCirclePlay,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
import { ProfileTtsAudioPlayer } from "../../../_common/ProfileTtsAudioPlayer";
|
||||
import { TextExpander } from "../../../_common/TextExpander";
|
||||
|
||||
const Fade = require("react-reveal/Fade");
|
||||
|
||||
@@ -31,6 +33,8 @@ interface TtsInferenceResult {
|
||||
|
||||
raw_inference_text: string;
|
||||
|
||||
public_bucket_wav_audio_path: string;
|
||||
|
||||
maybe_creator_user_token?: string;
|
||||
maybe_creator_username?: string;
|
||||
maybe_creator_display_name?: string;
|
||||
@@ -106,14 +110,16 @@ function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
|
||||
ttsResults.slice(0, 10).forEach((result) => {
|
||||
const duration_seconds = result.duration_millis / 1000;
|
||||
|
||||
const audioLink = new BucketConfig().getGcsUrl(
|
||||
result.public_bucket_wav_audio_path
|
||||
);
|
||||
const wavesurfer = <ProfileTtsAudioPlayer filename={audioLink} />;
|
||||
const inferenceLink = `/tts/result/${result.tts_result_token}`;
|
||||
const modelLink = `/tts/${result.tts_model_token}`;
|
||||
|
||||
const text =
|
||||
result.raw_inference_text.length < 5
|
||||
? `Result: ${result.raw_inference_text}`
|
||||
: result.raw_inference_text;
|
||||
const text = (
|
||||
<TextExpander text={result.raw_inference_text} cutLength={250} />
|
||||
);
|
||||
|
||||
const createTime = new Date(result.created_at);
|
||||
const relativeCreateTime = formatDistance(createTime, now, {
|
||||
@@ -129,20 +135,40 @@ function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
|
||||
rows.push(
|
||||
<tr key={result.tts_result_token}>
|
||||
<td>{result.maybe_creator_result_id}</td>
|
||||
<td>{visibilityIcon}</td>
|
||||
<th className="overflow-fix">
|
||||
<Link to={inferenceLink}>
|
||||
<FontAwesomeIcon icon={faCirclePlay} className="me-2" />
|
||||
{text}
|
||||
</Link>
|
||||
|
||||
</th>
|
||||
<th>
|
||||
<Link to={modelLink}>Model: {result.tts_model_title}</Link>
|
||||
</th>
|
||||
<td>{duration_seconds} s</td>
|
||||
<td>{relativeCreateTime}</td>
|
||||
<td className="p-4 p-lg-4 overflow-fix">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
<div>
|
||||
<div className="d-flex flex-column flex-lg-row mb-2 pb-1 gap-2 align-items-lg-center">
|
||||
<h5 className="mb-0 fw-medium">
|
||||
<Link
|
||||
to={modelLink}
|
||||
className="fw-medium profile-model-title"
|
||||
>
|
||||
{result.tts_model_title}
|
||||
</Link>
|
||||
</h5>
|
||||
<span className="opacity-50 d-none d-lg-block">—</span>
|
||||
<Link className="fw-medium fs-6" to={inferenceLink}>
|
||||
View Details / Download
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<p>{text}</p>
|
||||
</div>
|
||||
|
||||
{wavesurfer}
|
||||
<div className="d-flex flex-column flex-lg-row gap-2 gap-lg-0">
|
||||
<p className="opacity-75">
|
||||
#{result.maybe_creator_result_id}
|
||||
<span className="px-2">·</span>
|
||||
{visibilityIcon}
|
||||
<span className="px-2">·</span>
|
||||
{duration_seconds} s<span className="px-2">·</span>
|
||||
{relativeCreateTime}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
@@ -157,43 +183,13 @@ function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
<div>
|
||||
<div className="table-responsive">
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<abbr title="Number">#</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Visibility">
|
||||
<FontAwesomeIcon icon={faEye} />
|
||||
</abbr>
|
||||
</th>
|
||||
<th className="table-mw">
|
||||
<abbr title="Download">Download & Play Link</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Model">Model</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Duration">Duration</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Created">Creation Time</abbr>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<Fade cascade bottom duration="200" distance="10px">
|
||||
<tbody>{rows}</tbody>
|
||||
<tbody className="">{rows}</tbody>
|
||||
</Fade>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p className="text-center py-3">
|
||||
Note: Results marked public (<FontAwesomeIcon icon={faEye} />) are
|
||||
visible by anyone visiting your profile.
|
||||
{/*You can change this by editing results. You can also set a default preference for new results.*/}
|
||||
</p>
|
||||
|
||||
<div className="justify-content-center d-flex gap-3">
|
||||
<div className="justify-content-center d-flex gap-3 p-3 p-lg-4">
|
||||
<button
|
||||
className="btn btn-secondary w-100"
|
||||
onClick={() => getPage(previousCursor, true)}
|
||||
|
||||
@@ -433,7 +433,7 @@ function TtsResultViewPage(props: Props) {
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div className="container py-5">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className="display-5 fw-bold mb-3" variants={item}>
|
||||
<motion.h1 className="display-5 fw-bold mb-2" variants={item}>
|
||||
{headingTitle}
|
||||
</motion.h1>
|
||||
{/* Rate Result Buttons */}
|
||||
@@ -477,10 +477,10 @@ function TtsResultViewPage(props: Props) {
|
||||
</div>
|
||||
</div>*/}
|
||||
|
||||
<motion.p className="mb-3 result-text mt-4 pt-2">
|
||||
<motion.p className="mb-3 result-text pt-2">
|
||||
<TextExpander
|
||||
text={ttsInferenceResult.raw_inference_text}
|
||||
cutLength={250}
|
||||
cutLength={240}
|
||||
/>
|
||||
</motion.p>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user