├── proto └── build.sh ├── README.md ├── cmd └── hello │ ├── oauth.go │ └── main.go ├── LICENSE └── google.golang.org └── genproto └── googleapis └── assistant └── embedded └── v1alpha1 └── embedded_assistant.pb.go /proto/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pushd $(dirname "$0") 3 | protoc -I. -I./googleapis -I$GOPATH/src --go_out=plugins=grpc:.. googleapis/google/assistant/embedded/v1alpha1/embedded_assistant.proto 4 | popd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OK Google - Fun with the Google Assistant SDK + Go 2 | 3 | ## Usage 4 | 5 | You first need to have a Google Cloud Platform project 6 | [Follow the steps](https://developers.google.com/assistant/sdk/prototype/getting-started-other-platforms/config-dev-project-and-account) to configure a Google API Console Project and a Google Account to use with the Google Assistant SDK. 7 | 8 | Download the client_secret_XXXXX.json file from the [Google API Console Project credentials section](https://console.developers.google.com/apis/credentials) and store it wherever you want. 9 | 10 | Run `cmd/hello/main.go -creds=` to start the Google Assistant. 11 | 12 | 13 | ## gRPC bindings 14 | 15 | The gRPC bindings were generated from the v1 alpha proto file vendored 16 | in the proto folder (in this repo). 17 | The source is available https://github.com/googleapis/googleapis 18 | and if/when the proto file will need updating, updating the vendored folder 19 | and regenerating the bindings will be needed. 20 | 21 | * You need to have gRPC setup on your machine 22 | * Update the googleapis proto files from the github repo 23 | * run `proto/build.sh` 24 | 25 | You will notice that the go binding file: `google.golang.org/genproto/googleapis/assistant/embedded/v1alpha1/embedded_assistant.pb.go` was updated to reflect the proto file changes. 26 | 27 | That's it! -------------------------------------------------------------------------------- /cmd/hello/oauth.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "log" 9 | "net/http" 10 | "os" 11 | "os/exec" 12 | "runtime" 13 | 14 | "golang.org/x/oauth2" 15 | ) 16 | 17 | var ( 18 | oauthToken *oauth2.Token 19 | gcp *gcpAuthWrapper 20 | oauthSrv *http.Server 21 | oauthRedirectURL = "http://localhost:8080" 22 | oauthTokenFilename = "oauthTokenCache" 23 | ) 24 | 25 | type JSONToken struct { 26 | Installed struct { 27 | ClientID string `json:"client_id"` 28 | ProjectID string `json:"project_id"` 29 | AuthURI string `json:"auth_uri"` 30 | TokenURI string `json:"token_uri"` 31 | AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"` 32 | ClientSecret string `json:"client_secret"` 33 | RedirectUris []string `json:"redirect_uris"` 34 | } `json:"installed"` 35 | } 36 | 37 | type gcpAuthWrapper struct { 38 | Conf *oauth2.Config 39 | } 40 | 41 | func (w *gcpAuthWrapper) Start() { 42 | f, err := os.Open(*flagCredentialsPath) 43 | if err != nil { 44 | panic(err) 45 | } 46 | defer f.Close() 47 | var token JSONToken 48 | if err = json.NewDecoder(f).Decode(&token); err != nil { 49 | log.Println("failed to decode json token", err) 50 | panic(err) 51 | } 52 | 53 | w.Conf = &oauth2.Config{ 54 | ClientID: token.Installed.ClientID, 55 | ClientSecret: token.Installed.ClientSecret, 56 | Scopes: []string{"https://www.googleapis.com/auth/assistant-sdk-prototype"}, 57 | RedirectURL: oauthRedirectURL, 58 | Endpoint: oauth2.Endpoint{ 59 | AuthURL: "https://accounts.google.com/o/oauth2/auth", 60 | TokenURL: "https://accounts.google.com/o/oauth2/token", 61 | }, 62 | } 63 | 64 | if *flagForceLogout { 65 | fmt.Println("Deleting potential oauth cache") 66 | os.Remove(oauthTokenFilename) 67 | } 68 | 69 | // check if we have an oauth file on disk 70 | if hasCachedOauth() { 71 | err = loadTokenSource() 72 | if err == nil { 73 | fmt.Println("Launching the Google Assistant using cached credentials") 74 | return 75 | } 76 | fmt.Println("Failed to load the token source", err) 77 | fmt.Println("Continuing program without cached credentials") 78 | } 79 | 80 | // Redirect user to consent page to ask for permission 81 | // for the scopes specified above. 82 | url := w.Conf.AuthCodeURL("state", oauth2.AccessTypeOffline) 83 | 84 | if runtime.GOOS != "darwin" { 85 | fmt.Printf("Copy and paste the following url into your browser to authenticate:\n%s\n", url) 86 | } else { 87 | cmd := exec.Command("open", url) 88 | cmd.Run() 89 | } 90 | // if we are using the builtin auth server locally 91 | if *flagRemoteAccess { 92 | // remote access 93 | reader := bufio.NewReader(os.Stdin) 94 | fmt.Println("Enter the auth code followed by enter") 95 | permissionCode, _ := reader.ReadString('\n') 96 | setTokenSource(permissionCode) 97 | } else { 98 | // Start the server to receive the code 99 | oauthSrv = &http.Server{Addr: ":8080", Handler: http.DefaultServeMux} 100 | http.HandleFunc("/", oauthHandler) 101 | err = oauthSrv.ListenAndServe() 102 | if err != http.ErrServerClosed { 103 | log.Fatalf("listen: %s\n", err) 104 | } 105 | } 106 | fmt.Println("Launching the Google Assistant") 107 | } 108 | 109 | func oauthHandler(w http.ResponseWriter, r *http.Request) { 110 | permissionCode := r.URL.Query().Get("code") 111 | // TODO: check the status code 112 | w.Write([]byte(fmt.Sprintf("

Your code is: %s

", permissionCode))) 113 | setTokenSource(permissionCode) 114 | // kill the http server 115 | oauthSrv.Shutdown(context.Background()) 116 | } 117 | 118 | func hasCachedOauth() bool { 119 | if _, err := os.Stat(oauthTokenFilename); os.IsNotExist(err) { 120 | return false 121 | } 122 | return true 123 | } 124 | 125 | func setTokenSource(permissionCode string) { 126 | var err error 127 | ctx := context.Background() 128 | oauthToken, err = gcp.Conf.Exchange(ctx, permissionCode) 129 | if err != nil { 130 | fmt.Println("failed to retrieve the oauth2 token") 131 | log.Fatal(err) 132 | } 133 | fmt.Println(oauthToken) 134 | of, err := os.Create(oauthTokenFilename) 135 | if err != nil { 136 | panic(err) 137 | } 138 | defer of.Close() 139 | if err = json.NewEncoder(of).Encode(oauthToken); err != nil { 140 | log.Println("Something went wrong when storing the token source", err) 141 | panic(err) 142 | } 143 | } 144 | 145 | // type StoredSourceToken struct { 146 | // SToken *oauth2.Token 147 | // } 148 | 149 | // func (t *StoredSourceToken) Token() (*oauth2.Token, error) { 150 | // return t.SToken, nil 151 | // } 152 | 153 | func loadTokenSource() error { 154 | f, err := os.Open(oauthTokenFilename) 155 | if err != nil { 156 | return fmt.Errorf("failed to load the token source (deleted from disk) %v", err) 157 | } 158 | defer f.Close() 159 | var token oauth2.Token 160 | if err = json.NewDecoder(f).Decode(&token); err != nil { 161 | return err 162 | } 163 | oauthToken = &token 164 | // tokenSource = &StoredSourceToken{SToken: &token} 165 | return nil 166 | } 167 | -------------------------------------------------------------------------------- /cmd/hello/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "encoding/binary" 8 | "fmt" 9 | "io" 10 | "log" 11 | "os" 12 | "time" 13 | 14 | "flag" 15 | 16 | "github.com/gordonklaus/portaudio" 17 | embedded "github.com/mattetti/ok-go/google.golang.org/genproto/googleapis/assistant/embedded/v1alpha1" 18 | "google.golang.org/api/option" 19 | "google.golang.org/api/transport" 20 | "google.golang.org/grpc" 21 | ) 22 | 23 | var ( 24 | // Debug allows the caller to see more debug print messages. 25 | Debug bool 26 | // keep the state in memory to advance the conversation. 27 | conversationState []byte 28 | canceler context.CancelFunc 29 | bgCtx = context.Background() 30 | 31 | flagCredentialsPath = flag.String("creds", os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"), "path to the credentials file") 32 | flagRemoteAccess = flag.Bool("remote", false, "is the machine running the program accessed remotely (via SSH for instance)") 33 | flagForceLogout = flag.Bool("logout", false, "should the current user be logged out") 34 | ) 35 | 36 | func main() { 37 | flag.Parse() 38 | if *flagCredentialsPath == "" { 39 | fmt.Println("you need to provide a path to your credentials or set GOOGLE_APPLICATION_CREDENTIALS") 40 | os.Exit(1) 41 | } 42 | if *flagRemoteAccess { 43 | oauthRedirectURL = "urn:ietf:wg:oauth:2.0:oob" 44 | } 45 | // connect to the audio drivers 46 | portaudio.Initialize() 47 | defer portaudio.Terminate() 48 | 49 | gcp = &gcpAuthWrapper{} 50 | gcp.Start() 51 | 52 | start() 53 | } 54 | 55 | func newConn(ctx context.Context) (conn *grpc.ClientConn, err error) { 56 | tokenSource := gcp.Conf.TokenSource(ctx, oauthToken) 57 | return transport.DialGRPC(ctx, 58 | option.WithTokenSource(tokenSource), 59 | option.WithEndpoint("embeddedassistant.googleapis.com:443"), 60 | option.WithScopes("https://www.googleapis.com/auth/assistant-sdk-prototype"), 61 | ) 62 | } 63 | 64 | func askTheUser() { 65 | fmt.Println("Press enter when ready to speak") 66 | reader := bufio.NewReader(os.Stdin) 67 | reader.ReadLine() 68 | 69 | start() 70 | fmt.Println() 71 | } 72 | 73 | func start() { 74 | var ( 75 | ctx context.Context 76 | conn *grpc.ClientConn 77 | err error 78 | ) 79 | micStopCh := make(chan bool) 80 | 81 | stop := func(quit bool) { 82 | micStopCh <- true 83 | ctx.Done() 84 | canceler() 85 | if quit { 86 | os.Exit(0) 87 | } 88 | askTheUser() 89 | } 90 | 91 | runDuration := 240 * time.Second 92 | ctx, canceler = context.WithDeadline(bgCtx, time.Now().Add(runDuration)) 93 | conn, err = newConn(ctx) 94 | if err != nil { 95 | log.Println("failed to acquire connection", err) 96 | return 97 | } 98 | defer conn.Close() 99 | 100 | assistant := embedded.NewEmbeddedAssistantClient(conn) 101 | config := &embedded.ConverseRequest_Config{ 102 | Config: &embedded.ConverseConfig{ 103 | AudioInConfig: &embedded.AudioInConfig{ 104 | Encoding: embedded.AudioInConfig_LINEAR16, 105 | SampleRateHertz: 16000, 106 | }, 107 | AudioOutConfig: &embedded.AudioOutConfig{ 108 | Encoding: embedded.AudioOutConfig_LINEAR16, 109 | SampleRateHertz: 16000, 110 | VolumePercentage: 60, 111 | }, 112 | }, 113 | } 114 | if len(conversationState) > 0 { 115 | log.Println("continuing conversation") 116 | config.Config.ConverseState = &embedded.ConverseState{ConversationState: conversationState} 117 | } 118 | conversation, err := assistant.Converse(ctx) 119 | if err != nil { 120 | log.Println("failed to setup the conversation", err) 121 | stop(false) 122 | os.Exit(1) 123 | } 124 | 125 | err = conversation.Send(&embedded.ConverseRequest{ 126 | ConverseRequest: config, 127 | }) 128 | if err != nil { 129 | fmt.Println("failed to connect to Google Assistant", err) 130 | stop(false) 131 | os.Exit(1) 132 | } 133 | 134 | // TODO: write to file. 135 | 136 | // listening in the background 137 | go func() { 138 | bufIn := make([]int16, 8196) 139 | var bufWriter bytes.Buffer 140 | micstream, err := portaudio.OpenDefaultStream(1, 0, 16000, len(bufIn), bufIn) 141 | if err != nil { 142 | log.Println("failed to connect to the set the default stream", err) 143 | stop(false) 144 | panic(err) 145 | } 146 | defer micstream.Close() 147 | 148 | if err = micstream.Start(); err != nil { 149 | log.Println("failed to connect to the input stream", err) 150 | stop(false) 151 | panic(err) 152 | } 153 | for { 154 | bufWriter.Reset() 155 | if err := micstream.Read(); err != nil { 156 | log.Println("failed to connect to read from the default stream", err) 157 | stop(false) 158 | panic(err) 159 | } 160 | binary.Write(&bufWriter, binary.LittleEndian, bufIn) 161 | 162 | err = conversation.Send(&embedded.ConverseRequest{ 163 | ConverseRequest: &embedded.ConverseRequest_AudioIn{ 164 | AudioIn: bufWriter.Bytes(), 165 | }, 166 | }) 167 | 168 | if err != nil { 169 | log.Printf("Could not send audio: %v", err) 170 | } 171 | select { 172 | case <-micStopCh: 173 | log.Println("turning off the mic") 174 | conversation.CloseSend() 175 | if err = micstream.Stop(); err != nil { 176 | log.Println("failed to stop the input") 177 | } 178 | return 179 | default: 180 | } 181 | if Debug { 182 | fmt.Print(".") 183 | } 184 | } 185 | }() 186 | 187 | // audio out 188 | bufOut := make([]int16, 799) 189 | 190 | // h, err := portaudio.DefaultHostApi() 191 | // p := portaudio.LowLatencyParameters(nil, h.DefaultOutputDevice) 192 | // p.Input.Channels = 1 193 | // p.Output.Channels = 1 194 | // bus := &audioBus{buffer: make([]int16, 1600)} 195 | // bus.Stream, err = portaudio.OpenStream(p, bus.processAudio) 196 | // defer bus.Stop() 197 | // if err := bus.Start(); err != nil { 198 | // log.Println("Failed to start audioport -", err) 199 | // } 200 | 201 | // var bufWriter bytes.Buffer 202 | streamOut, err := portaudio.OpenDefaultStream(0, 1, 16000, len(bufOut), &bufOut) 203 | defer func() { 204 | if err := streamOut.Close(); err != nil { 205 | log.Println("failed to close the stream", err) 206 | } 207 | log.Println("stream closed") 208 | }() 209 | if err = streamOut.Start(); err != nil { 210 | log.Println("failed to start audio out") 211 | panic(err) 212 | } 213 | 214 | fmt.Println("Listening") 215 | // outF, err := os.Create("audioOut.mp3") 216 | // if err != nil { 217 | // panic(err) 218 | // } 219 | // defer outF.Close() 220 | // waiting for google assistant response 221 | for { 222 | resp, err := conversation.Recv() 223 | if err == io.EOF { 224 | log.Println("we are done!!!!") 225 | // micStopCh <- true 226 | askTheUser() 227 | // stop(false) 228 | break 229 | } 230 | if err != nil { 231 | log.Fatalf("Cannot get a response from the assistant: %v", err) 232 | continue 233 | } 234 | result := resp.GetResult() 235 | 236 | // log.Println("result from Google Assistant") 237 | // log.Printf("%#v\n", result) 238 | if transcript := result.GetSpokenRequestText(); transcript != "" { 239 | log.Printf("Transcript of what you said: %s\n", transcript) 240 | if transcript == "quit" || transcript == "exit" { 241 | log.Println("Got it, see you later!") 242 | stop(true) 243 | return 244 | } 245 | } 246 | // if msg := result.GetSpokenResponseText(); msg != "" { 247 | // log.Printf("Response from the Assistant %s\n", msg) 248 | // } 249 | 250 | // handle the conversation state so the next connection can resume our dialog 251 | if result != nil && result.ConversationState != nil { 252 | log.Println("storing conversation state") 253 | conversationState = result.ConversationState 254 | } 255 | if resp.GetEventType() == embedded.ConverseResponse_END_OF_UTTERANCE { 256 | log.Println("Google said you are done, are you?!") 257 | micStopCh <- true 258 | // askTheUser() 259 | // return 260 | } 261 | audioOut := resp.GetAudioOut() 262 | if audioOut != nil { 263 | log.Printf("audio out from the assistant (%d bytes)\n", len(audioOut.AudioData)) 264 | 265 | // write to disk 266 | // outF.Write(audioOut.AudioData) 267 | 268 | signal := bytes.NewBuffer(audioOut.AudioData) 269 | var err error 270 | // var buffedSize int 271 | for err == nil { 272 | // tmpBuf := make([]int16, len(audioOut.AudioData)/2-1) 273 | err = binary.Read(signal, binary.LittleEndian, bufOut) 274 | if err != nil { 275 | // log.Println(err) 276 | break 277 | } 278 | 279 | // fmt.Println(len(bufOut), bufOut[:16]) 280 | // TODO: append the signal to a buffer that we read from in processAudio 281 | // if buffedSize >= 1600 { 282 | // log.Println("Writing to the audio card") 283 | if portErr := streamOut.Write(); portErr != nil { 284 | log.Println("Failed to write to audio out", err) 285 | } 286 | // } 287 | 288 | // if err != nil && (err != io.EOF || err != io.ErrUnexpectedEOF) { 289 | // log.Println("failed to read audio out", err) 290 | // streamOut.Write() 291 | // break 292 | // } 293 | // if portErr := streamOut.Write(); portErr != nil { 294 | // log.Println("Failed to write to audio out", err) 295 | // // break 296 | // } 297 | } 298 | } 299 | micMode := result.GetMicrophoneMode() 300 | switch micMode { 301 | case embedded.ConverseResult_CLOSE_MICROPHONE: 302 | log.Println("microphone closed") 303 | // stop(false) 304 | // return 305 | case embedded.ConverseResult_DIALOG_FOLLOW_ON: 306 | log.Println("continuing dialog") 307 | case embedded.ConverseResult_MICROPHONE_MODE_UNSPECIFIED: 308 | default: 309 | log.Println("unmanaged microphone mode", micMode) 310 | // stop(false) 311 | // return 312 | } 313 | if err := resp.GetError(); err != nil { 314 | log.Fatalf("Received error from the assistant: %v", err) 315 | // continue 316 | } 317 | } 318 | 319 | } 320 | 321 | type audioBus struct { 322 | *portaudio.Stream 323 | buffer []int16 324 | i int 325 | } 326 | 327 | func (b *audioBus) processAudio(in, out []int16) { 328 | // fmt.Println(len(out)) 329 | // for i := range out { 330 | // out[i] = .7 * b.buffer[b.i] 331 | // b.buffer[b.i] = in[i] 332 | // b.i = (b.i + 1) % len(b.buffer) 333 | // } 334 | } 335 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /google.golang.org/genproto/googleapis/assistant/embedded/v1alpha1/embedded_assistant.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: googleapis/google/assistant/embedded/v1alpha1/embedded_assistant.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package embedded is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | googleapis/google/assistant/embedded/v1alpha1/embedded_assistant.proto 10 | 11 | It has these top-level messages: 12 | ConverseConfig 13 | AudioInConfig 14 | AudioOutConfig 15 | ConverseState 16 | AudioOut 17 | ConverseResult 18 | ConverseRequest 19 | ConverseResponse 20 | */ 21 | package embedded 22 | 23 | import proto "github.com/golang/protobuf/proto" 24 | import fmt "fmt" 25 | import math "math" 26 | import _ "google.golang.org/genproto/googleapis/api/annotations" 27 | import google_rpc "google.golang.org/genproto/googleapis/rpc/status" 28 | 29 | import ( 30 | context "golang.org/x/net/context" 31 | grpc "google.golang.org/grpc" 32 | ) 33 | 34 | // Reference imports to suppress errors if they are not otherwise used. 35 | var _ = proto.Marshal 36 | var _ = fmt.Errorf 37 | var _ = math.Inf 38 | 39 | // This is a compile-time assertion to ensure that this generated file 40 | // is compatible with the proto package it is being compiled against. 41 | // A compilation error at this line likely means your copy of the 42 | // proto package needs to be updated. 43 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 44 | 45 | // Audio encoding of the data sent in the audio message. 46 | // Audio must be one-channel (mono). The only language supported is "en-US". 47 | type AudioInConfig_Encoding int32 48 | 49 | const ( 50 | // Not specified. Will return result [google.rpc.Code.INVALID_ARGUMENT][]. 51 | AudioInConfig_ENCODING_UNSPECIFIED AudioInConfig_Encoding = 0 52 | // Uncompressed 16-bit signed little-endian samples (Linear PCM). 53 | // This encoding includes no header, only the raw audio bytes. 54 | AudioInConfig_LINEAR16 AudioInConfig_Encoding = 1 55 | // [`FLAC`](https://xiph.org/flac/documentation.html) (Free Lossless Audio 56 | // Codec) is the recommended encoding because it is 57 | // lossless--therefore recognition is not compromised--and 58 | // requires only about half the bandwidth of `LINEAR16`. This encoding 59 | // includes the `FLAC` stream header followed by audio data. It supports 60 | // 16-bit and 24-bit samples, however, not all fields in `STREAMINFO` are 61 | // supported. 62 | AudioInConfig_FLAC AudioInConfig_Encoding = 2 63 | ) 64 | 65 | var AudioInConfig_Encoding_name = map[int32]string{ 66 | 0: "ENCODING_UNSPECIFIED", 67 | 1: "LINEAR16", 68 | 2: "FLAC", 69 | } 70 | var AudioInConfig_Encoding_value = map[string]int32{ 71 | "ENCODING_UNSPECIFIED": 0, 72 | "LINEAR16": 1, 73 | "FLAC": 2, 74 | } 75 | 76 | func (x AudioInConfig_Encoding) String() string { 77 | return proto.EnumName(AudioInConfig_Encoding_name, int32(x)) 78 | } 79 | func (AudioInConfig_Encoding) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1, 0} } 80 | 81 | // Audio encoding of the data returned in the audio message. All encodings are 82 | // raw audio bytes with no header, except as indicated below. 83 | type AudioOutConfig_Encoding int32 84 | 85 | const ( 86 | // Not specified. Will return result [google.rpc.Code.INVALID_ARGUMENT][]. 87 | AudioOutConfig_ENCODING_UNSPECIFIED AudioOutConfig_Encoding = 0 88 | // Uncompressed 16-bit signed little-endian samples (Linear PCM). 89 | AudioOutConfig_LINEAR16 AudioOutConfig_Encoding = 1 90 | // MP3 audio encoding. The sample rate is encoded in the payload. 91 | AudioOutConfig_MP3 AudioOutConfig_Encoding = 2 92 | // Opus-encoded audio wrapped in an ogg container. The result will be a 93 | // file which can be played natively on Android and in some browsers (such 94 | // as Chrome). The quality of the encoding is considerably higher than MP3 95 | // while using the same bitrate. The sample rate is encoded in the payload. 96 | AudioOutConfig_OPUS_IN_OGG AudioOutConfig_Encoding = 3 97 | ) 98 | 99 | var AudioOutConfig_Encoding_name = map[int32]string{ 100 | 0: "ENCODING_UNSPECIFIED", 101 | 1: "LINEAR16", 102 | 2: "MP3", 103 | 3: "OPUS_IN_OGG", 104 | } 105 | var AudioOutConfig_Encoding_value = map[string]int32{ 106 | "ENCODING_UNSPECIFIED": 0, 107 | "LINEAR16": 1, 108 | "MP3": 2, 109 | "OPUS_IN_OGG": 3, 110 | } 111 | 112 | func (x AudioOutConfig_Encoding) String() string { 113 | return proto.EnumName(AudioOutConfig_Encoding_name, int32(x)) 114 | } 115 | func (AudioOutConfig_Encoding) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } 116 | 117 | // Possible states of the microphone after a `Converse` RPC completes. 118 | type ConverseResult_MicrophoneMode int32 119 | 120 | const ( 121 | // No mode specified. 122 | ConverseResult_MICROPHONE_MODE_UNSPECIFIED ConverseResult_MicrophoneMode = 0 123 | // The service is not expecting a follow-on question from the user. 124 | // The microphone should remain off until the user re-activates it. 125 | ConverseResult_CLOSE_MICROPHONE ConverseResult_MicrophoneMode = 1 126 | // The service is expecting a follow-on question from the user. The 127 | // microphone should be re-opened when the `AudioOut` playback completes 128 | // (by starting a new `Converse` RPC call to send the new audio). 129 | ConverseResult_DIALOG_FOLLOW_ON ConverseResult_MicrophoneMode = 2 130 | ) 131 | 132 | var ConverseResult_MicrophoneMode_name = map[int32]string{ 133 | 0: "MICROPHONE_MODE_UNSPECIFIED", 134 | 1: "CLOSE_MICROPHONE", 135 | 2: "DIALOG_FOLLOW_ON", 136 | } 137 | var ConverseResult_MicrophoneMode_value = map[string]int32{ 138 | "MICROPHONE_MODE_UNSPECIFIED": 0, 139 | "CLOSE_MICROPHONE": 1, 140 | "DIALOG_FOLLOW_ON": 2, 141 | } 142 | 143 | func (x ConverseResult_MicrophoneMode) String() string { 144 | return proto.EnumName(ConverseResult_MicrophoneMode_name, int32(x)) 145 | } 146 | func (ConverseResult_MicrophoneMode) EnumDescriptor() ([]byte, []int) { 147 | return fileDescriptor0, []int{5, 0} 148 | } 149 | 150 | // Indicates the type of event. 151 | type ConverseResponse_EventType int32 152 | 153 | const ( 154 | // No event specified. 155 | ConverseResponse_EVENT_TYPE_UNSPECIFIED ConverseResponse_EventType = 0 156 | // This event indicates that the server has detected the end of the user's 157 | // speech utterance and expects no additional speech. Therefore, the server 158 | // will not process additional audio (although it may subsequently return 159 | // additional results). The client should stop sending additional audio 160 | // data, half-close the gRPC connection, and wait for any additional results 161 | // until the server closes the gRPC connection. 162 | ConverseResponse_END_OF_UTTERANCE ConverseResponse_EventType = 1 163 | ) 164 | 165 | var ConverseResponse_EventType_name = map[int32]string{ 166 | 0: "EVENT_TYPE_UNSPECIFIED", 167 | 1: "END_OF_UTTERANCE", 168 | } 169 | var ConverseResponse_EventType_value = map[string]int32{ 170 | "EVENT_TYPE_UNSPECIFIED": 0, 171 | "END_OF_UTTERANCE": 1, 172 | } 173 | 174 | func (x ConverseResponse_EventType) String() string { 175 | return proto.EnumName(ConverseResponse_EventType_name, int32(x)) 176 | } 177 | func (ConverseResponse_EventType) EnumDescriptor() ([]byte, []int) { 178 | return fileDescriptor0, []int{7, 0} 179 | } 180 | 181 | // Specifies how to process the `ConverseRequest` messages. 182 | type ConverseConfig struct { 183 | // *Required* Specifies how to process the subsequent incoming audio. 184 | AudioInConfig *AudioInConfig `protobuf:"bytes,1,opt,name=audio_in_config,json=audioInConfig" json:"audio_in_config,omitempty"` 185 | // *Required* Specifies how to format the audio that will be returned. 186 | AudioOutConfig *AudioOutConfig `protobuf:"bytes,2,opt,name=audio_out_config,json=audioOutConfig" json:"audio_out_config,omitempty"` 187 | // *Required* Represents the current dialog state. 188 | ConverseState *ConverseState `protobuf:"bytes,3,opt,name=converse_state,json=converseState" json:"converse_state,omitempty"` 189 | } 190 | 191 | func (m *ConverseConfig) Reset() { *m = ConverseConfig{} } 192 | func (m *ConverseConfig) String() string { return proto.CompactTextString(m) } 193 | func (*ConverseConfig) ProtoMessage() {} 194 | func (*ConverseConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 195 | 196 | func (m *ConverseConfig) GetAudioInConfig() *AudioInConfig { 197 | if m != nil { 198 | return m.AudioInConfig 199 | } 200 | return nil 201 | } 202 | 203 | func (m *ConverseConfig) GetAudioOutConfig() *AudioOutConfig { 204 | if m != nil { 205 | return m.AudioOutConfig 206 | } 207 | return nil 208 | } 209 | 210 | func (m *ConverseConfig) GetConverseState() *ConverseState { 211 | if m != nil { 212 | return m.ConverseState 213 | } 214 | return nil 215 | } 216 | 217 | // Specifies how to process the `audio_in` data that will be provided in 218 | // subsequent requests. For recommended settings, see the Google Assistant SDK 219 | // [best practices](https://developers.google.com/assistant/best-practices). 220 | type AudioInConfig struct { 221 | // *Required* Encoding of audio data sent in all `audio_in` messages. 222 | Encoding AudioInConfig_Encoding `protobuf:"varint,1,opt,name=encoding,enum=google.assistant.embedded.v1alpha1.AudioInConfig_Encoding" json:"encoding,omitempty"` 223 | // *Required* Sample rate (in Hertz) of the audio data sent in all `audio_in` 224 | // messages. Valid values are from 16000-24000, but 16000 is optimal. 225 | // For best results, set the sampling rate of the audio source to 16000 Hz. 226 | // If that's not possible, use the native sample rate of the audio source 227 | // (instead of re-sampling). 228 | SampleRateHertz int32 `protobuf:"varint,2,opt,name=sample_rate_hertz,json=sampleRateHertz" json:"sample_rate_hertz,omitempty"` 229 | } 230 | 231 | func (m *AudioInConfig) Reset() { *m = AudioInConfig{} } 232 | func (m *AudioInConfig) String() string { return proto.CompactTextString(m) } 233 | func (*AudioInConfig) ProtoMessage() {} 234 | func (*AudioInConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 235 | 236 | func (m *AudioInConfig) GetEncoding() AudioInConfig_Encoding { 237 | if m != nil { 238 | return m.Encoding 239 | } 240 | return AudioInConfig_ENCODING_UNSPECIFIED 241 | } 242 | 243 | func (m *AudioInConfig) GetSampleRateHertz() int32 { 244 | if m != nil { 245 | return m.SampleRateHertz 246 | } 247 | return 0 248 | } 249 | 250 | // Specifies the desired format for the server to use when it returns 251 | // `audio_out` messages. 252 | type AudioOutConfig struct { 253 | // *Required* The encoding of audio data to be returned in all `audio_out` 254 | // messages. 255 | Encoding AudioOutConfig_Encoding `protobuf:"varint,1,opt,name=encoding,enum=google.assistant.embedded.v1alpha1.AudioOutConfig_Encoding" json:"encoding,omitempty"` 256 | // *Required* The sample rate in Hertz of the audio data returned in 257 | // `audio_out` messages. Valid values are: 16000-24000. 258 | SampleRateHertz int32 `protobuf:"varint,2,opt,name=sample_rate_hertz,json=sampleRateHertz" json:"sample_rate_hertz,omitempty"` 259 | // *Required* Current volume setting of the device's audio output. 260 | // Valid values are 1 to 100 (corresponding to 1% to 100%). 261 | VolumePercentage int32 `protobuf:"varint,3,opt,name=volume_percentage,json=volumePercentage" json:"volume_percentage,omitempty"` 262 | } 263 | 264 | func (m *AudioOutConfig) Reset() { *m = AudioOutConfig{} } 265 | func (m *AudioOutConfig) String() string { return proto.CompactTextString(m) } 266 | func (*AudioOutConfig) ProtoMessage() {} 267 | func (*AudioOutConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } 268 | 269 | func (m *AudioOutConfig) GetEncoding() AudioOutConfig_Encoding { 270 | if m != nil { 271 | return m.Encoding 272 | } 273 | return AudioOutConfig_ENCODING_UNSPECIFIED 274 | } 275 | 276 | func (m *AudioOutConfig) GetSampleRateHertz() int32 { 277 | if m != nil { 278 | return m.SampleRateHertz 279 | } 280 | return 0 281 | } 282 | 283 | func (m *AudioOutConfig) GetVolumePercentage() int32 { 284 | if m != nil { 285 | return m.VolumePercentage 286 | } 287 | return 0 288 | } 289 | 290 | // Provides information about the current dialog state. 291 | type ConverseState struct { 292 | // *Required* The `conversation_state` value returned in the prior 293 | // `ConverseResponse`. Omit (do not set the field) if there was no prior 294 | // `ConverseResponse`. If there was a prior `ConverseResponse`, do not omit 295 | // this field; doing so will end that conversation (and this new request will 296 | // start a new conversation). 297 | ConversationState []byte `protobuf:"bytes,1,opt,name=conversation_state,json=conversationState,proto3" json:"conversation_state,omitempty"` 298 | } 299 | 300 | func (m *ConverseState) Reset() { *m = ConverseState{} } 301 | func (m *ConverseState) String() string { return proto.CompactTextString(m) } 302 | func (*ConverseState) ProtoMessage() {} 303 | func (*ConverseState) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } 304 | 305 | func (m *ConverseState) GetConversationState() []byte { 306 | if m != nil { 307 | return m.ConversationState 308 | } 309 | return nil 310 | } 311 | 312 | // The audio containing the assistant's response to the query. Sequential chunks 313 | // of audio data are received in sequential `ConverseResponse` messages. 314 | type AudioOut struct { 315 | // *Output-only* The audio data containing the assistant's response to the 316 | // query. Sequential chunks of audio data are received in sequential 317 | // `ConverseResponse` messages. 318 | AudioData []byte `protobuf:"bytes,1,opt,name=audio_data,json=audioData,proto3" json:"audio_data,omitempty"` 319 | } 320 | 321 | func (m *AudioOut) Reset() { *m = AudioOut{} } 322 | func (m *AudioOut) String() string { return proto.CompactTextString(m) } 323 | func (*AudioOut) ProtoMessage() {} 324 | func (*AudioOut) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } 325 | 326 | func (m *AudioOut) GetAudioData() []byte { 327 | if m != nil { 328 | return m.AudioData 329 | } 330 | return nil 331 | } 332 | 333 | // The semantic result for the user's spoken query. 334 | type ConverseResult struct { 335 | // *Output-only* The recognized transcript of what the user said. 336 | SpokenRequestText string `protobuf:"bytes,1,opt,name=spoken_request_text,json=spokenRequestText" json:"spoken_request_text,omitempty"` 337 | // *Output-only* The text of the assistant's spoken response. This is only 338 | // returned for an IFTTT action. 339 | SpokenResponseText string `protobuf:"bytes,2,opt,name=spoken_response_text,json=spokenResponseText" json:"spoken_response_text,omitempty"` 340 | // *Output-only* State information for subsequent `ConverseRequest`. This 341 | // value should be saved in the client and returned in the 342 | // `conversation_state` with the next `ConverseRequest`. (The client does not 343 | // need to interpret or otherwise use this value.) There is no need to save 344 | // this information across device restarts. 345 | ConversationState []byte `protobuf:"bytes,3,opt,name=conversation_state,json=conversationState,proto3" json:"conversation_state,omitempty"` 346 | // *Output-only* Specifies the mode of the microphone after this `Converse` 347 | // RPC is processed. 348 | MicrophoneMode ConverseResult_MicrophoneMode `protobuf:"varint,4,opt,name=microphone_mode,json=microphoneMode,enum=google.assistant.embedded.v1alpha1.ConverseResult_MicrophoneMode" json:"microphone_mode,omitempty"` 349 | // *Output-only* Updated volume level. The value will be 0 or omitted 350 | // (indicating no change) unless a voice command such as "Increase the volume" 351 | // or "Set volume level 4" was recognized, in which case the value will be 352 | // between 1 and 100 (corresponding to the new volume level of 1% to 100%). 353 | // Typically, a client should use this volume level when playing the 354 | // `audio_out` data, and retain this value as the current volume level and 355 | // supply it in the `AudioOutConfig` of the next `ConverseRequest`. (Some 356 | // clients may also implement other ways to allow the current volume level to 357 | // be changed, for example, by providing a knob that the user can turn.) 358 | VolumePercentage int32 `protobuf:"varint,5,opt,name=volume_percentage,json=volumePercentage" json:"volume_percentage,omitempty"` 359 | } 360 | 361 | func (m *ConverseResult) Reset() { *m = ConverseResult{} } 362 | func (m *ConverseResult) String() string { return proto.CompactTextString(m) } 363 | func (*ConverseResult) ProtoMessage() {} 364 | func (*ConverseResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } 365 | 366 | func (m *ConverseResult) GetSpokenRequestText() string { 367 | if m != nil { 368 | return m.SpokenRequestText 369 | } 370 | return "" 371 | } 372 | 373 | func (m *ConverseResult) GetSpokenResponseText() string { 374 | if m != nil { 375 | return m.SpokenResponseText 376 | } 377 | return "" 378 | } 379 | 380 | func (m *ConverseResult) GetConversationState() []byte { 381 | if m != nil { 382 | return m.ConversationState 383 | } 384 | return nil 385 | } 386 | 387 | func (m *ConverseResult) GetMicrophoneMode() ConverseResult_MicrophoneMode { 388 | if m != nil { 389 | return m.MicrophoneMode 390 | } 391 | return ConverseResult_MICROPHONE_MODE_UNSPECIFIED 392 | } 393 | 394 | func (m *ConverseResult) GetVolumePercentage() int32 { 395 | if m != nil { 396 | return m.VolumePercentage 397 | } 398 | return 0 399 | } 400 | 401 | // The top-level message sent by the client. Clients must send at least two, and 402 | // typically numerous `ConverseRequest` messages. The first message must 403 | // contain a `config` message and must not contain `audio_in` data. All 404 | // subsequent messages must contain `audio_in` data and must not contain a 405 | // `config` message. 406 | type ConverseRequest struct { 407 | // Exactly one of these fields must be specified in each `ConverseRequest`. 408 | // 409 | // Types that are valid to be assigned to ConverseRequest: 410 | // *ConverseRequest_Config 411 | // *ConverseRequest_AudioIn 412 | ConverseRequest isConverseRequest_ConverseRequest `protobuf_oneof:"converse_request"` 413 | } 414 | 415 | func (m *ConverseRequest) Reset() { *m = ConverseRequest{} } 416 | func (m *ConverseRequest) String() string { return proto.CompactTextString(m) } 417 | func (*ConverseRequest) ProtoMessage() {} 418 | func (*ConverseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } 419 | 420 | type isConverseRequest_ConverseRequest interface { 421 | isConverseRequest_ConverseRequest() 422 | } 423 | 424 | type ConverseRequest_Config struct { 425 | Config *ConverseConfig `protobuf:"bytes,1,opt,name=config,oneof"` 426 | } 427 | type ConverseRequest_AudioIn struct { 428 | AudioIn []byte `protobuf:"bytes,2,opt,name=audio_in,json=audioIn,proto3,oneof"` 429 | } 430 | 431 | func (*ConverseRequest_Config) isConverseRequest_ConverseRequest() {} 432 | func (*ConverseRequest_AudioIn) isConverseRequest_ConverseRequest() {} 433 | 434 | func (m *ConverseRequest) GetConverseRequest() isConverseRequest_ConverseRequest { 435 | if m != nil { 436 | return m.ConverseRequest 437 | } 438 | return nil 439 | } 440 | 441 | func (m *ConverseRequest) GetConfig() *ConverseConfig { 442 | if x, ok := m.GetConverseRequest().(*ConverseRequest_Config); ok { 443 | return x.Config 444 | } 445 | return nil 446 | } 447 | 448 | func (m *ConverseRequest) GetAudioIn() []byte { 449 | if x, ok := m.GetConverseRequest().(*ConverseRequest_AudioIn); ok { 450 | return x.AudioIn 451 | } 452 | return nil 453 | } 454 | 455 | // XXX_OneofFuncs is for the internal use of the proto package. 456 | func (*ConverseRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { 457 | return _ConverseRequest_OneofMarshaler, _ConverseRequest_OneofUnmarshaler, _ConverseRequest_OneofSizer, []interface{}{ 458 | (*ConverseRequest_Config)(nil), 459 | (*ConverseRequest_AudioIn)(nil), 460 | } 461 | } 462 | 463 | func _ConverseRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { 464 | m := msg.(*ConverseRequest) 465 | // converse_request 466 | switch x := m.ConverseRequest.(type) { 467 | case *ConverseRequest_Config: 468 | b.EncodeVarint(1<<3 | proto.WireBytes) 469 | if err := b.EncodeMessage(x.Config); err != nil { 470 | return err 471 | } 472 | case *ConverseRequest_AudioIn: 473 | b.EncodeVarint(2<<3 | proto.WireBytes) 474 | b.EncodeRawBytes(x.AudioIn) 475 | case nil: 476 | default: 477 | return fmt.Errorf("ConverseRequest.ConverseRequest has unexpected type %T", x) 478 | } 479 | return nil 480 | } 481 | 482 | func _ConverseRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { 483 | m := msg.(*ConverseRequest) 484 | switch tag { 485 | case 1: // converse_request.config 486 | if wire != proto.WireBytes { 487 | return true, proto.ErrInternalBadWireType 488 | } 489 | msg := new(ConverseConfig) 490 | err := b.DecodeMessage(msg) 491 | m.ConverseRequest = &ConverseRequest_Config{msg} 492 | return true, err 493 | case 2: // converse_request.audio_in 494 | if wire != proto.WireBytes { 495 | return true, proto.ErrInternalBadWireType 496 | } 497 | x, err := b.DecodeRawBytes(true) 498 | m.ConverseRequest = &ConverseRequest_AudioIn{x} 499 | return true, err 500 | default: 501 | return false, nil 502 | } 503 | } 504 | 505 | func _ConverseRequest_OneofSizer(msg proto.Message) (n int) { 506 | m := msg.(*ConverseRequest) 507 | // converse_request 508 | switch x := m.ConverseRequest.(type) { 509 | case *ConverseRequest_Config: 510 | s := proto.Size(x.Config) 511 | n += proto.SizeVarint(1<<3 | proto.WireBytes) 512 | n += proto.SizeVarint(uint64(s)) 513 | n += s 514 | case *ConverseRequest_AudioIn: 515 | n += proto.SizeVarint(2<<3 | proto.WireBytes) 516 | n += proto.SizeVarint(uint64(len(x.AudioIn))) 517 | n += len(x.AudioIn) 518 | case nil: 519 | default: 520 | panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) 521 | } 522 | return n 523 | } 524 | 525 | // The top-level message received by the client. A series of one or more 526 | // `ConverseResponse` messages are streamed back to the client. 527 | type ConverseResponse struct { 528 | // Exactly one of these fields will be populated in each `ConverseResponse`. 529 | // 530 | // Types that are valid to be assigned to ConverseResponse: 531 | // *ConverseResponse_Error 532 | // *ConverseResponse_EventType_ 533 | // *ConverseResponse_AudioOut 534 | // *ConverseResponse_Result 535 | ConverseResponse isConverseResponse_ConverseResponse `protobuf_oneof:"converse_response"` 536 | } 537 | 538 | func (m *ConverseResponse) Reset() { *m = ConverseResponse{} } 539 | func (m *ConverseResponse) String() string { return proto.CompactTextString(m) } 540 | func (*ConverseResponse) ProtoMessage() {} 541 | func (*ConverseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } 542 | 543 | type isConverseResponse_ConverseResponse interface { 544 | isConverseResponse_ConverseResponse() 545 | } 546 | 547 | type ConverseResponse_Error struct { 548 | Error *google_rpc.Status `protobuf:"bytes,1,opt,name=error,oneof"` 549 | } 550 | type ConverseResponse_EventType_ struct { 551 | EventType ConverseResponse_EventType `protobuf:"varint,2,opt,name=event_type,json=eventType,enum=google.assistant.embedded.v1alpha1.ConverseResponse_EventType,oneof"` 552 | } 553 | type ConverseResponse_AudioOut struct { 554 | AudioOut *AudioOut `protobuf:"bytes,3,opt,name=audio_out,json=audioOut,oneof"` 555 | } 556 | type ConverseResponse_Result struct { 557 | Result *ConverseResult `protobuf:"bytes,5,opt,name=result,oneof"` 558 | } 559 | 560 | func (*ConverseResponse_Error) isConverseResponse_ConverseResponse() {} 561 | func (*ConverseResponse_EventType_) isConverseResponse_ConverseResponse() {} 562 | func (*ConverseResponse_AudioOut) isConverseResponse_ConverseResponse() {} 563 | func (*ConverseResponse_Result) isConverseResponse_ConverseResponse() {} 564 | 565 | func (m *ConverseResponse) GetConverseResponse() isConverseResponse_ConverseResponse { 566 | if m != nil { 567 | return m.ConverseResponse 568 | } 569 | return nil 570 | } 571 | 572 | func (m *ConverseResponse) GetError() *google_rpc.Status { 573 | if x, ok := m.GetConverseResponse().(*ConverseResponse_Error); ok { 574 | return x.Error 575 | } 576 | return nil 577 | } 578 | 579 | func (m *ConverseResponse) GetEventType() ConverseResponse_EventType { 580 | if x, ok := m.GetConverseResponse().(*ConverseResponse_EventType_); ok { 581 | return x.EventType 582 | } 583 | return ConverseResponse_EVENT_TYPE_UNSPECIFIED 584 | } 585 | 586 | func (m *ConverseResponse) GetAudioOut() *AudioOut { 587 | if x, ok := m.GetConverseResponse().(*ConverseResponse_AudioOut); ok { 588 | return x.AudioOut 589 | } 590 | return nil 591 | } 592 | 593 | func (m *ConverseResponse) GetResult() *ConverseResult { 594 | if x, ok := m.GetConverseResponse().(*ConverseResponse_Result); ok { 595 | return x.Result 596 | } 597 | return nil 598 | } 599 | 600 | // XXX_OneofFuncs is for the internal use of the proto package. 601 | func (*ConverseResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { 602 | return _ConverseResponse_OneofMarshaler, _ConverseResponse_OneofUnmarshaler, _ConverseResponse_OneofSizer, []interface{}{ 603 | (*ConverseResponse_Error)(nil), 604 | (*ConverseResponse_EventType_)(nil), 605 | (*ConverseResponse_AudioOut)(nil), 606 | (*ConverseResponse_Result)(nil), 607 | } 608 | } 609 | 610 | func _ConverseResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { 611 | m := msg.(*ConverseResponse) 612 | // converse_response 613 | switch x := m.ConverseResponse.(type) { 614 | case *ConverseResponse_Error: 615 | b.EncodeVarint(1<<3 | proto.WireBytes) 616 | if err := b.EncodeMessage(x.Error); err != nil { 617 | return err 618 | } 619 | case *ConverseResponse_EventType_: 620 | b.EncodeVarint(2<<3 | proto.WireVarint) 621 | b.EncodeVarint(uint64(x.EventType)) 622 | case *ConverseResponse_AudioOut: 623 | b.EncodeVarint(3<<3 | proto.WireBytes) 624 | if err := b.EncodeMessage(x.AudioOut); err != nil { 625 | return err 626 | } 627 | case *ConverseResponse_Result: 628 | b.EncodeVarint(5<<3 | proto.WireBytes) 629 | if err := b.EncodeMessage(x.Result); err != nil { 630 | return err 631 | } 632 | case nil: 633 | default: 634 | return fmt.Errorf("ConverseResponse.ConverseResponse has unexpected type %T", x) 635 | } 636 | return nil 637 | } 638 | 639 | func _ConverseResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { 640 | m := msg.(*ConverseResponse) 641 | switch tag { 642 | case 1: // converse_response.error 643 | if wire != proto.WireBytes { 644 | return true, proto.ErrInternalBadWireType 645 | } 646 | msg := new(google_rpc.Status) 647 | err := b.DecodeMessage(msg) 648 | m.ConverseResponse = &ConverseResponse_Error{msg} 649 | return true, err 650 | case 2: // converse_response.event_type 651 | if wire != proto.WireVarint { 652 | return true, proto.ErrInternalBadWireType 653 | } 654 | x, err := b.DecodeVarint() 655 | m.ConverseResponse = &ConverseResponse_EventType_{ConverseResponse_EventType(x)} 656 | return true, err 657 | case 3: // converse_response.audio_out 658 | if wire != proto.WireBytes { 659 | return true, proto.ErrInternalBadWireType 660 | } 661 | msg := new(AudioOut) 662 | err := b.DecodeMessage(msg) 663 | m.ConverseResponse = &ConverseResponse_AudioOut{msg} 664 | return true, err 665 | case 5: // converse_response.result 666 | if wire != proto.WireBytes { 667 | return true, proto.ErrInternalBadWireType 668 | } 669 | msg := new(ConverseResult) 670 | err := b.DecodeMessage(msg) 671 | m.ConverseResponse = &ConverseResponse_Result{msg} 672 | return true, err 673 | default: 674 | return false, nil 675 | } 676 | } 677 | 678 | func _ConverseResponse_OneofSizer(msg proto.Message) (n int) { 679 | m := msg.(*ConverseResponse) 680 | // converse_response 681 | switch x := m.ConverseResponse.(type) { 682 | case *ConverseResponse_Error: 683 | s := proto.Size(x.Error) 684 | n += proto.SizeVarint(1<<3 | proto.WireBytes) 685 | n += proto.SizeVarint(uint64(s)) 686 | n += s 687 | case *ConverseResponse_EventType_: 688 | n += proto.SizeVarint(2<<3 | proto.WireVarint) 689 | n += proto.SizeVarint(uint64(x.EventType)) 690 | case *ConverseResponse_AudioOut: 691 | s := proto.Size(x.AudioOut) 692 | n += proto.SizeVarint(3<<3 | proto.WireBytes) 693 | n += proto.SizeVarint(uint64(s)) 694 | n += s 695 | case *ConverseResponse_Result: 696 | s := proto.Size(x.Result) 697 | n += proto.SizeVarint(5<<3 | proto.WireBytes) 698 | n += proto.SizeVarint(uint64(s)) 699 | n += s 700 | case nil: 701 | default: 702 | panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) 703 | } 704 | return n 705 | } 706 | 707 | func init() { 708 | proto.RegisterType((*ConverseConfig)(nil), "google.assistant.embedded.v1alpha1.ConverseConfig") 709 | proto.RegisterType((*AudioInConfig)(nil), "google.assistant.embedded.v1alpha1.AudioInConfig") 710 | proto.RegisterType((*AudioOutConfig)(nil), "google.assistant.embedded.v1alpha1.AudioOutConfig") 711 | proto.RegisterType((*ConverseState)(nil), "google.assistant.embedded.v1alpha1.ConverseState") 712 | proto.RegisterType((*AudioOut)(nil), "google.assistant.embedded.v1alpha1.AudioOut") 713 | proto.RegisterType((*ConverseResult)(nil), "google.assistant.embedded.v1alpha1.ConverseResult") 714 | proto.RegisterType((*ConverseRequest)(nil), "google.assistant.embedded.v1alpha1.ConverseRequest") 715 | proto.RegisterType((*ConverseResponse)(nil), "google.assistant.embedded.v1alpha1.ConverseResponse") 716 | proto.RegisterEnum("google.assistant.embedded.v1alpha1.AudioInConfig_Encoding", AudioInConfig_Encoding_name, AudioInConfig_Encoding_value) 717 | proto.RegisterEnum("google.assistant.embedded.v1alpha1.AudioOutConfig_Encoding", AudioOutConfig_Encoding_name, AudioOutConfig_Encoding_value) 718 | proto.RegisterEnum("google.assistant.embedded.v1alpha1.ConverseResult_MicrophoneMode", ConverseResult_MicrophoneMode_name, ConverseResult_MicrophoneMode_value) 719 | proto.RegisterEnum("google.assistant.embedded.v1alpha1.ConverseResponse_EventType", ConverseResponse_EventType_name, ConverseResponse_EventType_value) 720 | } 721 | 722 | // Reference imports to suppress errors if they are not otherwise used. 723 | var _ context.Context 724 | var _ grpc.ClientConn 725 | 726 | // This is a compile-time assertion to ensure that this generated file 727 | // is compatible with the grpc package it is being compiled against. 728 | const _ = grpc.SupportPackageIsVersion4 729 | 730 | // Client API for EmbeddedAssistant service 731 | 732 | type EmbeddedAssistantClient interface { 733 | // Initiates or continues a conversation with the embedded assistant service. 734 | // Each call performs one round-trip, sending an audio request to the service 735 | // and receiving the audio response. Uses bidirectional streaming to receive 736 | // results, such as the `END_OF_UTTERANCE` event, while sending audio. 737 | // 738 | // A conversation is one or more gRPC connections, each consisting of several 739 | // streamed requests and responses. 740 | // For example, the user says *Add to my shopping list* and the assistant 741 | // responds *What do you want to add?*. The sequence of streamed requests and 742 | // responses in the first gRPC message could be: 743 | // 744 | // * ConverseRequest.config 745 | // * ConverseRequest.audio_in 746 | // * ConverseRequest.audio_in 747 | // * ConverseRequest.audio_in 748 | // * ConverseRequest.audio_in 749 | // * ConverseResponse.event_type.END_OF_UTTERANCE 750 | // * ConverseResponse.result.microphone_mode.DIALOG_FOLLOW_ON 751 | // * ConverseResponse.audio_out 752 | // * ConverseResponse.audio_out 753 | // * ConverseResponse.audio_out 754 | // 755 | // The user then says *bagels* and the assistant responds 756 | // *OK, I've added bagels to your shopping list*. This is sent as another gRPC 757 | // connection call to the `Converse` method, again with streamed requests and 758 | // responses, such as: 759 | // 760 | // * ConverseRequest.config 761 | // * ConverseRequest.audio_in 762 | // * ConverseRequest.audio_in 763 | // * ConverseRequest.audio_in 764 | // * ConverseResponse.event_type.END_OF_UTTERANCE 765 | // * ConverseResponse.result.microphone_mode.CLOSE_MICROPHONE 766 | // * ConverseResponse.audio_out 767 | // * ConverseResponse.audio_out 768 | // * ConverseResponse.audio_out 769 | // * ConverseResponse.audio_out 770 | // 771 | // Although the precise order of responses is not guaranteed, sequential 772 | // ConverseResponse.audio_out messages will always contain sequential portions 773 | // of audio. 774 | Converse(ctx context.Context, opts ...grpc.CallOption) (EmbeddedAssistant_ConverseClient, error) 775 | } 776 | 777 | type embeddedAssistantClient struct { 778 | cc *grpc.ClientConn 779 | } 780 | 781 | func NewEmbeddedAssistantClient(cc *grpc.ClientConn) EmbeddedAssistantClient { 782 | return &embeddedAssistantClient{cc} 783 | } 784 | 785 | func (c *embeddedAssistantClient) Converse(ctx context.Context, opts ...grpc.CallOption) (EmbeddedAssistant_ConverseClient, error) { 786 | stream, err := grpc.NewClientStream(ctx, &_EmbeddedAssistant_serviceDesc.Streams[0], c.cc, "/google.assistant.embedded.v1alpha1.EmbeddedAssistant/Converse", opts...) 787 | if err != nil { 788 | return nil, err 789 | } 790 | x := &embeddedAssistantConverseClient{stream} 791 | return x, nil 792 | } 793 | 794 | type EmbeddedAssistant_ConverseClient interface { 795 | Send(*ConverseRequest) error 796 | Recv() (*ConverseResponse, error) 797 | grpc.ClientStream 798 | } 799 | 800 | type embeddedAssistantConverseClient struct { 801 | grpc.ClientStream 802 | } 803 | 804 | func (x *embeddedAssistantConverseClient) Send(m *ConverseRequest) error { 805 | return x.ClientStream.SendMsg(m) 806 | } 807 | 808 | func (x *embeddedAssistantConverseClient) Recv() (*ConverseResponse, error) { 809 | m := new(ConverseResponse) 810 | if err := x.ClientStream.RecvMsg(m); err != nil { 811 | return nil, err 812 | } 813 | return m, nil 814 | } 815 | 816 | // Server API for EmbeddedAssistant service 817 | 818 | type EmbeddedAssistantServer interface { 819 | // Initiates or continues a conversation with the embedded assistant service. 820 | // Each call performs one round-trip, sending an audio request to the service 821 | // and receiving the audio response. Uses bidirectional streaming to receive 822 | // results, such as the `END_OF_UTTERANCE` event, while sending audio. 823 | // 824 | // A conversation is one or more gRPC connections, each consisting of several 825 | // streamed requests and responses. 826 | // For example, the user says *Add to my shopping list* and the assistant 827 | // responds *What do you want to add?*. The sequence of streamed requests and 828 | // responses in the first gRPC message could be: 829 | // 830 | // * ConverseRequest.config 831 | // * ConverseRequest.audio_in 832 | // * ConverseRequest.audio_in 833 | // * ConverseRequest.audio_in 834 | // * ConverseRequest.audio_in 835 | // * ConverseResponse.event_type.END_OF_UTTERANCE 836 | // * ConverseResponse.result.microphone_mode.DIALOG_FOLLOW_ON 837 | // * ConverseResponse.audio_out 838 | // * ConverseResponse.audio_out 839 | // * ConverseResponse.audio_out 840 | // 841 | // The user then says *bagels* and the assistant responds 842 | // *OK, I've added bagels to your shopping list*. This is sent as another gRPC 843 | // connection call to the `Converse` method, again with streamed requests and 844 | // responses, such as: 845 | // 846 | // * ConverseRequest.config 847 | // * ConverseRequest.audio_in 848 | // * ConverseRequest.audio_in 849 | // * ConverseRequest.audio_in 850 | // * ConverseResponse.event_type.END_OF_UTTERANCE 851 | // * ConverseResponse.result.microphone_mode.CLOSE_MICROPHONE 852 | // * ConverseResponse.audio_out 853 | // * ConverseResponse.audio_out 854 | // * ConverseResponse.audio_out 855 | // * ConverseResponse.audio_out 856 | // 857 | // Although the precise order of responses is not guaranteed, sequential 858 | // ConverseResponse.audio_out messages will always contain sequential portions 859 | // of audio. 860 | Converse(EmbeddedAssistant_ConverseServer) error 861 | } 862 | 863 | func RegisterEmbeddedAssistantServer(s *grpc.Server, srv EmbeddedAssistantServer) { 864 | s.RegisterService(&_EmbeddedAssistant_serviceDesc, srv) 865 | } 866 | 867 | func _EmbeddedAssistant_Converse_Handler(srv interface{}, stream grpc.ServerStream) error { 868 | return srv.(EmbeddedAssistantServer).Converse(&embeddedAssistantConverseServer{stream}) 869 | } 870 | 871 | type EmbeddedAssistant_ConverseServer interface { 872 | Send(*ConverseResponse) error 873 | Recv() (*ConverseRequest, error) 874 | grpc.ServerStream 875 | } 876 | 877 | type embeddedAssistantConverseServer struct { 878 | grpc.ServerStream 879 | } 880 | 881 | func (x *embeddedAssistantConverseServer) Send(m *ConverseResponse) error { 882 | return x.ServerStream.SendMsg(m) 883 | } 884 | 885 | func (x *embeddedAssistantConverseServer) Recv() (*ConverseRequest, error) { 886 | m := new(ConverseRequest) 887 | if err := x.ServerStream.RecvMsg(m); err != nil { 888 | return nil, err 889 | } 890 | return m, nil 891 | } 892 | 893 | var _EmbeddedAssistant_serviceDesc = grpc.ServiceDesc{ 894 | ServiceName: "google.assistant.embedded.v1alpha1.EmbeddedAssistant", 895 | HandlerType: (*EmbeddedAssistantServer)(nil), 896 | Methods: []grpc.MethodDesc{}, 897 | Streams: []grpc.StreamDesc{ 898 | { 899 | StreamName: "Converse", 900 | Handler: _EmbeddedAssistant_Converse_Handler, 901 | ServerStreams: true, 902 | ClientStreams: true, 903 | }, 904 | }, 905 | Metadata: "googleapis/google/assistant/embedded/v1alpha1/embedded_assistant.proto", 906 | } 907 | 908 | func init() { 909 | proto.RegisterFile("googleapis/google/assistant/embedded/v1alpha1/embedded_assistant.proto", fileDescriptor0) 910 | } 911 | 912 | var fileDescriptor0 = []byte{ 913 | // 896 bytes of a gzipped FileDescriptorProto 914 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xdd, 0x72, 0xdb, 0x44, 915 | 0x14, 0xb6, 0xec, 0xa6, 0xb5, 0x4f, 0x13, 0x59, 0xde, 0x66, 0x20, 0x93, 0xc2, 0xc0, 0xe8, 0x82, 916 | 0x29, 0x05, 0xe4, 0xc6, 0x61, 0xb8, 0xa0, 0xd0, 0x19, 0xc7, 0x96, 0x63, 0x83, 0x2d, 0x79, 0xd6, 917 | 0x4e, 0x4b, 0x19, 0x98, 0x9d, 0xad, 0xbc, 0x38, 0x02, 0x7b, 0x57, 0x48, 0xeb, 0x4c, 0xc3, 0x03, 918 | 0x70, 0xd9, 0xe1, 0x96, 0x6b, 0x9e, 0x88, 0x37, 0x62, 0xb4, 0x2b, 0x29, 0x36, 0xa4, 0x10, 0x97, 919 | 0x3b, 0xed, 0x39, 0xfb, 0x7d, 0x3a, 0xe7, 0x3b, 0x3f, 0xb3, 0xd0, 0x9b, 0x0b, 0x31, 0x5f, 0x30, 920 | 0x1a, 0x85, 0x49, 0x53, 0x7f, 0x36, 0x69, 0x92, 0x84, 0x89, 0xa4, 0x5c, 0x36, 0xd9, 0xf2, 0x05, 921 | 0x9b, 0xcd, 0xd8, 0xac, 0x79, 0x71, 0x44, 0x17, 0xd1, 0x39, 0x3d, 0x2a, 0x2c, 0xa4, 0xb8, 0xe4, 922 | 0x44, 0xb1, 0x90, 0x02, 0xd9, 0x1a, 0xec, 0x5c, 0xd9, 0xf3, 0xab, 0x4e, 0x0e, 0x3e, 0x7c, 0x27, 923 | 0xff, 0x41, 0x14, 0x36, 0x29, 0xe7, 0x42, 0x52, 0x19, 0x0a, 0x9e, 0x68, 0x86, 0xc3, 0xb7, 0x33, 924 | 0x6f, 0x1c, 0x05, 0xcd, 0x44, 0x52, 0xb9, 0xca, 0x1c, 0xf6, 0x1f, 0x65, 0x30, 0x3b, 0x82, 0x5f, 925 | 0xb0, 0x38, 0x61, 0x1d, 0xc1, 0x7f, 0x08, 0xe7, 0xe8, 0x39, 0xd4, 0xe9, 0x6a, 0x16, 0x0a, 0x12, 926 | 0x72, 0x12, 0x28, 0xd3, 0x81, 0xf1, 0xbe, 0xf1, 0xe0, 0x6e, 0xeb, 0xc8, 0xf9, 0xef, 0x38, 0x9c, 927 | 0x76, 0x0a, 0x1d, 0x70, 0xcd, 0x85, 0xf7, 0xe8, 0xfa, 0x11, 0x7d, 0x07, 0x96, 0xa6, 0x16, 0x2b, 928 | 0x99, 0x73, 0x97, 0x15, 0x77, 0xeb, 0xc6, 0xdc, 0xfe, 0x4a, 0x66, 0xe4, 0x26, 0xdd, 0x38, 0xa3, 929 | 0x6f, 0xc0, 0x0c, 0xb2, 0x54, 0x48, 0x9a, 0x24, 0x3b, 0xa8, 0xdc, 0x3c, 0xee, 0x5c, 0x84, 0x49, 930 | 0x0a, 0xc4, 0x7b, 0xc1, 0xfa, 0xd1, 0xfe, 0xd3, 0x80, 0xbd, 0x8d, 0xc4, 0xd0, 0x53, 0xa8, 0x32, 931 | 0x1e, 0x88, 0x59, 0xc8, 0xb5, 0x3a, 0x66, 0xeb, 0xf3, 0xad, 0xd5, 0x71, 0xdc, 0x8c, 0x01, 0x17, 932 | 0x5c, 0xe8, 0x21, 0x34, 0x12, 0xba, 0x8c, 0x16, 0x8c, 0xc4, 0x54, 0x32, 0x72, 0xce, 0x62, 0xf9, 933 | 0x8b, 0x92, 0x68, 0x07, 0xd7, 0xb5, 0x03, 0x53, 0xc9, 0xfa, 0xa9, 0xd9, 0xfe, 0x02, 0xaa, 0x39, 934 | 0x03, 0x3a, 0x80, 0x7d, 0xd7, 0xeb, 0xf8, 0xdd, 0x81, 0x77, 0x4a, 0xce, 0xbc, 0xc9, 0xd8, 0xed, 935 | 0x0c, 0x7a, 0x03, 0xb7, 0x6b, 0x95, 0xd0, 0x2e, 0x54, 0x87, 0x03, 0xcf, 0x6d, 0xe3, 0xa3, 0xcf, 936 | 0x2c, 0x03, 0x55, 0xe1, 0x56, 0x6f, 0xd8, 0xee, 0x58, 0x65, 0xfb, 0xb7, 0x32, 0x98, 0x9b, 0x82, 937 | 0xa2, 0x67, 0xff, 0x48, 0xea, 0xf1, 0xf6, 0x65, 0xf9, 0x9f, 0x59, 0xa1, 0x8f, 0xa0, 0x71, 0x21, 938 | 0x16, 0xab, 0x25, 0x23, 0x11, 0x8b, 0x03, 0xc6, 0x25, 0x9d, 0xeb, 0x42, 0xee, 0x60, 0x4b, 0x3b, 939 | 0xc6, 0x85, 0xdd, 0x1e, 0xbe, 0x81, 0x04, 0x77, 0xa0, 0x32, 0x1a, 0x1f, 0x5b, 0x65, 0x54, 0x87, 940 | 0xbb, 0xfe, 0xf8, 0x6c, 0x42, 0x06, 0x1e, 0xf1, 0x4f, 0x4f, 0xad, 0x8a, 0xfd, 0x04, 0xf6, 0x36, 941 | 0xda, 0x00, 0x7d, 0x02, 0x28, 0x6b, 0x04, 0x35, 0x4d, 0x59, 0x57, 0xa5, 0xd2, 0xec, 0xe2, 0xc6, 942 | 0xba, 0x47, 0xb7, 0xc9, 0x87, 0x50, 0xcd, 0xb5, 0x40, 0xef, 0x02, 0xe8, 0x56, 0x9f, 0x51, 0x49, 943 | 0x33, 0x48, 0x4d, 0x59, 0xba, 0x54, 0x52, 0xfb, 0xf7, 0xca, 0xd5, 0xdc, 0x61, 0x96, 0xac, 0x16, 944 | 0x12, 0x39, 0x70, 0x2f, 0x89, 0xc4, 0x4f, 0x8c, 0x93, 0x98, 0xfd, 0xbc, 0x62, 0x89, 0x24, 0x92, 945 | 0xbd, 0x94, 0x0a, 0x5a, 0xc3, 0x0d, 0xed, 0xc2, 0xda, 0x33, 0x65, 0x2f, 0x25, 0x7a, 0x04, 0xfb, 946 | 0xc5, 0xfd, 0x24, 0x12, 0x3c, 0x61, 0x1a, 0x50, 0x56, 0x00, 0x94, 0x03, 0xb4, 0x4b, 0x21, 0xae, 947 | 0x4f, 0xa7, 0xf2, 0x9a, 0x74, 0xd0, 0x8f, 0x50, 0x5f, 0x86, 0x41, 0x2c, 0xa2, 0x73, 0xc1, 0x19, 948 | 0x59, 0x8a, 0x19, 0x3b, 0xb8, 0xa5, 0xba, 0xa2, 0xbd, 0xcd, 0x40, 0xe9, 0xec, 0x9c, 0x51, 0xc1, 949 | 0x34, 0x12, 0x33, 0x86, 0xcd, 0xe5, 0xc6, 0xf9, 0xfa, 0xaa, 0xef, 0xbc, 0xa6, 0xea, 0xdf, 0x83, 950 | 0xb9, 0x49, 0x87, 0xde, 0x83, 0xfb, 0xa3, 0x41, 0x07, 0xfb, 0xe3, 0xbe, 0xef, 0xb9, 0x64, 0xe4, 951 | 0x77, 0xdd, 0xbf, 0xb5, 0xc0, 0x3e, 0x58, 0x9d, 0xa1, 0x3f, 0x71, 0xc9, 0xd5, 0x35, 0xcb, 0x48, 952 | 0xad, 0xdd, 0x41, 0x7b, 0xe8, 0x9f, 0x92, 0x9e, 0x3f, 0x1c, 0xfa, 0xcf, 0x88, 0xef, 0xa5, 0x93, 953 | 0x61, 0x40, 0xfd, 0x2a, 0x7a, 0x25, 0x38, 0x1a, 0xc2, 0xed, 0x8d, 0x5d, 0xd8, 0xda, 0x46, 0x02, 954 | 0x3d, 0x18, 0xfd, 0x12, 0xce, 0x38, 0xd0, 0x7d, 0xa8, 0xe6, 0x2b, 0x56, 0x95, 0x6b, 0xb7, 0x5f, 955 | 0xc2, 0x77, 0xb2, 0x55, 0x79, 0x82, 0xc0, 0x2a, 0xd6, 0x58, 0xd6, 0x09, 0xf6, 0xab, 0x0a, 0x58, 956 | 0x6b, 0x82, 0xaa, 0x92, 0xa2, 0x87, 0xb0, 0xc3, 0xe2, 0x58, 0xc4, 0x59, 0x48, 0x28, 0x0f, 0x29, 957 | 0x8e, 0x02, 0x67, 0xa2, 0x96, 0x7c, 0xbf, 0x84, 0xf5, 0x15, 0x44, 0x00, 0xd8, 0x05, 0xe3, 0x92, 958 | 0xc8, 0xcb, 0x88, 0xa9, 0x7f, 0x9a, 0xad, 0x27, 0x5b, 0x96, 0x51, 0xfd, 0xd5, 0x71, 0x53, 0x9a, 959 | 0xe9, 0x65, 0xc4, 0xfa, 0x25, 0x5c, 0x63, 0xf9, 0x01, 0x7d, 0x0d, 0xb5, 0x62, 0xb5, 0x67, 0x7b, 960 | 0xf7, 0xe3, 0x6d, 0x96, 0x47, 0xbf, 0x84, 0xab, 0xf9, 0x3e, 0x4f, 0xd5, 0x8e, 0x55, 0xdb, 0xa8, 961 | 0x16, 0xd8, 0x52, 0x6d, 0xdd, 0x70, 0xa9, 0xda, 0x9a, 0xc3, 0xfe, 0x12, 0x6a, 0x45, 0xd0, 0xe8, 962 | 0x10, 0xde, 0x72, 0x9f, 0xba, 0xde, 0x94, 0x4c, 0x9f, 0x8f, 0xaf, 0x69, 0x12, 0xd7, 0xeb, 0x12, 963 | 0xbf, 0x47, 0xce, 0xa6, 0x53, 0x17, 0xb7, 0xbd, 0x8e, 0x6b, 0x19, 0x27, 0xf7, 0xa0, 0xb1, 0x56, 964 | 0x0f, 0xad, 0x42, 0xeb, 0x95, 0x01, 0x0d, 0x37, 0x0b, 0xa1, 0x9d, 0x07, 0x85, 0x2e, 0xa1, 0x9a, 965 | 0x47, 0x81, 0x8e, 0xb7, 0x8b, 0x59, 0xd5, 0xf9, 0xf0, 0xd3, 0x37, 0x29, 0xc9, 0x03, 0xe3, 0x91, 966 | 0x71, 0xf2, 0xab, 0x01, 0x1f, 0x04, 0x62, 0x79, 0x03, 0xfc, 0x89, 0x59, 0x04, 0x3c, 0x4e, 0xdf, 967 | 0x00, 0x63, 0xe3, 0xdb, 0xaf, 0x32, 0xd4, 0x5c, 0x2c, 0x28, 0x9f, 0x3b, 0x22, 0x9e, 0x37, 0xe7, 968 | 0x8c, 0xab, 0x17, 0x42, 0x73, 0xed, 0x0d, 0xf3, 0x2f, 0x8f, 0x97, 0xc7, 0xb9, 0xe5, 0xc5, 0x6d, 969 | 0x05, 0x3b, 0xfe, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x79, 0x93, 0x70, 0xfd, 0x08, 0x00, 0x00, 970 | } 971 | --------------------------------------------------------------------------------