alphacep / vosk-api

Offline speech recognition API for Android, iOS, Raspberry Pi and servers with Python, Java, C# and Node
Apache License 2.0
7.36k stars 1.04k forks source link

Go wrapper result structs #1517

Open gregtzar opened 4 months ago

gregtzar commented 4 months ago

Hey there devs... I'm working on a project which uses the golang bindings in this library, and I had to build a mapping layer between the json strings and golang structs so that I could use the structs in my go program. This could easily be built into your go bindings, so that an existing wrapper func like func (r *VoskRecognizer) Result() string could return a go struct rather than a json string. That would be a contract change to the wrapper func signatures, and maybe you are keeping those signatures as close to the original c library as you can on purpose.

I would be happy to submit a PR to enhance the go bindings. Would you be interested in this? Which strategy would you prefer?:

  1. Change the signatures on your original go wrapper funcs.
  2. Create an alternate set of "formatted" wrapper funcs with different names, so for example in addition to the original func (r *VoskRecognizer) Result() string we would create func (r *VoskRecognizer) ResultFmt() *ResultSet which would perform the additional operation of unmarshaling the json into the ResultSet struct and return that instead. These could simply decorate/wrap the original wrapper funcs.
  3. Create a separate set of mapping functions which you could pass the json string result and get back the string unmarshalled into the structs. Their use would be optional.

If we went with option one they could still obtain a json response should they want one. The struct would simply be the transport type but they could easily marshall back into the original json if they wanted since the structs retain the tag names.

Also in go if you do want to pass around a raw json string it is recommended to use the json.RawMessage type instead of string.

Mapping layer example:

type ResultSet struct {
    Result []Result `json:"result"`
    Text   string   `json:"text"`
}

type Result struct {
    Conf  float64 `json:"conf"`
    End   float64 `json:"end"`
    Start float64 `json:"start"`
    Word  string  `json:"word"`
}

func MapResult(result string) (*ResultSet, error) {
    res := ResultSet{}
    if err := json.Unmarshal([]byte(result), &res); err != nil {
        return nil, err
    }
    return &res, nil
}

func main() {

    ...

    if res, err := MapResult(rec.FinalResult()); err != nil {
        log.Fatalf("failed map result: %v", err)
    } else {
        fmt.Printf("%+v\n", res)
    }
}

// &{Result:[{Conf:0.801859 End:6.69 Start:6.24 Word:zero} {Conf:1 End:6.9 Start:6.69 Word:one} {Conf:1 End:7.11 Start:6.93 Word:eight} {Conf:1 End:7.5 Start:7.11 Word:zero} {Conf:1 End:7.98 Start:7.5 Word:three}] Text:zero one eight zero three}