Nik Afiq 5238298b55
Some checks failed
CI / test (push) Successful in 6s
CI / build-ai-gateway (push) Failing after 28s
CI / build-ha-gateway (push) Failing after 24s
CI / build-discord-bot (push) Failing after 29s
Add TTS model components and inference server
- Implemented core model components in `modules.py` including various convolutional layers and normalization techniques.
- Added transformation functions in `transforms.py` for piecewise rational quadratic transformations.
- Created utility functions in `utils.py` for checkpoint management, logging, and hyperparameter handling.
- Introduced monotonic alignment functionality with Cython optimization in `monotonic_align`.
- Developed a minimal inference server in `server.py` to handle synthesis requests.
- Updated requirements to include necessary dependencies for Cython and scipy.
2026-07-24 22:38:36 +09:00

131 lines
3.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package jtalk
import (
"reflect"
"testing"
)
func TestIsJapaneseChar(t *testing.T) {
tests := []struct {
name string
r rune
want bool
}{
{"ascii letter", 'a', true},
{"ascii digit", '5', true},
{"hiragana", 'お', true},
{"katakana", 'ー', true}, // U+30FC, within ぀-ヿ
{"kanji", '様', true},
{"iteration mark", '々', true},
{"fullwidth digit 1-9", '', true},
{"fullwidth digit 0 excluded (quirk in the original regex)", '', false},
{"fullwidth letter", '', true},
{"halfwidth katakana", 'ヲ', true},
{"japanese comma is a mark, not a char", '、', false},
{"japanese period is a mark", '。', false},
{"ascii punctuation is a mark", '!', false},
{"space is a mark", ' ', false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isJapaneseChar(tt.r); got != tt.want {
t.Errorf("isJapaneseChar(%q) = %v, want %v", tt.r, got, tt.want)
}
})
}
}
func TestSplitByMarks(t *testing.T) {
tests := []struct {
name string
text string
wantSpans []string
wantMarks []rune
}{
{
name: "no marks",
text: "おはよう",
wantSpans: []string{"おはよう"},
wantMarks: nil,
},
{
name: "one internal mark",
text: "おにー様、すきです",
wantSpans: []string{"おにー様", "すきです"},
wantMarks: []rune{'、'},
},
{
name: "consecutive marks produce an empty span between them",
text: "すごい!!すごい",
wantSpans: []string{"すごい", "", "すごい"},
wantMarks: []rune{'!', '!'},
},
{
name: "trailing mark leaves an empty final span",
text: "ありがとう。",
wantSpans: []string{"ありがとう", ""},
wantMarks: []rune{'。'},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotSpans, gotMarks := splitByMarks(tt.text)
if !reflect.DeepEqual(gotSpans, tt.wantSpans) {
t.Errorf("splitByMarks() spans = %#v, want %#v", gotSpans, tt.wantSpans)
}
if !reflect.DeepEqual(gotMarks, tt.wantMarks) {
t.Errorf("splitByMarks() marks = %#v, want %#v", gotMarks, tt.wantMarks)
}
})
}
}
func TestMarkToASCII(t *testing.T) {
tests := []struct {
r rune
want string
}{
{'、', ","},
{'。', "."},
{'', "!"},
{'!', "!"}, // ASCII passthrough
{'(', "("}, // ASCII passthrough
{'鳥', ""}, // unmapped non-ASCII rune falls back to empty, not a guess
}
for _, tt := range tests {
if got := markToASCII(tt.r); got != tt.want {
t.Errorf("markToASCII(%q) = %q, want %q", tt.r, got, tt.want)
}
}
}
func TestParseOutputLabelPhonemes(t *testing.T) {
t.Run("strips boundary sil and ignores content after the section", func(t *testing.T) {
raw := "[Text analysis result]\n" +
"some,morphological,analysis,-1\n" +
"\n[Output label]\n" +
"0 100 xx^xx-sil+o=n/A:xx+xx+xx\n" +
"100 200 xx^sil-o+n=i/A:0+1+5\n" +
"200 300 sil^o-n+i=i/A:1+2+4\n" +
"300 400 o^n-i+sil=xx/A:1+2+4\n" +
"\n[Global parameter]\n" +
"Some parameter -> value+with+plusses\n"
got, err := parseOutputLabelPhonemes(raw)
if err != nil {
t.Fatalf("parseOutputLabelPhonemes() error = %v", err)
}
want := []string{"o", "n", "i"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("parseOutputLabelPhonemes() = %#v, want %#v (must not include [Global parameter] content)", got, want)
}
})
t.Run("missing section returns an error", func(t *testing.T) {
_, err := parseOutputLabelPhonemes("no label section here")
if err == nil {
t.Fatal("parseOutputLabelPhonemes() error = nil, want non-nil")
}
})
}