package flow import ( "ai-agent/workflow/model/dto" flowDto "ai-agent/workflow/model/dto/flow" "bytes" "context" "fmt" "io" "mime/multipart" "net/http" "strings" commonHttp "gitea.com/red-future/common/http" "gitea.com/red-future/common/utils" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) func GetIsChatModel(ctx context.Context) (*flowDto.GetIsChatModelRes, error) { headers := make(map[string]string) if r := g.RequestFromCtx(ctx); r != nil { for k, v := range r.Request.Header { if len(v) > 0 { headers[k] = v[0] } } } res := new(flowDto.GetIsChatModelRes) err := commonHttp.Get(ctx, "model-gateway/model/getIsChatModel", headers, res, nil) if err != nil { return nil, err } return res, nil } func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string, error) { headers := make(map[string]string) if r := g.RequestFromCtx(ctx); r != nil { for k, v := range r.Request.Header { if len(v) > 0 { headers[k] = v[0] } } } res := new(flowDto.CreateTaskRes) err := commonHttp.Post(ctx, "model-gateway/task/createTask", headers, res, &req) if err != nil { return "", err } return res.TaskId, nil } func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (*flowDto.ComposeMessagesRes, error) { headers := make(map[string]string) if r := g.RequestFromCtx(ctx); r != nil { for k, v := range r.Request.Header { if len(v) > 0 { headers[k] = v[0] } } } res := new(flowDto.ComposeMessagesRes) err := commonHttp.Post(ctx, "prompts-core/prompt/composeMessages", headers, res, &req) if err != nil { return nil, err } return res, nil } func GatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (any, error) { modelTaskId, err := CreateGatewayTask(ctx, &flowDto.CreateTaskReq{ ModelName: model, BizName: g.Cfg().MustGet(ctx, "server.name").String(), CallbackUrl: "/flow/execution/modelCallback", RequestPayload: content, EpicycleId: epicycleId, }) if err != nil { return nil, err } return Wait(ctx, modelTaskId) } func GetTaskResult(ctx context.Context, result any) (*flowDto.TaskCallback, error) { task := new(flowDto.TaskCallback) if err := gconv.Struct(result, task); err != nil { return nil, err } url, err := utils.GetFileAddressPrefix(ctx) if err != nil { return nil, err } // 获取远程文件内容 file, err := FetchRemoteJsonFile(ctx, url+task.OssFile) if err != nil { return nil, err } task.Text = gconv.String(file) return task, nil } func FetchRemoteJsonFile(ctx context.Context, fileUrl string) ([]byte, error) { // 1. 下载文件 resp, err := g.Client().Get(ctx, fileUrl) if err != nil { return nil, fmt.Errorf("get file failed: %w", err) } defer resp.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("http status error: %d", resp.StatusCode) } return io.ReadAll(resp.Body) } func GetImageBytesFromURL(url string) (all []byte, contentType string, err error) { resp, err := http.Get(url) if err != nil { return } defer resp.Body.Close() all, err = io.ReadAll(resp.Body) if err != nil { return } contentType = resp.Header.Get("Content-Type") return } func Upload(ctx context.Context, req *dto.UploadFileBytesReq) (*dto.UploadFileBytesRes, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("file", req.FileName) if err != nil { return nil, err } if _, err = part.Write(req.FileBytes); err != nil { return nil, err } if err = writer.Close(); err != nil { return nil, err } headers := make(map[string]string) headers["Content-Type"] = writer.FormDataContentType() if r := g.RequestFromCtx(ctx); r != nil { if auth := r.Header.Get("Authorization"); auth != "" { headers["Authorization"] = auth } } // 发起上传请求 res := &dto.UploadFileBytesRes{} url := "oss/file/uploadFile" if err = commonHttp.Post(ctx, url, headers, res, body.Bytes()); err != nil { return nil, err } g.Log().Infof(ctx, "[Upload] success url=%s size=%d", res.FileURL, res.FileSize) return res, nil } func buildMergeHtml(texts []string, images []string) string { html := strings.Builder{} html.WriteString(`
`) // 1. 先渲染图片(无任何上下边距,占满宽度) if len(images) > 0 { html.WriteString(`
`) for _, img := range images { html.WriteString(fmt.Sprintf(``, img)) } html.WriteString(`
`) } // 2. 渲染文案(紧贴图片下方,仅用内边距留白) if len(texts) > 0 { html.WriteString(`
`) // 段落之间用
而不是

,减少空行 html.WriteString(strings.Join(texts, "
")) html.WriteString(`
`) } html.WriteString(`
`) return html.String() }