This repository has been archived on 2023-07-05. You can view files and clone it, but cannot push or open issues or pull requests.
clessy/mods-toupdate/talk.go

215 lines
6.0 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"strings"
"time"
"github.com/hamcha/tg"
)
type QRequest struct {
SessionID string `json:"sessionId"`
Query string `json:"query"`
Language string `json:"lang"`
}
type QResponse struct {
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 map[string]string `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 talk_init() {
if strings.HasPrefix(*talktoken, "@") {
data, err := ioutil.ReadFile((*talktoken)[1:])
if err != nil {
panic(err)
}
*talktoken = strings.TrimSpace(string(data))
}
if *talktoken == "" {
panic(fmt.Errorf("API token for api.ai must be provided! (provide it or --disable talk)"))
}
}
func talk_message(broker *tg.Broker, update tg.APIMessage) {
// Must be a text message
if update.Text == nil {
return
}
text := *(update.Text)
// Must not be a command
if text[0] == '/' {
return
}
quoted := false
// 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
quoted = true
} 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
}
if !quoted {
broker.SendChatAction(update.Chat, tg.ActionTyping)
}
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") {
reply = metaforaAPI()
}
return
}
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 - ")
}
case "input.unknown":
// Don't reply if quoted (probably just a comment)
if quoted {
return
}
default:
log.Printf("[talk] Unknown action called:\n%s\n", record.Result.Action)
}
}
broker.SendTextMessage(update.Chat, reply, &update.MessageID)
}