Added correction visualizers for the Speaking transcript correction
This commit is contained in:
@@ -4,7 +4,7 @@ import {BsArrowRepeat} from "react-icons/bs";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
color?: "rose" | "purple" | "red" | "green" | "gray";
|
color?: "rose" | "purple" | "red" | "green" | "gray" | "pink";
|
||||||
variant?: "outline" | "solid";
|
variant?: "outline" | "solid";
|
||||||
className?: string;
|
className?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -49,6 +49,11 @@ export default function Button({
|
|||||||
outline:
|
outline:
|
||||||
"bg-transparent text-mti-rose-light border border-mti-rose-light hover:bg-mti-rose-light disabled:text-mti-rose disabled:bg-mti-rose-ultralight disabled:border-none selection:bg-mti-rose-dark hover:text-white selection:text-white",
|
"bg-transparent text-mti-rose-light border border-mti-rose-light hover:bg-mti-rose-light disabled:text-mti-rose disabled:bg-mti-rose-ultralight disabled:border-none selection:bg-mti-rose-dark hover:text-white selection:text-white",
|
||||||
},
|
},
|
||||||
|
pink: {
|
||||||
|
solid: "bg-ielts-speaking text-white border border-ielts-speaking hover:bg-ielts-speaking disabled:text-ielts-speaking disabled:bg-ielts-speaking-transparent selection:bg-ielts-speaking",
|
||||||
|
outline:
|
||||||
|
"bg-transparent text-ielts-speaking border border-ielts-speaking hover:bg-ielts-speaking disabled:text-ielts-speaking disabled:bg-ielts-speaking-transparent disabled:border-none selection:bg-ielts-speaking hover:text-white selection:text-white",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import axios from "axios";
|
|||||||
import {speakingReverseMarking} from "@/utils/score";
|
import {speakingReverseMarking} from "@/utils/score";
|
||||||
import {Tab} from "@headlessui/react";
|
import {Tab} from "@headlessui/react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import Modal from "../Modal";
|
||||||
|
import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
|
||||||
|
|
||||||
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@ export default function InteractiveSpeaking({
|
|||||||
onBack,
|
onBack,
|
||||||
}: InteractiveSpeakingExercise & CommonProps) {
|
}: InteractiveSpeakingExercise & CommonProps) {
|
||||||
const [solutionsURL, setSolutionsURL] = useState<string[]>([]);
|
const [solutionsURL, setSolutionsURL] = useState<string[]>([]);
|
||||||
|
const [diffNumber, setDiffNumber] = useState<0 | 1 | 2 | 3>(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userSolutions && userSolutions.length > 0) {
|
if (userSolutions && userSolutions.length > 0) {
|
||||||
@@ -42,6 +45,44 @@ export default function InteractiveSpeaking({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Modal title={`Correction (Prompt ${diffNumber})`} isOpen={diffNumber !== 0} onClose={() => setDiffNumber(0)}>
|
||||||
|
<>
|
||||||
|
{userSolutions &&
|
||||||
|
userSolutions.length > 0 &&
|
||||||
|
diffNumber !== 0 &&
|
||||||
|
userSolutions[0].evaluation &&
|
||||||
|
userSolutions[0].evaluation[`transcript_${diffNumber}`] &&
|
||||||
|
userSolutions[0].evaluation[`fixed_text_${diffNumber}`] && (
|
||||||
|
<div className="w-full h-full rounded-xl overflow-hidden flex flex-col mt-4">
|
||||||
|
<div className="w-full grid grid-cols-2 bg-neutral-100">
|
||||||
|
<span className="p-3 font-medium text-lg border-r border-r-neutral-200">Transcript</span>
|
||||||
|
<span className="p-3 font-medium text-lg border-l border-l-neutral-200">Recommended Improvements</span>
|
||||||
|
</div>
|
||||||
|
<ReactDiffViewer
|
||||||
|
styles={{
|
||||||
|
contentText: {
|
||||||
|
fontFamily: '"Open Sans", system-ui, -apple-system, "Helvetica Neue", sans-serif',
|
||||||
|
padding: "32px 28px",
|
||||||
|
},
|
||||||
|
marker: {display: "none"},
|
||||||
|
diffRemoved: {padding: "32px 28px"},
|
||||||
|
diffAdded: {padding: "32px 28px"},
|
||||||
|
|
||||||
|
wordRemoved: {padding: "0px", display: "initial"},
|
||||||
|
wordAdded: {padding: "0px", display: "initial"},
|
||||||
|
wordDiff: {padding: "0px", display: "initial"},
|
||||||
|
}}
|
||||||
|
oldValue={userSolutions[0].evaluation[`transcript_${diffNumber}`]?.replaceAll("\\n", "\n")}
|
||||||
|
newValue={userSolutions[0].evaluation[`fixed_text_${diffNumber}`]?.replaceAll("\\n", "\n")}
|
||||||
|
splitView
|
||||||
|
hideLineNumbers
|
||||||
|
showDiffOnly={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div className="flex flex-col h-full w-full gap-8 mb-20">
|
<div className="flex flex-col h-full w-full gap-8 mb-20">
|
||||||
<div className="flex flex-col w-full gap-8 bg-mti-gray-smoke rounded-xl py-8 pb-12 px-16">
|
<div className="flex flex-col w-full gap-8 bg-mti-gray-smoke rounded-xl py-8 pb-12 px-16">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
@@ -67,10 +108,23 @@ export default function InteractiveSpeaking({
|
|||||||
{solutionsURL.map((x, index) => (
|
{solutionsURL.map((x, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="w-full p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex-col gap-8 items-center">
|
className="w-full p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex flex-col gap-4">
|
||||||
<div className="flex gap-8 items-center justify-center py-8">
|
<div className="flex gap-8 items-center justify-center py-8">
|
||||||
<Waveform audio={x} waveColor="#FCDDEC" progressColor="#EF5DA8" />
|
<Waveform audio={x} waveColor="#FCDDEC" progressColor="#EF5DA8" />
|
||||||
</div>
|
</div>
|
||||||
|
{userSolutions &&
|
||||||
|
userSolutions.length > 0 &&
|
||||||
|
userSolutions[0].evaluation &&
|
||||||
|
userSolutions[0].evaluation[`transcript_${(index + 1) as 1 | 2 | 3}`] &&
|
||||||
|
userSolutions[0].evaluation[`fixed_text_${(index + 1) as 1 | 2 | 3}`] && (
|
||||||
|
<Button
|
||||||
|
className="w-full max-w-[180px] !py-2 self-center"
|
||||||
|
color="pink"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setDiffNumber((index + 1) as 1 | 2 | 3)}>
|
||||||
|
View Correction
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ import axios from "axios";
|
|||||||
import {speakingReverseMarking} from "@/utils/score";
|
import {speakingReverseMarking} from "@/utils/score";
|
||||||
import {Tab} from "@headlessui/react";
|
import {Tab} from "@headlessui/react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import Modal from "../Modal";
|
||||||
|
import {BsQuestionCircleFill} from "react-icons/bs";
|
||||||
|
import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
|
||||||
|
|
||||||
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
||||||
|
|
||||||
export default function Speaking({id, type, title, video_url, text, prompts, userSolutions, onNext, onBack}: SpeakingExercise & CommonProps) {
|
export default function Speaking({id, type, title, video_url, text, prompts, userSolutions, onNext, onBack}: SpeakingExercise & CommonProps) {
|
||||||
const [solutionURL, setSolutionURL] = useState<string>();
|
const [solutionURL, setSolutionURL] = useState<string>();
|
||||||
|
const [showDiff, setShowDiff] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userSolutions && userSolutions.length > 0) {
|
if (userSolutions && userSolutions.length > 0) {
|
||||||
@@ -25,8 +29,48 @@ export default function Speaking({id, type, title, video_url, text, prompts, use
|
|||||||
}
|
}
|
||||||
}, [userSolutions]);
|
}, [userSolutions]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(userSolutions);
|
||||||
|
}, [userSolutions]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Modal title="Correction" isOpen={showDiff} onClose={() => setShowDiff(false)}>
|
||||||
|
<>
|
||||||
|
{userSolutions &&
|
||||||
|
userSolutions.length > 0 &&
|
||||||
|
userSolutions[0].evaluation?.transcript_1 &&
|
||||||
|
userSolutions[0].evaluation?.fixed_text_1 && (
|
||||||
|
<div className="w-full h-full rounded-xl overflow-hidden flex flex-col mt-4">
|
||||||
|
<div className="w-full grid grid-cols-2 bg-neutral-100">
|
||||||
|
<span className="p-3 font-medium text-lg border-r border-r-neutral-200">Transcript</span>
|
||||||
|
<span className="p-3 font-medium text-lg border-l border-l-neutral-200">Recommended Improvements</span>
|
||||||
|
</div>
|
||||||
|
<ReactDiffViewer
|
||||||
|
styles={{
|
||||||
|
contentText: {
|
||||||
|
fontFamily: '"Open Sans", system-ui, -apple-system, "Helvetica Neue", sans-serif',
|
||||||
|
padding: "32px 28px",
|
||||||
|
},
|
||||||
|
marker: {display: "none"},
|
||||||
|
diffRemoved: {padding: "32px 28px"},
|
||||||
|
diffAdded: {padding: "32px 28px"},
|
||||||
|
|
||||||
|
wordRemoved: {padding: "0px", display: "initial"},
|
||||||
|
wordAdded: {padding: "0px", display: "initial"},
|
||||||
|
wordDiff: {padding: "0px", display: "initial"},
|
||||||
|
}}
|
||||||
|
oldValue={userSolutions[0].evaluation.transcript_1.replaceAll("\\n", "\n")}
|
||||||
|
newValue={userSolutions[0].evaluation.fixed_text_1.replaceAll("\\n", "\n")}
|
||||||
|
splitView
|
||||||
|
hideLineNumbers
|
||||||
|
showDiffOnly={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div className="flex flex-col h-full w-full gap-8 mb-20">
|
<div className="flex flex-col h-full w-full gap-8 mb-20">
|
||||||
<div className="flex flex-col w-full gap-2 bg-mti-gray-smoke rounded-xl py-8 px-16">
|
<div className="flex flex-col w-full gap-2 bg-mti-gray-smoke rounded-xl py-8 px-16">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
@@ -65,10 +109,19 @@ export default function Speaking({id, type, title, video_url, text, prompts, use
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full h-full flex flex-col gap-8">
|
<div className="w-full h-full flex flex-col gap-8 relative">
|
||||||
<div className="w-full p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex-col gap-8 items-center">
|
<div className="w-full p-4 px-8 bg-transparent border-2 border-mti-gray-platinum rounded-2xl flex-col gap-8 items-center relative">
|
||||||
<div className="flex gap-8 items-center justify-center py-8">
|
<div className="flex gap-8 items-center justify-center py-8">
|
||||||
{solutionURL && <Waveform audio={solutionURL} waveColor="#FCDDEC" progressColor="#EF5DA8" />}
|
{solutionURL && <Waveform audio={solutionURL} waveColor="#FCDDEC" progressColor="#EF5DA8" />}
|
||||||
|
|
||||||
|
{userSolutions &&
|
||||||
|
userSolutions.length > 0 &&
|
||||||
|
userSolutions[0].evaluation?.transcript_1 &&
|
||||||
|
userSolutions[0].evaluation?.fixed_text_1 && (
|
||||||
|
<Button className="w-full max-w-[180px] !py-2" color="pink" variant="outline" onClick={() => setShowDiff(true)}>
|
||||||
|
View Correction
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{userSolutions && userSolutions.length > 0 && userSolutions[0].evaluation && typeof userSolutions[0].evaluation !== "string" && (
|
{userSolutions && userSolutions.length > 0 && userSolutions[0].evaluation && typeof userSolutions[0].evaluation !== "string" && (
|
||||||
|
|||||||
@@ -103,13 +103,24 @@ export interface Evaluation {
|
|||||||
|
|
||||||
interface InteractiveSpeakingEvaluation extends Evaluation {
|
interface InteractiveSpeakingEvaluation extends Evaluation {
|
||||||
perfect_answer_1?: string;
|
perfect_answer_1?: string;
|
||||||
|
transcript_1?: string;
|
||||||
|
fixed_text_1?: string;
|
||||||
perfect_answer_2?: string;
|
perfect_answer_2?: string;
|
||||||
|
transcript_2?: string;
|
||||||
|
fixed_text_2?: string;
|
||||||
perfect_answer_3?: string;
|
perfect_answer_3?: string;
|
||||||
|
transcript_3?: string;
|
||||||
|
fixed_text_3?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeakingEvaluation extends CommonEvaluation {
|
||||||
|
perfect_answer_1?: string;
|
||||||
|
transcript_1?: string;
|
||||||
|
fixed_text_1?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CommonEvaluation extends Evaluation {
|
interface CommonEvaluation extends Evaluation {
|
||||||
perfect_answer?: string;
|
perfect_answer?: string;
|
||||||
perfect_answer_1?: string;
|
|
||||||
fixed_text?: string;
|
fixed_text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +152,7 @@ export interface SpeakingExercise {
|
|||||||
userSolutions: {
|
userSolutions: {
|
||||||
id: string;
|
id: string;
|
||||||
solution: string;
|
solution: string;
|
||||||
evaluation?: CommonEvaluation;
|
evaluation?: SpeakingEvaluation;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user