2017-04-19 16:10:33 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-05-09 11:34:52 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2017-04-19 16:10:33 +00:00
|
|
|
"fmt"
|
2017-05-09 11:37:23 +00:00
|
|
|
"io/ioutil"
|
2017-05-09 11:34:52 +00:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2017-04-19 16:10:33 +00:00
|
|
|
|
|
|
|
"github.com/hamcha/clessy/tg"
|
|
|
|
)
|
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
type QRequest struct {
|
|
|
|
SessionID string `json:"sessionId"`
|
|
|
|
Query string `json:"query"`
|
|
|
|
Language string `json:"lang"`
|
2017-04-19 16:10:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
type QResponse struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Timestamp time.Time `json:"timestamp"`
|
|
|
|
Result struct {
|
2017-05-09 13:47:49 +00:00
|
|
|
Source string `json:"source"`
|
|
|
|
ResolvedQuery string `json:"resolvedQuery"`
|
|
|
|
Action string `json:"action"`
|
|
|
|
ActionIncomplete bool `json:"actionIncomplete"`
|
|
|
|
Parameters map[string]string `json:"parameters"`
|
|
|
|
Contexts []struct {
|
2017-05-09 11:34:52 +00:00
|
|
|
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"
|
2017-04-19 16:10:33 +00:00
|
|
|
|
|
|
|
func inittalk() {
|
2017-05-09 11:37:23 +00:00
|
|
|
if strings.HasPrefix(*talktoken, "@") {
|
|
|
|
data, err := ioutil.ReadFile((*talktoken)[1:])
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2017-05-09 11:39:08 +00:00
|
|
|
*talktoken = strings.TrimSpace(string(data))
|
2017-05-09 11:37:23 +00:00
|
|
|
}
|
2017-05-09 11:34:52 +00:00
|
|
|
if *talktoken == "" {
|
|
|
|
panic(fmt.Errorf("API token for api.ai must be provided! (provide it or --disable talk)"))
|
2017-04-19 16:10:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func talk(broker *tg.Broker, update tg.APIMessage) {
|
2017-05-09 11:34:52 +00:00
|
|
|
// Must be a text message
|
|
|
|
if update.Text == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
text := *(update.Text)
|
2017-05-09 13:59:42 +00:00
|
|
|
quoted := false
|
2017-04-19 16:10:33 +00:00
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
// 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
|
2017-05-09 13:59:42 +00:00
|
|
|
quoted = true
|
2017-05-09 11:34:52 +00:00
|
|
|
} else if update.Chat.Username != nil {
|
|
|
|
// Private chat, pass
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
text = strings.TrimSpace(text)
|
2017-04-19 16:10:33 +00:00
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
// Generate unique id for user
|
|
|
|
id := strconv.FormatInt(update.User.UserID, 36)
|
|
|
|
if len(id) > 36 {
|
|
|
|
id = id[:36]
|
|
|
|
}
|
2017-04-19 16:10:33 +00:00
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2017-05-09 13:47:49 +00:00
|
|
|
broker.SendChatAction(update.Chat, tg.ActionTyping)
|
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
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") {
|
2017-05-09 13:47:49 +00:00
|
|
|
reply = metaforaAPI()
|
2017-05-09 11:34:52 +00:00
|
|
|
}
|
|
|
|
return
|
2017-04-19 16:10:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 13:47:49 +00:00
|
|
|
if record.Result.Action != "" && !record.Result.ActionIncomplete {
|
|
|
|
switch record.Result.Action {
|
|
|
|
case "viaggi":
|
|
|
|
// Check that both parameters are given
|
|
|
|
if record.Result.Parameters["from-city"] != "" && record.Result.Parameters["to-city"] != "" {
|
|
|
|
data, err := viaggiAPI(record.Result.Parameters["from-city"], record.Result.Parameters["to-city"])
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[talk] viaggi failed:\n%s\n", record.Result.Action)
|
|
|
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply += "\n" + data
|
|
|
|
}
|
|
|
|
case "search":
|
|
|
|
result, err := searchAPI(record.Result.Parameters["search-item"])
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[talk] search failed:\n%s\n", record.Result.Action)
|
|
|
|
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if result.None {
|
|
|
|
broker.SendTextMessage(update.Chat, "Non ho trovato nulla, mi spiace :(", &update.MessageID)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply = fmt.Sprintf("%s\n<b>%s</b>", reply, result.Name)
|
|
|
|
if result.Description != nil {
|
|
|
|
reply += "\n" + *(result.Description)
|
|
|
|
}
|
|
|
|
if len(result.Alternatives) > 0 {
|
|
|
|
reply += "\nAlternativamente:\n - " + strings.Join(result.Alternatives, "\n - ")
|
|
|
|
}
|
2017-05-09 13:52:23 +00:00
|
|
|
case "input.unknown":
|
2017-05-09 13:59:42 +00:00
|
|
|
// Don't reply if quoted (probably just a comment)
|
|
|
|
if quoted {
|
|
|
|
return
|
|
|
|
}
|
2017-05-09 13:47:49 +00:00
|
|
|
default:
|
|
|
|
log.Printf("[talk] Unknown action called:\n%s\n", record.Result.Action)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-09 11:34:52 +00:00
|
|
|
broker.SendTextMessage(update.Chat, reply, &update.MessageID)
|
2017-04-19 16:10:33 +00:00
|
|
|
}
|