312 lines
8.2 KiB
Go
312 lines
8.2 KiB
Go
|
package moonshot
|
|||
|
|
|||
|
import (
|
|||
|
"bytes"
|
|||
|
"encoding/json"
|
|||
|
"fmt"
|
|||
|
"github.com/PuerkitoBio/goquery"
|
|||
|
"github.com/tidwall/gjson"
|
|||
|
"io"
|
|||
|
"log"
|
|||
|
"mime/multipart"
|
|||
|
"net/http"
|
|||
|
"os"
|
|||
|
"strings"
|
|||
|
"week/tools"
|
|||
|
"week/udesk"
|
|||
|
)
|
|||
|
|
|||
|
//请求月之暗面所需要的常量
|
|||
|
|
|||
|
const (
|
|||
|
MoonshotFileApiUrl = "https://api.moonshot.cn/v1/files/"
|
|||
|
moonshotApiKey = "sk-DwKNLIVfGFi5CUocISixedd2kLcNzYVRFShbScKtbxMNOPkQ"
|
|||
|
)
|
|||
|
|
|||
|
// 上传文件
|
|||
|
|
|||
|
func ReqMoonShotFileSendApi() *string {
|
|||
|
filePath := "./周报.xlsx"
|
|||
|
// 打开文件
|
|||
|
file, err := os.Open(filePath)
|
|||
|
if err != nil {
|
|||
|
log.Printf("打开周报excel失败,错误是:%v", err)
|
|||
|
}
|
|||
|
defer file.Close()
|
|||
|
|
|||
|
// 创建一个缓冲区
|
|||
|
body := &bytes.Buffer{}
|
|||
|
writer := multipart.NewWriter(body)
|
|||
|
|
|||
|
// 创建一个文件表单字段
|
|||
|
part, err := writer.CreateFormFile("file", filePath)
|
|||
|
if err != nil {
|
|||
|
log.Printf("写文件缓存失败,错误是%v", err)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 将文件内容拷贝到表单字段
|
|||
|
_, err = io.Copy(part, file)
|
|||
|
if err != nil {
|
|||
|
log.Printf("拷贝文件到缓存失败,错误是%v", err)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 添加其他表单字段
|
|||
|
writer.WriteField("purpose", "file-extract")
|
|||
|
|
|||
|
// 完成表单写入
|
|||
|
writer.Close()
|
|||
|
|
|||
|
// 创建 HTTP 请求
|
|||
|
req, err := http.NewRequest("POST", MoonshotFileApiUrl, body)
|
|||
|
if err != nil {
|
|||
|
log.Printf("请求月之暗面api过程,创建http请求失败,错误是:%s", err)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 设置请求头
|
|||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|||
|
req.Header.Set("Authorization", "Bearer "+moonshotApiKey)
|
|||
|
|
|||
|
// 发送请求
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(req)
|
|||
|
if err != nil {
|
|||
|
log.Printf("请求月之暗面api过程,请求失败,错误是:%s", err)
|
|||
|
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
|
|||
|
// 读取响应
|
|||
|
responseBody, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
log.Printf("请求月之暗面api过程,读取响应失败,错误是:%s", err)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 打印响应内容
|
|||
|
fileId := gjson.Get(string(responseBody), "id").String()
|
|||
|
log.Printf("文件上传成功,你上传的文件id是:%s", fileId)
|
|||
|
return &fileId
|
|||
|
}
|
|||
|
|
|||
|
// 删除文件
|
|||
|
|
|||
|
func ReqMoonShotFileDeleteApi(fileID *string) {
|
|||
|
// 设置 API endpoint
|
|||
|
url := fmt.Sprintf(MoonshotFileApiUrl + *fileID)
|
|||
|
|
|||
|
// 创建 HTTP 请求
|
|||
|
req, err := http.NewRequest("DELETE", url, nil)
|
|||
|
if err != nil {
|
|||
|
log.Printf("调用月之暗面删除文件api过程,创建http请求失败,错误是%v", err)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 设置请求头(如果需要的话)
|
|||
|
req.Header.Set("Authorization", "Bearer "+moonshotApiKey)
|
|||
|
|
|||
|
// 发送请求
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(req)
|
|||
|
if err != nil {
|
|||
|
log.Printf("调用月之暗面删除文件api过程,发送http请求失败,错误是%v", err)
|
|||
|
return
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
|
|||
|
// 检查响应状态码
|
|||
|
if resp.StatusCode == http.StatusOK {
|
|||
|
log.Printf("请求月之暗面删除文件api成功~")
|
|||
|
} else {
|
|||
|
log.Println("请求月之暗面删除文件api失败>_<, http状态码是:", resp.StatusCode)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 开启ai对话主函数
|
|||
|
|
|||
|
func AiChat() (string, error) {
|
|||
|
fileId := ReqMoonShotFileSendApi()
|
|||
|
contentStr := GetFileContent(fileId)
|
|||
|
// 设置 API endpoint
|
|||
|
url := "https://api.moonshot.cn/v1/chat/completions"
|
|||
|
|
|||
|
// 构造请求体
|
|||
|
requestBody := map[string]interface{}{
|
|||
|
"model": "moonshot-v1-128k",
|
|||
|
"messages": []map[string]string{
|
|||
|
{"role": "system", "content": contentStr},
|
|||
|
{"role": "user", "content": "帮忙分析下工单中的错别字,告诉我对应的工单id"},
|
|||
|
},
|
|||
|
"temperature": 0.2,
|
|||
|
}
|
|||
|
|
|||
|
// 将请求体转换为 JSON 格式
|
|||
|
jsonBody, err := json.Marshal(requestBody)
|
|||
|
if err != nil {
|
|||
|
log.Printf("开启会话过程,将请求体转换为json格式失败,错误是:%v", err)
|
|||
|
return "", err
|
|||
|
}
|
|||
|
|
|||
|
// 创建 HTTP 请求
|
|||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
|
|||
|
if err != nil {
|
|||
|
log.Printf("开启会话过程,创建请求失败,错误是:%v", err)
|
|||
|
return "", err
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 设置请求头
|
|||
|
req.Header.Set("Content-Type", "application/json")
|
|||
|
req.Header.Set("Authorization", "Bearer "+moonshotApiKey)
|
|||
|
|
|||
|
// 发送请求
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(req)
|
|||
|
if err != nil {
|
|||
|
log.Printf("开启会话过程,发送请求失败,错误是:%v:", err)
|
|||
|
return "", err
|
|||
|
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
|
|||
|
// 读取响应
|
|||
|
responseBody := new(bytes.Buffer)
|
|||
|
_, err = responseBody.ReadFrom(resp.Body)
|
|||
|
if err != nil {
|
|||
|
log.Printf("开启会话过程,读取响应失败,错误是:%v:", err)
|
|||
|
return "", err
|
|||
|
}
|
|||
|
|
|||
|
defer ReqMoonShotFileDeleteApi(fileId) //对话后清空文件
|
|||
|
// 打印响应内容
|
|||
|
jsonData := responseBody.String()
|
|||
|
repFromAi := gjson.Get(jsonData, "choices.#.message.content").String()
|
|||
|
repFromAi = strings.Replace(repFromAi, "\\n", "\n", -1)
|
|||
|
repFromAi = strings.Replace(repFromAi, "\\", "", -1)
|
|||
|
repFromAi = strings.Replace(repFromAi, "[", "", -1)
|
|||
|
repFromAi = strings.Replace(repFromAi, "]", "", -1)
|
|||
|
repFromAi = strings.Replace(repFromAi, "\"", "", 1)
|
|||
|
log.Println(repFromAi)
|
|||
|
return repFromAi, nil
|
|||
|
}
|
|||
|
|
|||
|
// 获取文件内容
|
|||
|
|
|||
|
func GetFileContent(fileID *string) string {
|
|||
|
|
|||
|
// 设置 API endpoint
|
|||
|
url := fmt.Sprintf(MoonshotFileApiUrl + *fileID + "/content")
|
|||
|
|
|||
|
// 创建 HTTP 请求
|
|||
|
req, err := http.NewRequest("GET", url, nil)
|
|||
|
if err != nil {
|
|||
|
log.Printf("月之暗面api,获取文件内容过程,创建http请求,错误是:%v:", err)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 设置请求头
|
|||
|
req.Header.Set("Authorization", "Bearer "+moonshotApiKey)
|
|||
|
|
|||
|
// 发送请求
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(req)
|
|||
|
if err != nil {
|
|||
|
log.Printf("月之暗面api,获取文件内容过程,发送请求,错误是:%v", err)
|
|||
|
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
|
|||
|
// 读取响应内容
|
|||
|
content, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
log.Printf("月之暗面api,获取文件内容过程,读取响应失败,错误是:%v", err)
|
|||
|
|
|||
|
}
|
|||
|
contentStr := string(content)
|
|||
|
// 打印文件内容
|
|||
|
fmt.Println(contentStr)
|
|||
|
return contentStr
|
|||
|
}
|
|||
|
|
|||
|
// 根据工单id循环获取工单回复内容
|
|||
|
|
|||
|
func CreateExcel() error {
|
|||
|
totalPages, err := udesk.GetUdeskTicketId()
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
id, err := udesk.LoopGetTicketId(totalPages)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
contentMap := make(map[string][]string)
|
|||
|
j := 1
|
|||
|
for _, v := range id {
|
|||
|
|
|||
|
idUrl := fmt.Sprintf("https://servicecenter-alauda.udesk.cn/open_api_v1/tickets/%v/replies?", v)
|
|||
|
repliesUrl := udesk.Geturlstring(idUrl)
|
|||
|
resp, err := http.Get(repliesUrl)
|
|||
|
if err != nil {
|
|||
|
// 处理错误
|
|||
|
log.Printf("获取工单过滤器下的回复信息失败,发送请求过程,错误是:%v\n", err)
|
|||
|
return err
|
|||
|
}
|
|||
|
defer func(Body io.ReadCloser) {
|
|||
|
err := Body.Close()
|
|||
|
if err != nil {
|
|||
|
|
|||
|
}
|
|||
|
}(resp.Body)
|
|||
|
body, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
// 处理错误
|
|||
|
log.Printf("获取工单过滤器下的回复信息失败,读取返回体过程,错误是:%v\n", err)
|
|||
|
return err
|
|||
|
}
|
|||
|
jsonData := string(body)
|
|||
|
repliesContent := gjson.Get(jsonData, "replies.#.content").String()
|
|||
|
repliesContent = strings.Trim(repliesContent, "[]")
|
|||
|
//repliesContent = trimHtml(repliesContent)
|
|||
|
//查找回复内容和配图
|
|||
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(repliesContent))
|
|||
|
var s = make([]string, 0)
|
|||
|
doc.Find("p,img").Each(func(i int, selection *goquery.Selection) {
|
|||
|
imgSrc, exists := selection.Attr("src")
|
|||
|
if exists {
|
|||
|
s = append(s, imgSrc)
|
|||
|
s = append(s, "\n")
|
|||
|
}
|
|||
|
s = append(s, selection.Text())
|
|||
|
s = append(s, "\n")
|
|||
|
})
|
|||
|
|
|||
|
//跳过没有回复内容的工单,即运维服务,减少给模型的错误条件
|
|||
|
if len(s) == 0 {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
repliesContentSlice := tools.ReverseSlice(s)
|
|||
|
|
|||
|
cloudId := udesk.Id2CloudId(v)
|
|||
|
log.Printf("正在处理map中的第%v个数据,键是%v\n", j, v)
|
|||
|
if cloudId == "" {
|
|||
|
contentMap[v] = repliesContentSlice
|
|||
|
} else {
|
|||
|
contentMap[cloudId] = repliesContentSlice
|
|||
|
}
|
|||
|
log.Printf("第%v个数据数据处理完成\n", j)
|
|||
|
j++
|
|||
|
}
|
|||
|
log.Printf("所有回复数据处理完成,map中键的数量:%v\n", len(contentMap))
|
|||
|
//fmt.Printf("map的值:%v\n", contentMap) //回复内容的map,待办:将这个map中的建存储第一列,将这个map中的值作为第二列存储
|
|||
|
// 生成excel表格内容为id --> 回复内容
|
|||
|
// 保存到某地
|
|||
|
tools.CreateNewExcel(contentMap) //创建了excel
|
|||
|
//sk-DwKNLIVfGFi5CUocISixedd2kLcNzYVRFShbScKtbxMNOPkQ
|
|||
|
//卡点,如何根据文件内容获取回复,目前这个结构只能开启单轮对话
|
|||
|
return nil
|
|||
|
|
|||
|
}
|