| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- package dialog
- import (
- stdcontext "context"
- "crypto/rand"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "strings"
- "time"
- "github.com/silenceper/wechat/v2/aispeech/config"
- "github.com/silenceper/wechat/v2/aispeech/context"
- "github.com/silenceper/wechat/v2/aispeech/encryptor"
- "github.com/silenceper/wechat/v2/util"
- )
- const (
- // tokenPath 获取 AccessToken.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/token.html
- tokenPath = "/v2/token"
- // importJSONPath 简单问答 JSON 导入.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/import.html
- importJSONPath = "/v2/bot/import/json"
- // fetchAsyncPath 异步任务查询.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/fetch.html
- fetchAsyncPath = "/v2/async/fetch"
- // publishPath 发布机器人.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/publish.html
- publishPath = "/v2/bot/publish"
- // effectiveProgressPath 查询机器人发布进度.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/progress.html
- effectiveProgressPath = "/v2/bot/effective_progress"
- // queryPath 调用智能对话.
- // 官方文档: https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/bot/query.html
- queryPath = "/v2/bot/query"
- )
- // Dialog 智能对话平台.
- type Dialog struct {
- *context.Context
- }
- // NewDialog init.
- func NewDialog(ctx *context.Context) *Dialog {
- return &Dialog{ctx}
- }
- func (d *Dialog) postJSON(ctx stdcontext.Context, path string, req interface{}, res interface{}, apiName string) (string, error) {
- body, err := json.Marshal(req)
- if err != nil {
- return "", err
- }
- accessToken, err := d.GetAccessTokenContext(ctx)
- if err != nil {
- return "", err
- }
- if accessToken == "" {
- return "", errEmptyAccessToken
- }
- response, err := post(ctx, d.Config, path, body, "application/json", accessToken, "")
- if err != nil {
- return "", err
- }
- return decodeResponse(response, res, apiName)
- }
- func (d *Dialog) postEmpty(ctx stdcontext.Context, path string, res interface{}, apiName string) (string, error) {
- accessToken, err := d.GetAccessTokenContext(ctx)
- if err != nil {
- return "", err
- }
- if accessToken == "" {
- return "", errEmptyAccessToken
- }
- response, err := post(ctx, d.Config, path, nil, "application/json", accessToken, "")
- if err != nil {
- return "", err
- }
- return decodeResponse(response, res, apiName)
- }
- func post(ctx stdcontext.Context, cfg *config.Config, path string, body []byte, contentType, accessToken, appID string) ([]byte, error) {
- timestamp := time.Now().Unix()
- nonce, err := randomString(16)
- if err != nil {
- return nil, err
- }
- requestID, err := randomString(32)
- if err != nil {
- return nil, err
- }
- header := map[string]string{
- "request_id": requestID,
- "timestamp": fmt.Sprintf("%d", timestamp),
- "nonce": nonce,
- "sign": encryptor.Sign(cfg.Token, timestamp, nonce, body),
- "Content-Type": contentType,
- }
- if accessToken != "" {
- header["X-OPENAI-TOKEN"] = accessToken
- } else {
- header["X-APPID"] = appID
- }
- return util.HTTPPostContext(ctx, buildURL(cfg.GetBaseURL(), path), body, header)
- }
- func buildURL(baseURL, path string) string {
- return strings.TrimRight(baseURL, "/") + "/" + strings.TrimLeft(path, "/")
- }
- func randomString(length int) (string, error) {
- buf := make([]byte, (length+1)/2)
- if _, err := rand.Read(buf); err != nil {
- return "", err
- }
- return hex.EncodeToString(buf)[:length], nil
- }
|