dialog.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package dialog
  2. import (
  3. stdcontext "context"
  4. "crypto/rand"
  5. "encoding/hex"
  6. "encoding/json"
  7. "fmt"
  8. "strings"
  9. "time"
  10. "github.com/silenceper/wechat/v2/aispeech/config"
  11. "github.com/silenceper/wechat/v2/aispeech/context"
  12. "github.com/silenceper/wechat/v2/aispeech/encryptor"
  13. "github.com/silenceper/wechat/v2/util"
  14. )
  15. const (
  16. // tokenPath 获取 AccessToken.
  17. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/token.html
  18. tokenPath = "/v2/token"
  19. // importJSONPath 简单问答 JSON 导入.
  20. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/import.html
  21. importJSONPath = "/v2/bot/import/json"
  22. // fetchAsyncPath 异步任务查询.
  23. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/fetch.html
  24. fetchAsyncPath = "/v2/async/fetch"
  25. // publishPath 发布机器人.
  26. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/publish.html
  27. publishPath = "/v2/bot/publish"
  28. // effectiveProgressPath 查询机器人发布进度.
  29. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/progress.html
  30. effectiveProgressPath = "/v2/bot/effective_progress"
  31. // queryPath 调用智能对话.
  32. // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/query.html
  33. queryPath = "/v2/bot/query"
  34. )
  35. // Dialog 智能对话平台.
  36. type Dialog struct {
  37. *context.Context
  38. }
  39. // NewDialog init.
  40. func NewDialog(ctx *context.Context) *Dialog {
  41. return &Dialog{ctx}
  42. }
  43. func (d *Dialog) postJSON(ctx stdcontext.Context, path string, req interface{}, res interface{}, apiName string) (string, error) {
  44. body, err := json.Marshal(req)
  45. if err != nil {
  46. return "", err
  47. }
  48. accessToken, err := d.GetAccessTokenContext(ctx)
  49. if err != nil {
  50. return "", err
  51. }
  52. if accessToken == "" {
  53. return "", errEmptyAccessToken
  54. }
  55. response, err := post(ctx, d.Config, path, body, "application/json", accessToken, "")
  56. if err != nil {
  57. return "", err
  58. }
  59. return decodeResponse(response, res, apiName)
  60. }
  61. func (d *Dialog) postEmpty(ctx stdcontext.Context, path string, res interface{}, apiName string) (string, error) {
  62. accessToken, err := d.GetAccessTokenContext(ctx)
  63. if err != nil {
  64. return "", err
  65. }
  66. if accessToken == "" {
  67. return "", errEmptyAccessToken
  68. }
  69. response, err := post(ctx, d.Config, path, nil, "application/json", accessToken, "")
  70. if err != nil {
  71. return "", err
  72. }
  73. return decodeResponse(response, res, apiName)
  74. }
  75. func post(ctx stdcontext.Context, cfg *config.Config, path string, body []byte, contentType, accessToken, appID string) ([]byte, error) {
  76. timestamp := time.Now().Unix()
  77. nonce, err := randomString(16)
  78. if err != nil {
  79. return nil, err
  80. }
  81. requestID, err := randomString(32)
  82. if err != nil {
  83. return nil, err
  84. }
  85. header := map[string]string{
  86. "request_id": requestID,
  87. "timestamp": fmt.Sprintf("%d", timestamp),
  88. "nonce": nonce,
  89. "sign": encryptor.Sign(cfg.Token, timestamp, nonce, body),
  90. "Content-Type": contentType,
  91. }
  92. if accessToken != "" {
  93. header["X-OPENAI-TOKEN"] = accessToken
  94. } else {
  95. header["X-APPID"] = appID
  96. }
  97. return util.HTTPPostContext(ctx, buildURL(cfg.GetBaseURL(), path), body, header)
  98. }
  99. func buildURL(baseURL, path string) string {
  100. return strings.TrimRight(baseURL, "/") + "/" + strings.TrimLeft(path, "/")
  101. }
  102. func randomString(length int) (string, error) {
  103. buf := make([]byte, (length+1)/2)
  104. if _, err := rand.Read(buf); err != nil {
  105. return "", err
  106. }
  107. return hex.EncodeToString(buf)[:length], nil
  108. }