mods: Add api.ai module (replaces wit.ai WIP module)
This commit is contained in:
parent
1ae8af29ce
commit
318a3f8d16
2 changed files with 143 additions and 46 deletions
13
mods/main.go
13
mods/main.go
|
@ -43,11 +43,10 @@ var mods = map[string]Mod{
|
||||||
OnInit: initproverbio,
|
OnInit: initproverbio,
|
||||||
OnMessage: proverbio,
|
OnMessage: proverbio,
|
||||||
},
|
},
|
||||||
/*
|
"talk": {
|
||||||
"talk": {
|
OnInit: inittalk,
|
||||||
OnInit: inittalk,
|
OnMessage: talk,
|
||||||
OnMessage: talk,
|
},
|
||||||
},*/
|
|
||||||
"stt": {
|
"stt": {
|
||||||
OnInit: initstt,
|
OnInit: initstt,
|
||||||
OnMessage: stt,
|
OnMessage: stt,
|
||||||
|
@ -96,7 +95,7 @@ var impact *string
|
||||||
var gillmt *string
|
var gillmt *string
|
||||||
var sourcesans *string
|
var sourcesans *string
|
||||||
var proverbi *string
|
var proverbi *string
|
||||||
var wittoken *string
|
var talktoken *string
|
||||||
var gapifile *string
|
var gapifile *string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -108,7 +107,7 @@ func main() {
|
||||||
macropath = flag.String("macropath", "macros.json", "Path to macros db (JSON)")
|
macropath = flag.String("macropath", "macros.json", "Path to macros db (JSON)")
|
||||||
remindpath = flag.String("remindpath", "reminders.json", "Path to reminder db (JSON)")
|
remindpath = flag.String("remindpath", "reminders.json", "Path to reminder db (JSON)")
|
||||||
proverbi = flag.String("proverbi", "proverbi.txt", "Path to proverbi pairs (separated by /)")
|
proverbi = flag.String("proverbi", "proverbi.txt", "Path to proverbi pairs (separated by /)")
|
||||||
wittoken = flag.String("wit", "", "Wit.ai token")
|
talktoken = flag.String("apiai", "", "api.ai token")
|
||||||
gapifile = flag.String("gapi", "gapi.json", "Google API Service Credentials file")
|
gapifile = flag.String("gapi", "gapi.json", "Google API Service Credentials file")
|
||||||
disable := flag.String("disable", "", "Blacklist mods (separated by comma)")
|
disable := flag.String("disable", "", "Blacklist mods (separated by comma)")
|
||||||
enable := flag.String("enable", "", "Whitelist mods (separated by comma)")
|
enable := flag.String("enable", "", "Whitelist mods (separated by comma)")
|
||||||
|
|
176
mods/talk.go
176
mods/talk.go
|
@ -1,58 +1,156 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hamcha/clessy/tg"
|
"github.com/hamcha/clessy/tg"
|
||||||
"github.com/kurrik/witgo/v1/witgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClessyHandler struct {
|
type QRequest struct {
|
||||||
|
SessionID string `json:"sessionId"`
|
||||||
|
Query string `json:"query"`
|
||||||
|
Language string `json:"lang"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var wit *witgo.Witgo
|
type QResponse struct {
|
||||||
var witHandler ClessyHandler
|
ID string `json:"id"`
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
Result struct {
|
||||||
|
Source string `json:"source"`
|
||||||
|
ResolvedQuery string `json:"resolvedQuery"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
ActionIncomplete bool `json:"actionIncomplete"`
|
||||||
|
Parameters struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"parameters"`
|
||||||
|
Contexts []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Parameters struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"parameters"`
|
||||||
|
Lifespan int `json:"lifespan"`
|
||||||
|
} `json:"contexts"`
|
||||||
|
Metadata struct {
|
||||||
|
IntentID string `json:"intentId"`
|
||||||
|
IntentName string `json:"intentName"`
|
||||||
|
} `json:"metadata"`
|
||||||
|
Fulfillment struct {
|
||||||
|
Speech string `json:"speech"`
|
||||||
|
} `json:"fulfillment"`
|
||||||
|
} `json:"result"`
|
||||||
|
Status struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
ErrorType string `json:"errorType"`
|
||||||
|
} `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const talkBaseURL = "https://api.api.ai/v1"
|
||||||
|
|
||||||
func inittalk() {
|
func inittalk() {
|
||||||
// Disable if token is not provided
|
if *talktoken == "" {
|
||||||
if *wittoken == "" {
|
panic(fmt.Errorf("API token for api.ai must be provided! (provide it or --disable talk)"))
|
||||||
panic(errors.New("No or empty wit token provided (-wit)"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
witgo.NewWitgo(witgo.NewClient(*wittoken), &witHandler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func talk(broker *tg.Broker, update tg.APIMessage) {
|
func talk(broker *tg.Broker, update tg.APIMessage) {
|
||||||
}
|
// Must be a text message
|
||||||
|
if update.Text == nil {
|
||||||
func (h *ClessyHandler) Action(session *witgo.Session, action string) (response *witgo.Session, err error) {
|
return
|
||||||
response = session
|
|
||||||
response.Context.Set("forecast", "sunny")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ClessyHandler) Say(session *witgo.Session, msg string) (response *witgo.Session, err error) {
|
|
||||||
response = session
|
|
||||||
fmt.Printf("< %v\n", msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ClessyHandler) Merge(session *witgo.Session, entities witgo.EntityMap) (response *witgo.Session, err error) {
|
|
||||||
var (
|
|
||||||
value string
|
|
||||||
)
|
|
||||||
response = session
|
|
||||||
if value, err = entities.FirstEntityValue("location"); err != nil {
|
|
||||||
response.Context = witgo.Context{}
|
|
||||||
err = nil
|
|
||||||
} else {
|
|
||||||
response.Context.Merge(witgo.Context{
|
|
||||||
"loc": value,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return
|
text := *(update.Text)
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ClessyHandler) Error(session *witgo.Session, msg string) {
|
// Make sure it's aimed at Clessy
|
||||||
|
if strings.Index(text, "@"+*botname) >= 0 {
|
||||||
|
// @maudbot <something>
|
||||||
|
text = strings.Replace(text, "@"+*botname, "", 1)
|
||||||
|
} else if idx := strings.Index(strings.ToLower(text), "clessy"); idx == 0 && len(text) > 7 {
|
||||||
|
// Clessy, <something>
|
||||||
|
text = strings.TrimLeft(text[len("clessy"):], ":,")
|
||||||
|
} else if text[0] != '/' && update.ReplyTo != nil && update.ReplyTo.User.Username == *botname {
|
||||||
|
// Reply to Clessy (previous prompt?) which is not a command (such as unsplash), pass
|
||||||
|
} else if update.Chat.Username != nil {
|
||||||
|
// Private chat, pass
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
|
|
||||||
|
// Generate unique id for user
|
||||||
|
id := strconv.FormatInt(update.User.UserID, 36)
|
||||||
|
if len(id) > 36 {
|
||||||
|
id = id[:36]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create POST body
|
||||||
|
data, err := json.Marshal(QRequest{
|
||||||
|
SessionID: id,
|
||||||
|
Query: text,
|
||||||
|
Language: "it",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[talk] Could not create JSON body: %s\n", err.Error())
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the request
|
||||||
|
req, err := http.NewRequest("POST", talkBaseURL+"/query?v=20150910", bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[talk] Could not create POST request: %s\n", err.Error())
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Authorization", "Bearer "+*talktoken)
|
||||||
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[talk] Request error: %s\n", err.Error())
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var record QResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
|
||||||
|
log.Printf("[talk] Could not decode JSON response: %s\n", err.Error())
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.Status.ErrorType != "success" {
|
||||||
|
body, _ := json.MarshalIndent(record, "", " ")
|
||||||
|
log.Printf("[talk] Non-success status, full response body follows:\n%s\n", body)
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reply := record.Result.Fulfillment.Speech
|
||||||
|
|
||||||
|
// Replace tokens if found
|
||||||
|
if strings.Index(reply, "$") >= 0 {
|
||||||
|
reply = strings.Replace(reply, "$name", update.User.FirstName, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call command if needed
|
||||||
|
if reply[0] == '#' {
|
||||||
|
//TODO Find a better way?
|
||||||
|
if strings.HasPrefix(reply, "#metafora") {
|
||||||
|
message := "/metafora"
|
||||||
|
update.Text = &message
|
||||||
|
metafora(broker, update)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
broker.SendTextMessage(update.Chat, reply, &update.MessageID)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue