Beatrice Speaker graph

WIP: Web version
This commit is contained in:
w-okada 2023-11-19 22:28:38 +09:00
parent 079043ff6a
commit d44119f9bf
30 changed files with 4606 additions and 2187 deletions

2
.gitignore vendored
View File

@ -37,7 +37,9 @@ server/memo.md
client/lib/dist
client/lib/worklet/dist
client/demo/public/models
client/demo/public/models_
client/demo/dist/models
client/demo/dist_web
client/demo/src/001_provider/backup
# client/demo/dist/ # demo用に残す

View File

@ -0,0 +1,928 @@
<?xml version='1.0' encoding='utf-8'?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ns2="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="100 60 420 450" version="1.1">
<metadata>
<rdf:RDF>
<ns2:Work>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:date>2023-11-19T11:21:56.358384</dc:date>
<dc:format>image/svg+xml</dc:format>
<dc:creator>
<ns2:Agent>
<dc:title>Matplotlib v3.7.1, https://matplotlib.org/</dc:title>
</ns2:Agent>
</dc:creator>
</ns2:Work>
</rdf:RDF>
</metadata>
<defs>
<style type="text/css">
* {
stroke-linejoin: round;
stroke-linecap: butt
}
</style>
<style type="text/css">
.beatrice-node-pointer {
cursor: pointer;
}
.beatrice-node-pointer:hover {
stroke: gray;
}
.beatrice-node-pointer-selected {
stroke: #ef6767c2;
stroke-width: 3
}
.beatrice-text-pointer {
cursor: pointer;
pointer-events: none
}
.beatrice-text-pointer:hover {
/* ホバー時のスタイルは既に設定されたスタイルと異なる特定の属性を変更することができます。 */
}
</style>
</defs>
<g id="figure_1">
<g id="patch_1">
<path d="M 0 576 L 576 576 L 576 0 L 0 0 z " style="fill: #ffffff" />
</g>
<g id="axes_1">
<g id="LineCollection_1">
<path d="M 403.96157 149.258085 L 366.630583 148.159991 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 396.547407 371.476481 L 372.120414 365.421971 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 396.547407 371.476481 L 416.760989 346.999139 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 396.547407 371.476481 L 404.238335 402.754731 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 258.035169 326.134244 L 298.859694 332.465911 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 167.453327 366.897955 L 203.987537 347.931194 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 436.352807 416.173738 L 404.238335 402.754731 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 391.514336 242.048236 L 417.560846 259.464346 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 391.514336 242.048236 L 355.734145 235.68791 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 391.514336 242.048236 L 424.070309 219.021704 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 205.541044 459.711101 L 230.303076 436.148139 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 160.44225 292.540336 L 167.396334 325.961848 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 345.679012 107.607273 L 366.630583 148.159991 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 325.345004 219.195921 L 355.734145 235.68791 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 325.345004 219.195921 L 297.530501 194.55124 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 363.075301 201.701937 L 355.734145 235.68791 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 363.075301 201.701937 L 341.462109 170.414842 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 366.630583 148.159991 L 341.462109 170.414842 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 167.396334 325.961848 L 203.987537 347.931194 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 262.111309 181.887977 L 297.530501 194.55124 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 189.293496 262.735141 L 222.122563 261.416721 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 277.95603 462.622539 L 293.230217 421.393405 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 333.932593 269.342364 L 301.9174 258.124913 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 333.932593 269.342364 L 355.734145 235.68791 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 334.666605 338.097578 L 320.07566 368.578481 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 203.987537 347.931194 L 242.811958 354.082183 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 288.059985 363.924972 L 320.07566 368.578481 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 288.059985 363.924972 L 276.198518 388.99868 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 288.059985 363.924972 L 298.859694 332.465911 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 288.059985 363.924972 L 242.811958 354.082183 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 276.198518 388.99868 L 293.230217 421.393405 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 293.230217 421.393405 L 309.530924 454.827332 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 293.230217 421.393405 L 260.004712 426.426278 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 423.853712 378.321354 L 404.238335 402.754731 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 205.214352 217.066163 L 222.122563 261.416721 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 154.047193 423.153273 L 193.933786 408.004355 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 298.859694 332.465911 L 277.79477 306.980241 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 277.79477 306.980241 L 282.261978 282.779534 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 260.004712 426.426278 L 230.303076 436.148139 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 260.004712 426.426278 L 228.689744 409.959215 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 260.004712 426.426278 L 261.506403 474.152727 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 301.9174 258.124913 L 282.261978 282.779534 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 254.897329 263.033159 L 282.261978 282.779534 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 254.897329 263.033159 L 222.122563 261.416721 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 321.267463 403.021207 L 320.07566 368.578481 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 345.750267 380.131711 L 320.07566 368.578481 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 345.750267 380.131711 L 372.120414 365.421971 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 345.750267 380.131711 L 351.226176 419.342667 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 404.238335 402.754731 L 400.607869 434.730447 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
<path d="M 193.933786 408.004355 L 230.303076 436.148139 " clip-path="url(#pe3de578e26)"
style="fill: none; stroke: #808080" />
</g>
<g id="PathCollection_1">
<defs>
<path id="C0_0_b0ffb3bf4a"
d="M 0 11.18034 C 2.965061 11.18034 5.80908 10.002309 7.905694 7.905694 C 10.002309 5.80908 11.18034 2.965061 11.18034 -0 C 11.18034 -2.965061 10.002309 -5.80908 7.905694 -7.905694 C 5.80908 -10.002309 2.965061 -11.18034 0 -11.18034 C -2.965061 -11.18034 -5.80908 -10.002309 -7.905694 -7.905694 C -10.002309 -5.80908 -11.18034 -2.965061 -11.18034 0 C -11.18034 2.965061 -10.002309 5.80908 -7.905694 7.905694 C -5.80908 10.002309 -2.965061 11.18034 0 11.18034 z " />
</defs>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-0"
onclick="(()=&gt;{console.log('node 0')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="403.96157" y="149.258085" style="fill: #e7f5d2" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-1"
onclick="(()=&gt;{console.log('node 1')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="396.547407" y="371.476481" style="fill: #fbe8f2" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-2"
onclick="(()=&gt;{console.log('node 2')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="258.035169" y="326.134244" style="fill: #cfebaa" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-3"
onclick="(()=&gt;{console.log('node 3')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="167.453327" y="366.897955" style="fill: #f1f6e8" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-4"
onclick="(()=&gt;{console.log('node 4')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="436.352807" y="416.173738" style="fill: #e89ac6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-5"
onclick="(()=&gt;{console.log('node 5')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="391.514336" y="242.048236" style="fill: #f3bcdd" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-6"
onclick="(()=&gt;{console.log('node 6')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="205.541044" y="459.711101" style="fill: #fbd9ec" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-7"
onclick="(()=&gt;{console.log('node 7')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="160.44225" y="292.540336" style="fill: #9ed067" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-8"
onclick="(()=&gt;{console.log('node 8')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="424.070309" y="219.021704" style="fill: #e1f3c7" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-9"
onclick="(()=&gt;{console.log('node 9')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="345.679012" y="107.607273" style="fill: #d0ecad" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-10"
onclick="(()=&gt;{console.log('node 10')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="325.345004" y="219.195921" style="fill: #eff6e4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-11"
onclick="(()=&gt;{console.log('node 11')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="363.075301" y="201.701937" style="fill: #f9f0f5" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-12"
onclick="(()=&gt;{console.log('node 12')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="366.630583" y="148.159991" style="fill: #ebf6dc" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-13"
onclick="(()=&gt;{console.log('node 13')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="341.462109" y="170.414842" style="fill: #fad6ea" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-14"
onclick="(()=&gt;{console.log('node 14')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="167.396334" y="325.961848" style="fill: #f5f7f3" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-15"
onclick="(()=&gt;{console.log('node 15')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="262.111309" y="181.887977" style="fill: #e9f5d6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-16"
onclick="(()=&gt;{console.log('node 16')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="189.293496" y="262.735141" style="fill: #fce5f1" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-17"
onclick="(()=&gt;{console.log('node 17')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="277.95603" y="462.622539" style="fill: #c4e699" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-18"
onclick="(()=&gt;{console.log('node 18')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="333.932593" y="269.342364" style="fill: #f8f4f6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-19"
onclick="(()=&gt;{console.log('node 19')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="416.760989" y="346.999139" style="fill: #eef6e2" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-20"
onclick="(()=&gt;{console.log('node 20')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="334.666605" y="338.097578" style="fill: #f5f7f3" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-21"
onclick="(()=&gt;{console.log('node 21')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="203.987537" y="347.931194" style="fill: #edf6df" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-22"
onclick="(()=&gt;{console.log('node 22')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="288.059985" y="363.924972" style="fill: #ddf1c1" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-23"
onclick="(()=&gt;{console.log('node 23')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="276.198518" y="388.99868" style="fill: #f5f7f3" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-24"
onclick="(()=&gt;{console.log('node 24')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="293.230217" y="421.393405" style="fill: #f3f7ef" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-25"
onclick="(()=&gt;{console.log('node 25')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="423.853712" y="378.321354" style="fill: #edf6df" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-26"
onclick="(()=&gt;{console.log('node 26')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="205.214352" y="217.066163" style="fill: #e7f5d2" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-27"
onclick="(()=&gt;{console.log('node 27')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="242.811958" y="354.082183" style="fill: #d2ecb0" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-28"
onclick="(()=&gt;{console.log('node 28')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="154.047193" y="423.153273" style="fill: #e6f5d0" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-29"
onclick="(()=&gt;{console.log('node 29')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="298.859694" y="332.465911" style="fill: #ecf6de" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-30"
onclick="(()=&gt;{console.log('node 30')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="277.79477" y="306.980241" style="fill: #eaf5d9" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-31"
onclick="(()=&gt;{console.log('node 31')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="260.004712" y="426.426278" style="fill: #f9f1f5" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-32"
onclick="(()=&gt;{console.log('node 32')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="301.9174" y="258.124913" style="fill: #dbf0bf" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-33"
onclick="(()=&gt;{console.log('node 33')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="254.897329" y="263.033159" style="fill: #eff6e4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-34"
onclick="(()=&gt;{console.log('node 34')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="321.267463" y="403.021207" style="fill: #d0ecad" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-35"
onclick="(()=&gt;{console.log('node 35')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="345.750267" y="380.131711" style="fill: #f9eef4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-36"
onclick="(()=&gt;{console.log('node 36')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="404.238335" y="402.754731" style="fill: #f9eef4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-37"
onclick="(()=&gt;{console.log('node 37')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="355.734145" y="235.68791" style="fill: #f9eef4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-38"
onclick="(()=&gt;{console.log('node 38')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="193.933786" y="408.004355" style="fill: #f0f6e7" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-39"
onclick="(()=&gt;{console.log('node 39')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="297.530501" y="194.55124" style="fill: #f3f6ed" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-40"
onclick="(()=&gt;{console.log('node 40')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="320.07566" y="368.578481" style="fill: #dbf0bf" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-41"
onclick="(()=&gt;{console.log('node 41')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="228.689744" y="409.959215" style="fill: #f9eff4" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-42"
onclick="(()=&gt;{console.log('node 42')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="351.226176" y="419.342667" style="fill: #cfebaa" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-43"
onclick="(()=&gt;{console.log('node 43')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="372.120414" y="365.421971" style="fill: #f7f6f7" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-44"
onclick="(()=&gt;{console.log('node 44')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="230.303076" y="436.148139" style="fill: #f8cee6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-45"
onclick="(()=&gt;{console.log('node 45')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="261.506403" y="474.152727" style="fill: #e6f5d0" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-46"
onclick="(()=&gt;{console.log('node 46')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="417.560846" y="259.464346" style="fill: #b7e085" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-47"
onclick="(()=&gt;{console.log('node 47')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="400.607869" y="434.730447" style="fill: #f8cee6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-48"
onclick="(()=&gt;{console.log('node 48')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="282.261978" y="282.779534" style="fill: #d6eeb6" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-49"
onclick="(()=&gt;{console.log('node 49')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="222.122563" y="261.416721" style="fill: #edf6df" />
</g>
<g clip-path="url(#pe3de578e26)" id="beatrice-node-female-50"
onclick="(()=&gt;{console.log('node 50')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_b0ffb3bf4a" x="309.530924" y="454.827332" style="fill: #f9eef4" />
</g>
</g>
<g id="beatrice-text-female-0" onclick="(()=&gt;{console.log('text 0 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(399.786883 152.569335) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-32"
d="M 1844 884 L 3897 884 L 3897 0 L 506 0 L 506 884 L 2209 2388 Q 2438 2594 2547 2791 Q 2656 2988 2656 3200 Q 2656 3528 2436 3728 Q 2216 3928 1850 3928 Q 1569 3928 1234 3808 Q 900 3688 519 3450 L 519 4475 Q 925 4609 1322 4679 Q 1719 4750 2100 4750 Q 2938 4750 3402 4381 Q 3866 4013 3866 3353 Q 3866 2972 3669 2642 Q 3472 2313 2841 1759 L 1844 884 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-32" />
</g>
</g>
</g>
<g id="beatrice-text-female-1" onclick="(()=&gt;{console.log('text 1 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(392.37272 374.787731) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-34"
d="M 2356 3675 L 1038 1722 L 2356 1722 L 2356 3675 z M 2156 4666 L 3494 4666 L 3494 1722 L 4159 1722 L 4159 850 L 3494 850 L 3494 0 L 2356 0 L 2356 850 L 288 850 L 288 1881 L 2156 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-34" />
</g>
</g>
</g>
<g id="beatrice-text-female-2" onclick="(()=&gt;{console.log('text 2 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(253.860482 329.445494) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-37"
d="M 428 4666 L 3944 4666 L 3944 3988 L 2125 0 L 953 0 L 2675 3781 L 428 3781 L 428 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-37" />
</g>
</g>
</g>
<g id="beatrice-text-female-3" onclick="(()=&gt;{console.log('text 3 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(163.27864 370.209205) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-38"
d="M 2228 2088 Q 1891 2088 1709 1903 Q 1528 1719 1528 1375 Q 1528 1031 1709 848 Q 1891 666 2228 666 Q 2563 666 2741 848 Q 2919 1031 2919 1375 Q 2919 1722 2741 1905 Q 2563 2088 2228 2088 z M 1350 2484 Q 925 2613 709 2878 Q 494 3144 494 3541 Q 494 4131 934 4440 Q 1375 4750 2228 4750 Q 3075 4750 3515 4442 Q 3956 4134 3956 3541 Q 3956 3144 3739 2878 Q 3522 2613 3097 2484 Q 3572 2353 3814 2058 Q 4056 1763 4056 1313 Q 4056 619 3595 264 Q 3134 -91 2228 -91 Q 1319 -91 855 264 Q 391 619 391 1313 Q 391 1763 633 2058 Q 875 2353 1350 2484 z M 1631 3419 Q 1631 3141 1786 2991 Q 1941 2841 2228 2841 Q 2509 2841 2662 2991 Q 2816 3141 2816 3419 Q 2816 3697 2662 3845 Q 2509 3994 2228 3994 Q 1941 3994 1786 3844 Q 1631 3694 1631 3419 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-38" />
</g>
</g>
</g>
<g id="beatrice-text-female-4" onclick="(()=&gt;{console.log('text 4 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(428.003432 419.484988) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-31"
d="M 750 831 L 1813 831 L 1813 3847 L 722 3622 L 722 4441 L 1806 4666 L 2950 4666 L 2950 831 L 4013 831 L 4013 0 L 750 0 L 750 831 z "
transform="scale(0.015625)" />
<path id="DejaVuSans-Bold-30"
d="M 2944 2338 Q 2944 3213 2780 3570 Q 2616 3928 2228 3928 Q 1841 3928 1675 3570 Q 1509 3213 1509 2338 Q 1509 1453 1675 1090 Q 1841 728 2228 728 Q 2613 728 2778 1090 Q 2944 1453 2944 2338 z M 4147 2328 Q 4147 1169 3647 539 Q 3147 -91 2228 -91 Q 1306 -91 806 539 Q 306 1169 306 2328 Q 306 3491 806 4120 Q 1306 4750 2228 4750 Q 3147 4750 3647 4120 Q 4147 3491 4147 2328 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-5" onclick="(()=&gt;{console.log('text 5 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(383.164961 245.359486) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-6" onclick="(()=&gt;{console.log('text 6 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(197.191669 463.022351) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-35"
d="M 678 4666 L 3669 4666 L 3669 3781 L 1638 3781 L 1638 3059 Q 1775 3097 1914 3117 Q 2053 3138 2203 3138 Q 3056 3138 3531 2711 Q 4006 2284 4006 1522 Q 4006 766 3489 337 Q 2972 -91 2053 -91 Q 1656 -91 1267 -14 Q 878 63 494 219 L 494 1166 Q 875 947 1217 837 Q 1559 728 1863 728 Q 2300 728 2551 942 Q 2803 1156 2803 1522 Q 2803 1891 2551 2103 Q 2300 2316 1863 2316 Q 1603 2316 1309 2248 Q 1016 2181 678 2041 L 678 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-7" onclick="(()=&gt;{console.log('text 7 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(152.092875 295.851586) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-36"
d="M 2316 2303 Q 2000 2303 1842 2098 Q 1684 1894 1684 1484 Q 1684 1075 1842 870 Q 2000 666 2316 666 Q 2634 666 2792 870 Q 2950 1075 2950 1484 Q 2950 1894 2792 2098 Q 2634 2303 2316 2303 z M 3803 4544 L 3803 3681 Q 3506 3822 3243 3889 Q 2981 3956 2731 3956 Q 2194 3956 1894 3657 Q 1594 3359 1544 2772 Q 1750 2925 1990 3001 Q 2231 3078 2516 3078 Q 3231 3078 3670 2659 Q 4109 2241 4109 1563 Q 4109 813 3618 361 Q 3128 -91 2303 -91 Q 1394 -91 895 523 Q 397 1138 397 2266 Q 397 3422 980 4083 Q 1563 4744 2578 4744 Q 2900 4744 3203 4694 Q 3506 4644 3803 4544 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-8" onclick="(()=&gt;{console.log('text 8 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(415.720934 222.332954) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-9" onclick="(()=&gt;{console.log('text 9 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(337.329637 110.918523) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-10" onclick="(()=&gt;{console.log('text 10 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(316.995629 222.507171) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-39"
d="M 641 103 L 641 966 Q 928 831 1190 764 Q 1453 697 1709 697 Q 2247 697 2547 995 Q 2847 1294 2900 1881 Q 2688 1725 2447 1647 Q 2206 1569 1925 1569 Q 1209 1569 770 1986 Q 331 2403 331 3084 Q 331 3838 820 4291 Q 1309 4744 2131 4744 Q 3044 4744 3544 4128 Q 4044 3513 4044 2388 Q 4044 1231 3459 570 Q 2875 -91 1856 -91 Q 1528 -91 1228 -42 Q 928 6 641 103 z M 2125 2350 Q 2441 2350 2600 2554 Q 2759 2759 2759 3169 Q 2759 3575 2600 3781 Q 2441 3988 2125 3988 Q 1809 3988 1650 3781 Q 1491 3575 1491 3169 Q 1491 2759 1650 2554 Q 1809 2350 2125 2350 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-11" onclick="(()=&gt;{console.log('text 11 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(354.725926 205.013187) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-12" onclick="(()=&gt;{console.log('text 12 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(358.281208 151.471241) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-13" onclick="(()=&gt;{console.log('text 13 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(333.112734 173.726092) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-14" onclick="(()=&gt;{console.log('text 14 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(159.046959 329.273098) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-15" onclick="(()=&gt;{console.log('text 15 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(253.761934 185.199227) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-16" onclick="(()=&gt;{console.log('text 16 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(180.944121 266.046391) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-33"
d="M 2981 2516 Q 3453 2394 3698 2092 Q 3944 1791 3944 1325 Q 3944 631 3412 270 Q 2881 -91 1863 -91 Q 1503 -91 1142 -33 Q 781 25 428 141 L 428 1069 Q 766 900 1098 814 Q 1431 728 1753 728 Q 2231 728 2486 893 Q 2741 1059 2741 1369 Q 2741 1688 2480 1852 Q 2219 2016 1709 2016 L 1228 2016 L 1228 2791 L 1734 2791 Q 2188 2791 2409 2933 Q 2631 3075 2631 3366 Q 2631 3634 2415 3781 Q 2200 3928 1806 3928 Q 1516 3928 1219 3862 Q 922 3797 628 3669 L 628 4550 Q 984 4650 1334 4700 Q 1684 4750 2022 4750 Q 2931 4750 3382 4451 Q 3834 4153 3834 3553 Q 3834 3144 3618 2883 Q 3403 2622 2981 2516 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-17" onclick="(()=&gt;{console.log('text 17 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(269.606655 465.933789) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-18" onclick="(()=&gt;{console.log('text 18 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(325.583218 272.653614) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-19" onclick="(()=&gt;{console.log('text 19 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(408.411614 350.310389) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-20" onclick="(()=&gt;{console.log('text 20 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(326.31723 341.408828) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-21" onclick="(()=&gt;{console.log('text 21 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(195.638162 351.242444) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-22" onclick="(()=&gt;{console.log('text 22 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(279.71061 367.236222) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-23" onclick="(()=&gt;{console.log('text 23 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(267.849143 392.30993) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-24" onclick="(()=&gt;{console.log('text 24 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(284.880842 424.704655) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-25" onclick="(()=&gt;{console.log('text 25 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(415.504337 381.632604) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-26" onclick="(()=&gt;{console.log('text 26 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(196.864977 220.377413) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-27" onclick="(()=&gt;{console.log('text 27 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(234.462583 357.393433) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-28" onclick="(()=&gt;{console.log('text 28 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(145.697818 426.464523) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-29" onclick="(()=&gt;{console.log('text 29 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(290.510319 335.777161) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-30" onclick="(()=&gt;{console.log('text 30 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(269.445395 310.291491) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-31" onclick="(()=&gt;{console.log('text 31 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(251.655337 429.737528) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-32" onclick="(()=&gt;{console.log('text 32 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(293.568025 261.436163) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-33" onclick="(()=&gt;{console.log('text 33 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(246.547954 266.344409) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-34" onclick="(()=&gt;{console.log('text 34 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(312.918088 406.332457) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-35" onclick="(()=&gt;{console.log('text 35 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(337.400892 383.442961) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-36" onclick="(()=&gt;{console.log('text 36 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(395.88896 406.065981) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-37" onclick="(()=&gt;{console.log('text 37 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(347.38477 238.99916) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-38" onclick="(()=&gt;{console.log('text 38 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(185.584411 411.315605) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-39" onclick="(()=&gt;{console.log('text 39 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(289.181126 197.86249) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-40" onclick="(()=&gt;{console.log('text 40 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(311.726285 371.889731) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-41" onclick="(()=&gt;{console.log('text 41 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(220.340369 413.270465) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-42" onclick="(()=&gt;{console.log('text 42 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(342.876801 422.653917) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-43" onclick="(()=&gt;{console.log('text 43 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(363.771039 368.733221) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-44" onclick="(()=&gt;{console.log('text 44 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(221.953701 439.459389) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-45" onclick="(()=&gt;{console.log('text 45 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(253.157028 477.463977) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-46" onclick="(()=&gt;{console.log('text 46 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(409.211471 262.775596) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-47" onclick="(()=&gt;{console.log('text 47 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(392.258494 438.041697) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-48" onclick="(()=&gt;{console.log('text 48 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(273.912603 286.090784) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-49" onclick="(()=&gt;{console.log('text 49 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(213.773188 264.727971) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-female-50" onclick="(()=&gt;{console.log('text 50 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pe3de578e26)">
<g transform="translate(301.181549 458.138582) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
</g>
</g>
<defs>
<clipPath id="pe3de578e26">
<rect x="124.405104" y="69.12" width="341.589792" height="443.52" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,898 @@
<?xml version='1.0' encoding='utf-8'?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ns2="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="100 60 420 450" version="1.1">
<metadata>
<rdf:RDF>
<ns2:Work>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:date>2023-11-19T11:21:55.705408</dc:date>
<dc:format>image/svg+xml</dc:format>
<dc:creator>
<ns2:Agent>
<dc:title>Matplotlib v3.7.1, https://matplotlib.org/</dc:title>
</ns2:Agent>
</dc:creator>
</ns2:Work>
</rdf:RDF>
</metadata>
<defs>
<style type="text/css">
* {
stroke-linejoin: round;
stroke-linecap: butt
}
</style>
<style type="text/css">
.beatrice-node-pointer {
cursor: pointer;
}
.beatrice-node-pointer:hover {
stroke: gray;
}
.beatrice-node-pointer-selected {
stroke: #ef6767c2;
stroke-width: 3
}
.beatrice-text-pointer {
cursor: pointer;
pointer-events: none
}
.beatrice-text-pointer:hover {
/* ホバー時のスタイルは既に設定されたスタイルと異なる特定の属性を変更することができます。 */
}
</style>
</defs>
<g id="figure_1">
<g id="patch_1">
<path d="M 0 576 L 576 576 L 576 0 L 0 0 z " style="fill: #ffffff" />
</g>
<g id="axes_1">
<g id="LineCollection_1">
<path d="M 383.475478 335.382791 L 350.123561 336.312105 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 383.475478 335.382791 L 393.562573 295.917472 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 383.475478 335.382791 L 396.396073 371.656412 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 395.592267 184.349842 L 344.302973 166.290216 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 166.614267 246.553188 L 214.405523 244.575019 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 362.886037 395.352171 L 389.299516 416.267064 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 362.886037 395.352171 L 367.134249 434.454954 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 362.886037 395.352171 L 396.396073 371.656412 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 362.886037 395.352171 L 321.091057 403.95329 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 291.699254 114.456198 L 287.429936 148.935339 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 309.72476 346.813492 L 326.464644 303.679747 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 396.396073 371.656412 L 422.276969 403.842356 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 396.396073 371.656412 L 419.504487 334.14189 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 311.713 188.802087 L 278.840744 190.572938 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 311.713 188.802087 L 287.429936 148.935339 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 311.713 188.802087 L 344.302973 166.290216 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 213.805036 285.720019 L 216.196468 317.113868 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 213.805036 285.720019 L 241.321249 255.242558 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 213.805036 285.720019 L 169.41455 268.66905 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 326.464644 303.679747 L 341.073251 272.287852 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 326.464644 303.679747 L 281.878613 277.846944 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 326.464644 303.679747 L 350.123561 336.312105 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 468.104517 290.196764 L 453.314054 329.209099 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 252.522958 107.607273 L 287.429936 148.935339 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 241.817 158.353487 L 278.840744 190.572938 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 278.840744 190.572938 L 264.569363 223.030096 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 190.32114 223.314542 L 214.405523 244.575019 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 233.41271 348.401671 L 216.196468 317.113868 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 122.295483 352.502553 L 162.445269 355.484449 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 158.624602 400.46174 L 162.445269 355.484449 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 214.405523 244.575019 L 241.321249 255.242558 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 214.405523 244.575019 L 207.563253 203.013335 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 264.569363 223.030096 L 298.808991 236.296491 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 264.569363 223.030096 L 241.321249 255.242558 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 264.569363 223.030096 L 236.649711 206.251683 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 220.79649 394.869471 L 213.931911 434.927829 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 220.79649 394.869471 L 208.453065 361.465389 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 241.321249 255.242558 L 281.878613 277.846944 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 257.120877 296.156882 L 281.878613 277.846944 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 453.314054 329.209099 L 419.504487 334.14189 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 287.180764 309.56402 L 281.878613 277.846944 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 287.429936 148.935339 L 321.071206 134.027026 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 300.632415 433.812968 L 321.091057 403.95329 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 216.196468 317.113868 L 181.944484 318.835753 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 216.196468 317.113868 L 208.453065 361.465389 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 419.504487 334.14189 L 436.061109 363.566053 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 366.514998 474.152727 L 367.134249 434.454954 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
<path d="M 208.453065 361.465389 L 162.445269 355.484449 " clip-path="url(#pd42c8a995e)"
style="fill: none; stroke: #808080" />
</g>
<g id="PathCollection_1">
<defs>
<path id="C0_0_3858269516"
d="M 0 11.18034 C 2.965061 11.18034 5.80908 10.002309 7.905694 7.905694 C 10.002309 5.80908 11.18034 2.965061 11.18034 -0 C 11.18034 -2.965061 10.002309 -5.80908 7.905694 -7.905694 C 5.80908 -10.002309 2.965061 -11.18034 0 -11.18034 C -2.965061 -11.18034 -5.80908 -10.002309 -7.905694 -7.905694 C -10.002309 -5.80908 -11.18034 -2.965061 -11.18034 0 C -11.18034 2.965061 -10.002309 5.80908 -7.905694 7.905694 C -5.80908 10.002309 -2.965061 11.18034 0 11.18034 z " />
</defs>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-0" onclick="(()=&gt;{console.log('node 0')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="383.475478" y="335.382791" style="fill: #fde2bb" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-1" onclick="(()=&gt;{console.log('node 1')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="393.562573" y="295.917472" style="fill: #fdba68" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-2" onclick="(()=&gt;{console.log('node 2')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="395.592267" y="184.349842" style="fill: #fbe9cf" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-3" onclick="(()=&gt;{console.log('node 3')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="166.614267" y="246.553188" style="fill: #7e70ab" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-4" onclick="(()=&gt;{console.log('node 4')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="362.886037" y="395.352171" style="fill: #e8e9f1" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-5" onclick="(()=&gt;{console.log('node 5')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="291.699254" y="114.456198" style="fill: #f9b158" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-6" onclick="(()=&gt;{console.log('node 6')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="309.72476" y="346.813492" style="fill: #e4e5f0" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-7" onclick="(()=&gt;{console.log('node 7')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="396.396073" y="371.656412" style="fill: #fdcc8c" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-8" onclick="(()=&gt;{console.log('node 8')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="311.713" y="188.802087" style="fill: #fedeb3" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-9" onclick="(()=&gt;{console.log('node 9')})()"
class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="213.805036" y="285.720019" style="fill: #bab5d7" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-10"
onclick="(()=&gt;{console.log('node 10')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="326.464644" y="303.679747" style="fill: #eaebf2" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-11"
onclick="(()=&gt;{console.log('node 11')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="468.104517" y="290.196764" style="fill: #f7f7f6" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-12"
onclick="(()=&gt;{console.log('node 12')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="169.41455" y="268.66905" style="fill: #dfe1ee" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-13"
onclick="(()=&gt;{console.log('node 13')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="252.522958" y="107.607273" style="fill: #eff0f4" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-14"
onclick="(()=&gt;{console.log('node 14')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="241.817" y="158.353487" style="fill: #e58a20" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-15"
onclick="(()=&gt;{console.log('node 15')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="278.840744" y="190.572938" style="fill: #fedbac" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-16"
onclick="(()=&gt;{console.log('node 16')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="190.32114" y="223.314542" style="fill: #dfe1ee" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-17"
onclick="(()=&gt;{console.log('node 17')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="233.41271" y="348.401671" style="fill: #c3c0dd" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-18"
onclick="(()=&gt;{console.log('node 18')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="122.295483" y="352.502553" style="fill: #fed8a6" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-19"
onclick="(()=&gt;{console.log('node 19')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="158.624602" y="400.46174" style="fill: #f7f6f3" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-20"
onclick="(()=&gt;{console.log('node 20')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="214.405523" y="244.575019" style="fill: #f9f2e9" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-21"
onclick="(()=&gt;{console.log('node 21')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="264.569363" y="223.030096" style="fill: #faecd7" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-22"
onclick="(()=&gt;{console.log('node 22')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="220.79649" y="394.869471" style="fill: #fbead2" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-23"
onclick="(()=&gt;{console.log('node 23')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="344.302973" y="166.290216" style="fill: #feddaf" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-24"
onclick="(()=&gt;{console.log('node 24')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="241.321249" y="255.242558" style="fill: #c3c0dd" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-25"
onclick="(()=&gt;{console.log('node 25')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="257.120877" y="296.156882" style="fill: #f9f0e4" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-26"
onclick="(()=&gt;{console.log('node 26')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="207.563253" y="203.013335" style="fill: #fbebd5" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-27"
onclick="(()=&gt;{console.log('node 27')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="453.314054" y="329.209099" style="fill: #fdc47b" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-28"
onclick="(()=&gt;{console.log('node 28')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="350.123561" y="336.312105" style="fill: #fbe9cf" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-29"
onclick="(()=&gt;{console.log('node 29')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="287.180764" y="309.56402" style="fill: #f7f6f3" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-30"
onclick="(()=&gt;{console.log('node 30')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="287.429936" y="148.935339" style="fill: #fbebd5" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-31"
onclick="(()=&gt;{console.log('node 31')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="281.878613" y="277.846944" style="fill: #d1d1e6" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-32"
onclick="(()=&gt;{console.log('node 32')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="300.632415" y="433.812968" style="fill: #fde2bb" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-33"
onclick="(()=&gt;{console.log('node 33')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="216.196468" y="317.113868" style="fill: #dddfed" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-34"
onclick="(()=&gt;{console.log('node 34')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="419.504487" y="334.14189" style="fill: #fdc57f" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-35"
onclick="(()=&gt;{console.log('node 35')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="321.071206" y="134.027026" style="fill: #fee0b6" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-36"
onclick="(()=&gt;{console.log('node 36')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="366.514998" y="474.152727" style="fill: #fdbd6e" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-37"
onclick="(()=&gt;{console.log('node 37')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="208.453065" y="361.465389" style="fill: #cccbe3" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-38"
onclick="(()=&gt;{console.log('node 38')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="236.649711" y="206.251683" style="fill: #faecd7" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-39"
onclick="(()=&gt;{console.log('node 39')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="298.808991" y="236.296491" style="fill: #fdc57f" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-40"
onclick="(()=&gt;{console.log('node 40')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="181.944484" y="318.835753" style="fill: #f9f0e4" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-41"
onclick="(()=&gt;{console.log('node 41')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="367.134249" y="434.454954" style="fill: #f6f6f7" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-42"
onclick="(()=&gt;{console.log('node 42')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="422.276969" y="403.842356" style="fill: #fdbf72" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-43"
onclick="(()=&gt;{console.log('node 43')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="321.091057" y="403.95329" style="fill: #f8f5f1" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-44"
onclick="(()=&gt;{console.log('node 44')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="162.445269" y="355.484449" style="fill: #eaebf2" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-45"
onclick="(()=&gt;{console.log('node 45')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="341.073251" y="272.287852" style="fill: #f6aa4f" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-46"
onclick="(()=&gt;{console.log('node 46')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="389.299516" y="416.267064" style="fill: #de8013" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-47"
onclick="(()=&gt;{console.log('node 47')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="213.931911" y="434.927829" style="fill: #fbb55e" />
</g>
<g clip-path="url(#pd42c8a995e)" id="beatrice-node-male-48"
onclick="(()=&gt;{console.log('node 48')})()" class="beatrice-node-pointer">
<use xlink:href="#C0_0_3858269516" x="436.061109" y="363.566053" style="fill: #ebecf3" />
</g>
</g>
<g id="beatrice-text-male-0" onclick="(()=&gt;{console.log('text 0 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(379.30079 338.694041) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-31"
d="M 750 831 L 1813 831 L 1813 3847 L 722 3622 L 722 4441 L 1806 4666 L 2950 4666 L 2950 831 L 4013 831 L 4013 0 L 750 0 L 750 831 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
</g>
</g>
</g>
<g id="beatrice-text-male-1" onclick="(()=&gt;{console.log('text 1 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(389.387885 299.228722) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-33"
d="M 2981 2516 Q 3453 2394 3698 2092 Q 3944 1791 3944 1325 Q 3944 631 3412 270 Q 2881 -91 1863 -91 Q 1503 -91 1142 -33 Q 781 25 428 141 L 428 1069 Q 766 900 1098 814 Q 1431 728 1753 728 Q 2231 728 2486 893 Q 2741 1059 2741 1369 Q 2741 1688 2480 1852 Q 2219 2016 1709 2016 L 1228 2016 L 1228 2791 L 1734 2791 Q 2188 2791 2409 2933 Q 2631 3075 2631 3366 Q 2631 3634 2415 3781 Q 2200 3928 1806 3928 Q 1516 3928 1219 3862 Q 922 3797 628 3669 L 628 4550 Q 984 4650 1334 4700 Q 1684 4750 2022 4750 Q 2931 4750 3382 4451 Q 3834 4153 3834 3553 Q 3834 3144 3618 2883 Q 3403 2622 2981 2516 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-33" />
</g>
</g>
</g>
<g id="beatrice-text-male-2" onclick="(()=&gt;{console.log('text 2 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(391.41758 187.661092) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-35"
d="M 678 4666 L 3669 4666 L 3669 3781 L 1638 3781 L 1638 3059 Q 1775 3097 1914 3117 Q 2053 3138 2203 3138 Q 3056 3138 3531 2711 Q 4006 2284 4006 1522 Q 4006 766 3489 337 Q 2972 -91 2053 -91 Q 1656 -91 1267 -14 Q 878 63 494 219 L 494 1166 Q 875 947 1217 837 Q 1559 728 1863 728 Q 2300 728 2551 942 Q 2803 1156 2803 1522 Q 2803 1891 2551 2103 Q 2300 2316 1863 2316 Q 1603 2316 1309 2248 Q 1016 2181 678 2041 L 678 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-35" />
</g>
</g>
</g>
<g id="beatrice-text-male-3" onclick="(()=&gt;{console.log('text 3 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(162.43958 249.864438) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-36"
d="M 2316 2303 Q 2000 2303 1842 2098 Q 1684 1894 1684 1484 Q 1684 1075 1842 870 Q 2000 666 2316 666 Q 2634 666 2792 870 Q 2950 1075 2950 1484 Q 2950 1894 2792 2098 Q 2634 2303 2316 2303 z M 3803 4544 L 3803 3681 Q 3506 3822 3243 3889 Q 2981 3956 2731 3956 Q 2194 3956 1894 3657 Q 1594 3359 1544 2772 Q 1750 2925 1990 3001 Q 2231 3078 2516 3078 Q 3231 3078 3670 2659 Q 4109 2241 4109 1563 Q 4109 813 3618 361 Q 3128 -91 2303 -91 Q 1394 -91 895 523 Q 397 1138 397 2266 Q 397 3422 980 4083 Q 1563 4744 2578 4744 Q 2900 4744 3203 4694 Q 3506 4644 3803 4544 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-36" />
</g>
</g>
</g>
<g id="beatrice-text-male-4" onclick="(()=&gt;{console.log('text 4 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(358.71135 398.663421) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-39"
d="M 641 103 L 641 966 Q 928 831 1190 764 Q 1453 697 1709 697 Q 2247 697 2547 995 Q 2847 1294 2900 1881 Q 2688 1725 2447 1647 Q 2206 1569 1925 1569 Q 1209 1569 770 1986 Q 331 2403 331 3084 Q 331 3838 820 4291 Q 1309 4744 2131 4744 Q 3044 4744 3544 4128 Q 4044 3513 4044 2388 Q 4044 1231 3459 570 Q 2875 -91 1856 -91 Q 1528 -91 1228 -42 Q 928 6 641 103 z M 2125 2350 Q 2441 2350 2600 2554 Q 2759 2759 2759 3169 Q 2759 3575 2600 3781 Q 2441 3988 2125 3988 Q 1809 3988 1650 3781 Q 1491 3575 1491 3169 Q 1491 2759 1650 2554 Q 1809 2350 2125 2350 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-39" />
</g>
</g>
</g>
<g id="beatrice-text-male-5" onclick="(()=&gt;{console.log('text 5 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(283.349879 117.767448) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-6" onclick="(()=&gt;{console.log('text 6 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(301.375385 350.124742) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-32"
d="M 1844 884 L 3897 884 L 3897 0 L 506 0 L 506 884 L 2209 2388 Q 2438 2594 2547 2791 Q 2656 2988 2656 3200 Q 2656 3528 2436 3728 Q 2216 3928 1850 3928 Q 1569 3928 1234 3808 Q 900 3688 519 3450 L 519 4475 Q 925 4609 1322 4679 Q 1719 4750 2100 4750 Q 2938 4750 3402 4381 Q 3866 4013 3866 3353 Q 3866 2972 3669 2642 Q 3472 2313 2841 1759 L 1844 884 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-7" onclick="(()=&gt;{console.log('text 7 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(388.046698 374.967662) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-8" onclick="(()=&gt;{console.log('text 8 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(303.363625 192.113337) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-30"
d="M 2944 2338 Q 2944 3213 2780 3570 Q 2616 3928 2228 3928 Q 1841 3928 1675 3570 Q 1509 3213 1509 2338 Q 1509 1453 1675 1090 Q 1841 728 2228 728 Q 2613 728 2778 1090 Q 2944 1453 2944 2338 z M 4147 2328 Q 4147 1169 3647 539 Q 3147 -91 2228 -91 Q 1306 -91 806 539 Q 306 1169 306 2328 Q 306 3491 806 4120 Q 1306 4750 2228 4750 Q 3147 4750 3647 4120 Q 4147 3491 4147 2328 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-9" onclick="(()=&gt;{console.log('text 9 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(205.455661 289.031269) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-10" onclick="(()=&gt;{console.log('text 10 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(318.115269 306.990997) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-11" onclick="(()=&gt;{console.log('text 11 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(459.755142 293.508014) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-12" onclick="(()=&gt;{console.log('text 12 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(161.065175 271.9803) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-38"
d="M 2228 2088 Q 1891 2088 1709 1903 Q 1528 1719 1528 1375 Q 1528 1031 1709 848 Q 1891 666 2228 666 Q 2563 666 2741 848 Q 2919 1031 2919 1375 Q 2919 1722 2741 1905 Q 2563 2088 2228 2088 z M 1350 2484 Q 925 2613 709 2878 Q 494 3144 494 3541 Q 494 4131 934 4440 Q 1375 4750 2228 4750 Q 3075 4750 3515 4442 Q 3956 4134 3956 3541 Q 3956 3144 3739 2878 Q 3522 2613 3097 2484 Q 3572 2353 3814 2058 Q 4056 1763 4056 1313 Q 4056 619 3595 264 Q 3134 -91 2228 -91 Q 1319 -91 855 264 Q 391 619 391 1313 Q 391 1763 633 2058 Q 875 2353 1350 2484 z M 1631 3419 Q 1631 3141 1786 2991 Q 1941 2841 2228 2841 Q 2509 2841 2662 2991 Q 2816 3141 2816 3419 Q 2816 3697 2662 3845 Q 2509 3994 2228 3994 Q 1941 3994 1786 3844 Q 1631 3694 1631 3419 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-32" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-13" onclick="(()=&gt;{console.log('text 13 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(244.173583 110.918523) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-14" onclick="(()=&gt;{console.log('text 14 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(233.467625 161.664737) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-15" onclick="(()=&gt;{console.log('text 15 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(270.491369 193.884188) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-16" onclick="(()=&gt;{console.log('text 16 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(181.971765 226.625792) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-34"
d="M 2356 3675 L 1038 1722 L 2356 1722 L 2356 3675 z M 2156 4666 L 3494 4666 L 3494 1722 L 4159 1722 L 4159 850 L 3494 850 L 3494 0 L 2356 0 L 2356 850 L 288 850 L 288 1881 L 2156 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-17" onclick="(()=&gt;{console.log('text 17 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(225.063335 351.712921) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-Bold-37"
d="M 428 4666 L 3944 4666 L 3944 3988 L 2125 0 L 953 0 L 2675 3781 L 428 3781 L 428 4666 z "
transform="scale(0.015625)" />
</defs>
<use xlink:href="#DejaVuSans-Bold-33" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-18" onclick="(()=&gt;{console.log('text 18 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(113.946108 355.813803) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-19" onclick="(()=&gt;{console.log('text 19 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(150.275227 403.77299) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-20" onclick="(()=&gt;{console.log('text 20 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(206.056148 247.886269) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-21" onclick="(()=&gt;{console.log('text 21 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(256.219988 226.341346) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-22" onclick="(()=&gt;{console.log('text 22 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(212.447115 398.180721) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-23" onclick="(()=&gt;{console.log('text 23 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(335.953598 169.601466) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-24" onclick="(()=&gt;{console.log('text 24 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(232.971874 258.553808) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-25" onclick="(()=&gt;{console.log('text 25 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(248.771502 299.468132) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-34" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-26" onclick="(()=&gt;{console.log('text 26 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(199.213878 206.324585) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-27" onclick="(()=&gt;{console.log('text 27 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(444.964679 332.520349) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-32" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-28" onclick="(()=&gt;{console.log('text 28 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(341.774186 339.623355) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-35" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-29" onclick="(()=&gt;{console.log('text 29 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(278.831389 312.87527) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-36" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-30" onclick="(()=&gt;{console.log('text 30 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(279.080561 152.246589) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-31" onclick="(()=&gt;{console.log('text 31 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(273.529238 281.158194) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-32" onclick="(()=&gt;{console.log('text 32 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(292.28304 437.124218) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-33" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-33" onclick="(()=&gt;{console.log('text 33 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(207.847093 320.425118) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-34" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-34" onclick="(()=&gt;{console.log('text 34 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(411.155112 337.45314) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-35" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-35" onclick="(()=&gt;{console.log('text 35 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(312.721831 137.338276) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-36" onclick="(()=&gt;{console.log('text 36 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(358.165623 477.463977) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-37" onclick="(()=&gt;{console.log('text 37 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(200.10369 364.776639) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-38" onclick="(()=&gt;{console.log('text 38 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(228.300336 209.562933) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-37" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-39" onclick="(()=&gt;{console.log('text 39 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(290.459616 239.607741) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-40" onclick="(()=&gt;{console.log('text 40 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(173.595109 322.147003) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-31" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-41" onclick="(()=&gt;{console.log('text 41 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(358.784874 437.766204) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-36" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-42" onclick="(()=&gt;{console.log('text 42 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(413.927594 407.153606) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-43" onclick="(()=&gt;{console.log('text 43 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(312.741682 407.26454) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-44" onclick="(()=&gt;{console.log('text 44 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(154.095894 358.795699) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-38" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-45" onclick="(()=&gt;{console.log('text 45 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(332.723876 275.599102) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-37" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-46" onclick="(()=&gt;{console.log('text 46 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(380.950141 419.578314) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-38" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-47" onclick="(()=&gt;{console.log('text 47 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(205.582536 438.239079) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-39" />
<use xlink:href="#DejaVuSans-Bold-39" x="69.580078" />
</g>
</g>
</g>
<g id="beatrice-text-male-48" onclick="(()=&gt;{console.log('text 48 clicked')})()"
class="beatrice-text-pointer">
<g clip-path="url(#pd42c8a995e)">
<g transform="translate(423.537047 366.877303) scale(0.12 -0.12)">
<use xlink:href="#DejaVuSans-Bold-31" />
<use xlink:href="#DejaVuSans-Bold-30" x="69.580078" />
<use xlink:href="#DejaVuSans-Bold-30" x="139.160156" />
</g>
</g>
</g>
</g>
</g>
<defs>
<clipPath id="pd42c8a995e">
<rect x="85.985534" y="69.12" width="418.428931" height="443.52" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 54 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,9 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/*!**********************!*\
!*** ./src/index.ts ***!
\**********************/
/**
* @license React
* react-dom.production.min.js

File diff suppressed because it is too large Load Diff

View File

@ -16,8 +16,8 @@
"test": "echo \"Error: no test specified\" && exit 1",
"____ comment ____": "ウェブバージョンのスクリプト",
"clean:web": "rimraf dist_web/",
"webpack:web:prod": "npx webpack --config webpack_web.prod.js && copy .\\public\\info_web .\\dist_web\\info",
"webpack:web:dev": "npx webpack --config webpack_web.dev.js && copy .\\public\\info_web .\\dist_web\\info",
"webpack:web:prod": "npx webpack --config webpack_web.prod.js && copy .\\public\\info_web .\\dist_web\\info && copy .\\public\\assets\\gui_settings\\edition_web.txt .\\dist_web\\assets\\gui_settings\\edition.txt",
"webpack:web:dev": "npx webpack --config webpack_web.dev.js && copy .\\public\\info_web .\\dist_web\\info && copy .\\public\\assets\\gui_settings\\edition_web.txt .\\dist_web\\assets\\gui_settings\\edition.txt",
"build:web:prod": "npm-run-all clean:web webpack:web:prod",
"build:web:dev": "npm-run-all clean:web webpack:web:dev",
"start:web": "webpack-dev-server --config webpack_web.dev.js"
@ -28,19 +28,19 @@
"author": "wataru.okada@flect.co.jp",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/plugin-transform-runtime": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.23.2",
"@types/node": "^20.9.0",
"@babel/core": "^7.23.3",
"@babel/plugin-transform-runtime": "^7.23.3",
"@babel/preset-env": "^7.23.3",
"@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3",
"@types/node": "^20.9.2",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"autoprefixer": "^10.4.16",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.8.1",
"eslint": "^8.53.0",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
@ -50,10 +50,10 @@
"npm-run-all": "^4.1.5",
"postcss-loader": "^7.3.3",
"postcss-nested": "^6.0.1",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"rimraf": "^5.0.5",
"style-loader": "^3.3.3",
"ts-loader": "^9.5.0",
"ts-loader": "^9.5.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.2.2",
"webpack": "^5.89.0",
@ -62,15 +62,16 @@
},
"dependencies": {
"@alexanderolsen/libsamplerate-js": "^2.1.0",
"@dannadori/voice-changer-client-js": "^1.0.176",
"@dannadori/worker-manager": "^1.0.12",
"@dannadori/voice-changer-client-js": "^1.0.177",
"@dannadori/voice-changer-js": "^1.0.2",
"@dannadori/worker-manager": "^1.0.20",
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-regular-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@tensorflow/tfjs": "^4.13.0",
"onnxruntime-web": "^1.16.1",
"onnxruntime-web": "^1.16.2",
"protobufjs": "^7.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,143 @@
import { ClientState, WebModelSlot } from "@dannadori/voice-changer-client-js";
import { VoiceChangerJSClientConfig, VoiceChangerJSClient } from "@dannadori/voice-changer-js";
import { useEffect, useMemo, useRef, useState } from "react";
export type UseWebInfoProps = {
clientState: ClientState | null;
};
export const WebModelLoadingState = {
none: "none",
loading: "loading",
warmup: "warmup",
ready: "ready",
} as const;
export type WebModelLoadingState = (typeof WebModelLoadingState)[keyof typeof WebModelLoadingState];
export type VoiceChangerConfig = {
config: VoiceChangerJSClientConfig;
modelUrl: string;
progressCallback?: ((data: any) => void) | null;
portrait: string;
name: string;
termOfUse: string;
f0: boolean;
};
export type WebInfoState = {
voiceChangerConfig: VoiceChangerConfig;
webModelLoadingState: WebModelLoadingState;
progressLoadPreprocess: number;
progressLoadVCModel: number;
webModelslot: WebModelSlot;
};
export type WebInfoStateAndMethod = WebInfoState & {
loadVoiceChanagerModel: () => Promise<void>;
};
// const modelUrl = `${baseUrl}/models/rvc2v_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvc2v_40k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvc2v_16k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_40k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_32k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_32k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_32k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_32k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_40k_nof0_24000.bin`;
const InitialVoiceChangerConfig: VoiceChangerConfig = {
config: {
voiceChangerType: "rvcv1",
inputLength: "24000",
baseUrl: window.location.origin,
inputSamplingRate: 48000,
outputSamplingRate: 48000,
},
// modelUrl: `${window.location.origin}/models/rvcv1_amitaro_v1_32k_nof0_24000.bin`,
modelUrl: `https://huggingface.co/wok000/vcclient_model/resolve/main/web_model/v_01_alpha/amitaro/rvcv1_amitaro_v1_32k_nof0_24000.bin`,
progressCallback: null,
portrait: `${window.location.origin}/models/amitaro.png`,
name: "あみたろ",
termOfUse: "https://huggingface.co/wok000/vcclient_model/raw/main/rvc/amitaro_contentvec_256/term_of_use.txt",
f0: false,
};
export const useWebInfo = (props: UseWebInfoProps): WebInfoStateAndMethod => {
const [voiceChangerConfig, setVoiceChangerConfig] = useState<VoiceChangerConfig>(InitialVoiceChangerConfig);
const [webModelLoadingState, setWebModelLoadingState] = useState<WebModelLoadingState>(WebModelLoadingState.none);
const [progressLoadPreprocess, setProgressLoadPreprocess] = useState<number>(0);
const [progressLoadVCModel, setProgressLoadVCModel] = useState<number>(0);
const voiceChangerJSClient = useRef<VoiceChangerJSClient>();
const webModelslot: WebModelSlot = useMemo(() => {
return {
slotIndex: -1,
voiceChangerType: "WebModel",
name: voiceChangerConfig.name,
description: "",
credit: "",
termsOfUseUrl: voiceChangerConfig.termOfUse,
iconFile: voiceChangerConfig.portrait,
speakers: {},
defaultTune: 0,
modelType: "pyTorchRVCNono",
f0: voiceChangerConfig.f0,
samplingRate: 0,
modelFile: "",
};
}, []);
useEffect(() => {
const progressCallback = (data: any) => {
if (data.progressUpdateType === "loadPreprocessModel") {
setProgressLoadPreprocess(data.progress);
} else if (data.progressUpdateType === "loadVCModel") {
setProgressLoadVCModel(data.progress);
}
};
setVoiceChangerConfig({ ...voiceChangerConfig, progressCallback });
}, []);
const loadVoiceChanagerModel = async () => {
if (!props.clientState) {
throw new Error("[useWebInfo] clientState is null");
}
if (!props.clientState.initialized) {
console.warn("[useWebInfo] clientState is not initialized yet");
return;
}
setWebModelLoadingState("loading");
voiceChangerJSClient.current = new VoiceChangerJSClient();
await voiceChangerJSClient.current.initialize(voiceChangerConfig.config, voiceChangerConfig.modelUrl, voiceChangerConfig.progressCallback);
// worm up
setWebModelLoadingState("warmup");
const warmupResult = await voiceChangerJSClient.current.checkResponseTime();
console.log("warmup result", warmupResult);
// check time
const responseTimeInfo = await voiceChangerJSClient.current.checkResponseTime();
console.log("responseTimeInfo", responseTimeInfo);
props.clientState?.setInternalAudioProcessCallback({
processAudio: async (data: Uint8Array) => {
const audioF32 = new Float32Array(data.buffer);
const res = await voiceChangerJSClient.current!.convert(audioF32);
const audio = new Uint8Array(res[0].buffer);
console.log("RESPONSE!", res[1]);
return audio;
},
});
setWebModelLoadingState("ready");
};
return {
voiceChangerConfig,
webModelLoadingState,
progressLoadPreprocess,
progressLoadVCModel,
webModelslot,
loadVoiceChanagerModel,
};
};

View File

@ -8,10 +8,10 @@ type Props = {
};
type AppRootValue = {
audioContextState: AudioConfigState
appGuiSettingState: AppGuiSettingStateAndMethod
getGUISetting: () => Promise<void>
}
audioContextState: AudioConfigState;
appGuiSettingState: AppGuiSettingStateAndMethod;
getGUISetting: () => Promise<void>;
};
const AppRootContext = React.createContext<AppRootValue | null>(null);
export const useAppRoot = (): AppRootValue => {
@ -23,17 +23,16 @@ export const useAppRoot = (): AppRootValue => {
};
export const AppRootProvider = ({ children }: Props) => {
const audioContextState = useAudioConfig()
const appGuiSettingState = useAppGuiSetting()
const audioContextState = useAudioConfig();
const appGuiSettingState = useAppGuiSetting();
const getGUISetting = async () => {
await appGuiSettingState.getAppGuiSetting(`/assets/gui_settings/GUI.json`)
}
await appGuiSettingState.getAppGuiSetting(`/assets/gui_settings/GUI.json`);
};
const providerValue: AppRootValue = {
audioContextState,
appGuiSettingState,
getGUISetting
getGUISetting,
};
return <AppRootContext.Provider value={providerValue}>{children}</AppRootContext.Provider>;
};

View File

@ -5,6 +5,7 @@ import { ReactNode } from "react";
import { useVCClient } from "../001_globalHooks/001_useVCClient";
import { useAppRoot } from "./001_AppRootProvider";
import { useMessageBuilder } from "../hooks/useMessageBuilder";
import { WebInfoStateAndMethod, useWebInfo } from "../001_globalHooks/100_useWebInfo";
type Props = {
children: ReactNode;
@ -13,6 +14,7 @@ type Props = {
type AppStateValue = ClientState & {
audioContext: AudioContext;
initializedRef: React.MutableRefObject<boolean>;
webInfoState: WebInfoStateAndMethod;
};
const AppStateContext = React.createContext<AppStateValue | null>(null);
@ -28,7 +30,8 @@ export const AppStateProvider = ({ children }: Props) => {
const appRoot = useAppRoot();
const clientState = useVCClient({ audioContext: appRoot.audioContextState.audioContext });
const messageBuilderState = useMessageBuilder();
const voiceChangerJSClient = useRef<VoiceChangerJSClient>();
const webInfoState = useWebInfo(clientState);
// const voiceChangerJSClient = useRef<VoiceChangerJSClient>();
useEffect(() => {
messageBuilderState.setMessage(__filename, "ioError", {
@ -56,41 +59,9 @@ export const AppStateProvider = ({ children }: Props) => {
}, [clientState.clientState.ioErrorCount]);
useEffect(() => {
if (clientState.clientState.initialized) {
// const baseUrl = "https://192.168.0.247:18888";
// const baseUrl = "https://192.168.0.247:8080";
const baseUrl = window.location.origin;
// const modelUrl = `${baseUrl}/models/rvc2v_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvc2v_40k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvc2v_16k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_40k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_32k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv2_amitaro_v2_32k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_32k_f0_24000.bin`;
const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_32k_nof0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_40k_f0_24000.bin`;
// const modelUrl = `${baseUrl}/models/rvcv1_amitaro_v1_40k_nof0_24000.bin`;
voiceChangerJSClient.current = new VoiceChangerJSClient();
voiceChangerJSClient.current.initialize(
{
baseUrl: baseUrl,
inputSamplingRate: 48000,
outputSamplingRate: 48000,
},
modelUrl,
);
clientState.clientState.setInternalAudioProcessCallback({
processAudio: async (data: Uint8Array) => {
const audioF32 = new Float32Array(data.buffer);
const converted = await voiceChangerJSClient.current!.convert(audioF32);
const res = new Uint8Array(converted.buffer);
return res;
},
});
if (appRoot.appGuiSettingState.edition.indexOf("web") >= 0 && clientState.clientState.initialized) {
clientState.clientState.setWorkletNodeSetting({ ...clientState.clientState.setting.workletNodeSetting, protocol: "internal" });
webInfoState.loadVoiceChanagerModel();
}
}, [clientState.clientState.initialized]);
@ -98,6 +69,7 @@ export const AppStateProvider = ({ children }: Props) => {
audioContext: appRoot.audioContextState.audioContext!,
...clientState.clientState,
initializedRef,
webInfoState,
};
return <AppStateContext.Provider value={providerValue}>{children}</AppStateContext.Provider>;

View File

@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState } from "react";
import { ReactNode } from "react";
import { useAppRoot } from "../../001_provider/001_AppRootProvider";
import { StateControlCheckbox, useStateControlCheckbox } from "../../hooks/useStateControlCheckbox";
import { useAppState } from "../../001_provider/001_AppStateProvider";
export const OpenServerControlCheckbox = "open-server-control-checkbox";
export const OpenModelSettingCheckbox = "open-model-setting-checkbox";
@ -83,6 +84,12 @@ type GuiStateAndMethod = {
textInputResolve: TextInputResolveType | null;
setTextInputResolve: (val: TextInputResolveType | null) => void;
// for Beatrice
beatriceJVSSpeakerId: number;
beatriceJVSSpeakerPitch: number;
setBeatriceJVSSpeakerId: (id: number) => void;
setBeatriceJVSSpeakerPitch: (pitch: number) => void;
};
const GuiStateContext = React.createContext<GuiStateAndMethod | null>(null);
@ -100,6 +107,7 @@ type TextInputResolveType = {
export const GuiStateProvider = ({ children }: Props) => {
const { appGuiSettingState } = useAppRoot();
const { serverSetting } = useAppState();
const [isConverting, setIsConverting] = useState<boolean>(false);
const [isAnalyzing, setIsAnalyzing] = useState<boolean>(false);
const [modelSlotNum, setModelSlotNum] = useState<number>(0);
@ -117,6 +125,9 @@ export const GuiStateProvider = ({ children }: Props) => {
const [textInputResolve, setTextInputResolve] = useState<TextInputResolveType | null>(null);
const [beatriceJVSSpeakerId, setBeatriceJVSSpeakerId] = useState<number>(1);
const [beatriceJVSSpeakerPitch, setBeatriceJVSSpeakerPitch] = useState<number>(0);
const reloadDeviceInfo = async () => {
try {
const ms = await navigator.mediaDevices.getUserMedia({ video: false, audio: true });
@ -242,6 +253,24 @@ export const GuiStateProvider = ({ children }: Props) => {
setTimeout(show);
}, [appGuiSettingState.edition]);
useEffect(() => {
let dstId;
if (beatriceJVSSpeakerPitch == 0) {
dstId = (beatriceJVSSpeakerId - 1) * 5;
} else if (beatriceJVSSpeakerPitch == 1) {
dstId = (beatriceJVSSpeakerId - 1) * 5 + 1;
} else if (beatriceJVSSpeakerPitch == 2) {
dstId = (beatriceJVSSpeakerId - 1) * 5 + 2;
} else if (beatriceJVSSpeakerPitch == -1) {
dstId = (beatriceJVSSpeakerId - 1) * 5 + 3;
} else if (beatriceJVSSpeakerPitch == -2) {
dstId = (beatriceJVSSpeakerId - 1) * 5 + 4;
} else {
throw new Error(`invalid beatriceJVSSpeakerPitch speaker:${beatriceJVSSpeakerId} pitch:${beatriceJVSSpeakerPitch}`);
}
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, dstId: dstId });
}, [beatriceJVSSpeakerId, beatriceJVSSpeakerPitch]);
const providerValue = {
stateControls: {
openServerControlCheckbox,
@ -296,6 +325,12 @@ export const GuiStateProvider = ({ children }: Props) => {
textInputResolve,
setTextInputResolve,
// For Beatrice
beatriceJVSSpeakerId,
beatriceJVSSpeakerPitch,
setBeatriceJVSSpeakerId,
setBeatriceJVSSpeakerPitch,
};
return <GuiStateContext.Provider value={providerValue}>{children}</GuiStateContext.Provider>;
};

View File

@ -19,6 +19,17 @@ export const StartingNoticeDialog = () => {
ja: "(1) 一部の設定変更を行うとgpuを使用していても変換処理が遅くなることが発生します。もしこの現象が発生したらGPUの値を-1にしてから再度0に戻してください。",
en: "(1) When some settings are changed, conversion process becomes slow even when using GPU. If this occurs, reset the GPU value to -1 and then back to 0.",
});
messageBuilderState.setMessage(__filename, "web_edditon_1", { ja: "このWebエディションは実験的バージョンです。", en: "This edition(web) is an experimental Edition." });
messageBuilderState.setMessage(__filename, "web_edditon_2", {
ja: "より高機能・高性能なFullエディションは、",
en: "The more advanced and high-performance Full Edition can be obtained for free from the following GitHub repository.",
});
messageBuilderState.setMessage(__filename, "web_edditon_3", {
ja: "次のgithubリポジトリから無料で取得できます。",
en: "",
});
messageBuilderState.setMessage(__filename, "github", { ja: "github", en: "github" });
messageBuilderState.setMessage(__filename, "click_to_start", { ja: "スタートボタンを押してください。", en: "Click to start" });
messageBuilderState.setMessage(__filename, "start", { ja: "スタート", en: "start" });
}, []);
@ -44,7 +55,6 @@ export const StartingNoticeDialog = () => {
const licenseNoticeLink = useMemo(() => {
return isDesktopApp() ? (
// @ts-ignore
<span
className="link"
onClick={() => {
@ -95,6 +105,34 @@ export const StartingNoticeDialog = () => {
const licenseInfo = <div className="dialog-content-part">{licenseNoticeLink}</div>;
const webEdtionMessage = (
<div className="dialog-content-part">
<div>{messageBuilderState.getMessage(__filename, "web_edditon_1")}</div>
<div>{messageBuilderState.getMessage(__filename, "web_edditon_2")}</div>
<div>{messageBuilderState.getMessage(__filename, "web_edditon_3")}</div>
</div>
);
const githubLink = isDesktopApp() ? (
<span
className="link tooltip"
onClick={() => {
// @ts-ignore
window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer");
}}
>
<img src="./assets/icons/github.svg" />
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
<div>github</div>
</span>
) : (
<a className="link tooltip" href="https://github.com/w-okada/voice-changer" target="_blank" rel="noopener noreferrer">
<img src="./assets/icons/github.svg" />
<span>github</span>
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
</a>
);
const clickToStartMessage = (
<div className="dialog-content-part">
<div>{messageBuilderState.getMessage(__filename, "click_to_start")}</div>
@ -110,12 +148,19 @@ export const StartingNoticeDialog = () => {
{clickToStartMessage}
</div>
);
const contentForWeb = (
<div className="body-row">
{webEdtionMessage}
{githubLink}
{clickToStartMessage}
</div>
);
return (
<div className="dialog-frame">
<div className="dialog-title">Message</div>
<div className="dialog-content">
{content}
{edition.indexOf("web") >= 0 ? contentForWeb : content}
{closeButtonRow}
</div>
</div>

View File

@ -5,122 +5,122 @@ import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useIndexedDB } from "@dannadori/voice-changer-client-js";
import { useMessageBuilder } from "../../../hooks/useMessageBuilder";
export type HeaderAreaProps = {
mainTitle: string
subTitle: string
}
mainTitle: string;
subTitle: string;
};
export const HeaderArea = (props: HeaderAreaProps) => {
const { appGuiSettingState } = useAppRoot()
const messageBuilderState = useMessageBuilder()
const { clearSetting } = useAppState()
const { appGuiSettingState } = useAppRoot();
const messageBuilderState = useMessageBuilder();
const { clearSetting, webInfoState } = useAppState();
const { removeItem } = useIndexedDB({ clientType: null })
const { removeItem } = useIndexedDB({ clientType: null });
useMemo(() => {
messageBuilderState.setMessage(__filename, "github", { "ja": "github", "en": "github" })
messageBuilderState.setMessage(__filename, "manual", { "ja": "マニュアル", "en": "manual" })
messageBuilderState.setMessage(__filename, "screenCapture", { "ja": "録画ツール", "en": "Record Screen" })
messageBuilderState.setMessage(__filename, "support", { "ja": "支援", "en": "Donation" })
}, [])
messageBuilderState.setMessage(__filename, "github", { ja: "github", en: "github" });
messageBuilderState.setMessage(__filename, "manual", { ja: "マニュアル", en: "manual" });
messageBuilderState.setMessage(__filename, "screenCapture", { ja: "録画ツール", en: "Record Screen" });
messageBuilderState.setMessage(__filename, "support", { ja: "支援", en: "Donation" });
}, []);
const githubLink = useMemo(() => {
return isDesktopApp() ?
(
// @ts-ignore
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer") }}>
<img src="./assets/icons/github.svg" />
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
</span>
)
:
(
<a className="link tooltip" href="https://github.com/w-okada/voice-changer" target="_blank" rel="noopener noreferrer">
<img src="./assets/icons/github.svg" />
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
</a>
)
}, [])
return isDesktopApp() ? (
<span
className="link tooltip"
onClick={() => {
// @ts-ignore
window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer");
}}
>
<img src="./assets/icons/github.svg" />
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
</span>
) : (
<a className="link tooltip" href="https://github.com/w-okada/voice-changer" target="_blank" rel="noopener noreferrer">
<img src="./assets/icons/github.svg" />
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
</a>
);
}, []);
const manualLink = useMemo(() => {
return isDesktopApp() ?
(
// @ts-ignore
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md") }}>
<img src="./assets/icons/help-circle.svg" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
</span>
)
:
(
<a className="link tooltip" href="https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md" target="_blank" rel="noopener noreferrer">
<img src="./assets/icons/help-circle.svg" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
</a>
)
}, [])
return isDesktopApp() ? (
<span
className="link tooltip"
onClick={() => {
// @ts-ignore
window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md");
}}
>
<img src="./assets/icons/help-circle.svg" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
</span>
) : (
<a className="link tooltip" href="https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md" target="_blank" rel="noopener noreferrer">
<img src="./assets/icons/help-circle.svg" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
</a>
);
}, []);
const toolLink = useMemo(() => {
return isDesktopApp() ?
(
<div className="link tooltip">
<img src="./assets/icons/tool.svg" />
<div className="tooltip-text tooltip-text-100px">
<p onClick={() => {
return isDesktopApp() ? (
<div className="link tooltip">
<img src="./assets/icons/tool.svg" />
<div className="tooltip-text tooltip-text-100px">
<p
onClick={() => {
// @ts-ignore
window.electronAPI.openBrowser("https://w-okada.github.io/screen-recorder-ts/")
}}>
{messageBuilderState.getMessage(__filename, "screenCapture")}
</p>
</div>
window.electronAPI.openBrowser("https://w-okada.github.io/screen-recorder-ts/");
}}
>
{messageBuilderState.getMessage(__filename, "screenCapture")}
</p>
</div>
)
:
(
<div className="link tooltip">
<img src="./assets/icons/tool.svg" />
<div className="tooltip-text tooltip-text-100px">
<p onClick={() => {
window.open("https://w-okada.github.io/screen-recorder-ts/", '_blank', "noreferrer")
}}>
{messageBuilderState.getMessage(__filename, "screenCapture")}
</p>
</div>
</div>
) : (
<div className="link tooltip">
<img src="./assets/icons/tool.svg" />
<div className="tooltip-text tooltip-text-100px">
<p
onClick={() => {
window.open("https://w-okada.github.io/screen-recorder-ts/", "_blank", "noreferrer");
}}
>
{messageBuilderState.getMessage(__filename, "screenCapture")}
</p>
</div>
)
}, [])
</div>
);
}, []);
const coffeeLink = useMemo(() => {
return isDesktopApp() ?
(
// @ts-ignore
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad") }}>
<img className="donate-img" src="./assets/buymeacoffee.png" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "support")}</div>
</span>
)
:
(
<a className="link tooltip" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
<img className="donate-img" src="./assets/buymeacoffee.png" />
<div className="tooltip-text tooltip-text-100px">
{messageBuilderState.getMessage(__filename, "support")}
</div>
</a>
)
}, [])
return isDesktopApp() ? (
<span
className="link tooltip"
onClick={() => {
// @ts-ignore
window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad");
}}
>
<img className="donate-img" src="./assets/buymeacoffee.png" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "support")}</div>
</span>
) : (
<a className="link tooltip" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
<img className="donate-img" src="./assets/buymeacoffee.png" />
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "support")}</div>
</a>
);
}, []);
const headerArea = useMemo(() => {
const onClearSettingClicked = async () => {
await clearSetting()
await removeItem(INDEXEDDB_KEY_AUDIO_OUTPUT)
location.reload()
}
await clearSetting();
await removeItem(INDEXEDDB_KEY_AUDIO_OUTPUT);
location.reload();
};
return (
<div className="headerArea">
@ -139,15 +139,16 @@ export const HeaderArea = (props: HeaderAreaProps) => {
{/* {licenseButton} */}
</span>
<span className="belongings">
<div className="belongings-button" onClick={onClearSettingClicked}>clear setting</div>
<div className="belongings-button" onClick={onClearSettingClicked}>
clear setting
</div>
{/* <div className="belongings-button" onClick={onReloadClicked}>reload</div>
<div className="belongings-button" onClick={onReselectVCClicked}>select vc</div> */}
</span>
</div>
</div>
)
}, [props.subTitle, props.mainTitle, appGuiSettingState.version, appGuiSettingState.edition])
);
}, [props.subTitle, props.mainTitle, appGuiSettingState.version, appGuiSettingState.edition]);
return headerArea
return headerArea;
};

View File

@ -3,6 +3,7 @@ import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useGuiState } from "../001_GuiStateProvider";
import { useMessageBuilder } from "../../../hooks/useMessageBuilder";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
export type ModelSlotAreaProps = {};
@ -14,6 +15,7 @@ export type SortTypes = (typeof SortTypes)[keyof typeof SortTypes];
export const ModelSlotArea = (_props: ModelSlotAreaProps) => {
const { serverSetting, getInfo } = useAppState();
const { appGuiSettingState } = useAppRoot();
const guiState = useGuiState();
const messageBuilderState = useMessageBuilder();
const [sortType, setSortType] = useState<SortTypes>("slot");
@ -116,5 +118,9 @@ export const ModelSlotArea = (_props: ModelSlotAreaProps) => {
);
}, [modelTiles, sortType]);
if (appGuiSettingState.edition.indexOf("web") >= 0) {
return <></>;
}
return modelSlotArea;
};

View File

@ -0,0 +1,205 @@
import React, { useEffect, useMemo, useState } from "react";
import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useMessageBuilder } from "../../../hooks/useMessageBuilder";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
export type PortraitProps = {};
const BeatriceSpeakerType = {
male: "male",
female: "female",
} as const;
type BeatriceSpeakerType = (typeof BeatriceSpeakerType)[keyof typeof BeatriceSpeakerType];
// @ts-ignore
import MyIcon from "./female-clickable.svg";
import { useGuiState } from "../001_GuiStateProvider";
export const Portrait = (_props: PortraitProps) => {
const { appGuiSettingState } = useAppRoot();
const { serverSetting, volume, bufferingTime, performance, webInfoState } = useAppState();
const messageBuilderState = useMessageBuilder();
const [beatriceSpeakerType, setBeatriceSpeakerType] = useState<BeatriceSpeakerType>(BeatriceSpeakerType.male);
const [beatriceSpeakerIndexInGender, setBeatriceSpeakerIndexInGender] = useState<string>("");
const { setBeatriceJVSSpeakerId } = useGuiState();
const beatriceMaleSpeakersList = [1, 3, 5, 6, 9, 11, 12, 13, 20, 21, 22, 23, 28, 31, 32, 33, 34, 37, 41, 42, 44, 45, 46, 47, 48, 49, 50, 52, 54, 68, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 86, 87, 88, 89, 97, 98, 99, 100];
const beatriceFemaleSpeakersList = [2, 4, 7, 8, 10, 14, 15, 16, 17, 18, 19, 24, 25, 26, 27, 29, 30, 35, 36, 38, 39, 40, 43, 51, 53, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 72, 82, 83, 84, 85, 90, 91, 92, 93, 94, 95, 96];
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
useMemo(() => {
messageBuilderState.setMessage(__filename, "terms_of_use", { ja: "利用規約", en: "terms of use" });
}, []);
const selected = useMemo(() => {
if (webEdition) {
return webInfoState.webModelslot;
}
if (serverSetting.serverSetting.modelSlotIndex == undefined) {
return;
} else if (serverSetting.serverSetting.modelSlotIndex == "Beatrice-JVS") {
const beatriceJVS = serverSetting.serverSetting.modelSlots.find((v) => v.slotIndex == "Beatrice-JVS");
return beatriceJVS;
} else {
return serverSetting.serverSetting.modelSlots[serverSetting.serverSetting.modelSlotIndex];
}
}, [serverSetting.serverSetting.modelSlotIndex, serverSetting.serverSetting.modelSlots, webEdition]);
useEffect(() => {
const vol = document.getElementById("status-vol") as HTMLSpanElement;
const buf = document.getElementById("status-buf") as HTMLSpanElement;
const res = document.getElementById("status-res") as HTMLSpanElement;
if (!vol || !buf || !res) {
return;
}
vol.innerText = volume.toFixed(4);
buf.innerText = bufferingTime.toString();
res.innerText = performance.responseTime.toString();
}, [volume, bufferingTime, performance]);
const setSelectedClass = () => {
const iframe = document.querySelector(".beatrice-speaker-graph-container");
if (!iframe) {
return;
}
// @ts-ignore
const svgDoc = iframe.contentDocument;
const gElements = svgDoc.getElementsByClassName("beatrice-node-pointer");
for (const gElement of gElements) {
gElement.classList.remove("beatrice-node-pointer-selected");
}
const keys = beatriceSpeakerIndexInGender.split("-");
const id = keys.pop();
const gender = keys.pop();
if (beatriceSpeakerType == gender) {
const selected = svgDoc.getElementById(`beatrice-node-${gender}-${id}`);
selected?.classList.add("beatrice-node-pointer-selected");
}
};
const setBeatriceSpeakerIndex = async (elementId: string) => {
setBeatriceSpeakerIndexInGender(elementId);
const keys = elementId.split("-");
const id = Number(keys.pop());
const gender = keys.pop();
let beatriceSpeakerIndex;
if (gender == "male") {
beatriceSpeakerIndex = beatriceMaleSpeakersList[id];
} else {
beatriceSpeakerIndex = beatriceFemaleSpeakersList[id];
}
setBeatriceJVSSpeakerId(beatriceSpeakerIndex);
};
useEffect(() => {
const iframe = document.querySelector(".beatrice-speaker-graph-container");
if (!iframe) {
return;
}
const setOnClick = () => {
// @ts-ignore
const svgDoc = iframe.contentDocument;
const gElements = svgDoc.getElementsByClassName("beatrice-node-pointer");
const textElements = svgDoc.getElementsByClassName("beatrice-text-pointer");
for (const gElement of gElements) {
gElement.onclick = () => {
setBeatriceSpeakerIndex(gElement.id);
};
}
for (const textElement of textElements) {
textElement.onclick = () => {
setBeatriceSpeakerIndex(textElement.id);
};
}
setSelectedClass();
};
iframe.addEventListener("load", setOnClick);
return () => {
iframe.removeEventListener("load", setOnClick);
};
}, [selected, beatriceSpeakerType]);
useEffect(() => {
setSelectedClass();
}, [selected, beatriceSpeakerType, beatriceSpeakerIndexInGender]);
const portrait = useMemo(() => {
if (!selected) {
return <></>;
}
let portrait;
if (webEdition) {
const icon = selected.iconFile;
portrait = <img className="portrait" src={icon} alt={selected.name} />;
} else if (selected.slotIndex == "Beatrice-JVS") {
const maleButtonClass = beatriceSpeakerType == "male" ? "button-selected" : "button";
const femaleButtonClass = beatriceSpeakerType == "male" ? "button" : "button-selected";
const svgURL = beatriceSpeakerType == "male" ? "./assets/beatrice/male-clickable.svg" : "./assets/beatrice/female-clickable.svg";
portrait = (
<>
<div className="beatrice-portrait-title">
Beatrice <span className="edition">JVS Corpus</span>
</div>
<div className="beatrice-portrait-select">
<div
className={maleButtonClass}
onClick={() => {
setBeatriceSpeakerType(BeatriceSpeakerType.male);
}}
>
male
</div>
<div
className={femaleButtonClass}
onClick={() => {
setBeatriceSpeakerType(BeatriceSpeakerType.female);
}}
>
female
</div>
</div>
{/* <iframe className="beatrice-speaker-graph-container" style={{ width: "20rem", height: "20rem", border: "none" }} src="./assets/beatrice/female-clickable.svg" title="terms_of_use" sandbox="allow-same-origin allow-scripts allow-popups allow-forms"></iframe> */}
<iframe className="beatrice-speaker-graph-container" src={svgURL} title="beatrice JVS Corpus speakers" sandbox="allow-same-origin allow-scripts allow-popups allow-forms"></iframe>
</>
);
} else {
const modelDir = serverSetting.serverSetting.modelSlotIndex == "Beatrice-JVS" ? "model_dir_static" : serverSetting.serverSetting.voiceChangerParams.model_dir;
const icon = selected.iconFile.length > 0 ? modelDir + "/" + selected.slotIndex + "/" + selected.iconFile.split(/[\/\\]/).pop() : "./assets/icons/human.png";
portrait = <img className="portrait" src={icon} alt={selected.name} />;
}
const selectedTermOfUseUrlLink = selected.termsOfUseUrl ? (
<a href={selected.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="portrait-area-terms-of-use-link">
[{messageBuilderState.getMessage(__filename, "terms_of_use")}]
</a>
) : (
<></>
);
return (
<div className="portrait-area">
<div className="portrait-container">
{portrait}
<div className="portrait-area-status">
<p>
<span className="portrait-area-status-vctype">{selected.voiceChangerType}</span>
</p>
<p>
vol: <span id="status-vol">0</span>
</p>
<p>
buf: <span id="status-buf">0</span> ms
</p>
<p>
res: <span id="status-res">0</span> ms
</p>
</div>
<div className="portrait-area-terms-of-use">{selectedTermOfUseUrlLink}</div>
</div>
</div>
);
}, [selected, beatriceSpeakerType]);
return portrait;
};

View File

@ -1,10 +1,12 @@
import React, { useMemo } from "react";
import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useGuiState } from "../001_GuiStateProvider";
export type TuningAreaProps = {};
export const TuningArea = (_props: TuningAreaProps) => {
const { serverSetting } = useAppState();
const { beatriceJVSSpeakerId, setBeatriceJVSSpeakerPitch, beatriceJVSSpeakerPitch } = useGuiState();
const selected = useMemo(() => {
if (serverSetting.serverSetting.modelSlotIndex == undefined) {
@ -25,6 +27,36 @@ export const TuningArea = (_props: TuningAreaProps) => {
return <></>;
}
// For Beatrice
if (selected.slotIndex == "Beatrice-JVS") {
const updateBeatriceJVSSpeakerPitch = async (pitch: number) => {
setBeatriceJVSSpeakerPitch(pitch);
};
return (
<div className="character-area-control">
<div className="character-area-control-title">TUNE:</div>
<div className="character-area-control-field">
<div className="character-area-slider-control">
<span className="character-area-slider-control-kind"></span>
<span className="character-area-slider-control-slider">
<input
type="range"
min="-2"
max="2"
step="1"
value={beatriceJVSSpeakerPitch}
onChange={(e) => {
updateBeatriceJVSSpeakerPitch(Number(e.target.value));
}}
></input>
</span>
<span className="character-area-slider-control-val">{beatriceJVSSpeakerPitch}</span>
</div>
</div>
</div>
);
}
const currentTuning = serverSetting.serverSetting.tran;
const tranValueUpdatedAction = async (val: number) => {
await serverSetting.updateServerSettings({ ...serverSetting.serverSetting, tran: val });

View File

@ -64,6 +64,9 @@ export const SpeakerArea = (_props: SpeakerAreaProps) => {
if (!selected) {
return <></>;
}
if (selected.slotIndex == "Beatrice-JVS") {
return; // beatrice JVS は変換先話者をグラフから選択するので、ここでは表示しない
}
const options = Object.keys(selected.speakers).map((key) => {
const val = selected.speakers[Number(key)];
@ -80,7 +83,7 @@ export const SpeakerArea = (_props: SpeakerAreaProps) => {
return (
<div className="character-area-control">
<div className="character-area-control-title">{selected.voiceChangerType == "DDSP-SVC" || selected.voiceChangerType == "so-vits-svc-40" || selected.voiceChangerType == "RVC" || selected.voiceChangerType == "Beatrice" ? "Voice:" : ""}</div>
<div className="character-area-control-title">{selected.voiceChangerType == "DDSP-SVC" || selected.voiceChangerType == "so-vits-svc-40" || selected.voiceChangerType == "RVC" ? "Voice:" : ""}</div>
<div className="character-area-control-field">
<div className="character-area-slider-control">
<span className="character-area-slider-control-kind">{selected.voiceChangerType == "MMVCv13" || selected.voiceChangerType == "MMVCv15" ? "dst" : ""}</span>

View File

@ -10,22 +10,28 @@ import { F0FactorArea } from "./101-4_F0FactorArea";
import { SoVitsSVC40SettingArea } from "./101-5_so-vits-svc40SettingArea";
import { DDSPSVC30SettingArea } from "./101-6_ddsp-svc30SettingArea";
import { DiffusionSVCSettingArea } from "./101-7_diffusion-svcSettingArea";
import { Portrait } from "./101-0_Portrait";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
export type CharacterAreaProps = {};
export const CharacterArea = (_props: CharacterAreaProps) => {
const { serverSetting, initializedRef, volume, bufferingTime, performance, setting, setVoiceChangerClientSetting, start, stop } = useAppState();
const { appGuiSettingState } = useAppRoot();
const { serverSetting, initializedRef, volume, bufferingTime, performance, setting, setVoiceChangerClientSetting, start, stop, webInfoState } = useAppState();
const guiState = useGuiState();
const messageBuilderState = useMessageBuilder();
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
const { beatriceJVSSpeakerId } = useGuiState();
useMemo(() => {
messageBuilderState.setMessage(__filename, "terms_of_use", { ja: "利用規約", en: "terms of use" });
messageBuilderState.setMessage(__filename, "export_to_onnx", { ja: "onnx出力", en: "export to onnx" });
messageBuilderState.setMessage(__filename, "save_default", { ja: "設定保存", en: "save setting" });
messageBuilderState.setMessage(__filename, "alert_onnx", { ja: "ボイチェン中はonnx出力できません", en: "cannot export onnx when voice conversion is enabled" });
}, []);
const selected = useMemo(() => {
if (webEdition) {
return webInfoState.webModelslot;
}
if (serverSetting.serverSetting.modelSlotIndex == undefined) {
return;
} else if (serverSetting.serverSetting.modelSlotIndex == "Beatrice-JVS") {
@ -34,58 +40,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
} else {
return serverSetting.serverSetting.modelSlots[serverSetting.serverSetting.modelSlotIndex];
}
}, [serverSetting.serverSetting.modelSlotIndex, serverSetting.serverSetting.modelSlots]);
useEffect(() => {
const vol = document.getElementById("status-vol") as HTMLSpanElement;
const buf = document.getElementById("status-buf") as HTMLSpanElement;
const res = document.getElementById("status-res") as HTMLSpanElement;
if (!vol || !buf || !res) {
return;
}
vol.innerText = volume.toFixed(4);
buf.innerText = bufferingTime.toString();
res.innerText = performance.responseTime.toString();
}, [volume, bufferingTime, performance]);
const portrait = useMemo(() => {
if (!selected) {
return <></>;
}
const modelDir = serverSetting.serverSetting.modelSlotIndex == "Beatrice-JVS" ? "model_dir_static" : serverSetting.serverSetting.voiceChangerParams.model_dir;
const icon = selected.iconFile.length > 0 ? modelDir + "/" + selected.slotIndex + "/" + selected.iconFile.split(/[\/\\]/).pop() : "./assets/icons/human.png";
const selectedTermOfUseUrlLink = selected.termsOfUseUrl ? (
<a href={selected.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="portrait-area-terms-of-use-link">
[{messageBuilderState.getMessage(__filename, "terms_of_use")}]
</a>
) : (
<></>
);
return (
<div className="portrait-area">
<div className="portrait-container">
<img className="portrait" src={icon} alt={selected.name} />
<div className="portrait-area-status">
<p>
<span className="portrait-area-status-vctype">{selected.voiceChangerType}</span>
</p>
<p>
vol: <span id="status-vol">0</span>
</p>
<p>
buf: <span id="status-buf">0</span> ms
</p>
<p>
res: <span id="status-res">0</span> ms
</p>
</div>
<div className="portrait-area-terms-of-use">{selectedTermOfUseUrlLink}</div>
</div>
</div>
);
}, [selected]);
}, [serverSetting.serverSetting.modelSlotIndex, serverSetting.serverSetting.modelSlots, webEdition]);
const [startWithAudioContextCreate, setStartWithAudioContextCreate] = useState<boolean>(false);
useEffect(() => {
@ -96,6 +51,22 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
start();
}, [startWithAudioContextCreate]);
const nameArea = useMemo(() => {
if (!selected) {
return <></>;
}
return (
<div className="character-area-control">
<div className="character-area-control-title">Name:</div>
<div className="character-area-control-field">
<div className="character-area-text">
{selected.name} {selected.slotIndex == "Beatrice-JVS" ? `speaker:${beatriceJVSSpeakerId}` : ""}
</div>
</div>
</div>
);
}, [selected, beatriceJVSSpeakerId]);
const startControl = useMemo(() => {
const onStartClicked = async () => {
if (serverSetting.serverSetting.enableServerAudio == 0) {
@ -143,22 +114,37 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
const stopClassName = guiState.isConverting ? "character-area-control-button-stanby" : "character-area-control-button-active";
const passThruClassName = serverSetting.serverSetting.passThrough == false ? "character-area-control-passthru-button-stanby" : "character-area-control-passthru-button-active blinking";
console.log("serverSetting.serverSetting.passThrough", passThruClassName, serverSetting.serverSetting.passThrough);
return (
<div className="character-area-control">
<div className="character-area-control-buttons">
<div onClick={onStartClicked} className={startClassName}>
start
</div>
<div onClick={onStopClicked} className={stopClassName}>
stop
</div>
<div onClick={onPassThroughClicked} className={passThruClassName}>
passthru
if (webEdition && webInfoState.webModelLoadingState != "ready") {
return (
<div className="character-area-control">
<div className="character-area-control-title">wait...</div>
<div className="character-area-control-field">
<div className="character-area-text blink">{webInfoState.webModelLoadingState}..</div>
<div className="character-area-text">
pre:{Math.floor(webInfoState.progressLoadPreprocess * 100)}%, model: {Math.floor(webInfoState.progressLoadVCModel * 100)}%
</div>
</div>
</div>
</div>
);
}, [guiState.isConverting, start, stop, serverSetting.serverSetting, serverSetting.updateServerSettings]);
);
} else {
return (
<div className="character-area-control">
<div className="character-area-control-buttons">
<div onClick={onStartClicked} className={startClassName}>
start
</div>
<div onClick={onStopClicked} className={stopClassName}>
stop
</div>
<div onClick={onPassThroughClicked} className={passThruClassName}>
passthru
</div>
</div>
</div>
);
}
}, [guiState.isConverting, start, stop, serverSetting.serverSetting, serverSetting.updateServerSettings, webInfoState.progressLoadPreprocess, webInfoState.progressLoadVCModel, webInfoState.webModelLoadingState]);
const gainControl = useMemo(() => {
const currentInputGain = serverSetting.serverSetting.enableServerAudio == 0 ? setting.voiceChangerClientSetting.inputGain : serverSetting.serverSetting.serverInputAudioGain;
@ -275,8 +261,9 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
const characterArea = useMemo(() => {
return (
<div className="character-area">
{portrait}
<Portrait></Portrait>
<div className="character-area-control-area">
{nameArea}
{startControl}
{gainControl}
<TuningArea />
@ -290,7 +277,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
</div>
</div>
);
}, [portrait, startControl, gainControl, modelSlotControl]);
}, [startControl, gainControl, modelSlotControl]);
return characterArea;
};

View File

@ -11,6 +11,7 @@ export const QualityArea = (props: QualityAreaProps) => {
const { setVoiceChangerClientSetting, serverSetting, setting } = useAppState();
const { appGuiSettingState } = useAppRoot();
const edition = appGuiSettingState.edition;
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
const qualityArea = useMemo(() => {
if (!serverSetting.updateServerSettings || !setVoiceChangerClientSetting || !serverSetting.serverSetting || !setting) {
@ -47,6 +48,52 @@ export const QualityArea = (props: QualityAreaProps) => {
};
const f0DetOptions = generateF0DetOptions();
const f0Det = webEdition ? (
<></>
) : (
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">F0 Det.:</div>
<div className="config-sub-area-control-field">
<select
className="body-select"
value={serverSetting.serverSetting.f0Detector}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, f0Detector: e.target.value as F0Detector });
}}
>
{f0DetOptions}
</select>
</div>
</div>
);
const threshold = webEdition ? (
<></>
) : (
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">S.Thresh.:</div>
<div className="config-sub-area-control-field">
<div className="config-sub-area-slider-control">
<span className="config-sub-area-slider-control-kind"></span>
<span className="config-sub-area-slider-control-slider">
<input
type="range"
className="config-sub-area-slider-control-slider"
min="0.00000"
max="0.001"
step="0.00001"
value={serverSetting.serverSetting.silentThreshold || 0}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, silentThreshold: Number(e.target.value) });
}}
></input>
</span>
<span className="config-sub-area-slider-control-val">{serverSetting.serverSetting.silentThreshold}</span>
</div>
</div>
</div>
);
return (
<div className="config-sub-area">
<div className="config-sub-area-control">
@ -101,42 +148,8 @@ export const QualityArea = (props: QualityAreaProps) => {
</div>
</div>
</div>
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">F0 Det.:</div>
<div className="config-sub-area-control-field">
<select
className="body-select"
value={serverSetting.serverSetting.f0Detector}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, f0Detector: e.target.value as F0Detector });
}}
>
{f0DetOptions}
</select>
</div>
</div>
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">S.Thresh.:</div>
<div className="config-sub-area-control-field">
<div className="config-sub-area-slider-control">
<span className="config-sub-area-slider-control-kind"></span>
<span className="config-sub-area-slider-control-slider">
<input
type="range"
className="config-sub-area-slider-control-slider"
min="0.00000"
max="0.001"
step="0.00001"
value={serverSetting.serverSetting.silentThreshold || 0}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, silentThreshold: Number(e.target.value) });
}}
></input>
</span>
<span className="config-sub-area-slider-control-val">{serverSetting.serverSetting.silentThreshold}</span>
</div>
</div>
</div>
{f0Det}
{threshold}
</div>
);
}, [serverSetting.serverSetting, setting, serverSetting.updateServerSettings, setVoiceChangerClientSetting]);

View File

@ -10,6 +10,8 @@ export const ConvertArea = (props: ConvertProps) => {
const { setting, serverSetting, setWorkletNodeSetting, trancateBuffer } = useAppState();
const { appGuiSettingState } = useAppRoot();
const edition = appGuiSettingState.edition;
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
const convertArea = useMemo(() => {
let nums: number[];
if (!props.inputChunkNums) {
@ -110,6 +112,8 @@ export const ConvertArea = (props: ConvertProps) => {
</div>
</div>
</>
) : webEdition ? (
<></>
) : (
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">GPU:</div>
@ -133,6 +137,32 @@ export const ConvertArea = (props: ConvertProps) => {
</div>
</div>
);
const extraArea = webEdition ? (
<></>
) : (
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">EXTRA:</div>
<div className="config-sub-area-control-field">
<select
className="body-select"
value={serverSetting.serverSetting.extraConvertSize}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, extraConvertSize: Number(e.target.value) });
trancateBuffer();
}}
>
{[1024 * 4, 1024 * 8, 1024 * 16, 1024 * 32, 1024 * 64, 1024 * 128].map((x) => {
return (
<option key={x} value={x}>
{x}
</option>
);
})}
</select>
</div>
</div>
);
return (
<div className="config-sub-area">
<div className="config-sub-area-control">
@ -157,27 +187,7 @@ export const ConvertArea = (props: ConvertProps) => {
</select>
</div>
</div>
<div className="config-sub-area-control">
<div className="config-sub-area-control-title">EXTRA:</div>
<div className="config-sub-area-control-field">
<select
className="body-select"
value={serverSetting.serverSetting.extraConvertSize}
onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, extraConvertSize: Number(e.target.value) });
trancateBuffer();
}}
>
{[1024 * 4, 1024 * 8, 1024 * 16, 1024 * 32, 1024 * 64, 1024 * 128].map((x) => {
return (
<option key={x} value={x}>
{x}
</option>
);
})}
</select>
</div>
</div>
{extraArea}
{gpuSelect}
</div>
);

View File

@ -2,16 +2,21 @@ import React, { useMemo, useState } from "react";
import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useGuiState } from "../001_GuiStateProvider";
import { AUDIO_ELEMENT_FOR_SAMPLING_INPUT, AUDIO_ELEMENT_FOR_SAMPLING_OUTPUT } from "../../../const";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
export type RecorderAreaProps = {};
export const RecorderArea = (_props: RecorderAreaProps) => {
const { serverSetting } = useAppState();
const { audioOutputForAnalyzer, setAudioOutputForAnalyzer, outputAudioDeviceInfo } = useGuiState();
const [serverIORecording, setServerIORecording] = useState<boolean>(false);
const { appGuiSettingState } = useAppRoot();
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
const serverIORecorderRow = useMemo(() => {
if (webEdition) {
return <> </>;
}
const onServerIORecordStartClicked = async () => {
setServerIORecording(true);
await serverSetting.updateServerSettings({ ...serverSetting.serverSetting, recordIO: 1 });

View File

@ -1,10 +1,13 @@
import React, { useMemo } from "react";
import { useGuiState } from "../001_GuiStateProvider";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
export type MoreActionAreaProps = {};
export const MoreActionArea = (_props: MoreActionAreaProps) => {
const { stateControls } = useGuiState();
const { appGuiSettingState } = useAppRoot();
const webEdition = appGuiSettingState.edition.indexOf("web") >= 0;
const serverIORecorderRow = useMemo(() => {
const onOpenMergeLabClicked = () => {
@ -44,5 +47,9 @@ export const MoreActionArea = (_props: MoreActionAreaProps) => {
);
}, [stateControls]);
return <div className="config-sub-area">{serverIORecorderRow}</div>;
if (webEdition) {
return <> </>;
} else {
return <div className="config-sub-area">{serverIORecorderRow}</div>;
}
};

View File

@ -1321,7 +1321,7 @@ body {
background: rgba(100, 100, 100, 0.5);
color: white;
position: absolute;
paddig: 2px;
padding: 2px;
font-size: 0.7rem;
right: 5px;
bottom: 5px;
@ -1402,6 +1402,9 @@ body {
display: flex;
flex-direction: column;
.character-area-text {
font-size: 0.9rem;
}
.character-area-slider-control {
display: flex;
flex-direction: row;
@ -1831,3 +1834,62 @@ audio::-webkit-media-controls-overlay-enclosure{
opacity: 0.5;
}
}
.blink {
animation: blinking 0.8s ease-in-out infinite alternate;
}
@keyframes blinking {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.beatrice-portrait-title {
font-size: 1rem;
font-weight: 700;
color: #333;
text-shadow: 0 0 2px #333;
text-align: center;
.edition {
font-size: 0.6rem;
}
}
.beatrice-portrait-select {
display: flex;
justify-content: center;
.button {
/* border: solid 2px #999; */
color: #615454;
font-weight: 700;
font-size: 0.8rem;
border-radius: 2px;
background: #adafad;
cursor: pointer;
padding: 0px 5px 0px 5px;
margin: 0px 5px 0px 5px;
line-height: 140%;
height: 1.1rem;
}
.button-selected {
/* border: solid 2px #999; */
color: #615454;
font-weight: 700;
font-size: 0.8rem;
border-radius: 2px;
background: #62b574;
cursor: pointer;
padding: 0px 5px 0px 5px;
margin: 0px 5px 0px 5px;
line-height: 140%;
height: 1.1rem;
}
}
.beatrice-speaker-graph-container {
width: 20rem;
height: 19rem;
border: none;
}

View File

@ -34,6 +34,7 @@ module.exports = {
use: ["style-loader", { loader: "css-loader", options: { importLoaders: 1 } }, "postcss-loader"],
},
{ test: /\.json$/, type: "asset/inline" },
{ test: /\.svg$/, type: "asset/resource" },
],
},
output: {
@ -56,9 +57,9 @@ module.exports = {
}),
// ダミーファイルコピー
new CopyPlugin({
patterns: [{ from: "public/assets/gui_settings/edition_web.txt", to: "assets/gui_settings/edition.txt" }],
}),
// new CopyPlugin({ //コピーの順番で上のassetのコピーで上書きされることがあるようだ。⇒npmスクリプトで対処。
// patterns: [{ from: "public/assets/gui_settings/edition_web.txt", to: "assets/gui_settings/edition.txt" }],
// }),
// new CopyPlugin({ // 拡張子なしのファイルコピーはできないようだ。⇒npmスクリプトで対処。
// patterns: [{ from: "public/info_web.txt", to: "info" }],
// }),
@ -103,5 +104,8 @@ module.exports = {
new CopyPlugin({
patterns: [{ from: "public/models/rvcv1_amitaro_v1_40k_nof0_24000.bin", to: "models/rvcv1_amitaro_v1_40k_nof0_24000.bin" }],
}),
new CopyPlugin({
patterns: [{ from: "public/models/amitaro.png", to: "models/amitaro.png" }],
}),
],
};

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@dannadori/voice-changer-client-js",
"version": "1.0.176",
"version": "1.0.177",
"description": "",
"main": "dist/index.js",
"directories": {
@ -28,27 +28,27 @@
"devDependencies": {
"@types/audioworklet": "^0.0.50",
"@types/jest": "^29.5.8",
"@types/node": "^20.9.0",
"@types/node": "^20.9.2",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
"eslint": "^8.53.0",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-webpack-plugin": "^4.0.1",
"jest": "^29.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"raw-loader": "^4.0.2",
"rimraf": "^5.0.5",
"ts-loader": "^9.5.0",
"ts-loader": "^9.5.1",
"typescript": "^5.2.2",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"dependencies": {
"@types/readable-stream": "^4.0.5",
"@types/readable-stream": "^4.0.6",
"amazon-chime-sdk-js": "^3.18.2",
"buffer": "^6.0.3",
"localforage": "^1.10.0",

View File

@ -12,6 +12,7 @@ export const VoiceChangerType = {
"Diffusion-SVC": "Diffusion-SVC",
Beatrice: "Beatrice",
LLVC: "LLVC",
WebModel: "WebModel",
} as const;
export type VoiceChangerType = (typeof VoiceChangerType)[keyof typeof VoiceChangerType];
@ -307,7 +308,15 @@ export type LLVCModelSlot = ModelSlot & {
speakers: { [key: number]: string };
};
export type ModelSlotUnion = RVCModelSlot | MMVCv13ModelSlot | MMVCv15ModelSlot | SoVitsSvc40ModelSlot | DDSPSVCModelSlot | DiffusionSVCModelSlot | BeatriceModelSlot | LLVCModelSlot;
export type WebModelSlot = ModelSlot & {
modelFile: string;
defaultTune: number;
modelType: RVCModelType;
f0: boolean;
samplingRate: number;
};
export type ModelSlotUnion = RVCModelSlot | MMVCv13ModelSlot | MMVCv15ModelSlot | SoVitsSvc40ModelSlot | DDSPSVCModelSlot | DiffusionSVCModelSlot | BeatriceModelSlot | LLVCModelSlot | WebModelSlot;
type ServerAudioDevice = {
kind: "audioinput" | "audiooutput";

View File

@ -44,6 +44,14 @@ class MMVC_SocketIOApp:
"filename": f"{getFrontendPath()}/ort-wasm-simd.wasm",
"content_type": "application/wasm",
},
"/assets/beatrice/female-clickable.svg": {
"filename": f"{getFrontendPath()}/assets/beatrice/female-clickable.svg",
"content_type": "image/svg+xml",
},
"/assets/beatrice/male-clickable.svg": {
"filename": f"{getFrontendPath()}/assets/beatrice/male-clickable.svg",
"content_type": "image/svg+xml",
},
"": f"{getFrontendPath()}",
"/": f"{getFrontendPath()}/index.html",
},