package spark import ( "StuAcaWorksAI/dao" "StuAcaWorksAI/proto" "StuAcaWorksAI/service" "StuAcaWorksAI/worker" "encoding/json" "errors" "fmt" "github.com/google/uuid" "io" "log" "net/http" "os" "path" "strconv" "strings" "time" ) func SparkPPTThemeList(model *proto.ModelParam, req proto.GetSparkPPTThemeReq) (proto.SparkPPTThemeListResponse, error) { url := "https://zwapi.xfyun.cn/api/ppt/v2/template/list" headers, err := getSparkRequestHeaders(model.APPID, model.APISecret) if err != nil { log.Println("Spark PPT Theme Error getting headers:", err) return proto.SparkPPTThemeListResponse{}, err } //log.Println("Spark PPT Theme headers:", headers) req_ := proto.PPTThemeRequest{ Style: req.Style, Color: req.Color, Industry: req.Industry, PageNum: 1, PageSize: 10, } reqStr, err := json.Marshal(req_) if err != nil { log.Println("Spark PPT Theme Error encoding request:", err) return proto.SparkPPTThemeListResponse{}, err } log.Println("Spark PPT Theme req:", string(reqStr)) err, resp := worker.DoPostRequestJSON(url, reqStr, headers) var response proto.SparkPPTThemeListResponse if err != nil { log.Println("Spark PPT Theme Error:", err) } else { err = json.Unmarshal(resp, &response) if err != nil { log.Println("Spark PPT Theme Error decoding response:", err) } } log.Println("Spark PPT Theme Response:", string(resp)) //log.Println("Spark PPT Theme Response:", response) return response, err } func getSparkRequestHeaders(appId, apiSecret string) (map[string]string, error) { headers := map[string]string{ "appId": "d3a4647c", "timestamp": strconv.FormatInt(time.Now().Unix(), 10), } algorithm := ApiAuthAlgorithm{} signature := algorithm.GetSignature(appId, apiSecret, time.Now().Unix()) headers["signature"] = signature return headers, nil } // 根据用户输入及文档生成大纲,文档可以是docx、doc、txt、pdf格式 func SparkCreateOutlineByDoc(model *proto.ModelParam, userReq *proto.SparkCreateOutlineRequest) (proto.SparkCreateOutlineResponse, error) { url := "https://zwapi.xfyun.cn/api/ppt/v2/createOutlineByDoc" headers, err := getSparkRequestHeaders(model.APPID, model.APISecret) if err != nil { log.Println("Spark PPT Theme Error getting headers:", err) return proto.SparkCreateOutlineResponse{}, err } log.Println("Spark create outline by doc headers:", headers) req := proto.SparkCreateOutlineByDocRequest{ Query: userReq.Query, FileUrl: userReq.FileUrl, FileName: userReq.FileName, } reqStr, err := json.Marshal(req) if err != nil { log.Println("Spark create outline by doc Error encoding request:", err) } log.Println("Spark create outline by doc req:", string(reqStr)) err, resp := worker.DoPostRequestForm(url, reqStr, headers) //log.Println("Spark create outline by doc Response:", string(resp)) var response proto.SparkCreateOutlineResponse if err != nil { log.Println("Spark create outline by doc Error:", err) } else { err = json.Unmarshal(resp, &response) if err != nil { log.Println("Spark create outline by doc Error decoding response:", err) } } log.Println("Spark create outline by doc Response struct:", response) return response, err } // 根据query生成大纲 func SparkCreateOutline(model *proto.ModelParam, userReq *proto.SparkCreateOutlineRequest) (proto.SparkCreateOutlineResponse, error) { url := "https://zwapi.xfyun.cn/api/ppt/v2/createOutline" headers, err := getSparkRequestHeaders(model.APPID, model.APISecret) if err != nil { log.Println("Spark PPT Theme Error getting headers:", err) return proto.SparkCreateOutlineResponse{}, err } log.Println("Spark create outline by doc headers:", headers) //自定义内容 req := proto.SparkCreateOutlineByDocRequest{ Query: userReq.Query, } reqStr, err := json.Marshal(req) if err != nil { log.Println("Spark create PPT Error encoding request:", err) } log.Println("Spark create PPT req:", string(reqStr)) err, resp := worker.DoPostRequestForm(url, reqStr, headers) log.Println("Spark create PPT Response:", string(resp)) var response proto.SparkCreateOutlineResponse if err != nil { log.Println("Spark create PPT Error:", err) } else { err = json.Unmarshal(resp, &response) if err != nil { log.Println("Spark create PPT Error decoding response:", err) } } log.Println("Spark create PPT Response struct:", response) return response, err } func SparkCreatePPTByOutline(model *proto.ModelParam, userReq *proto.SparkCreatePPTByOutlineUserRequest) (proto.SparkCreatePPTResponse, error) { url := "https://zwapi.xfyun.cn/api/ppt/v2/createPptByOutline" headers, err := getSparkRequestHeaders(model.APPID, model.APISecret) if err != nil { log.Println("Spark create ppt by outline Error encoding request:", err) return proto.SparkCreatePPTResponse{}, err } log.Println("Spark create ppt by outline headers:", headers) req := proto.SparkCreatePptByOutlineRequest{ Query: userReq.Query, FileUrl: userReq.FileUrl, FileName: userReq.FileName, Outline: userReq.Outline, } reqStr, err := json.Marshal(req) if err != nil { log.Println("Spark create ppt by outline Error encoding request:", err) } log.Println("Spark create ppt by outline req:", string(reqStr)) err, resp := worker.DoPostRequestJSON(url, reqStr, headers) log.Println("Spark create ppt by outline Response:", string(resp)) var response proto.SparkCreatePPTResponse if err != nil { log.Println("Spark create ppt by outline Error:", err) } else { err = json.Unmarshal(resp, &response) if err != nil { log.Println("Spark create ppt by outline Error decoding response:", err) } } log.Println("Spark create ppt by outline Response struct:", response) return response, err } func SparkGetPPTInfoBySID(model *proto.ModelParam, userReq *proto.SparkCreatePPTByOutlineUserRequest) (proto.SparkCreatePPTByOutlineResponse, error) { url := "https://zwapi.xfyun.cn/api/ppt/v2/progress?sid=" + userReq.Sid headers, err := getSparkRequestHeaders(model.APPID, model.APISecret) if err != nil { log.Println("Spark create ppt by outline Error encoding request:", err) return proto.SparkCreatePPTByOutlineResponse{}, err } log.Println("Spark create ppt by outline headers:", headers) err, resp := worker.DoGetRequest(url, headers) log.Println("Spark create ppt by outline Response:", string(resp)) var response proto.SparkCreatePPTByOutlineResponse if err != nil { log.Println("Spark create ppt by outline Error:", err) } else { err = json.Unmarshal(resp, &response) if err != nil { log.Println("Spark create ppt by outline Error decoding response:", err) } } log.Println("Spark create ppt by outline Response struct:", response) return response, err } // 处理制作大纲请求 func SparkDoCreateOutline(userReq *proto.SparkCreateOutlineRequest, base *proto.SparkCreatePPTBaseInfo) (proto.SparkCreateOutlineResponse, error) { var modelParam proto.ModelParam var err error //需要保存会话 sessionName := "" sessionName = userReq.Query //if len(userReq.Query) > 10 { // sessionName = userReq.Query[:10] //} else { // sessionName = userReq.Query //} log.Println("spark create outline base info:", *base) err2, sessionID := service.CreateSession((*base).UserID, proto.SessionTypeUserCreatePPT, sessionName) if err2 != nil { log.Println("Create session error:", err2) return proto.SparkCreateOutlineResponse{}, err2 } else { if len(sessionName) > 30 { //通过ai总结会话名称 go func() { sessionErr := service.UpdateSessionNameByAIAndID(int(sessionID), base.UserID, sessionName) if sessionErr != nil { log.Println("update spark create ppt ai session name error:", sessionErr) return } //更新会话名称 }() } } base.SessionID = sessionID //获取模型 models, funcs, mferr := service.FindFuncModelListByFunctionV2(userReq.Function) if mferr != nil { return proto.SparkCreateOutlineResponse{}, mferr } model := models[0] base.ModelID = int(model.ID) err = json.Unmarshal([]byte(model.Parameter), &modelParam) if err != nil { return proto.SparkCreateOutlineResponse{}, err } modelParam.Url = model.Url modelParam.System = funcs[0].Info //系统功能 //保存消息 userReqStr, err := json.Marshal(userReq) if err != nil { log.Println("Error parsing JSON:", err) return proto.SparkCreateOutlineResponse{}, err } err3, userMsgID := service.CreateMessage(proto.UserToModelMsgType, int(sessionID), base.UserID, int(model.ID), string(userReqStr), proto.UserToModelPPTMsgType, int(funcs[0].ID)) if err3 != nil { log.Println("Create message error:", err3, userMsgID) return proto.SparkCreateOutlineResponse{}, err3 } var outline proto.SparkCreateOutlineResponse //获取大纲 if proto.Config.SPARK_PPT_USAGE { if userReq.FileUrl == "" { outline, err = SparkCreateOutline(&modelParam, userReq) //根据query生成大纲 } else { outline, err = SparkCreateOutlineByDoc(&modelParam, userReq) //根据文档生成大纲 } } else { outline = testPPTOutline() //测试阶段 } //进行保存 if err != nil { log.Println("Spark create outline Error:", err) return outline, err } outlineStr, _ := json.Marshal(outline) //返回的数据保存 service.CreateAIStreamMsg(base.UserID, base.ModelID, int(base.SessionID), outline, modelParam.Model) //保存大纲 err3, userMsgID = service.CreateMessage(proto.ModelToUserMsgType, int(sessionID), int(model.ID), base.UserID, string(outlineStr), proto.UserToModelPPTMsgType, int(funcs[0].ID)) if err3 != nil { log.Println("Create message error:", err3, userMsgID) return proto.SparkCreateOutlineResponse{}, err3 } return outline, err } // 处理制作PPT请求 func SparkDoCreatePPTByOutline(userReq *proto.SparkCreatePPTByOutlineUserRequest, base *proto.SparkCreatePPTBaseInfo) (proto.SparkCreatePPTResponse, error) { var modelParam proto.ModelParam var err error //需要保存会话 if base.SessionID == 0 { log.Println("session id is 0, create ppt") return proto.SparkCreatePPTResponse{}, errors.New("create ppt,session id is 0, please create session first") } //获取模型 models, funcs, mferr := service.FindFuncModelListByFunctionV2(userReq.Function) if mferr != nil { return proto.SparkCreatePPTResponse{}, mferr } model := models[0] base.ModelID = int(model.ID) err = json.Unmarshal([]byte(model.Parameter), &modelParam) if err != nil { return proto.SparkCreatePPTResponse{}, err } modelParam.Url = model.Url modelParam.System = funcs[0].Info //系统功能 //保存消息 userReqStr, err := json.Marshal(userReq) if err != nil { log.Println("Error parsing JSON:", err) return proto.SparkCreatePPTResponse{}, err } err3, userMsgID := service.CreateMessage(proto.UserToModelMsgType, int(base.SessionID), base.UserID, int(model.ID), string(userReqStr), proto.UserToModelPPTMsgType, int(funcs[0].ID)) if err3 != nil { log.Println("Create message error:", err3, userMsgID) return proto.SparkCreatePPTResponse{}, err3 } var resp proto.SparkCreatePPTResponse if proto.Config.SPARK_PPT_USAGE { var err4 error resp, err4 = SparkCreatePPTByOutline(&modelParam, userReq) //根据大纲生成ppt if err4 != nil { log.Println("Spark create ppt by outline Error:", err4) return proto.SparkCreatePPTResponse{}, err4 } } else { //测试阶段 resp = testPPTInfo() } //进行保存 service.CreateAIStreamMsg(base.UserID, base.ModelID, int(base.SessionID), resp, modelParam.Model) //保存消息 //新协程获取ppt制作进度 userReq.Sid = resp.Data.SID go SparkDoGetPPTInfoBySID(&modelParam, userReq, base, &model) //根据大纲生成ppt return resp, nil } // 每3秒查询一次ppt制作情况 func SparkDoGetPPTInfoBySID(modelParam *proto.ModelParam, userReq *proto.SparkCreatePPTByOutlineUserRequest, base *proto.SparkCreatePPTBaseInfo, model *dao.Model) { //定时 ticker := time.NewTicker(3 * time.Second) defer ticker.Stop() i := 0 for { select { case <-ticker.C: i += 1 if i > 20 { log.Println("SparkDoGetPPTInfoBySID timeout more 1 min, stop ticker") return } log.Println("SparkDoGetPPTInfoBySID ticker") resp, err := SparkGetPPTInfoBySID(modelParam, userReq) //根据大纲生成ppt if err != nil { log.Println("Spark create ppt by outline Error:", err) return } outlineStr, _ := json.Marshal(userReq.Outline) resp.Desc = string(outlineStr) //大纲信息 service.CreateAIStreamMsg(base.UserID, base.ModelID, int(base.SessionID), resp, modelParam.Model) //保存消息 var respStr []byte respStr, _ = json.Marshal(resp) //添加到消息队列,用于前端查询 key := fmt.Sprintf("user-%d-session-%d-create-pptx", base.UserID, base.SessionID) worker.SetRedisWithExpire(key, string(respStr), time.Second*60*60) //设置60分钟过期 log.Println("Spark create ppt status set redis key:", key, "value:", string(respStr)) if resp.Code != 0 { log.Println("Spark create ppt by outline Error:", resp) return } if resp.Data.PptStatus == "done" { log.Println("ppt done") //下载文件,保存到指定用户的文件 fileName, filePath, err2 := SparkSavePPTFileToUser(resp.Data.PptUrl) if err2 != nil { log.Println("Spark save ppt file to user Error:", err2) return } //保存文件路径到数据库 fileRecord := dao.CreateFile(fileName, userReq.Outline.Title+".pptx", "", filePath, "", 0, base.UserID, false) fileAuth := service.CreateUserFile(base.UserID, fileRecord.FileName, int(fileRecord.ID), proto.UserFileTypeFile) if fileRecord.ID == 0 || fileAuth.ID == 0 { log.Println("save file info failed", fileRecord.ID, fileAuth.ID) } fileAuth.ShareCode = fileRecord.FileStoreName fileAuthStr, _ := json.Marshal(fileAuth) resp.Data.AiImageStatus = string(fileAuthStr) //文件信息 respStr, _ = json.Marshal(resp) //将model发送的消息保存到数据库 err3, userMsgID := service.CreateMessage(proto.ModelToUserMsgType, int(base.SessionID), int(model.ID), base.UserID, string(respStr), proto.UserToModelPPTMsgType, base.FunctionID) if err3 != nil { log.Println("Create message error:", err3, userMsgID) } log.Println("spark create ppt by outline success,msg id:", userMsgID) return } } } } // 将下载的文件保存到对应指定用户的文件,并对该会话添加ppt完成消息 func SparkSavePPTFileToUser(fileUrl string) (string, string, error) { log.Println("Spark save ppt file to user") //https://bjcdn.openstorage.cn/xinghuo-privatedata/zhiwen/2025-04-02/6ebfc0b2-824a-4acc-a030-01acce938dab/3209de1bca814ac48884e015277360fd.pptx fileName := fileUrl[strings.LastIndex(fileUrl, "/")+1:] //文件保存路径 path_ := service.GetFilePath(proto.FILE_BASE_DIR) //获取文件后缀 fileSuffix := path.Ext(fileName) //生成文件名 fileStoreName := uuid.NewString() + fileSuffix saveFile := path_ + "/" + fileStoreName //下载文件 err := DownloadFile(fileUrl, saveFile) if err != nil { log.Println("Download file error:", err) return "", "", err } log.Println("Download file success:", fileStoreName) return fileStoreName, path_, nil } func DownloadFile(url, filePath string) error { // 创建 HTTP GET 请求 resp, err := http.Get(url) if err != nil { return err } // 确保在函数结束时关闭响应体 defer resp.Body.Close() // 检查 HTTP 响应状态码 if resp.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code: %d", resp.StatusCode) } // 创建本地文件 out, err := os.Create(filePath) if err != nil { return err } // 确保在函数结束时关闭文件 defer out.Close() // 将响应体内容复制到本地文件 _, err = io.Copy(out, resp.Body) return err } func testPPTInfo() proto.SparkCreatePPTResponse { path := "/home/saw/saw_ppt_info.json" var pptInfo proto.SparkCreatePPTResponse //读取文件 file, err := os.Open(path) if err != nil { log.Println("Error opening file:", err) return pptInfo } defer file.Close() //读取文件内容 data, err := io.ReadAll(file) if err != nil { log.Println("Error reading file:", err) return pptInfo } err = json.Unmarshal(data, &pptInfo) if err != nil { log.Println("Error unmarshalling JSON:", err) return pptInfo } return pptInfo } func testPPTOutline() proto.SparkCreateOutlineResponse { path := "/home/saw/saw_ppt_outline.json" var outline proto.SparkCreateOutlineResponse //读取文件 file, err := os.Open(path) if err != nil { log.Println("Error opening file:", err) return outline } defer file.Close() //读取文件内容 data, err := io.ReadAll(file) if err != nil { log.Println("Error reading file:", err) return outline } err = json.Unmarshal(data, &outline) if err != nil { log.Println("Error unmarshalling JSON:", err) return outline } return outline } func TestPPTTHemeList() proto.SparkPPTThemeListResponse { path := "/home/saw/saw_ppt_theme.json" var themeList proto.SparkPPTThemeListResponse //读取文件 file, err := os.Open(path) if err != nil { log.Println("Error opening file:", err) return themeList } defer file.Close() //读取文件内容 data, err := io.ReadAll(file) if err != nil { log.Println("Error reading file:", err) return themeList } err = json.Unmarshal(data, &themeList) if err != nil { log.Println("Error unmarshalling JSON:", err) return themeList } return themeList }