2026-05-08 11:35:15 +08:00
|
|
|
|
package einograph
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"ai-agent/workflow/model/dto"
|
|
|
|
|
|
"ai-agent/workflow/skill"
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"io"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
2026-06-10 15:29:21 +08:00
|
|
|
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
|
|
|
|
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
2026-05-08 11:35:15 +08:00
|
|
|
|
"github.com/cloudwego/eino/schema"
|
|
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
|
|
|
"github.com/gogf/gf/v2/os/glog"
|
|
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 全局保存请求(最简单、最稳定、Eino 必不报错)
|
|
|
|
|
|
var currentReq *dto.CreationInput
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 1. 输入适配 ====================
|
|
|
|
|
|
func InputAdaptLambda(ctx context.Context, input any) (any, error) {
|
|
|
|
|
|
// 直接保存到全局
|
|
|
|
|
|
req, ok := input.(*dto.CreationInput)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return nil, fmt.Errorf("input must be CreationInput")
|
|
|
|
|
|
}
|
|
|
|
|
|
currentReq = req
|
|
|
|
|
|
return input, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 2. 构建Prompt ====================
|
|
|
|
|
|
func BuildPromptLambda(ctx context.Context, input any) (any, error) {
|
|
|
|
|
|
req, ok := input.(*dto.CreationInput)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return nil, fmt.Errorf("input must be CreationInput")
|
|
|
|
|
|
}
|
|
|
|
|
|
count := req.Count
|
|
|
|
|
|
if req.Count > 3 {
|
|
|
|
|
|
req.Count = 3
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
imagePerPost := req.ImagePerPost
|
|
|
|
|
|
if req.ImagePerPost > 3 {
|
|
|
|
|
|
imagePerPost = 3
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var imgPlaceholder strings.Builder
|
|
|
|
|
|
for i := 1; i <= imagePerPost; i++ {
|
|
|
|
|
|
imgPlaceholder.WriteString(fmt.Sprintf(`<div class="img-box"><img src="{{IMG_URL_%d}}"></div>`, i))
|
|
|
|
|
|
}
|
|
|
|
|
|
mode := req.Mode
|
|
|
|
|
|
|
|
|
|
|
|
// 核心:先用 embed 读取技能文案(完全不依赖运行目录)
|
|
|
|
|
|
skillContent, err := skill.ReadSkillMD()
|
|
|
|
|
|
prompt := ""
|
|
|
|
|
|
if len(skillContent) != 0 && err == nil {
|
|
|
|
|
|
prompt = skillContent
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据模式拼接(动态图片数量 + 动态比例 + 严格数量控制)
|
|
|
|
|
|
switch mode {
|
|
|
|
|
|
case "混合模式(文案 + 图片)":
|
|
|
|
|
|
s1 := `1. 整个输出只能有 %d 个 <html> 标签和 %d 个</html> 标签`
|
|
|
|
|
|
var a = fmt.Sprintf(`%s%d%d`, s1, count, count)
|
|
|
|
|
|
s2 := `2. 生成完成后立即停止,不续写、不扩展、不重复
|
|
|
|
|
|
3. 不要输出任何解释、前言、后语
|
|
|
|
|
|
4. 只输出纯HTML代码
|
|
|
|
|
|
5. 内容绝对不能重复!`
|
|
|
|
|
|
var b = fmt.Sprintf(`%s%s`, a, s2)
|
|
|
|
|
|
s3 := `6. 多个HTML文件之间必须用 --- 分隔,分隔符前后不能有任何多余文字!`
|
|
|
|
|
|
if count > 1 {
|
|
|
|
|
|
b = fmt.Sprintf(`%s%s`, b, s3)
|
|
|
|
|
|
}
|
|
|
|
|
|
prompt = fmt.Sprintf(`%s
|
|
|
|
|
|
|
|
|
|
|
|
【🔴 最高优先级强制规则】
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
【📄 HTML结构强制模板】
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<style>
|
|
|
|
|
|
* { margin:0; padding:0; box-sizing:border-box; font-family:system-ui, -apple-system, sans-serif; }
|
|
|
|
|
|
body { background:#F0F2F5; padding:16px; }
|
|
|
|
|
|
.card { background:#fff; border-radius:16px; padding:18px; max-width:500px; margin:0 auto; }
|
|
|
|
|
|
.title { font-size:22px; font-weight:700; margin-bottom:14px; line-height:1.4; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 动态图片比例:由参数决定 */
|
|
|
|
|
|
.img-box {
|
|
|
|
|
|
width:100%%;
|
|
|
|
|
|
aspect-ratio:%s;
|
|
|
|
|
|
border-radius:12px;
|
|
|
|
|
|
overflow:hidden;
|
|
|
|
|
|
margin-bottom:14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.img-box img { width:100%%; height:100%%; object-fit:cover; display:block; }
|
|
|
|
|
|
|
|
|
|
|
|
.content { font-size:16px; line-height:1.7; color:#333; margin-bottom:20px; }
|
|
|
|
|
|
.content p { margin:8px 0; }
|
|
|
|
|
|
.tags { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
|
|
|
|
|
|
.tag { background:#f5f5f5; padding:6px 12px; border-radius:20px; font-size:14px; color:#666; }
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<h2 class="title">%s</h2>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 图片数量由前端参数决定,直接使用传入的图片,不准修改 -->
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
<div class="content">
|
|
|
|
|
|
请按照小红书风格创作文案:分段清晰、使用emoji、重点内容加粗、排版美观
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="tags">
|
|
|
|
|
|
<span class="tag">#干货分享</span>
|
|
|
|
|
|
<span class="tag">#实用技巧</span>
|
|
|
|
|
|
<span class="tag">#知识科普</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|
|
|
|
|
|
|
|
|
|
|
|
【📌 必须遵守的细节规则】
|
|
|
|
|
|
1. 所有图片必须使用 .img-box 容器,不变形、不拉伸。
|
|
|
|
|
|
2. 文案必须分段清晰、美观、小红书风格、使用emoji、重点内容加粗,排版符合小红书风格。
|
|
|
|
|
|
3. 图片占位符里有几张图,就生成几张,不要自己额外添加或删除。
|
|
|
|
|
|
4. 标签自动根据主题生成,无需外部参数。
|
|
|
|
|
|
|
|
|
|
|
|
内容信息:
|
|
|
|
|
|
主题:%s
|
|
|
|
|
|
标题:%s
|
|
|
|
|
|
风格:%s
|
|
|
|
|
|
`,
|
|
|
|
|
|
prompt,
|
|
|
|
|
|
b,
|
|
|
|
|
|
req.ImageRatio,
|
|
|
|
|
|
req.Title,
|
|
|
|
|
|
imgPlaceholder.String(), // 你传入的图片(多张自动适配)
|
|
|
|
|
|
req.Theme,
|
|
|
|
|
|
req.Title,
|
|
|
|
|
|
req.Style,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
case "纯文案模式":
|
|
|
|
|
|
s1 := `1. 整个输出只能有 %d 个 <html> 标签和 %d 个</html> 标签`
|
|
|
|
|
|
var a = fmt.Sprintf(`%s%d%d`, s1, count, count)
|
|
|
|
|
|
s2 := `2. 生成完成后立即停止,不续写、不扩展、不重复
|
|
|
|
|
|
3. 不要输出任何解释、前言、后语
|
|
|
|
|
|
4. 只输出纯HTML代码
|
|
|
|
|
|
5. 内容绝对不能重复!`
|
|
|
|
|
|
var b = fmt.Sprintf(`%s%s`, a, s2)
|
|
|
|
|
|
s3 := `6. 多个HTML文件之间必须用 --- 分隔,分隔符前后不能有任何多余文字!`
|
|
|
|
|
|
if count > 1 {
|
|
|
|
|
|
b = fmt.Sprintf(`%s%s`, b, s3)
|
|
|
|
|
|
}
|
|
|
|
|
|
prompt = fmt.Sprintf(`%s
|
|
|
|
|
|
|
|
|
|
|
|
【🔴 最高优先级强制规则】
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
【📄 HTML结构强制模板】
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html>
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<style>
|
|
|
|
|
|
* { margin:0; padding:0; box-sizing:border-box; font-family:system-ui, -apple-system, sans-serif; }
|
|
|
|
|
|
body { background:#F0F2F5; padding:16px; }
|
|
|
|
|
|
.card { background:#fff; border-radius:16px; padding:18px; max-width:500px; margin:0 auto; }
|
|
|
|
|
|
.title { font-size:22px; font-weight:700; margin-bottom:14px; }
|
|
|
|
|
|
.content { font-size:16px; line-height:1.7; color:#333; margin-bottom:20px; }
|
|
|
|
|
|
.tags { display:flex; flex-wrap:wrap; gap:8px; }
|
|
|
|
|
|
.tag { background:#f5f5f5; padding:6px 12px; border-radius:20px; font-size:14px; color:#666; }
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<h2 class="title">%s</h2>
|
|
|
|
|
|
<div class="content">按照小红书风格创作文案:分段+emoji+重点加粗,排版美观</div>
|
|
|
|
|
|
<div class="tags">
|
|
|
|
|
|
<span class="tag">#干货分享</span>
|
|
|
|
|
|
<span class="tag">#实用技巧</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|
|
|
|
|
|
|
|
|
|
|
|
【📌 必须遵守的细节规则】
|
|
|
|
|
|
2. 必须分段清晰、美观、小红书风格、使用emoji、重点内容加粗,排版符合小红书风格。
|
|
|
|
|
|
3. 标签自动根据主题生成,无需外部参数。
|
|
|
|
|
|
|
|
|
|
|
|
内容:主题=%s,标题=%s,风格=%s
|
|
|
|
|
|
`,
|
|
|
|
|
|
prompt,
|
|
|
|
|
|
b,
|
|
|
|
|
|
req.Title,
|
|
|
|
|
|
req.Theme,
|
|
|
|
|
|
req.Title,
|
|
|
|
|
|
req.Style,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
case "纯图片模式":
|
|
|
|
|
|
s1 := `1. 必须**严格且只能生成 %d 组绘图关键词**,绝对不能多生成一组,也不能少生成一组!`
|
|
|
|
|
|
var a = fmt.Sprintf(`%s%d`, s1, count)
|
|
|
|
|
|
s2 := `2. 生成完成后立即停止,不续写、不扩展、不重复
|
|
|
|
|
|
3. 所有输出内容只能是关键词本身,**绝对不能出现任何解释、说明、额外文字**!
|
|
|
|
|
|
4. 内容绝对不能重复!`
|
|
|
|
|
|
var b = fmt.Sprintf(`%s%s`, a, s2)
|
|
|
|
|
|
s3 := `5. 多组关键词之间必须用 --- 分隔,分隔符前后不能有任何多余文字!`
|
|
|
|
|
|
if count > 1 {
|
|
|
|
|
|
b = fmt.Sprintf(`%s%s`, b, s3)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prompt = fmt.Sprintf(`%s
|
|
|
|
|
|
|
|
|
|
|
|
【🔴 最高优先级强制规则】
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
内容:主题:%s,比例:%s,风格:%s
|
|
|
|
|
|
`,
|
|
|
|
|
|
prompt,
|
|
|
|
|
|
b,
|
|
|
|
|
|
req.Theme,
|
|
|
|
|
|
req.ImageRatio,
|
|
|
|
|
|
req.Style,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
return nil, fmt.Errorf("不支持模式")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !g.IsEmpty(req.Desc) {
|
|
|
|
|
|
prompt = fmt.Sprintf(`%s,要求:%s`, prompt, req.Desc)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return []*schema.Message{schema.UserMessage(prompt)}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 4. 生成+上传(完全不解析input!) ====================
|
|
|
|
|
|
func GenerateImageLambda(ctx context.Context, input any) (any, error) {
|
|
|
|
|
|
|
|
|
|
|
|
msg, ok := input.(*schema.Message)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return nil, fmt.Errorf("input must be *schema.Message")
|
|
|
|
|
|
}
|
|
|
|
|
|
optimizedText := strings.TrimSpace(msg.Content)
|
|
|
|
|
|
|
|
|
|
|
|
list := strings.Split(optimizedText, "---")
|
|
|
|
|
|
var items []string
|
|
|
|
|
|
for _, s := range list {
|
|
|
|
|
|
if s = strings.TrimSpace(s); s != "" {
|
|
|
|
|
|
items = append(items, s)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
imgAddressPrefix, err := utils.GetFileAddressPrefix(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
mode := currentReq.Mode
|
|
|
|
|
|
|
|
|
|
|
|
imagePerPost := currentReq.ImagePerPost
|
|
|
|
|
|
if currentReq.ImagePerPost > 3 {
|
|
|
|
|
|
imagePerPost = 3
|
|
|
|
|
|
}
|
|
|
|
|
|
// ==============================================
|
|
|
|
|
|
// ✅ 核心修复:构建正确的绘图关键词(主题+标题+风格+比例)
|
|
|
|
|
|
// ==============================================
|
|
|
|
|
|
prompt := fmt.Sprintf(
|
|
|
|
|
|
"%s,%s,%s,风格:%s,比例:%s",
|
|
|
|
|
|
currentReq.ContentType,
|
|
|
|
|
|
currentReq.Theme,
|
|
|
|
|
|
currentReq.Title,
|
|
|
|
|
|
currentReq.Style,
|
|
|
|
|
|
currentReq.ImageRatio,
|
|
|
|
|
|
)
|
|
|
|
|
|
if !g.IsEmpty(currentReq.Desc) {
|
|
|
|
|
|
prompt = fmt.Sprintf(`%s,要求:%s`, prompt, currentReq.Desc)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 初始化返回结果
|
|
|
|
|
|
var output dto.CreationOutput
|
|
|
|
|
|
|
|
|
|
|
|
for idx, item := range items {
|
|
|
|
|
|
base := fmt.Sprintf("%s_%d", currentReq.Title, idx+1)
|
|
|
|
|
|
dir := currentReq.Theme
|
|
|
|
|
|
num := imagePerPost
|
|
|
|
|
|
var uploadItem dto.ImageUploadItem
|
|
|
|
|
|
uploadItem.Title = currentReq.Title
|
|
|
|
|
|
uploadItem.Index = idx + 1
|
|
|
|
|
|
uploadItem.Theme = currentReq.Theme
|
|
|
|
|
|
uploadItem.ContentType = currentReq.ContentType
|
|
|
|
|
|
|
|
|
|
|
|
switch mode {
|
|
|
|
|
|
case "混合模式(文案 + 图片)":
|
|
|
|
|
|
// 生成并上传多张图片
|
|
|
|
|
|
var imageUrls []string
|
|
|
|
|
|
imgMap := make(map[int]string)
|
|
|
|
|
|
for i := 1; i <= num; i++ {
|
|
|
|
|
|
url, _ := GenerateRealImage(prompt)
|
|
|
|
|
|
imageUrls = append(imageUrls, url) // 收集图片URL
|
|
|
|
|
|
bs, _ := getImageBytesFromURL(url)
|
|
|
|
|
|
uploadResp, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
|
|
|
|
FileName: fmt.Sprintf("%s_%d.png", base, i),
|
|
|
|
|
|
FileBytes: bs,
|
|
|
|
|
|
FileStoreURL: dir,
|
|
|
|
|
|
})
|
|
|
|
|
|
// 如果Upload返回了最终访问URL,替换成真实返回值
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
imageUrls[i-1] = uploadResp.FileURL
|
|
|
|
|
|
imgMap[i] = uploadResp.FileURL
|
|
|
|
|
|
}
|
|
|
|
|
|
uploadItem.ImageUrls = imageUrls // 存入结构体
|
|
|
|
|
|
|
|
|
|
|
|
// 替换HTML
|
|
|
|
|
|
final := item
|
|
|
|
|
|
if imagePerPost > 1 {
|
|
|
|
|
|
for i := 1; i <= num; i++ {
|
|
|
|
|
|
final = strings.ReplaceAll(final, fmt.Sprintf("{{IMG_URL_%d}}", i), imgAddressPrefix+imgMap[i])
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for i := 1; i <= num; i++ {
|
|
|
|
|
|
final = strings.ReplaceAll(final, fmt.Sprintf("{{IMG_URL_%d}}", idx+1), imgAddressPrefix+imgMap[i])
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
htmlUploadResp, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
|
|
|
|
FileName: base + ".html",
|
|
|
|
|
|
FileBytes: []byte(final),
|
|
|
|
|
|
FileStoreURL: dir,
|
|
|
|
|
|
})
|
|
|
|
|
|
// 保存HTML上传地址
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
uploadItem.HtmlFileUrl = htmlUploadResp.FileURL
|
|
|
|
|
|
|
|
|
|
|
|
case "纯图片模式":
|
|
|
|
|
|
var realImageUrls []string
|
|
|
|
|
|
for i := 1; i <= num; i++ {
|
|
|
|
|
|
tempUrl, _ := GenerateRealImage(prompt)
|
|
|
|
|
|
bs, _ := getImageBytesFromURL(tempUrl)
|
|
|
|
|
|
uploadResp, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
|
|
|
|
FileName: fmt.Sprintf("%s_%d.png", base, i),
|
|
|
|
|
|
FileBytes: bs,
|
|
|
|
|
|
FileStoreURL: dir,
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
realImageUrls = append(realImageUrls, uploadResp.FileURL)
|
|
|
|
|
|
}
|
|
|
|
|
|
uploadItem.ImageUrls = realImageUrls
|
|
|
|
|
|
|
|
|
|
|
|
case "纯文案模式":
|
|
|
|
|
|
htmlResp, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
|
|
|
|
FileName: base + ".html",
|
|
|
|
|
|
FileBytes: []byte(item),
|
|
|
|
|
|
FileStoreURL: dir,
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
uploadItem.HtmlFileUrl = htmlResp.FileURL
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
output.Items = append(output.Items, uploadItem)
|
|
|
|
|
|
fmt.Printf("✅ 第%d条上传成功\n,html:%s\n图片:%s\n", idx+1, gconv.String(uploadItem.HtmlFileUrl), gconv.String(uploadItem.ImageUrls))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计成功数量
|
|
|
|
|
|
output.SuccessCount = len(output.Items)
|
|
|
|
|
|
|
|
|
|
|
|
return output, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 工具 ====================
|
|
|
|
|
|
func getImageBytesFromURL(url string) ([]byte, error) {
|
|
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
return io.ReadAll(resp.Body)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Upload(ctx context.Context, req *dto.UploadFileBytesReq) (*dto.UploadFileBytesRes, error) {
|
|
|
|
|
|
headers := make(map[string]string)
|
|
|
|
|
|
if r := g.RequestFromCtx(ctx); r != nil {
|
|
|
|
|
|
for k, v := range r.Header {
|
|
|
|
|
|
headers[k] = v[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
res := &dto.UploadFileBytesRes{}
|
|
|
|
|
|
err := commonHttp.Post(ctx, "oss/file/uploadFileBytes", headers, res, req)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
glog.Error(ctx, err)
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return res, nil
|
|
|
|
|
|
}
|