package main
import (
"fmt"
"log"
"net/http"
"os/exec"
"os"
"io/ioutil"
"runtime"
"path"
"crypto/md5"
"encoding/hex"
)
func currentSourcePath() string {
_, filename, _, _ := runtime.Caller(1)
return path.Dir(filename)
}
func storagePath() string {
return currentSourcePath() + "\\..\\audio_data";
}
func storageFilePath(sapiId string) string {
return currentSourcePath() + "\\..\\audio_data\\" + sapiId
}
func getVoicesInfo() string {
cmd := exec.Command("CScript", "//nologo", currentSourcePath() + "\\sapi_voices.js")
output, _ := cmd.Output()
return string(output)
}
func md5Hash(text string) string {
hasher := md5.New()
hasher.Write([]byte(text))
return hex.EncodeToString(hasher.Sum(nil))
}
func createWaveWithSapi(message string, voiceIndex string, sapiId string) bool {
// create message txt
err := ioutil.WriteFile(storageFilePath(sapiId) + ".txt", []byte(message), os.ModePerm)
if err != nil {
// err handle
log.Print("file output error, is there permission?")
return false
}
// create wave
cmd := exec.Command("CScript", "//nologo", currentSourcePath() +"\\create_sapi.js", storageFilePath(sapiId), voiceIndex);
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
return true
}
func isExist(filename string) bool {
_, err := os.Stat(filename)
return err == nil
}
func sapiHandle(w http.ResponseWriter, r *http.Request) {
message := r.FormValue("message")
voiceIndex := r.FormValue("voice_index")
if message == "" || voiceIndex == "" {
w.WriteHeader(401)
fmt.Fprintf(w, "{\"error\":\"required params missing\"}")
return
}
sapiId := md5Hash(voiceIndex + message)
if !isExist(storageFilePath(sapiId) + ".wav") {
success := createWaveWithSapi(message, voiceIndex, sapiId)
if !success {
w.WriteHeader(500)
fmt.Fprintf(w, "{\"error\":\"unable to create wave file\"}")
return
}
}
http.ServeFile(w, r, storageFilePath(sapiId) + ".wav")
}
func voicesHandle(w http.ResponseWriter, r *http.Request) {
data := getVoicesInfo()
fmt.Fprintf(w, data)
}
func indexHandle(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, currentSourcePath() + "\\index.html")
}
func initialize() {
fmt.Println("start init")
currentVoices := getVoicesInfo()
// load prevoius voices
fmt.Println("load previous voices")
fi, fierr := os.Open("voices.json")
defer fi.Close()
previousVoices := ""
if fierr != nil {
fmt.Println("previous voices not detected")
}else{
fmt.Println("previous voices loaded")
buf := make([]byte, 1024)
fi.Read(buf)
previousVoices = string(buf)
}
// compare voices
if previousVoices != currentVoices {
fmt.Println("current voices chagned, clear caches")
// clear caches if voices updated
err := os.RemoveAll(storagePath())
if err != nil {
panic(err)
}
err = os.Mkdir(storagePath(), 077)
if err != nil {
panic(err)
}
}
// update latest voices
fmt.Println("update voices")
fo, err := os.Create("voices.json")
if err != nil {
panic(err)
}
defer fo.Close()
fo.WriteString(getVoicesInfo())
}
func main(){
initialize()
http.HandleFunc("/sapi/create", sapiHandle)
http.HandleFunc("/sapi/voices", voicesHandle)
http.HandleFunc("/", indexHandle)
if err := http.ListenAndServe(":9081", nil); err != nil {
log.Fatal("ListenAndServe ", err)
}
}