Skip to content

Commit 440359f

Browse files
committed
sample
1 parent 5bdf9d8 commit 440359f

8 files changed

Lines changed: 677 additions & 84 deletions

File tree

app/(taxonomy)/graph/page.jsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"use client"
2+
3+
import React, { useEffect, useState } from "react"
4+
import TTSFlow from "./ttsflow.jsx"
5+
import TTSFlowChart from "./ttsflow.jsx"
6+
7+
export const nodes = [
8+
{ id: "Text", group: 1 },
9+
{ id: "Linguistic Features", group: 1 },
10+
{ id: "Acoustic Features", group: 2 },
11+
{ id: "Mel-Spectrogram", group: 2 },
12+
{ id: "Waveform", group: 3 },
13+
{ id: "Character/Phoneme", group: 1 },
14+
{ id: "Acoustic Model", group: 2 },
15+
{ id: "Vocoder", group: 3 },
16+
{ id: "Fully End-to-End", group: 4 },
17+
]
18+
19+
export const links = [
20+
{ source: "Text", target: "Linguistic Features" },
21+
{ source: "Linguistic Features", target: "Acoustic Model" },
22+
{ source: "Acoustic Model", target: "Mel-Spectrogram" },
23+
{ source: "Mel-Spectrogram", target: "Vocoder" },
24+
{ source: "Vocoder", target: "Waveform" },
25+
{ source: "Character/Phoneme", target: "Acoustic Model" },
26+
{ source: "Fully End-to-End", target: "Waveform" },
27+
]
28+
29+
export default function Page() {
30+
// const [data, setData] = useState([])
31+
32+
// useEffect(() => {
33+
// fetch("/data/flare-2.json")
34+
// .then((res) => res.json())
35+
// .then((data) => setData(data))
36+
// }, [])
37+
38+
return (
39+
<div className="w-full min-h-[1000px] mx-auto px-4 sm:px-6 lg:px-8">
40+
{/* <h1 className="mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">Evaluation Result</h1> */}
41+
<TTSFlowChart />
42+
</div>
43+
)
44+
}

app/(taxonomy)/graph/ttsflow.jsx

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
import React, { useEffect, useRef, useState } from 'react';
2+
import * as d3 from 'd3';
3+
4+
const TTSFlowChart = () => {
5+
const svgRef = useRef();
6+
const [selectedPipeline, setSelectedPipeline] = useState(0);
7+
8+
const pipelines = [
9+
{
10+
id: 0,
11+
title: "Traditional TTS Pipeline",
12+
description: "Multi-stage pipeline with separate text analysis, acoustic model, and vocoder",
13+
stages: [
14+
{ id: "text", label: "Text", type: "input" },
15+
{ id: "analysis", label: "Text Analysis", type: "process" },
16+
{ id: "linguistic", label: "Linguistic Features", type: "intermediate" },
17+
{ id: "acoustic", label: "Acoustic Model", type: "process" },
18+
{ id: "features", label: "Acoustic Features", type: "intermediate" },
19+
{ id: "vocoder1", label: "Vocoder", type: "process" },
20+
{ id: "waveform1", label: "Waveform", type: "output" }
21+
]
22+
},
23+
{
24+
id: 1,
25+
title: "Mel-Spectrogram Based TTS",
26+
description: "Uses mel-spectrogram as intermediate representation",
27+
stages: [
28+
{ id: "char1", label: "Character", type: "input" },
29+
{ id: "acoustic1", label: "Acoustic Model", type: "process" },
30+
{ id: "melspec", label: "Mel-Spectrogram", type: "intermediate" },
31+
{ id: "vocoder2", label: "Vocoder", type: "process" },
32+
{ id: "waveform2", label: "Waveform", type: "output" }
33+
]
34+
},
35+
{
36+
id: 2,
37+
title: "Direct Character-to-Waveform TTS",
38+
description: "Simplified pipeline from characters directly to waveform",
39+
stages: [
40+
{ id: "char2", label: "Character", type: "input" },
41+
{ id: "vocoder3", label: "Vocoder", type: "process" },
42+
{ id: "waveform3", label: "Waveform", type: "output" }
43+
]
44+
},
45+
{
46+
id: 3,
47+
title: "Advanced Multi-Stage TTS",
48+
description: "Enhanced pipeline with detailed acoustic processing",
49+
stages: [
50+
{ id: "char3", label: "Character/Phoneme", type: "input" },
51+
{ id: "acoustic2", label: "Acoustic Model", type: "process" },
52+
{ id: "features2", label: "Acoustic Features", type: "intermediate" },
53+
{ id: "vocoder4", label: "Vocoder", type: "process" },
54+
{ id: "waveform4", label: "Waveform", type: "output" }
55+
]
56+
},
57+
{
58+
id: 4,
59+
title: "Fully End-to-End TTS Model",
60+
description: "Single model that learns the entire text-to-speech mapping",
61+
stages: [
62+
{ id: "char4", label: "Character/Phoneme", type: "input" },
63+
{ id: "e2e", label: "Fully End-to-End TTS Model", type: "process", isMain: true },
64+
{ id: "waveform5", label: "Waveform", type: "output" }
65+
]
66+
}
67+
];
68+
69+
const colors = {
70+
input: "#4ade80",
71+
process: "#3b82f6",
72+
intermediate: "#f59e0b",
73+
output: "#ef4444",
74+
connection: "#64748b"
75+
};
76+
77+
useEffect(() => {
78+
const svg = d3.select(svgRef.current);
79+
svg.selectAll("*").remove();
80+
81+
const width = 900;
82+
const height = 500;
83+
const margin = { top: 20, right: 20, bottom: 20, left: 20 };
84+
85+
svg.attr("width", width).attr("height", height);
86+
87+
const g = svg.append("g")
88+
.attr("transform", `translate(${margin.left},${margin.top})`);
89+
90+
// Add gradient definitions
91+
const defs = svg.append("defs");
92+
93+
// Gradient for connections
94+
const gradient = defs.append("linearGradient")
95+
.attr("id", "connectionGradient")
96+
.attr("gradientUnits", "userSpaceOnUse");
97+
98+
gradient.append("stop")
99+
.attr("offset", "0%")
100+
.attr("stop-color", colors.connection)
101+
.attr("stop-opacity", 0.8);
102+
103+
gradient.append("stop")
104+
.attr("offset", "100%")
105+
.attr("stop-color", colors.connection)
106+
.attr("stop-opacity", 0.3);
107+
108+
// Glow effect for main process
109+
const filter = defs.append("filter")
110+
.attr("id", "glow");
111+
112+
filter.append("feGaussianBlur")
113+
.attr("stdDeviation", "3")
114+
.attr("result", "coloredBlur");
115+
116+
const feMerge = filter.append("feMerge");
117+
feMerge.append("feMergeNode").attr("in", "coloredBlur");
118+
feMerge.append("feMergeNode").attr("in", "SourceGraphic");
119+
120+
const currentPipeline = pipelines[selectedPipeline];
121+
const stages = currentPipeline.stages;
122+
123+
const stageWidth = (width - margin.left - margin.right) / stages.length;
124+
const centerY = (height - margin.top - margin.bottom) / 2;
125+
126+
// Create flowing connections
127+
const connections = [];
128+
for (let i = 0; i < stages.length - 1; i++) {
129+
connections.push({
130+
source: i,
131+
target: i + 1
132+
});
133+
}
134+
135+
// Draw flowing connections with animation
136+
const connectionGroup = g.append("g").attr("class", "connections");
137+
138+
connections.forEach((conn, index) => {
139+
const sourceX = conn.source * stageWidth + stageWidth / 2;
140+
const targetX = conn.target * stageWidth + stageWidth / 2;
141+
const controlX1 = sourceX + (targetX - sourceX) / 3;
142+
const controlX2 = sourceX + 2 * (targetX - sourceX) / 3;
143+
144+
const path = connectionGroup.append("path")
145+
.attr("d", `M ${sourceX} ${centerY} C ${controlX1} ${centerY - 30} ${controlX2} ${centerY - 30} ${targetX} ${centerY}`)
146+
.attr("stroke", "url(#connectionGradient)")
147+
.attr("stroke-width", 3)
148+
.attr("fill", "none")
149+
.attr("opacity", 0);
150+
151+
// Animate connection appearance
152+
path.transition()
153+
.delay(index * 200)
154+
.duration(800)
155+
.attr("opacity", 1);
156+
157+
// Add flowing particles
158+
const particle = connectionGroup.append("circle")
159+
.attr("r", 4)
160+
.attr("fill", colors.connection)
161+
.attr("opacity", 0);
162+
163+
const pathLength = path.node().getTotalLength();
164+
165+
const animateParticle = () => {
166+
particle
167+
.attr("opacity", 0.8)
168+
.transition()
169+
.duration(2000)
170+
.ease(d3.easeLinear)
171+
.attrTween("transform", () => {
172+
return (t) => {
173+
const point = path.node().getPointAtLength(t * pathLength);
174+
return `translate(${point.x}, ${point.y})`;
175+
};
176+
})
177+
.transition()
178+
.duration(100)
179+
.attr("opacity", 0)
180+
.on("end", () => {
181+
setTimeout(animateParticle, Math.random() * 2000 + 1000);
182+
});
183+
};
184+
185+
setTimeout(() => animateParticle(), index * 300 + 1000);
186+
});
187+
188+
// Draw stages
189+
const stageGroup = g.append("g").attr("class", "stages");
190+
191+
stages.forEach((stage, index) => {
192+
const x = index * stageWidth + stageWidth / 2;
193+
const isMainProcess = stage.isMain;
194+
195+
const stageContainer = stageGroup.append("g")
196+
.attr("class", "stage")
197+
.attr("transform", `translate(${x}, ${centerY})`);
198+
199+
// Add stage box
200+
const rect = stageContainer.append("rect")
201+
.attr("x", -60)
202+
.attr("y", -25)
203+
.attr("width", 120)
204+
.attr("height", 50)
205+
.attr("rx", 8)
206+
.attr("fill", colors[stage.type])
207+
.attr("stroke", "#ffffff")
208+
.attr("stroke-width", 2)
209+
.attr("opacity", 0)
210+
.style("cursor", "pointer");
211+
212+
if (isMainProcess) {
213+
rect.attr("filter", "url(#glow)")
214+
.attr("width", 160)
215+
.attr("x", -80)
216+
.attr("height", 60)
217+
.attr("y", -30);
218+
}
219+
220+
// Animate stage appearance
221+
rect.transition()
222+
.delay(index * 150)
223+
.duration(600)
224+
.attr("opacity", 1);
225+
226+
// Add stage label
227+
const text = stageContainer.append("text")
228+
.attr("text-anchor", "middle")
229+
.attr("dy", "0.35em")
230+
.attr("fill", "white")
231+
.attr("font-size", isMainProcess ? "11px" : "12px")
232+
.attr("font-weight", "600")
233+
.attr("opacity", 0)
234+
.style("pointer-events", "none");
235+
236+
// Handle text wrapping for longer labels
237+
const words = stage.label.split(/\s+/);
238+
if (words.length > 1 && !isMainProcess) {
239+
words.forEach((word, i) => {
240+
text.append("tspan")
241+
.attr("x", 0)
242+
.attr("dy", i === 0 ? "-0.2em" : "1.2em")
243+
.text(word);
244+
});
245+
} else if (isMainProcess) {
246+
const lines = stage.label.split(/(?<=TTS)\s/);
247+
lines.forEach((line, i) => {
248+
text.append("tspan")
249+
.attr("x", 0)
250+
.attr("dy", i === 0 ? "-0.6em" : "1.2em")
251+
.text(line);
252+
});
253+
} else {
254+
text.text(stage.label);
255+
}
256+
257+
text.transition()
258+
.delay(index * 150 + 300)
259+
.duration(400)
260+
.attr("opacity", 1);
261+
262+
// Add hover effects
263+
stageContainer
264+
.on("mouseover", function() {
265+
d3.select(this).select("rect")
266+
.transition()
267+
.duration(200)
268+
.attr("transform", "scale(1.05)");
269+
})
270+
.on("mouseout", function() {
271+
d3.select(this).select("rect")
272+
.transition()
273+
.duration(200)
274+
.attr("transform", "scale(1)");
275+
});
276+
});
277+
278+
}, [selectedPipeline]);
279+
280+
return (
281+
<div className="w-full max-w-6xl mx-auto p-6 bg-gradient-to-br from-slate-50 to-slate-100 rounded-xl shadow-lg">
282+
<div className="mb-8">
283+
<h1 className="text-3xl font-bold text-gray-800 mb-2">
284+
Text-to-Speech Pipeline Architectures
285+
</h1>
286+
<p className="text-gray-600">
287+
Interactive visualization of different TTS model approaches
288+
</p>
289+
</div>
290+
291+
{/* Pipeline Selection */}
292+
<div className="mb-6">
293+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
294+
{pipelines.map((pipeline) => (
295+
<button
296+
key={pipeline.id}
297+
onClick={() => setSelectedPipeline(pipeline.id)}
298+
className={`p-3 rounded-lg text-left transition-all duration-200 ${
299+
selectedPipeline === pipeline.id
300+
? 'bg-blue-500 text-white shadow-lg transform scale-105'
301+
: 'bg-white text-gray-700 hover:bg-blue-50 hover:shadow-md'
302+
}`}
303+
>
304+
<div className="font-semibold text-sm mb-1">{pipeline.title}</div>
305+
<div className={`text-xs ${
306+
selectedPipeline === pipeline.id ? 'text-blue-100' : 'text-gray-500'
307+
}`}>
308+
{pipeline.stages.length} stages
309+
</div>
310+
</button>
311+
))}
312+
</div>
313+
</div>
314+
315+
{/* Current Pipeline Info */}
316+
<div className="mb-6 p-4 bg-white rounded-lg shadow-sm border-l-4 border-blue-500">
317+
<h3 className="font-bold text-gray-800 mb-2">
318+
{pipelines[selectedPipeline].title}
319+
</h3>
320+
<p className="text-gray-600 text-sm">
321+
{pipelines[selectedPipeline].description}
322+
</p>
323+
</div>
324+
325+
{/* SVG Chart */}
326+
<div className="bg-white rounded-lg shadow-sm p-4 overflow-x-auto">
327+
<svg ref={svgRef} className="w-full"></svg>
328+
</div>
329+
330+
{/* Legend */}
331+
<div className="mt-6 flex flex-wrap justify-center gap-6 text-sm">
332+
<div className="flex items-center gap-2">
333+
<div className="w-4 h-4 rounded bg-green-400"></div>
334+
<span className="text-gray-700">Input</span>
335+
</div>
336+
<div className="flex items-center gap-2">
337+
<div className="w-4 h-4 rounded bg-blue-500"></div>
338+
<span className="text-gray-700">Processing</span>
339+
</div>
340+
<div className="flex items-center gap-2">
341+
<div className="w-4 h-4 rounded bg-amber-500"></div>
342+
<span className="text-gray-700">Intermediate</span>
343+
</div>
344+
<div className="flex items-center gap-2">
345+
<div className="w-4 h-4 rounded bg-red-500"></div>
346+
<span className="text-gray-700">Output</span>
347+
</div>
348+
</div>
349+
</div>
350+
);
351+
};
352+
353+
export default TTSFlowChart;

0 commit comments

Comments
 (0)