package service import ( "context" "geo/internal/ai_tool" "geo/internal/biz" "geo/internal/config" "geo/internal/data/impl" "geo/internal/data/model" "geo/internal/entitys" "geo/pkg" "geo/tmpl/dataTemp" "geo/tmpl/errcode" "io" "os" "path/filepath" "strings" "time" "github.com/go-viper/mapstructure/v2" "github.com/gofiber/fiber/v2" "xorm.io/builder" ) type ProductService struct { cfg *config.Config productImpl *impl.ProductImpl authBiz *biz.AuthBiz productBiz *biz.ProductBiz aiBiz *biz.AiBiz } func NewProductService( cfg *config.Config, ProductImpl *impl.ProductImpl, authBiz *biz.AuthBiz, productBiz *biz.ProductBiz, aiBiz *biz.AiBiz, collect *impl.CollectImpl, collectTask *impl.CollectTaskImpl, ) *ProductService { return &ProductService{ cfg: cfg, productImpl: ProductImpl, authBiz: authBiz, productBiz: productBiz, aiBiz: aiBiz, } } func (p *ProductService) Add(c *fiber.Ctx, req *entitys.CreateProductRequest) error { _, _, err := p.authBiz.UserAndTokenValid(c.UserContext(), req.UserIndex, req.AccessToken) if err != nil { return err } var data model.Product err = mapstructure.Decode(req, &data) if err != nil { return err } err = p.productImpl.Add(c.UserContext(), &data) if err != nil { return err } return nil } func (p *ProductService) Detail(c *fiber.Ctx, req *entitys.ProductDetailRequest) error { _, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) if err != nil { return err } var detail model.Product cond := builder.NewCond(). And(builder.Eq{"id": req.Id}) err = p.productImpl.GetOneBySearchStruct(c.UserContext(), &cond, &detail) if err != nil { return err } return pkg.HandleResponse(c, detail) } func (p *ProductService) List(c *fiber.Ctx, req *entitys.ProductListRequest) error { _, _, err := p.authBiz.UserAndTokenValid(c.UserContext(), req.UserIndex, req.AccessToken) if err != nil { return err } page := req.Page if page < 1 { page = 1 } pageSize := req.PageSize if pageSize < 1 { pageSize = 20 } if pageSize > 100 { pageSize = 100 } var list []*model.Product cond := builder.NewCond(). And(builder.Eq{"user_index": req.UserIndex}). And(builder.Eq{"status": 1}) total, err := p.productImpl.GetListToStruct(c.UserContext(), &cond, &dataTemp.ReqPageBo{Page: page, Limit: pageSize}, &list, "") if err != nil { return err } return pkg.SuccessWithPageMsg(c, list, total.Total, page, pageSize) } func (p *ProductService) Update(c *fiber.Ctx, req *entitys.ProductUpdateRequest) error { _, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) if err != nil { return err } var data model.Product err = mapstructure.Decode(req, &data) if err != nil { return err } err = p.productImpl.UpdateByKey(c.UserContext(), p.productImpl.PrimaryKey(), req.Id, &data) return nil } func (p *ProductService) Del(c *fiber.Ctx, req *entitys.ProductDelRequest) error { _, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) if err != nil { return err } err = p.productImpl.DeleteByKey(c.UserContext(), p.productImpl.PrimaryKey(), req.Id) return nil } func (p *ProductService) ImgUpload(c *fiber.Ctx) error { access := c.FormValue("access_token", "") if access == "" { return errcode.ParamErr("access_token未找到") } // 验证token _, err := p.authBiz.ValidateAccessToken(c.UserContext(), access) if err != nil { return err } fileHeader, err := c.FormFile("file") if err != nil { return errcode.ParamErr("未找到上传文件") } file, err := fileHeader.Open() if err != nil { return errcode.ParamErrf("无法打开文件:%S", err.Error()) } defer file.Close() fileBytes, err := io.ReadAll(file) if err != nil { return errcode.ParamErrf("读取文件失败:%s", err.Error()) } // 获取文件扩展名 ext := pkg.GetFileExtension(fileHeader.Filename) // 根据图片类型生成文件名 fileName := pkg.GenerateImageFileName(ext) url, err := p.productBiz.SourceUpload(c.UserContext(), fileBytes, fileName) if err != nil { return err } return pkg.HandleResponse(c, fiber.Map{"url": url}) } func (p *ProductService) CreateProductInfoByDocx(c *fiber.Ctx) error { access := c.FormValue("access_token", "") if access == "" { return errcode.ParamErr("access_token未找到") } userIndex := c.FormValue("user_index", "") if userIndex == "" { return errcode.ParamErr("user_index未找到") } // 验证token _, err := p.authBiz.ValidateAccessToken(c.UserContext(), access) if err != nil { return err } fileHeader, err := c.FormFile("file") if err != nil { return errcode.ParamErr("未找到上传文件") } file, err := fileHeader.Open() if err != nil { return errcode.ParamErrf("无法打开文件:%s", err.Error()) } defer file.Close() // 创建临时文件 tempFile, err := os.CreateTemp("", "upload_*.docx") if err != nil { return errcode.ParamErrf("创建临时文件失败:%s", err.Error()) } defer tempFile.Close() // 获取临时文件的绝对路径 absPath, err := filepath.Abs(tempFile.Name()) if err != nil { return errcode.ParamErrf("获取文件绝对路径失败:%s", err.Error()) } // 将上传的文件内容复制到临时文件 _, err = io.Copy(tempFile, file) if err != nil { return errcode.ParamErrf("保存文件失败:%s", err.Error()) } // 确保文件内容已写入磁盘 err = tempFile.Sync() if err != nil { return errcode.ParamErrf("同步文件失败:%s", err.Error()) } markContent, err := pkg.ExtractWordContent(absPath, "markdown") if err != nil { return err } var productInfo entitys.ProductInfo mes := p.aiBiz.CreateProjectInfoPrompt(c.UserContext(), markContent) err = ai_tool.NewHsyq().RequestHsyqBotToJson(c.UserContext(), p.cfg.Hsyq.ApiKey, p.cfg.AiBot.ProductInfo, mes, &productInfo) if err != nil { return err } return pkg.HandleResponse(c, productInfo) } type CollectInfo struct { AIPlatformIndex string `json:"ai_platform_index"` ContentHtml string `json:"content_html"` ShareUrl string `json:"share_url"` Source []Source `json:"source"` } type Source struct { Title string `json:"name"` Url string `json:"url"` PlatformName string `json:"platform"` PlatformIcon string `json:"Platform_icon"` } func (p *ProductService) Collect(c *fiber.Ctx, req *entitys.ProductCollectRequest) error { return nil _, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) if err != nil { return err } productInfo, err := p.productBiz.GetProduct(c.UserContext(), req.ProductId) if err != nil { return err } collect := ai_tool.NewCollect(p.cfg.Collect.ApiKey) ctx, cancel := context.WithTimeout(context.Background(), time.Second*120) defer cancel() for _, v := range req.Platform { go func() { defer func() { if r := recover(); r != nil { } }() request := ai_tool.CreateReq{ Keywords: strings.Join(req.Keywords, ","), Question: req.Question, Platform: v, ThirdID: "11", } _, _err := collect.Create(ctx, &request) if _err != nil { return } }() } return pkg.HandleResponse(c, productInfo) }