upgrade wavesuffer to 7.3.4 (#329)

* upgrade wavesuffer to 7.3.4

* fix typo issue for wavesurfer

* fix

* fix
This commit is contained in:
Hoan Luu Huu
2023-10-19 00:54:59 +07:00
committed by GitHub
parent 729cefb06c
commit 3a19ff6840
5 changed files with 90 additions and 110 deletions

45
package-lock.json generated
View File

@@ -21,7 +21,7 @@
"react-dom": "^18.0.0",
"react-feather": "^2.0.10",
"react-router-dom": "^6.3.0",
"wavesurfer.js": "^6.6.3"
"wavesurfer.js": "^7.3.4"
},
"devDependencies": {
"@types/cors": "^2.8.12",
@@ -30,7 +30,6 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/uuid": "^9.0.1",
"@types/wavesurfer.js": "^6.0.6",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"@vitejs/plugin-react": "^1.3.0",
@@ -900,12 +899,6 @@
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==",
"dev": true
},
"node_modules/@types/debounce": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz",
"integrity": "sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==",
"dev": true
},
"node_modules/@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
@@ -1014,15 +1007,6 @@
"integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==",
"dev": true
},
"node_modules/@types/wavesurfer.js": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/@types/wavesurfer.js/-/wavesurfer.js-6.0.6.tgz",
"integrity": "sha512-fD54o0RXZXxkOb+69Rt6rGViaHpIc1Mmde2aOX9qPhlQhrCPepybGnsekiG407+7scPlaK+hmuPez5AnnmlzGg==",
"dev": true,
"dependencies": {
"@types/debounce": "*"
}
},
"node_modules/@types/yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
@@ -6867,9 +6851,9 @@
}
},
"node_modules/wavesurfer.js": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-6.6.3.tgz",
"integrity": "sha512-XqUOXe8+SOTe8uKCHaqW0vJ5etCCQvq/NgaPycn9HAX/nUi+2zoWD+w9i7H5vBT9UCDNawOia+vS5Ct3kZGQzA=="
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.3.4.tgz",
"integrity": "sha512-x2Ue4Dh+4RoaWay3LOLHhXgkdxPAIoC/BcbXh0yk8WNhQH2NboPoa52XXoCo4jEfjSe1bc7nxuM5vBIxUMZyBA=="
},
"node_modules/which": {
"version": "2.0.2",
@@ -7678,12 +7662,6 @@
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==",
"dev": true
},
"@types/debounce": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz",
"integrity": "sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==",
"dev": true
},
"@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
@@ -7787,15 +7765,6 @@
"integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==",
"dev": true
},
"@types/wavesurfer.js": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/@types/wavesurfer.js/-/wavesurfer.js-6.0.6.tgz",
"integrity": "sha512-fD54o0RXZXxkOb+69Rt6rGViaHpIc1Mmde2aOX9qPhlQhrCPepybGnsekiG407+7scPlaK+hmuPez5AnnmlzGg==",
"dev": true,
"requires": {
"@types/debounce": "*"
}
},
"@types/yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
@@ -11657,9 +11626,9 @@
}
},
"wavesurfer.js": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-6.6.3.tgz",
"integrity": "sha512-XqUOXe8+SOTe8uKCHaqW0vJ5etCCQvq/NgaPycn9HAX/nUi+2zoWD+w9i7H5vBT9UCDNawOia+vS5Ct3kZGQzA=="
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.3.4.tgz",
"integrity": "sha512-x2Ue4Dh+4RoaWay3LOLHhXgkdxPAIoC/BcbXh0yk8WNhQH2NboPoa52XXoCo4jEfjSe1bc7nxuM5vBIxUMZyBA=="
},
"which": {
"version": "2.0.2",

View File

@@ -42,6 +42,8 @@
},
"dependencies": {
"@jambonz/ui-kit": "^0.0.21",
"@stripe/react-stripe-js": "^2.1.1",
"@stripe/stripe-js": "^1.54.1",
"dayjs": "^1.11.5",
"immutability-helper": "^3.1.1",
"react": "^18.0.0",
@@ -50,9 +52,7 @@
"react-dom": "^18.0.0",
"react-feather": "^2.0.10",
"react-router-dom": "^6.3.0",
"wavesurfer.js": "^6.6.3",
"@stripe/react-stripe-js": "^2.1.1",
"@stripe/stripe-js": "^1.54.1"
"wavesurfer.js": "^7.3.4"
},
"devDependencies": {
"@types/cors": "^2.8.12",
@@ -61,7 +61,6 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/uuid": "^9.0.1",
"@types/wavesurfer.js": "^6.0.6",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"@vitejs/plugin-react": "^1.3.0",

View File

@@ -37,14 +37,14 @@ export interface JaegerAttribute {
value: JaegerValue;
}
export interface WaveSufferSttResult {
export interface WaveSurferSttResult {
vendor: string;
transcript: string;
confidence: number;
language_code: string;
}
export interface WaveSufferDtmfResult {
export interface WaveSurferDtmfResult {
dtmf: string;
duration: string;
}

View File

@@ -6,14 +6,14 @@ import { Icon, P } from "@jambonz/ui-kit";
import { Icons, Modal, ModalClose } from "src/components";
import { deleteRecord, getBlob, getJaegerTrace } from "src/api";
import { DownloadedBlob, RecentCall } from "src/api/types";
import RegionsPlugin, { Region } from "wavesurfer.js/src/plugin/regions";
import TimelinePlugin from "wavesurfer.js/src/plugin/timeline";
import RegionsPlugin, { Region } from "wavesurfer.js/dist/plugins/regions";
import TimelinePlugin from "wavesurfer.js/dist/plugins/timeline";
import { API_BASE_URL } from "src/api/constants";
import {
JaegerRoot,
JaegerSpan,
WaveSufferDtmfResult,
WaveSufferSttResult,
WaveSurferDtmfResult,
WaveSurferSttResult,
} from "src/api/jaeger-types";
import {
getSpanAttributeByName,
@@ -38,23 +38,26 @@ export const Player = ({ call }: PlayerProps) => {
const [isReady, setIsReady] = useState(false);
const [playBackTime, setPlayBackTime] = useState("");
const [jaegerRoot, setJeagerRoot] = useState<JaegerRoot>();
const [waveSufferRegionData, setWaveSufferRegionData] =
useState<WaveSufferSttResult | null>();
const [waveSufferDtmfData, setWaveSufferDtmfData] =
useState<WaveSufferDtmfResult | null>();
const [waveSurferRegionData, setWaveSurferRegionData] =
useState<WaveSurferSttResult | null>();
const [waveSurferDtmfData, setWaveSurferDtmfData] =
useState<WaveSurferDtmfResult | null>();
const [regionChecked, setRegionChecked] = useState(false);
const wavesurferId = `wavesurfer--${call_sid}`;
const wavesurferTimelineId = `timeline-${wavesurferId}`;
const waveSufferRef = useRef<WaveSurfer | null>(null);
const waveSurferRef = useRef<WaveSurfer | null>(null);
const waveSurferRegionsPluginRef = useRef<RegionsPlugin | null>();
const [record, setRecord] = useState<DownloadedBlob | null>(null);
const [deleteRecordUrl, setDeleteRecordUrl] = useState("");
const drawDtmfRegionForSpan = (s: JaegerSpan, startPoint: JaegerSpan) => {
if (waveSufferRef.current) {
const r = waveSufferRef.current.regions.list[s.spanId];
if (waveSurferRegionsPluginRef.current) {
waveSurferRef.current;
const r = waveSurferRegionsPluginRef.current
.getRegions()
.find((r) => r.id === s.spanId);
if (!r) {
const [dtmfValue] = getSpanAttributeByName(s.attributes, "dtmf");
const [durationValue] = getSpanAttributeByName(
@@ -67,29 +70,28 @@ export const Player = ({ call }: PlayerProps) => {
1_000_000_000;
const duration =
Number(durationValue.value.stringValue.replace("ms", "")) / 1_000;
// as duration of DTMF is short, cannot be shown in wavesuffer,
// as duration of DTMF is short, cannot be shown in wavesurfer,
// adjust region width here.
const delta = duration <= 0.1 ? 0.1 : duration;
const end = start + delta;
const region = waveSufferRef.current.addRegion({
const region = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start,
end,
color: "rgba(138, 43, 226, 0.15)",
drag: false,
loop: false,
resize: false,
});
changeRegionMouseStyle(region);
const att: WaveSufferDtmfResult = {
const att: WaveSurferDtmfResult = {
dtmf: dtmfValue.value.stringValue,
duration: durationValue.value.stringValue,
};
region.on("click", () => {
setWaveSufferDtmfData(att);
setWaveSurferDtmfData(att);
});
}
}
@@ -115,8 +117,10 @@ export const Player = ({ call }: PlayerProps) => {
startPoint: JaegerSpan,
channel = 0
) => {
if (waveSufferRef.current) {
const r = waveSufferRef.current.regions.list[s.spanId];
if (waveSurferRegionsPluginRef.current) {
const r = waveSurferRegionsPluginRef.current
.getRegions()
.find((r) => r.id === s.spanId);
if (!r) {
const start =
(s.startTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000 +
@@ -124,18 +128,18 @@ export const Player = ({ call }: PlayerProps) => {
const end =
(s.endTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
const region = waveSufferRef.current.addRegion({
const region = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start,
end,
color: "rgba(255, 0, 0, 0.15)",
drag: false,
loop: false,
resize: false,
});
changeRegionMouseStyle(region, channel);
const [sttResult] = getSpanAttributeByName(s.attributes, "stt.result");
let att: WaveSufferSttResult;
let att: WaveSurferSttResult;
if (sttResult) {
const data = JSON.parse(sttResult.value.stringValue);
att = {
@@ -168,13 +172,13 @@ export const Player = ({ call }: PlayerProps) => {
}
region.on("click", () => {
setWaveSufferRegionData(att);
setWaveSurferRegionData(att);
});
}
}
};
const buildWavesufferRegion = () => {
const buildWavesurferRegion = () => {
if (jaegerRoot) {
const spans = getSpansFromJaegerRoot(jaegerRoot);
const [startPoint] = getSpansByName(spans, "background-listen:listen");
@@ -218,7 +222,7 @@ export const Player = ({ call }: PlayerProps) => {
};
useEffect(() => {
buildWavesufferRegion();
buildWavesurferRegion();
}, [jaegerRoot, isReady]);
useEffect(() => {
@@ -251,8 +255,9 @@ export const Player = ({ call }: PlayerProps) => {
}
useEffect(() => {
if (waveSufferRef.current !== null || !record) return;
waveSufferRef.current = WaveSurfer.create({
if (waveSurferRef.current !== null || !record) return;
waveSurferRegionsPluginRef.current = RegionsPlugin.create();
waveSurferRef.current = WaveSurfer.create({
container: `#${wavesurferId}`,
waveColor: "#da1c5c",
progressColor: "grey",
@@ -260,62 +265,68 @@ export const Player = ({ call }: PlayerProps) => {
cursorWidth: 1,
cursorColor: "lightgray",
normalize: true,
responsive: true,
fillParent: true,
splitChannels: true,
scrollParent: true,
autoScroll: true,
splitChannels: [],
minPxPerSec: 100,
plugins: [
RegionsPlugin.create({}),
waveSurferRegionsPluginRef.current,
TimelinePlugin.create({
container: `#${wavesurferTimelineId}`,
timeInterval: 0.2,
primaryLabelInterval: 5,
secondaryLabelInterval: 1,
style: {
fontSize: "15px",
color: "#000000",
fontWeight: "bold",
},
}),
],
});
waveSufferRef.current.load(record?.data_url);
waveSurferRef.current.load(record?.data_url);
// All event should be after load
waveSufferRef.current.on("finish", () => {
waveSurferRef.current.on("finish", () => {
setIsPlaying(false);
});
waveSufferRef.current.on("play", () => {
waveSurferRef.current.on("play", () => {
setIsPlaying(true);
});
waveSufferRef.current.on("pause", () => {
waveSurferRef.current.on("pause", () => {
setIsPlaying(false);
});
waveSufferRef.current.on("ready", () => {
waveSurferRef.current.on("ready", () => {
setIsReady(true);
setPlayBackTime(formatTime(waveSufferRef.current?.getDuration() || 0));
setPlayBackTime(formatTime(waveSurferRef.current?.getDuration() || 0));
});
waveSufferRef.current.on("audioprocess", () => {
setPlayBackTime(formatTime(waveSufferRef.current?.getCurrentTime() || 0));
waveSurferRef.current.on("audioprocess", () => {
setPlayBackTime(formatTime(waveSurferRef.current?.getCurrentTime() || 0));
});
}, [record]);
const togglePlayback = () => {
if (waveSufferRef.current) {
if (waveSurferRef.current) {
if (!isPlaying) {
waveSufferRef.current.play();
waveSurferRef.current.play();
} else {
waveSufferRef.current.pause();
waveSurferRef.current.pause();
}
}
};
const setPlaybackJump = (delta: number) => {
if (waveSufferRef.current) {
const idx = waveSufferRef.current.getCurrentTime() + delta;
if (waveSurferRef.current) {
const idx = waveSurferRef.current.getCurrentTime() + delta;
const value =
idx <= 0
? 0
: idx >= waveSufferRef.current.getDuration()
? waveSufferRef.current.getDuration() - 1
: idx >= waveSurferRef.current.getDuration()
? waveSurferRef.current.getDuration() - 1
: idx;
waveSufferRef.current.setCurrentTime(value);
waveSurferRef.current.setTime(value);
setPlayBackTime(formatTime(value));
}
};
@@ -326,7 +337,6 @@ export const Player = ({ call }: PlayerProps) => {
<>
<div className="media-container">
<div id={wavesurferId} />
<div id={wavesurferTimelineId} />
<div className="media-container__center">
<strong>{playBackTime}</strong>
</div>
@@ -404,8 +414,9 @@ export const Player = ({ call }: PlayerProps) => {
checked={regionChecked}
onChange={(e) => {
setRegionChecked(e.target.checked);
if (waveSufferRef.current) {
const regionsList = waveSufferRef.current.regions.list;
if (waveSurferRegionsPluginRef.current) {
const regionsList =
waveSurferRegionsPluginRef.current.getRegions();
for (const [, region] of Object.entries(regionsList)) {
region.element.style.display = e.target.checked ? "" : "none";
}
@@ -415,8 +426,8 @@ export const Player = ({ call }: PlayerProps) => {
<div>Overlay STT and DTMF events</div>
</label>
</div>
{waveSufferRegionData && (
<ModalClose handleClose={() => setWaveSufferRegionData(null)}>
{waveSurferRegionData && (
<ModalClose handleClose={() => setWaveSurferRegionData(null)}>
<div className="spanDetailsWrapper__header">
<P>
<strong>Speech to text result</strong>
@@ -424,43 +435,43 @@ export const Player = ({ call }: PlayerProps) => {
</div>
<div className="spanDetailsWrapper">
<div className="spanDetailsWrapper__detailsWrapper">
{waveSufferRegionData.vendor && (
{waveSurferRegionData.vendor && (
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Vendor:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferRegionData.vendor}
{waveSurferRegionData.vendor}
</div>
</div>
)}
{waveSufferRegionData.confidence !== 0 && (
{waveSurferRegionData.confidence !== 0 && (
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Confidence:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferRegionData.confidence}
{waveSurferRegionData.confidence}
</div>
</div>
)}
{waveSufferRegionData.language_code && (
{waveSurferRegionData.language_code && (
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Language code:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferRegionData.language_code}
{waveSurferRegionData.language_code}
</div>
</div>
)}
{waveSufferRegionData.transcript && (
{waveSurferRegionData.transcript && (
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Transcript:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferRegionData.transcript}
{waveSurferRegionData.transcript}
</div>
</div>
)}
@@ -468,8 +479,8 @@ export const Player = ({ call }: PlayerProps) => {
</div>
</ModalClose>
)}
{waveSufferDtmfData && (
<ModalClose handleClose={() => setWaveSufferDtmfData(null)}>
{waveSurferDtmfData && (
<ModalClose handleClose={() => setWaveSurferDtmfData(null)}>
<div className="spanDetailsWrapper__header">
<P>
<strong>Dtmf result</strong>
@@ -482,7 +493,7 @@ export const Player = ({ call }: PlayerProps) => {
<strong>Dtmf:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferDtmfData.dtmf}
{waveSurferDtmfData.dtmf}
</div>
</div>
@@ -491,7 +502,7 @@ export const Player = ({ call }: PlayerProps) => {
<strong>Duration:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSufferDtmfData.duration}
{waveSurferDtmfData.duration}
</div>
</div>
</div>

View File

@@ -71,6 +71,7 @@
}
.media-container {
overflow-x: auto;
border: 1px solid black;
border-radius: ui-vars.$px01;
padding: 13px;