├── .gitignore ├── README.md ├── TutorialChatbot.zip ├── main.go └── tutorialchatbot-XXX.json /.gitignore: -------------------------------------------------------------------------------- 1 | dialogflow-auth 2 | tutorialchatbot-d4db0-0fea9ca7f682.json 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Golang Dialogflow Integration 2 | This code is related to medium tutorial by Rodrigo Beceiro. 3 | For more information: rodrigo@marvik.ai 4 | -------------------------------------------------------------------------------- /TutorialChatbot.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robeceiro/dialogflow-golang/5e6f7f0687c3069dcba43a5e58557d0dc71a0f65/TutorialChatbot.zip -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | "strconv" 11 | 12 | dialogflow "cloud.google.com/go/dialogflow/apiv2" 13 | "github.com/golang/protobuf/ptypes/struct" 14 | "google.golang.org/api/option" 15 | dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" 16 | ) 17 | 18 | // DialogflowProcessor has all the information for connecting with Dialogflow 19 | type DialogflowProcessor struct { 20 | projectID string 21 | authJSONFilePath string 22 | lang string 23 | timeZone string 24 | sessionClient *dialogflow.SessionsClient 25 | ctx context.Context 26 | } 27 | 28 | // NLPResponse is the struct for the response 29 | type NLPResponse struct { 30 | Intent string `json:"intent"` 31 | Confidence float32 `json:"confidence"` 32 | Entities map[string]string `json:"entities"` 33 | } 34 | 35 | var dp DialogflowProcessor 36 | 37 | func main() { 38 | dp.init("tutorialchatbot-d4db0", "tutorialchatbot-d4db0-0fea9ca7f682.json", "en", "America/Montevideo") 39 | http.HandleFunc("/", requestHandler) 40 | fmt.Println("Started listening...") 41 | http.ListenAndServe(":5000", nil) 42 | } 43 | 44 | func requestHandler(w http.ResponseWriter, r *http.Request) { 45 | if r.Method == "POST" { 46 | //POST method, receives a json to parse 47 | body, err := ioutil.ReadAll(r.Body) 48 | if err != nil { 49 | http.Error(w, "Error reading request body", 50 | http.StatusInternalServerError) 51 | } 52 | type inboundMessage struct { 53 | Message string 54 | } 55 | var m inboundMessage 56 | err = json.Unmarshal(body, &m) 57 | if err != nil { 58 | panic(err) 59 | } 60 | 61 | // Use NLP 62 | response := dp.processNLP(m.Message, "testUser") 63 | fmt.Printf("%#v", response) 64 | w.Header().Set("Content-Type", "application/json") 65 | //json.NewEncoder(w).Encode(response) 66 | json.NewEncoder(w).Encode(response) 67 | } 68 | } 69 | 70 | func (dp *DialogflowProcessor) init(a ...string) (err error) { 71 | dp.projectID = a[0] 72 | dp.authJSONFilePath = a[1] 73 | dp.lang = a[2] 74 | dp.timeZone = a[3] 75 | 76 | // Auth process: https://dialogflow.com/docs/reference/v2-auth-setup 77 | 78 | dp.ctx = context.Background() 79 | sessionClient, err := dialogflow.NewSessionsClient(dp.ctx, option.WithCredentialsFile(dp.authJSONFilePath)) 80 | if err != nil { 81 | log.Fatal("Error in auth with Dialogflow") 82 | } 83 | dp.sessionClient = sessionClient 84 | 85 | return 86 | } 87 | 88 | func (dp *DialogflowProcessor) processNLP(rawMessage string, username string) (r NLPResponse) { 89 | sessionID := username 90 | request := dialogflowpb.DetectIntentRequest{ 91 | Session: fmt.Sprintf("projects/%s/agent/sessions/%s", dp.projectID, sessionID), 92 | QueryInput: &dialogflowpb.QueryInput{ 93 | Input: &dialogflowpb.QueryInput_Text{ 94 | Text: &dialogflowpb.TextInput{ 95 | Text: rawMessage, 96 | LanguageCode: dp.lang, 97 | }, 98 | }, 99 | }, 100 | QueryParams: &dialogflowpb.QueryParameters{ 101 | TimeZone: dp.timeZone, 102 | }, 103 | } 104 | response, err := dp.sessionClient.DetectIntent(dp.ctx, &request) 105 | if err != nil { 106 | log.Fatalf("Error in communication with Dialogflow %s", err.Error()) 107 | return 108 | } 109 | queryResult := response.GetQueryResult() 110 | if queryResult.Intent != nil { 111 | r.Intent = queryResult.Intent.DisplayName 112 | r.Confidence = float32(queryResult.IntentDetectionConfidence) 113 | } 114 | r.Entities = make(map[string]string) 115 | params := queryResult.Parameters.GetFields() 116 | if len(params) > 0 { 117 | for paramName, p := range params { 118 | fmt.Printf("Param %s: %s (%s)", paramName, p.GetStringValue(), p.String()) 119 | extractedValue := extractDialogflowEntities(p) 120 | r.Entities[paramName] = extractedValue 121 | } 122 | } 123 | return 124 | } 125 | 126 | func extractDialogflowEntities(p *structpb.Value) (extractedEntity string) { 127 | kind := p.GetKind() 128 | switch kind.(type) { 129 | case *structpb.Value_StringValue: 130 | return p.GetStringValue() 131 | case *structpb.Value_NumberValue: 132 | return strconv.FormatFloat(p.GetNumberValue(), 'f', 6, 64) 133 | case *structpb.Value_BoolValue: 134 | return strconv.FormatBool(p.GetBoolValue()) 135 | case *structpb.Value_StructValue: 136 | s := p.GetStructValue() 137 | fields := s.GetFields() 138 | extractedEntity = "" 139 | for key, value := range fields { 140 | if key == "amount" { 141 | extractedEntity = fmt.Sprintf("%s%s", extractedEntity, strconv.FormatFloat(value.GetNumberValue(), 'f', 6, 64)) 142 | } 143 | if key == "unit" { 144 | extractedEntity = fmt.Sprintf("%s%s", extractedEntity, value.GetStringValue()) 145 | } 146 | if key == "date_time" { 147 | extractedEntity = fmt.Sprintf("%s%s", extractedEntity, value.GetStringValue()) 148 | } 149 | // @TODO: Other entity types can be added here 150 | } 151 | return extractedEntity 152 | case *structpb.Value_ListValue: 153 | list := p.GetListValue() 154 | if len(list.GetValues()) > 1 { 155 | // @TODO: Extract more values 156 | } 157 | extractedEntity = extractDialogflowEntities(list.GetValues()[0]) 158 | return extractedEntity 159 | default: 160 | return "" 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /tutorialchatbot-XXX.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "XXX", 4 | "private_key_id": "....", 5 | "private_key": "-----BEGIN PRIVATE KEY-----\n......=\n-----END PRIVATE KEY-----\n", 6 | "client_email": "tutorialserviceaccount@XXX.iam.gserviceaccount.com", 7 | "client_id": "...", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://oauth2.googleapis.com/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/tutorialserviceaccount%XXX.iam.gserviceaccount.com" 12 | } 13 | --------------------------------------------------------------------------------