mirror of
https://github.com/fumiama/ahsai.git
synced 2026-06-04 23:30:24 +08:00
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
// Package ahsai AH Soft フリーテキスト音声合成 demo API
|
|
package ahsai
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
const api = "https://cloud.ai-j.jp/demo/aitalk2webapi_nop.php?callback=callback&speaker_id=%d&text=%s&ext=ogg&volume=%.1f&speed=%.1f&pitch=%.1f&range=%.1f&anger=%.1f&sadness=%.1f&joy=%.1f&_=%d"
|
|
|
|
var (
|
|
speakers = map[string]uint32{
|
|
"琴葉葵": 551,
|
|
"琴葉茜": 552,
|
|
"紲星あかり": 554,
|
|
"吉田くん": 1201,
|
|
"東北ずん子": 1202,
|
|
"月読アイ": 1203,
|
|
"月読ショウタ": 1204,
|
|
"民安ともえ": 1205,
|
|
"結月ゆかり": 1206,
|
|
"水奈瀬コウ": 1207,
|
|
"京町セイカ": 1208,
|
|
"東北きりたん": 1209,
|
|
"桜乃そら": 1210,
|
|
"東北イタコ": 1211,
|
|
"ついなちゃん標準語": 1212,
|
|
"ついなちゃん関西弁": 1213,
|
|
"伊織弓鶴": 1214,
|
|
"音街ウナ": 2006,
|
|
}
|
|
)
|
|
|
|
// Speaker is a particular setting of the API
|
|
type Speaker struct {
|
|
id uint32
|
|
Volume, Speed, Pitch, Range, Anger, Sadness, Joy float32
|
|
}
|
|
|
|
// NewSpeaker init default para of a speaker.
|
|
// Use s.SetName() to set the real speaker.
|
|
func NewSpeaker() (s Speaker) {
|
|
s.Volume = 1
|
|
s.Speed = 1
|
|
s.Pitch = 1
|
|
s.Range = 1
|
|
return
|
|
}
|
|
|
|
var (
|
|
// ErrTextTooLong 文本超过 100 字
|
|
ErrTextTooLong = errors.New("text too long")
|
|
// ErrNoSuchSpeaker 查无此人
|
|
ErrNoSuchSpeaker = errors.New("no such speaker")
|
|
)
|
|
|
|
// SetName set the speaker id.
|
|
func (s *Speaker) SetName(name string) error {
|
|
id, ok := speakers[name]
|
|
if !ok {
|
|
return ErrNoSuchSpeaker
|
|
}
|
|
s.id = id
|
|
return nil
|
|
}
|
|
|
|
// Speak text, return ogg url
|
|
func (s *Speaker) Speak(text string) (string, error) {
|
|
if len([]rune(text)) > 100 {
|
|
return "", ErrTextTooLong
|
|
}
|
|
resp, err := http.Get(fmt.Sprintf(api, s.id, url.QueryEscape(text), s.Volume, s.Speed, s.Pitch, s.Range, s.Anger, s.Sadness, s.Joy, time.Now().UnixMilli()))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
data = bytes.TrimPrefix(data, []byte(`callback({"url":"`))
|
|
data = bytes.TrimSuffix(data, []byte(`"})`))
|
|
data = bytes.ReplaceAll(data, []byte(`\/`), []byte(`/`))
|
|
return "https:" + string(data), nil
|
|
}
|