Compare commits
2 Commits
d4614e3cc9
...
ffba1f30ec
| Author | SHA1 | Date | |
|---|---|---|---|
| ffba1f30ec | |||
| b1ee117f6c |
42
update.sql
42
update.sql
@@ -279,6 +279,42 @@ COMMENT ON COLUMN black_deacon_creation_info.title IS '标题';
|
|||||||
|
|
||||||
--------------------pgsql创建creation_info表语句---------------------------
|
--------------------pgsql创建creation_info表语句---------------------------
|
||||||
|
|
||||||
|
--------------------pgsql创建black_deacon_file_temp表语句---------------------------
|
||||||
|
-- 临时文件表
|
||||||
|
CREATE TABLE IF NOT EXISTS black_deacon_file_temp (
|
||||||
|
-- 基础字段(完全对齐项目规范)
|
||||||
|
id BIGINT PRIMARY KEY,
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||||||
|
creator VARCHAR(64) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updater VARCHAR(64) NOT NULL,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at timestamp(6),
|
||||||
|
|
||||||
|
-- 业务字段
|
||||||
|
business_id VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
|
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 索引
|
||||||
|
CREATE INDEX idx_file_temp_tenant_id ON black_deacon_file_temp(tenant_id);
|
||||||
|
CREATE INDEX idx_file_temp_business_id ON black_deacon_file_temp(business_id);
|
||||||
|
CREATE INDEX idx_file_temp_file_url ON black_deacon_file_temp(file_url);
|
||||||
|
CREATE INDEX idx_file_temp_deleted_at ON black_deacon_file_temp(deleted_at);
|
||||||
|
|
||||||
|
-- 注释
|
||||||
|
COMMENT ON TABLE black_deacon_file_temp IS '临时文件表';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.id IS '主键ID';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.tenant_id IS '租户ID';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.creator IS '创建人';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.created_at IS '创建时间';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.updater IS '更新人';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.updated_at IS '更新时间';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.deleted_at IS '删除时间(软删)';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.business_id IS '业务ID';
|
||||||
|
COMMENT ON COLUMN black_deacon_file_temp.file_url IS '文件地址';
|
||||||
|
--------------------pgsql创建black_deacon_file_temp表语句---------------------------
|
||||||
|
|
||||||
--------------------pgsql创建black_deacon_skill_template表语句---------------------------
|
--------------------pgsql创建black_deacon_skill_template表语句---------------------------
|
||||||
-- 技能模板表
|
-- 技能模板表
|
||||||
CREATE TABLE IF NOT EXISTS black_deacon_skill_template (
|
CREATE TABLE IF NOT EXISTS black_deacon_skill_template (
|
||||||
@@ -294,14 +330,12 @@ CREATE TABLE IF NOT EXISTS black_deacon_skill_template (
|
|||||||
-- 业务字段
|
-- 业务字段
|
||||||
name VARCHAR(128) NOT NULL DEFAULT '',
|
name VARCHAR(128) NOT NULL DEFAULT '',
|
||||||
description TEXT DEFAULT '',
|
description TEXT DEFAULT '',
|
||||||
category VARCHAR(64) NOT NULL DEFAULT '',
|
|
||||||
file_name VARCHAR(255) NOT NULL DEFAULT '',
|
file_name VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 索引
|
-- 索引
|
||||||
CREATE INDEX idx_skill_template_tenant_id ON black_deacon_skill_template(tenant_id);
|
CREATE INDEX idx_skill_template_tenant_id ON black_deacon_skill_template(tenant_id);
|
||||||
CREATE INDEX idx_skill_template_category ON black_deacon_skill_template(category);
|
|
||||||
CREATE INDEX idx_skill_template_deleted_at ON black_deacon_skill_template(deleted_at);
|
CREATE INDEX idx_skill_template_deleted_at ON black_deacon_skill_template(deleted_at);
|
||||||
|
|
||||||
-- 注释
|
-- 注释
|
||||||
@@ -315,7 +349,6 @@ COMMENT ON COLUMN black_deacon_skill_template.updated_at IS '更新时间';
|
|||||||
COMMENT ON COLUMN black_deacon_skill_template.deleted_at IS '删除时间(软删)';
|
COMMENT ON COLUMN black_deacon_skill_template.deleted_at IS '删除时间(软删)';
|
||||||
COMMENT ON COLUMN black_deacon_skill_template.name IS '技能模板名称';
|
COMMENT ON COLUMN black_deacon_skill_template.name IS '技能模板名称';
|
||||||
COMMENT ON COLUMN black_deacon_skill_template.description IS '描述';
|
COMMENT ON COLUMN black_deacon_skill_template.description IS '描述';
|
||||||
COMMENT ON COLUMN black_deacon_skill_template.category IS '分类';
|
|
||||||
COMMENT ON COLUMN black_deacon_skill_template.file_name IS '文件名称';
|
COMMENT ON COLUMN black_deacon_skill_template.file_name IS '文件名称';
|
||||||
COMMENT ON COLUMN black_deacon_skill_template.file_url IS '文件地址';
|
COMMENT ON COLUMN black_deacon_skill_template.file_url IS '文件地址';
|
||||||
--------------------pgsql创建black_deacon_skill_template表语句---------------------------
|
--------------------pgsql创建black_deacon_skill_template表语句---------------------------
|
||||||
@@ -335,14 +368,12 @@ CREATE TABLE IF NOT EXISTS black_deacon_skill_user (
|
|||||||
-- 业务字段
|
-- 业务字段
|
||||||
name VARCHAR(128) NOT NULL DEFAULT '',
|
name VARCHAR(128) NOT NULL DEFAULT '',
|
||||||
description TEXT DEFAULT '',
|
description TEXT DEFAULT '',
|
||||||
category VARCHAR(64) NOT NULL DEFAULT '',
|
|
||||||
file_name VARCHAR(255) NOT NULL DEFAULT '',
|
file_name VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 索引
|
-- 索引
|
||||||
CREATE INDEX idx_skill_user_tenant_id ON black_deacon_skill_user(tenant_id);
|
CREATE INDEX idx_skill_user_tenant_id ON black_deacon_skill_user(tenant_id);
|
||||||
CREATE INDEX idx_skill_user_category ON black_deacon_skill_user(category);
|
|
||||||
CREATE INDEX idx_skill_user_deleted_at ON black_deacon_skill_user(deleted_at);
|
CREATE INDEX idx_skill_user_deleted_at ON black_deacon_skill_user(deleted_at);
|
||||||
|
|
||||||
-- 注释
|
-- 注释
|
||||||
@@ -356,7 +387,6 @@ COMMENT ON COLUMN black_deacon_skill_user.updated_at IS '更新时间';
|
|||||||
COMMENT ON COLUMN black_deacon_skill_user.deleted_at IS '删除时间(软删)';
|
COMMENT ON COLUMN black_deacon_skill_user.deleted_at IS '删除时间(软删)';
|
||||||
COMMENT ON COLUMN black_deacon_skill_user.name IS '技能名称';
|
COMMENT ON COLUMN black_deacon_skill_user.name IS '技能名称';
|
||||||
COMMENT ON COLUMN black_deacon_skill_user.description IS '描述';
|
COMMENT ON COLUMN black_deacon_skill_user.description IS '描述';
|
||||||
COMMENT ON COLUMN black_deacon_skill_user.category IS '分类';
|
|
||||||
COMMENT ON COLUMN black_deacon_skill_user.file_name IS '文件名称';
|
COMMENT ON COLUMN black_deacon_skill_user.file_name IS '文件名称';
|
||||||
COMMENT ON COLUMN black_deacon_skill_user.file_url IS '文件地址';
|
COMMENT ON COLUMN black_deacon_skill_user.file_url IS '文件地址';
|
||||||
--------------------pgsql创建black_deacon_skill_user表语句---------------------------
|
--------------------pgsql创建black_deacon_skill_user表语句---------------------------
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ var (
|
|||||||
FlowExecutionStatusRunning = newFlowExecutionStatus(gconv.PtrInt8(1), "running") // 运行中
|
FlowExecutionStatusRunning = newFlowExecutionStatus(gconv.PtrInt8(1), "running") // 运行中
|
||||||
FlowExecutionStatusSuccess = newFlowExecutionStatus(gconv.PtrInt8(2), "success") // 成功
|
FlowExecutionStatusSuccess = newFlowExecutionStatus(gconv.PtrInt8(2), "success") // 成功
|
||||||
FlowExecutionStatusFailed = newFlowExecutionStatus(gconv.PtrInt8(3), "failed") // 失败
|
FlowExecutionStatusFailed = newFlowExecutionStatus(gconv.PtrInt8(3), "failed") // 失败
|
||||||
FlowExecutionStatusPaused = newFlowExecutionStatus(gconv.PtrInt8(4), "paused") // 暂停
|
FlowExecutionStatusCancel = newFlowExecutionStatus(gconv.PtrInt8(4), "cancel") // 取消
|
||||||
)
|
)
|
||||||
|
|
||||||
type FlowExecutionStatus *int8
|
type FlowExecutionStatus *int8
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ const (
|
|||||||
TableNameFlowUser = "flow_user"
|
TableNameFlowUser = "flow_user"
|
||||||
TableNameSkillTemplate = "skill_template"
|
TableNameSkillTemplate = "skill_template"
|
||||||
TableNameSkillUser = "skill_user"
|
TableNameSkillUser = "skill_user"
|
||||||
|
TableNameFileTemp = "file_temp"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,11 +16,24 @@ func (c *skillUser) Create(ctx context.Context, req *skillDto.CreateSkillUserReq
|
|||||||
return skillService.SkillUserService.Create(ctx, req)
|
return skillService.SkillUserService.Create(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *skillUser) Update(ctx context.Context, req *skillDto.UpdateSkillUserReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
err = skillService.SkillUserService.Update(ctx, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (c *skillUser) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (res *beans.ResponseEmpty, err error) {
|
func (c *skillUser) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (res *beans.ResponseEmpty, err error) {
|
||||||
err = skillService.SkillUserService.Delete(ctx, req)
|
err = skillService.SkillUserService.Delete(ctx, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *skillUser) Get(ctx context.Context, req *skillDto.GetSkillUserReq) (res *skillDto.SkillUserVO, err error) {
|
||||||
|
return skillService.SkillUserService.Get(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *skillUser) GetUserOrTemplate(ctx context.Context, req *skillDto.GetSkillReq) (res *skillDto.SkillUserVO, err error) {
|
||||||
|
return skillService.SkillUserService.GetUserOrTemplate(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *skillUser) List(ctx context.Context, req *skillDto.ListSkillReq) (res *skillDto.ListSkillUserRes, err error) {
|
func (c *skillUser) List(ctx context.Context, req *skillDto.ListSkillReq) (res *skillDto.ListSkillUserRes, err error) {
|
||||||
return skillService.SkillUserService.List(ctx, req)
|
return skillService.SkillUserService.List(ctx, req)
|
||||||
}
|
}
|
||||||
|
|||||||
59
workflow/dao/file/file_temp_dao.go
Normal file
59
workflow/dao/file/file_temp_dao.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ai-agent/workflow/consts/public"
|
||||||
|
fileDto "ai-agent/workflow/model/dto/file"
|
||||||
|
"ai-agent/workflow/model/entity"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.com/red-future/common/db/gfdb"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FileTempDao = &fileTempDao{}
|
||||||
|
|
||||||
|
type fileTempDao struct{}
|
||||||
|
|
||||||
|
func (d *fileTempDao) Insert(ctx context.Context, req *fileDto.CreateFileTempReq) (id int64, err error) {
|
||||||
|
fileTemp := new(entity.FileTemp)
|
||||||
|
err = gconv.Struct(req, &fileTemp)
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFileTemp).Insert(&fileTemp)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return r.LastInsertId()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fileTempDao) BatchInsert(ctx context.Context, req []*fileDto.CreateFileTempReq) (rows int64, err error) {
|
||||||
|
var res []*entity.FileTemp
|
||||||
|
if err = gconv.Structs(req, &res); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFileTemp).Data(res).Save()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return r.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fileTempDao) Delete(ctx context.Context, req *fileDto.DeleteFileTempReq) (rows int64, err error) {
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFileTemp).Where(entity.FileTempCol.Id, req.Id).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return r.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fileTempDao) List(ctx context.Context, req *fileDto.ListFileTempReq, fields ...string) (res []*entity.FileTemp, total int, err error) {
|
||||||
|
model := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFileTemp).NoTenantId(ctx).Fields(fields).OmitEmpty()
|
||||||
|
model.OrderDesc(entity.FileTempCol.CreatedAt)
|
||||||
|
if req.Page != nil {
|
||||||
|
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||||
|
}
|
||||||
|
r, total, err := model.AllAndCount(false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = r.Structs(&res)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -25,6 +25,14 @@ func (d *skillTemplateDao) Insert(ctx context.Context, req *skillDto.CreateSkill
|
|||||||
return r.LastInsertId()
|
return r.LastInsertId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *skillTemplateDao) Update(ctx context.Context, req *skillDto.UpdateSkillTemplateReq) (rows int64, err error) {
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).OmitEmpty().Data(&req).Where(entity.SkillTemplateCol.Id, req.Id).Update()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return r.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *skillTemplateDao) Delete(ctx context.Context, req *skillDto.DeleteSkillTemplateReq) (rows int64, err error) {
|
func (d *skillTemplateDao) Delete(ctx context.Context, req *skillDto.DeleteSkillTemplateReq) (rows int64, err error) {
|
||||||
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).Where(entity.SkillTemplateCol.Id, req.Id).Delete()
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).Where(entity.SkillTemplateCol.Id, req.Id).Delete()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -33,6 +41,26 @@ func (d *skillTemplateDao) Delete(ctx context.Context, req *skillDto.DeleteSkill
|
|||||||
return r.RowsAffected()
|
return r.RowsAffected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *skillTemplateDao) Count(ctx context.Context, req *skillDto.GetSkillTemplateReq) (count int, err error) {
|
||||||
|
count, err = gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).NoTenantId(ctx).OmitEmpty().
|
||||||
|
WhereNot(entity.SkillTemplateCol.Id, req.NotInId).
|
||||||
|
Where(entity.SkillTemplateCol.Name, req.Name).
|
||||||
|
Where(entity.SkillTemplateCol.Id, req.Id).Count()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *skillTemplateDao) Get(ctx context.Context, req *skillDto.GetSkillTemplateReq, fields ...string) (res *entity.SkillTemplate, err error) {
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).NoTenantId(ctx).OmitEmpty().
|
||||||
|
Where(entity.SkillTemplateCol.Id, req.Id).
|
||||||
|
Where(entity.SkillTemplateCol.Name, req.Name).
|
||||||
|
Fields(fields).One()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = r.Struct(&res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (d *skillTemplateDao) List(ctx context.Context, req *skillDto.ListSkillTemplateReq, fields ...string) (res []*entity.SkillTemplate, total int, err error) {
|
func (d *skillTemplateDao) List(ctx context.Context, req *skillDto.ListSkillTemplateReq, fields ...string) (res []*entity.SkillTemplate, total int, err error) {
|
||||||
model := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).NoTenantId(ctx).Fields(fields).OmitEmpty()
|
model := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillTemplate).NoTenantId(ctx).Fields(fields).OmitEmpty()
|
||||||
if !g.IsEmpty(req.Keyword) {
|
if !g.IsEmpty(req.Keyword) {
|
||||||
|
|||||||
@@ -25,6 +25,14 @@ func (d *skillUserDao) Insert(ctx context.Context, req *skillDto.CreateSkillUser
|
|||||||
return r.LastInsertId()
|
return r.LastInsertId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *skillUserDao) Update(ctx context.Context, req *skillDto.UpdateSkillUserReq) (rows int64, err error) {
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).OmitEmpty().Data(&req).Where(entity.SkillUserCol.Id, req.Id).Update()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return r.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *skillUserDao) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (rows int64, err error) {
|
func (d *skillUserDao) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (rows int64, err error) {
|
||||||
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).Where(entity.SkillUserCol.Id, req.Id).Delete()
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).Where(entity.SkillUserCol.Id, req.Id).Delete()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -33,6 +41,28 @@ func (d *skillUserDao) Delete(ctx context.Context, req *skillDto.DeleteSkillUser
|
|||||||
return r.RowsAffected()
|
return r.RowsAffected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *skillUserDao) Count(ctx context.Context, req *skillDto.GetSkillUserReq) (count int, err error) {
|
||||||
|
count, err = gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).NoTenantId(ctx).OmitEmpty().
|
||||||
|
Where(entity.SkillUserCol.Name, req.Name).
|
||||||
|
Where(entity.SkillUserCol.Creator, req.Creator).
|
||||||
|
WhereNot(entity.SkillUserCol.Id, req.NotInId).
|
||||||
|
Where(entity.SkillUserCol.Id, req.Id).Count()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *skillUserDao) Get(ctx context.Context, req *skillDto.GetSkillUserReq, fields ...string) (res *entity.SkillUser, err error) {
|
||||||
|
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).NoTenantId(ctx).OmitEmpty().
|
||||||
|
Where(entity.SkillUserCol.Id, req.Id).
|
||||||
|
Where(entity.SkillUserCol.Name, req.Name).
|
||||||
|
Where(entity.SkillUserCol.Creator, req.Creator).
|
||||||
|
Fields(fields).One()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = r.Struct(&res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (d *skillUserDao) List(ctx context.Context, req *skillDto.ListSkillUserReq, fields ...string) (res []*entity.SkillUser, total int, err error) {
|
func (d *skillUserDao) List(ctx context.Context, req *skillDto.ListSkillUserReq, fields ...string) (res []*entity.SkillUser, total int, err error) {
|
||||||
model := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).NoTenantId(ctx).Fields(fields).OmitEmpty()
|
model := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameSkillUser).NoTenantId(ctx).Fields(fields).OmitEmpty()
|
||||||
model.Where(entity.SkillUserCol.Creator, req.Creator)
|
model.Where(entity.SkillUserCol.Creator, req.Creator)
|
||||||
|
|||||||
45
workflow/model/dto/file/file_temp_dto.go
Normal file
45
workflow/model/dto/file/file_temp_dto.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.com/red-future/common/beans"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateFileTempReq struct {
|
||||||
|
g.Meta `path:"/create" method:"post" tags:"临时文件管理" summary:"创建临时文件" dc:"创建临时文件"`
|
||||||
|
|
||||||
|
BusinessId string `json:"businessId"`
|
||||||
|
FileUrl string `json:"fileUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateFileTempRes struct {
|
||||||
|
Id int64 `json:"id,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteFileTempReq struct {
|
||||||
|
g.Meta `path:"/delete" method:"delete" tags:"临时文件管理" summary:"删除临时文件" dc:"删除临时文件"`
|
||||||
|
|
||||||
|
Id int64 `json:"id" v:"required#ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListFileTempReq struct {
|
||||||
|
g.Meta `path:"/list" method:"get" tags:"临时文件管理" summary:"临时文件列表" dc:"临时文件列表"`
|
||||||
|
|
||||||
|
Page *beans.Page `json:"page"`
|
||||||
|
BusinessId string `json:"businessId"`
|
||||||
|
CreatedAt *gtime.Time `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListFileTempRes struct {
|
||||||
|
List []*FileTempVO `json:"list"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileTempVO struct {
|
||||||
|
Id int64 `json:"id,string" dc:"id"`
|
||||||
|
BusinessId string `json:"businessId"`
|
||||||
|
FileUrl string `json:"fileUrl"`
|
||||||
|
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||||
|
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ type NodeExecutionInput struct {
|
|||||||
|
|
||||||
// FlowExecutionInput 工作流执行入参(全程不变)
|
// FlowExecutionInput 工作流执行入参(全程不变)
|
||||||
type FlowExecutionInput struct {
|
type FlowExecutionInput struct {
|
||||||
|
IsDialogue bool `json:"isDialogue"`
|
||||||
ExecutionId int64 `json:"executionId"`
|
ExecutionId int64 `json:"executionId"`
|
||||||
ConfigMap map[string]*entity.FlowNode `json:"configMap"`
|
ConfigMap map[string]*entity.FlowNode `json:"configMap"`
|
||||||
SessionId string `json:"sessionId" dc:"会话ID"`
|
SessionId string `json:"sessionId" dc:"会话ID"`
|
||||||
@@ -27,15 +28,15 @@ type FlowExecutionInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ComposeMessagesReq struct {
|
type ComposeMessagesReq struct {
|
||||||
ModelTypeId int `json:"modelTypeId"`
|
BuildType int `json:"buildType"`
|
||||||
ModelName string `json:"modelName"`
|
ModelName string `json:"modelName"`
|
||||||
SkillName string `json:"skillName"`
|
SkillName string `json:"skillName"`
|
||||||
Form map[string]any `json:"form"`
|
Form map[string]any `json:"form"`
|
||||||
UserForm map[string]any `json:"userForm"`
|
UserForm map[string]any `json:"userForm"`
|
||||||
UserFiles []string `json:"userFiles"`
|
UserFiles []string `json:"userFiles"`
|
||||||
SessionId string `json:"sessionId" dc:"会话ID"`
|
SessionId string `json:"sessionId" dc:"会话ID"`
|
||||||
IsBuild bool `json:"isBuild"`
|
IsBuild bool `json:"isBuild"`
|
||||||
Cause string `json:"cause"`
|
Cause string `json:"cause"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComposeMessagesRes struct {
|
type ComposeMessagesRes struct {
|
||||||
@@ -143,9 +144,9 @@ type ExecuteRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CancelReq struct {
|
type CancelReq struct {
|
||||||
g.Meta `path:"/cancel" method:"get" tags:"任务管理" summary:"取消任务" dc:"取消任务"`
|
g.Meta `path:"/cancel" method:"post" tags:"任务管理" summary:"取消任务" dc:"取消任务"`
|
||||||
|
|
||||||
FlowId int64 `json:"flowId" dc:"用户流程ID"`
|
SessionId string `json:"sessionId" dc:"会话ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateFlowExecutionReq struct {
|
type CreateFlowExecutionReq struct {
|
||||||
@@ -195,19 +196,21 @@ type ListFlowExecutionRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VOFlowExecution struct {
|
type VOFlowExecution struct {
|
||||||
Id int64 `json:"id,string" dc:"id"`
|
Id int64 `json:"id,string" dc:"id"`
|
||||||
FlowUserId int64 `json:"flowUserId,string" description:"流程ID"`
|
FlowUserId int64 `json:"flowUserId,string" description:"流程ID"`
|
||||||
FlowName string `json:"flowName"`
|
FlowName string `json:"flowName"`
|
||||||
TriggerType flow.FlowExecutionTriggerType `json:"triggerType" description:"触发类型"`
|
TriggerType flow.FlowExecutionTriggerType `json:"triggerType" description:"触发类型"`
|
||||||
DurationMs int64 `json:"durationMs" description:"执行时长(毫秒)"`
|
DurationMs int64 `json:"durationMs" description:"执行时长(毫秒)"`
|
||||||
Status flow.FlowExecutionStatus `json:"status" description:"状态:1-运行中,2-成功,3-失败"`
|
Status flow.FlowExecutionStatus `json:"status" description:"状态:1-运行中,2-成功,3-失败"`
|
||||||
FlowContent *entity.FlowInfo `json:"flowContent" description:"流程内容"`
|
FlowContent *entity.FlowInfo `json:"flowContent" description:"流程内容"`
|
||||||
NodeInputParams []*entity.FlowNode `json:"nodeInputParams" description:"节点输入参数"`
|
NodeInputParams []*entity.FlowNode `json:"nodeInputParams" description:"节点输入参数"`
|
||||||
OutputParams []map[string]interface{} `json:"outputParams" description:"输出参数"`
|
OutputParams []map[string]interface{} `json:"outputParams" description:"输出参数"`
|
||||||
ErrorMessage string `json:"errorMessage" description:"错误信息"`
|
ErrorMessage string `json:"errorMessage" description:"错误信息"`
|
||||||
TraceId string `json:"traceId" description:"跟踪ID"`
|
TraceId string `json:"traceId" description:"跟踪ID"`
|
||||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
SessionId string `json:"sessionId" dc:"会话ID"`
|
||||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||||
|
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||||
|
ImgAddressPrefix string `json:"imgAddressPrefix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 核心:构建树状结构 ==========
|
// ========== 核心:构建树状结构 ==========
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type CreateSkillTemplateReq struct {
|
|||||||
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Category string `json:"category"`
|
|
||||||
FileName string `json:"fileName"`
|
FileName string `json:"fileName"`
|
||||||
FileUrl string `json:"fileUrl"`
|
FileUrl string `json:"fileUrl"`
|
||||||
}
|
}
|
||||||
@@ -20,12 +19,30 @@ type CreateSkillTemplateRes struct {
|
|||||||
Id int64 `json:"id,string"`
|
Id int64 `json:"id,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateSkillTemplateReq struct {
|
||||||
|
g.Meta `path:"/update" method:"put" tags:"Skill技能管理" summary:"修改Skill用户技能" dc:"修改Skill用户技能"`
|
||||||
|
|
||||||
|
Id int64 `json:"id" v:"required#ID不能为空"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
FileUrl string `json:"fileUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
type DeleteSkillTemplateReq struct {
|
type DeleteSkillTemplateReq struct {
|
||||||
g.Meta `path:"/delete" method:"delete" tags:"Skill技能管理" summary:"删除Skill技能" dc:"删除Skill技能"`
|
g.Meta `path:"/delete" method:"delete" tags:"Skill技能管理" summary:"删除Skill技能" dc:"删除Skill技能"`
|
||||||
|
|
||||||
Id int64 `json:"id" v:"required#ID不能为空"`
|
Id int64 `json:"id" v:"required#ID不能为空"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetSkillTemplateReq struct {
|
||||||
|
g.Meta `path:"/get" method:"get" tags:"Skill技能管理" summary:"Skill技能详情" dc:"Skill技能详情"`
|
||||||
|
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
NotInId int64 `json:"notInId"`
|
||||||
|
}
|
||||||
|
|
||||||
type ListSkillTemplateReq struct {
|
type ListSkillTemplateReq struct {
|
||||||
g.Meta `path:"/list" method:"get" tags:"Skill技能管理" summary:"Skill技能列表" dc:"Skill技能列表"`
|
g.Meta `path:"/list" method:"get" tags:"Skill技能管理" summary:"Skill技能列表" dc:"Skill技能列表"`
|
||||||
|
|
||||||
@@ -42,7 +59,6 @@ type SkillTemplateVO struct {
|
|||||||
Id int64 `json:"id,string" dc:"id"`
|
Id int64 `json:"id,string" dc:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Category string `json:"category"`
|
|
||||||
FileName string `json:"fileName"`
|
FileName string `json:"fileName"`
|
||||||
FileUrl string `json:"fileUrl"`
|
FileUrl string `json:"fileUrl"`
|
||||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type CreateSkillUserReq struct {
|
|||||||
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Category string `json:"category"`
|
|
||||||
FileName string `json:"fileName"`
|
FileName string `json:"fileName"`
|
||||||
FileUrl string `json:"fileUrl"`
|
FileUrl string `json:"fileUrl"`
|
||||||
}
|
}
|
||||||
@@ -20,12 +19,40 @@ type CreateSkillUserRes struct {
|
|||||||
Id int64 `json:"id,string"`
|
Id int64 `json:"id,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateSkillUserReq struct {
|
||||||
|
g.Meta `path:"/update" method:"put" tags:"Skill用户技能管理" summary:"修改Skill用户技能" dc:"修改Skill用户技能"`
|
||||||
|
|
||||||
|
Id int64 `json:"id" v:"required#ID不能为空"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
FileUrl string `json:"fileUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
type DeleteSkillUserReq struct {
|
type DeleteSkillUserReq struct {
|
||||||
g.Meta `path:"/delete" method:"delete" tags:"Skill用户技能管理" summary:"删除Skill用户技能" dc:"删除Skill用户技能"`
|
g.Meta `path:"/delete" method:"delete" tags:"Skill用户技能管理" summary:"删除Skill用户技能" dc:"删除Skill用户技能"`
|
||||||
|
|
||||||
Id int64 `json:"id" v:"required#ID不能为空"`
|
Id int64 `json:"id" v:"required#ID不能为空"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetSkillUserReq struct {
|
||||||
|
g.Meta `path:"/get" method:"get" tags:"Skill用户技能管理" summary:"Skill用户技能详情" dc:"Skill用户技能详情"`
|
||||||
|
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
NotInId int64 `json:"notInId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetSkillReq struct {
|
||||||
|
g.Meta `path:"/getUserOrTemplate" method:"get" tags:"Skill用户技能管理" summary:"Skill技能详情" dc:"Skill技能详情"`
|
||||||
|
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
NotInId int64 `json:"notInId"`
|
||||||
|
}
|
||||||
|
|
||||||
type ListSkillReq struct {
|
type ListSkillReq struct {
|
||||||
g.Meta `path:"/list" method:"get" tags:"Skill用户技能管理" summary:"Skill用户技能列表" dc:"Skill用户技能列表"`
|
g.Meta `path:"/list" method:"get" tags:"Skill用户技能管理" summary:"Skill用户技能列表" dc:"Skill用户技能列表"`
|
||||||
|
|
||||||
@@ -48,12 +75,12 @@ type ListSkillUserRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SkillUserVO struct {
|
type SkillUserVO struct {
|
||||||
Id int64 `json:"id,string" dc:"id"`
|
Id int64 `json:"id,string" dc:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Category string `json:"category"`
|
FileName string `json:"fileName"`
|
||||||
FileName string `json:"fileName"`
|
FileUrl string `json:"fileUrl"`
|
||||||
FileUrl string `json:"fileUrl"`
|
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
ImgAddressPrefix string `json:"imgAddressPrefix"`
|
||||||
}
|
}
|
||||||
|
|||||||
24
workflow/model/entity/file_temp.go
Normal file
24
workflow/model/entity/file_temp.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileTemp struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段:Id, TenantId, Creator, CreatedAt, Updater, UpdatedAt, DeletedAt
|
||||||
|
|
||||||
|
BusinessId string `orm:"business_id" json:"businessId"`
|
||||||
|
FileUrl string `orm:"file_url" json:"fileUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileTempCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
BusinessId string
|
||||||
|
FileUrl string
|
||||||
|
}
|
||||||
|
|
||||||
|
var FileTempCol = fileTempCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
BusinessId: "business_id",
|
||||||
|
FileUrl: "file_url",
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ type SkillTemplate struct {
|
|||||||
|
|
||||||
Name string `orm:"name" json:"name"`
|
Name string `orm:"name" json:"name"`
|
||||||
Description string `orm:"description" json:"description"`
|
Description string `orm:"description" json:"description"`
|
||||||
Category string `orm:"category" json:"category"`
|
|
||||||
FileName string `orm:"file_name" json:"fileName"`
|
FileName string `orm:"file_name" json:"fileName"`
|
||||||
FileUrl string `orm:"file_url" json:"fileUrl"`
|
FileUrl string `orm:"file_url" json:"fileUrl"`
|
||||||
}
|
}
|
||||||
@@ -18,7 +17,6 @@ type skillTemplateCol struct {
|
|||||||
beans.SQLBaseCol
|
beans.SQLBaseCol
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
Category string
|
|
||||||
FileName string
|
FileName string
|
||||||
FileUrl string
|
FileUrl string
|
||||||
}
|
}
|
||||||
@@ -27,7 +25,6 @@ var SkillTemplateCol = skillTemplateCol{
|
|||||||
SQLBaseCol: beans.DefSQLBaseCol,
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Description: "description",
|
Description: "description",
|
||||||
Category: "category",
|
|
||||||
FileName: "file_name",
|
FileName: "file_name",
|
||||||
FileUrl: "file_url",
|
FileUrl: "file_url",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ type SkillUser struct {
|
|||||||
|
|
||||||
Name string `orm:"name" json:"name"`
|
Name string `orm:"name" json:"name"`
|
||||||
Description string `orm:"description" json:"description"`
|
Description string `orm:"description" json:"description"`
|
||||||
Category string `orm:"category" json:"category"`
|
|
||||||
FileName string `orm:"file_name" json:"fileName"`
|
FileName string `orm:"file_name" json:"fileName"`
|
||||||
FileUrl string `orm:"file_url" json:"fileUrl"`
|
FileUrl string `orm:"file_url" json:"fileUrl"`
|
||||||
}
|
}
|
||||||
@@ -16,7 +15,6 @@ type skillUserCol struct {
|
|||||||
beans.SQLBaseCol
|
beans.SQLBaseCol
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
Category string
|
|
||||||
FileName string
|
FileName string
|
||||||
FileUrl string
|
FileUrl string
|
||||||
}
|
}
|
||||||
@@ -25,7 +23,6 @@ var SkillUserCol = skillUserCol{
|
|||||||
SQLBaseCol: beans.DefSQLBaseCol,
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Description: "description",
|
Description: "description",
|
||||||
Category: "category",
|
|
||||||
FileName: "file_name",
|
FileName: "file_name",
|
||||||
FileUrl: "file_url",
|
FileUrl: "file_url",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ package flow
|
|||||||
import (
|
import (
|
||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/consts/node"
|
"ai-agent/workflow/consts/node"
|
||||||
|
fileDao "ai-agent/workflow/dao/file"
|
||||||
flowDao "ai-agent/workflow/dao/flow"
|
flowDao "ai-agent/workflow/dao/flow"
|
||||||
|
fileDto "ai-agent/workflow/model/dto/file"
|
||||||
flowDto "ai-agent/workflow/model/dto/flow"
|
flowDto "ai-agent/workflow/model/dto/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -31,6 +34,10 @@ func (s *flowExecutionService) Get(ctx context.Context, req *flowDto.GetFlowExec
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res = new(flowDto.VOFlowExecution)
|
res = new(flowDto.VOFlowExecution)
|
||||||
|
res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
err = gconv.Struct(r, &res)
|
err = gconv.Struct(r, &res)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@@ -227,15 +234,61 @@ func Notify(taskId string, result any) {
|
|||||||
delete(asyncTasks, taskId)
|
delete(asyncTasks, taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (s *flowExecutionService) Cancel(ctx context.Context, req *flowDto.CancelReq) (err error) {
|
// ===================== 核心改造:替换为 sync.Map 存储取消上下文 =====================
|
||||||
// res, err := flowDao.FlowExecutionDao.Get(ctx, &flowDto.GetFlowExecutionReq{
|
var (
|
||||||
// Id: req.FlowId,
|
// cancelMap: traceID -> context.CancelFunc
|
||||||
// })
|
cancelMap sync.Map
|
||||||
// res.TraceId
|
)
|
||||||
// return
|
|
||||||
//}
|
func (s *flowExecutionService) Cancel(ctx context.Context, req *flowDto.CancelReq) (err error) {
|
||||||
|
getRes, err := flowDao.FlowExecutionDao.Get(ctx, &flowDto.GetFlowExecutionReq{
|
||||||
|
SessionId: req.SessionId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if g.IsEmpty(getRes) {
|
||||||
|
return fmt.Errorf("会话[%s] 不存在", req.SessionId)
|
||||||
|
}
|
||||||
|
// 从 sync.Map 获取取消函数
|
||||||
|
cancelVal, exist := cancelMap.Load(getRes.TraceId)
|
||||||
|
if !exist {
|
||||||
|
return fmt.Errorf("traceID[%s] 不存在或已执行完成", getRes.TraceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行取消
|
||||||
|
cancel, ok := cancelVal.(context.CancelFunc)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("traceID[%s] 对应的取消函数类型错误", getRes.TraceId)
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
// 取消后清理(可选:也可以在流程结束时统一清理)
|
||||||
|
cancelMap.Delete(getRes.TraceId)
|
||||||
|
|
||||||
|
// 同步更新流程执行状态为已取消
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: getRes.Id,
|
||||||
|
Status: flow.FlowExecutionStatusCancel.Code(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("更新取消状态失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.ExecuteReq) (res *flowDto.ExecuteRes, err error) {
|
func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.ExecuteReq) (res *flowDto.ExecuteRes, err error) {
|
||||||
|
// ===================== 核心改造1:创建可取消的上下文 =====================
|
||||||
|
execCtx, cancel := context.WithCancel(ctx)
|
||||||
|
traceId := ""
|
||||||
|
defer func() {
|
||||||
|
// 流程结束(成功/失败)时清理 cancelMap
|
||||||
|
if traceId != "" {
|
||||||
|
cancelMap.Delete(traceId)
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
flowInfo, err := flowDao.FlowExecutionDao.Get(ctx, &flowDto.GetFlowExecutionReq{
|
flowInfo, err := flowDao.FlowExecutionDao.Get(ctx, &flowDto.GetFlowExecutionReq{
|
||||||
SessionId: req.SessionId,
|
SessionId: req.SessionId,
|
||||||
@@ -244,7 +297,9 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var executionId int64
|
var executionId int64
|
||||||
|
var isDialogue bool
|
||||||
if flowInfo == nil {
|
if flowInfo == nil {
|
||||||
|
isDialogue = false
|
||||||
var r = new(flowDto.CreateFlowExecutionReq)
|
var r = new(flowDto.CreateFlowExecutionReq)
|
||||||
r.FlowUserId = req.FlowId
|
r.FlowUserId = req.FlowId
|
||||||
r.FlowName = req.FlowName
|
r.FlowName = req.FlowName
|
||||||
@@ -256,24 +311,55 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
span := trace.SpanFromContext(ctx)
|
span := trace.SpanFromContext(ctx)
|
||||||
if span != nil && span.SpanContext().HasTraceID() {
|
if span != nil && span.SpanContext().HasTraceID() {
|
||||||
r.TraceId = span.SpanContext().TraceID().String()
|
r.TraceId = span.SpanContext().TraceID().String()
|
||||||
|
traceId = r.TraceId
|
||||||
|
cancelMap.Store(traceId, cancel)
|
||||||
}
|
}
|
||||||
executionId, err = flowDao.FlowExecutionDao.Insert(ctx, r)
|
executionId, err = flowDao.FlowExecutionDao.Insert(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
isDialogue = true
|
||||||
executionId = flowInfo.Id
|
executionId = flowInfo.Id
|
||||||
|
span := trace.SpanFromContext(ctx)
|
||||||
|
if span != nil && span.SpanContext().HasTraceID() {
|
||||||
|
traceId = span.SpanContext().TraceID().String()
|
||||||
|
cancelMap.Store(traceId, cancel)
|
||||||
|
}
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: executionId,
|
||||||
|
Status: flow.FlowExecutionStatusRunning.Code(),
|
||||||
|
TraceId: traceId,
|
||||||
|
}
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = flowDao.FlowUserDao.Update(ctx, &flowDto.UpdateFlowUserReq{
|
if !g.IsEmpty(req.FileUrl) {
|
||||||
Id: req.FlowId,
|
createFileTempReq := make([]*fileDto.CreateFileTempReq, 0, len(req.FileUrl))
|
||||||
FlowContent: req.FlowContent,
|
for _, fileUrl := range req.FileUrl {
|
||||||
NodeInputParams: req.NodeInputParams,
|
var createReq = new(fileDto.CreateFileTempReq)
|
||||||
})
|
createReq.BusinessId = req.SessionId
|
||||||
if err != nil {
|
createReq.FileUrl = fileUrl
|
||||||
return nil, err
|
createFileTempReq = append(createFileTempReq, createReq)
|
||||||
|
}
|
||||||
|
_, err = fileDao.FileTempDao.BatchInsert(ctx, createFileTempReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//_, err = flowDao.FlowUserDao.Update(ctx, &flowDto.UpdateFlowUserReq{
|
||||||
|
// Id: req.FlowId,
|
||||||
|
// FlowContent: req.FlowContent,
|
||||||
|
// NodeInputParams: req.NodeInputParams,
|
||||||
|
//})
|
||||||
|
//if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
//}
|
||||||
|
|
||||||
//nodeInsert := make([]*nodeDto.CreateNodeExecutionReq, 0, len(flowInfo.NodeInputParams))
|
//nodeInsert := make([]*nodeDto.CreateNodeExecutionReq, 0, len(flowInfo.NodeInputParams))
|
||||||
//for _, flowNode := range flowInfo.NodeInputParams {
|
//for _, flowNode := range flowInfo.NodeInputParams {
|
||||||
// nodeInsert = append(nodeInsert, &nodeDto.CreateNodeExecutionReq{
|
// nodeInsert = append(nodeInsert, &nodeDto.CreateNodeExecutionReq{
|
||||||
@@ -329,18 +415,18 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
// ✅【第2步】构建执行图
|
// ✅【第2步】构建执行图
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
runGraph, err := BuildGraphFromFlowContent(ctx, req.FlowContent, judge2IntentNodeMap, summaryNodeID)
|
runGraph, err := BuildGraphFromFlowContent(execCtx, req.FlowContent, judge2IntentNodeMap, summaryNodeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
Id: executionId,
|
Id: executionId,
|
||||||
|
Status: flow.FlowExecutionStatusFailed.Code(),
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
}
|
}
|
||||||
executionReq.Status = flow.FlowExecutionStatusFailed.Code()
|
|
||||||
executionReq.ErrorMessage = err.Error()
|
|
||||||
_, err1 := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
_, err1 := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, fmt.Errorf("执行工作流失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -363,6 +449,7 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
// ✅【第4步】构建全局执行入参(现在 schemaMap 是有值的!)
|
// ✅【第4步】构建全局执行入参(现在 schemaMap 是有值的!)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
execInput := &flowDto.FlowExecutionInput{
|
execInput := &flowDto.FlowExecutionInput{
|
||||||
|
IsDialogue: isDialogue,
|
||||||
ExecutionId: executionId,
|
ExecutionId: executionId,
|
||||||
ConfigMap: configMap,
|
ConfigMap: configMap,
|
||||||
SessionId: req.SessionId,
|
SessionId: req.SessionId,
|
||||||
@@ -371,18 +458,27 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
FileUrl: req.FileUrl,
|
FileUrl: req.FileUrl,
|
||||||
}
|
}
|
||||||
// 执行工作流
|
// 执行工作流
|
||||||
_, err = runGraph.Invoke(ctx, execInput)
|
_, err = runGraph.Invoke(execCtx, execInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
// 检测是否是取消导致的错误
|
||||||
Id: executionId,
|
if errors.Is(execCtx.Err(), context.Canceled) {
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: executionId,
|
||||||
|
Status: flow.FlowExecutionStatusCancel.Code(),
|
||||||
|
}
|
||||||
|
_, _ = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
return nil, fmt.Errorf("工作流已被取消: %v", err)
|
||||||
|
}
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: executionId,
|
||||||
|
Status: flow.FlowExecutionStatusFailed.Code(),
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
}
|
}
|
||||||
executionReq.Status = flow.FlowExecutionStatusFailed.Code()
|
|
||||||
executionReq.ErrorMessage = err.Error()
|
|
||||||
_, err1 := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
_, err1 := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, fmt.Errorf("执行工作流失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ package flow
|
|||||||
import (
|
import (
|
||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/consts/node"
|
"ai-agent/workflow/consts/node"
|
||||||
|
"ai-agent/workflow/consts/public"
|
||||||
|
fileDao "ai-agent/workflow/dao/file"
|
||||||
flowDao "ai-agent/workflow/dao/flow"
|
flowDao "ai-agent/workflow/dao/flow"
|
||||||
"ai-agent/workflow/model/dto"
|
"ai-agent/workflow/model/dto"
|
||||||
|
fileDto "ai-agent/workflow/model/dto/file"
|
||||||
flowDto "ai-agent/workflow/model/dto/flow"
|
flowDto "ai-agent/workflow/model/dto/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
@@ -14,7 +17,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitea.com/red-future/common/db/gfdb"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.com/red-future/common/utils"
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
@@ -160,10 +165,15 @@ func JudgeLambda(ctx context.Context, input any) (string, error) {
|
|||||||
for _, v := range nodeInput.Config.FormConfig {
|
for _, v := range nodeInput.Config.FormConfig {
|
||||||
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
||||||
}
|
}
|
||||||
for _, v := range *out {
|
if !nodeInput.Global.IsDialogue {
|
||||||
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
for _, v := range *out {
|
||||||
|
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !g.IsEmpty(nodeInput.Global.Desc) {
|
||||||
|
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, "描述", nodeInput.Global.Desc)
|
||||||
|
}
|
||||||
configMap := gconv.Map(nodeInput.Config.Config)
|
configMap := gconv.Map(nodeInput.Config.Config)
|
||||||
ids := gconv.Strings(configMap["branch_ids"])
|
ids := gconv.Strings(configMap["branch_ids"])
|
||||||
branchIdNameMap := gconv.Map(configMap["branch_id_name_map"])
|
branchIdNameMap := gconv.Map(configMap["branch_id_name_map"])
|
||||||
@@ -175,33 +185,18 @@ func JudgeLambda(ctx context.Context, input any) (string, error) {
|
|||||||
branchIdNameLines = append(branchIdNameLines, fmt.Sprintf("%s: %s", id, name))
|
branchIdNameLines = append(branchIdNameLines, fmt.Sprintf("%s: %s", id, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt := fmt.Sprintf(`
|
|
||||||
你是流程路由助手,你的任务是根据上下文,选择一个正确的节点ID返回。
|
|
||||||
|
|
||||||
规则:
|
|
||||||
1. 只允许从下面的可选节点ID列表中选择一个返回
|
|
||||||
2. 不要返回任何多余文字、标点、解释、标题
|
|
||||||
3. 只返回纯节点ID
|
|
||||||
|
|
||||||
可选节点ID(ID: 节点描述):
|
|
||||||
%s
|
|
||||||
|
|
||||||
上下文内容:
|
|
||||||
%s
|
|
||||||
`, strings.Join(branchIdNameLines, "\n"), contextParts)
|
|
||||||
|
|
||||||
getIsChatModel, err := GetIsChatModel(ctx)
|
getIsChatModel, err := GetIsChatModel(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
req := flowDto.ComposeMessagesReq{
|
||||||
|
BuildType: 2,
|
||||||
ModelName: getIsChatModel.ModelName,
|
ModelName: getIsChatModel.ModelName,
|
||||||
SkillName: "",
|
SkillName: "",
|
||||||
IsBuild: true,
|
|
||||||
Cause: "判断节点",
|
Cause: "判断节点",
|
||||||
Form: map[string]any{},
|
Form: map[string]any{"prompt": strings.Join(branchIdNameLines, "\n")},
|
||||||
UserForm: map[string]any{"prompt": prompt},
|
UserForm: map[string]any{"prompt": contextParts},
|
||||||
UserFiles: nodeInput.Global.FileUrl,
|
UserFiles: nodeInput.Global.FileUrl,
|
||||||
SessionId: nodeInput.Global.SessionId,
|
SessionId: nodeInput.Global.SessionId,
|
||||||
}
|
}
|
||||||
@@ -209,19 +204,13 @@ func JudgeLambda(ctx context.Context, input any) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
taskResult, err := GatewayTask(ctx, msg.EpicycleId, getIsChatModel.ModelName, msg.Messages)
|
if g.IsEmpty(msg.Messages) {
|
||||||
if err != nil {
|
return "", fmt.Errorf("msg is empty")
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
result, err := GetTaskResult(ctx, taskResult)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
mapTaskResult := gconv.Map(result.Text)
|
|
||||||
|
|
||||||
content := ""
|
content := ""
|
||||||
for key, _ := range getIsChatModel.ResponseBody {
|
for key, _ := range getIsChatModel.ResponseBody {
|
||||||
content = gconv.String(mapTaskResult[key])
|
content = gconv.String(msg.Messages[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("JudgeLambda路由:目标节点ID=%s\n", gconv.String(content))
|
fmt.Printf("JudgeLambda路由:目标节点ID=%s\n", gconv.String(content))
|
||||||
@@ -244,10 +233,16 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
outputResult = append(outputResult, field)
|
outputResult = append(outputResult, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultUserFrom := make(map[string]any)
|
||||||
|
|
||||||
for _, valueAny := range outputMap {
|
for _, valueAny := range outputMap {
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
if !strings.Contains(field.Field, "html") && !strings.Contains(field.Field, "img") {
|
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
||||||
outputResult = append(outputResult, field)
|
if strings.Contains(field.Field, "text_content") {
|
||||||
|
field.Value = stripHtmlTags(field.Value, false)
|
||||||
|
}
|
||||||
|
resultUserFrom[field.Label] = field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,13 +251,13 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
outputResult = append(outputResult, field)
|
outputResult = append(outputResult, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !nodeInput.Global.IsDialogue {
|
||||||
resultUserFrom := make(map[string]any)
|
for _, item := range outputResult {
|
||||||
for _, item := range outputResult {
|
resultUserFrom[item.Label] = item
|
||||||
resultUserFrom[item.Label] = item
|
}
|
||||||
}
|
for _, item := range nodeInput.Config.FormConfig {
|
||||||
for _, item := range nodeInput.Config.FormConfig {
|
resultUserFrom[item.Label] = item
|
||||||
resultUserFrom[item.Label] = item
|
}
|
||||||
}
|
}
|
||||||
if !g.IsEmpty(nodeInput.Global.Desc) {
|
if !g.IsEmpty(nodeInput.Global.Desc) {
|
||||||
resultUserFrom["desc"] = node.NodeFormField{
|
resultUserFrom["desc"] = node.NodeFormField{
|
||||||
@@ -282,31 +277,30 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
if g.IsEmpty(nodeInput.Config.SkillName) {
|
if g.IsEmpty(nodeInput.Config.SkillName) {
|
||||||
skillName = nodeInput.Global.SkillName
|
skillName = nodeInput.Global.SkillName
|
||||||
}
|
}
|
||||||
contentStr := "你是专业内容生成助手,请严格按以下规则输出内容:\n1. 输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释\n2. 整体用 <div class=\"report-container\"> 包裹\n3. 主标题使用 <h2 class=\"title\">\n4. 章节标题使用 <h3 class=\"section-title\">\n5. 正文段落使用 <p class=\"paragraph\">\n6. 列表使用 <ul class=\"list\"><li>...</li></ul>\n7. 重点内容使用 <strong> 加粗\n8. 段落之间清晰分隔,结构规整\n9. 如果生成多条文案,每条文案独立用 <div class=\"content-item\" id=\"content-{序号}\"> 包裹(序号从1开始)\n10. 每条文案内部必须在最上方添加一行固定格式:<p class=\"image-count\">需要配图:N 张</p> N 是这条文案需要的图片数量,只能是数字,不能是其他文字\n11. 只输出 HTML 结构,不输出任何额外文字"
|
contentStr := "你是专业内容生成助手,请严格按以下规则输出内容:1、输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释,2、整体用 <div class=\"report-container\"> 包裹,3、主标题使用 <h2 class=\"title\">,4、章节标题使用 <h3 class=\"section-title\">,5、正文段落使用 <p class=\"paragraph\">,6、列表使用 <ul class=\"list\"><li>...</li></ul>,7、重点内容使用 <strong> 加粗,8、段落之间清晰分隔,结构规整,9、如果生成多条文案,每条文案独立用 <div class=\"content-item\" id=\"content-{序号}\"> 包裹(序号从1开始),10、每条文案内部必须在最上方添加一行固定格式:<p class=\"image-count\">需要配图:N 张</p> N 是这条文案需要的图片数量,只能是数字,不能是其他文字,11、只输出 HTML 结构,不输出任何额外文字"
|
||||||
resultUserFrom["prompt"] = contentStr
|
resultUserFrom["prompt"] = contentStr
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
req := flowDto.ComposeMessagesReq{
|
||||||
|
BuildType: 1,
|
||||||
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
||||||
SkillName: skillName,
|
SkillName: skillName,
|
||||||
IsBuild: true,
|
|
||||||
Cause: "文案节点",
|
Cause: "文案节点",
|
||||||
Form: resultFrom,
|
Form: resultFrom,
|
||||||
UserForm: resultUserFrom,
|
UserForm: resultUserFrom,
|
||||||
UserFiles: nodeInput.Global.FileUrl,
|
UserFiles: nodeInput.Global.FileUrl,
|
||||||
SessionId: nodeInput.Global.SessionId,
|
SessionId: nodeInput.Global.SessionId,
|
||||||
}
|
}
|
||||||
//contentStr := "你是专业内容生成助手,请按以下通用规则输出内容:\n1. 输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释\n2. 整体用 <div class=\"report-container\"> 包裹\n3. 主标题使用 <h2 class=\"title\">\n4. 章节标题使用 <h3 class=\"section-title\">\n5. 正文段落使用 <p class=\"paragraph\">\n6. 列表使用 <ul class=\"list\"><li>...</li></ul>\n7. 重点内容使用 <strong> 加粗\n8. 段落之间清晰分隔,结构规整\n9. 只输出 HTML 结构,不输出任何额外文字"
|
|
||||||
|
|
||||||
//contentStr := "你是专业内容生成助手,请按以下通用规则输出内容:\n1. 输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释\n2. 整体用 <div class=\"report-container\"> 包裹\n3. 主标题使用 <h2 class=\"title\">\n4. 章节标题使用 <h3 class=\"section-title\">\n5. 正文段落使用 <p class=\"paragraph\">\n6. 列表使用 <ul class=\"list\"><li>...</li></ul>\n7. 重点内容使用 <strong> 加粗\n8. 段落之间清晰分隔,结构规整\n9. 如果生成多条文案,每条文案独立用 <div class=\"content-item\" id=\"content-{序号}\"> 包裹(序号从1开始)\n10. 只输出 HTML 结构,不输出任何额外文字"
|
|
||||||
|
|
||||||
msg, err := ComposeMessages(ctx, &req)
|
msg, err := ComposeMessages(ctx, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if g.IsEmpty(msg.Messages) {
|
||||||
|
return nil, fmt.Errorf("msg is empty")
|
||||||
|
}
|
||||||
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := GetTaskResult(ctx, taskResult)
|
result, err := GetTaskResult(ctx, taskResult)
|
||||||
@@ -335,7 +329,7 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 1. 去掉 HTML 标签,生成纯文本
|
// 1. 去掉 HTML 标签,生成纯文本
|
||||||
plainText := stripHtmlTags(content)
|
plainText := stripHtmlTags(content, true)
|
||||||
// 2. 上传纯文本到 OSS
|
// 2. 上传纯文本到 OSS
|
||||||
textFileName := fmt.Sprintf("ai_text_%d_%d.txt", time.Now().UnixMilli(), i)
|
textFileName := fmt.Sprintf("ai_text_%d_%d.txt", time.Now().UnixMilli(), i)
|
||||||
textUrl, err := Upload(ctx, &dto.UploadFileBytesReq{
|
textUrl, err := Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
@@ -349,7 +343,7 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
outputRes = append(outputRes, node.NodeFormField{
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
Field: fmt.Sprintf("%v:text_url:%d", nodeInput.Config.Id, i),
|
Field: fmt.Sprintf("%v:text_url:%d", nodeInput.Config.Id, i),
|
||||||
Value: textUrl.FileURL,
|
Value: textUrl.FileURL,
|
||||||
Label: fmt.Sprintf("文案纯文本_%d", i),
|
Label: fmt.Sprintf("文案纯文本_txt_%d", i),
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Expand: extractImageCount(content),
|
Expand: extractImageCount(content),
|
||||||
})
|
})
|
||||||
@@ -361,17 +355,23 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
|
|
||||||
// 从 HTML 内容里提取图片数量(例如从 <p class="image-count">需要配图:3 张</p> 拿到 3)
|
// 从 HTML 内容里提取图片数量(例如从 <p class="image-count">需要配图:3 张</p> 拿到 3)
|
||||||
func extractImageCount(content string) int {
|
func extractImageCount(content string) int {
|
||||||
re := regexp.MustCompile(`<p class="image-count">需要配图:(\d+) 张</p>`)
|
re := regexp.MustCompile(`<p class="image-count">[^\d]*(\d+)[^\d]*</p>`)
|
||||||
match := re.FindStringSubmatch(content)
|
match := re.FindStringSubmatch(content)
|
||||||
if len(match) >= 2 {
|
if len(match) >= 2 {
|
||||||
num, _ := strconv.Atoi(match[1])
|
num, _ := strconv.Atoi(match[1])
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
return 0 // 没找到默认 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// stripHtmlTags 去掉所有HTML标签,保留换行和文本结构,并删除配图标记行
|
// stripHtmlTags 去掉所有HTML标签,保留换行和文本结构,并删除配图标记行
|
||||||
func stripHtmlTags(html string) string {
|
func stripHtmlTags(html string, delImageCount bool) string {
|
||||||
|
if delImageCount {
|
||||||
|
// 🔥 第一步:直接删除整个 <p class="image-count">...</p> 标签(包含内容)
|
||||||
|
imageTagRegex := regexp.MustCompile(`<p class="image-count">[\s\S]*?</p>`)
|
||||||
|
html = imageTagRegex.ReplaceAllString(html, "")
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 替换块级标签为换行,保证排版
|
// 1. 替换块级标签为换行,保证排版
|
||||||
blockTags := regexp.MustCompile(`</?(div|p|h1|h2|h3|h4|h5|h6|li|ul|ol|br|tr|td|th)[^>]*>`)
|
blockTags := regexp.MustCompile(`</?(div|p|h1|h2|h3|h4|h5|h6|li|ul|ol|br|tr|td|th)[^>]*>`)
|
||||||
text := blockTags.ReplaceAllString(html, "\n")
|
text := blockTags.ReplaceAllString(html, "\n")
|
||||||
@@ -380,11 +380,7 @@ func stripHtmlTags(html string) string {
|
|||||||
allTags := regexp.MustCompile(`<[^>]+>`)
|
allTags := regexp.MustCompile(`<[^>]+>`)
|
||||||
text = allTags.ReplaceAllString(text, "")
|
text = allTags.ReplaceAllString(text, "")
|
||||||
|
|
||||||
// 3. 🔥 新增:删除 "需要配图:X 张" 这一行(含前后可能的空格/换行)
|
// 4. 清理多余空行(多个换行只保留一个)
|
||||||
imageCountLine := regexp.MustCompile(`(?m)^\s*需要配图:\d+\s*张\s*$`)
|
|
||||||
text = imageCountLine.ReplaceAllString(text, "")
|
|
||||||
|
|
||||||
// 4. 清理多余空行(多个换行只保留一个,更干净)
|
|
||||||
text = regexp.MustCompile(`\n\s*\n`).ReplaceAllString(text, "\n")
|
text = regexp.MustCompile(`\n\s*\n`).ReplaceAllString(text, "\n")
|
||||||
|
|
||||||
// 5. 只去掉首尾空白,中间换行保留
|
// 5. 只去掉首尾空白,中间换行保留
|
||||||
@@ -429,10 +425,16 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
outputResult = append(outputResult, field)
|
outputResult = append(outputResult, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultUserFrom := make(map[string]any)
|
||||||
|
|
||||||
for _, valueAny := range outputMap {
|
for _, valueAny := range outputMap {
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
if !strings.Contains(field.Field, "html") && !strings.Contains(field.Field, "img") {
|
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
||||||
outputResult = append(outputResult, field)
|
if strings.Contains(field.Field, "text_content") {
|
||||||
|
field.Value = stripHtmlTags(field.Value, false)
|
||||||
|
}
|
||||||
|
resultUserFrom[field.Label] = field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,12 +444,13 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resultUserFrom := make(map[string]any)
|
if !nodeInput.Global.IsDialogue {
|
||||||
for _, item := range outputResult {
|
for _, item := range outputResult {
|
||||||
resultUserFrom[item.Label] = item
|
resultUserFrom[item.Label] = item
|
||||||
}
|
}
|
||||||
for _, item := range nodeInput.Config.FormConfig {
|
for _, item := range nodeInput.Config.FormConfig {
|
||||||
resultUserFrom[item.Label] = item
|
resultUserFrom[item.Label] = item
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !g.IsEmpty(nodeInput.Global.Desc) {
|
if !g.IsEmpty(nodeInput.Global.Desc) {
|
||||||
resultUserFrom["desc"] = node.NodeFormField{
|
resultUserFrom["desc"] = node.NodeFormField{
|
||||||
@@ -469,9 +472,9 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
req := flowDto.ComposeMessagesReq{
|
||||||
|
BuildType: 1,
|
||||||
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
||||||
SkillName: skillName,
|
SkillName: skillName,
|
||||||
IsBuild: true,
|
|
||||||
Cause: "图片节点",
|
Cause: "图片节点",
|
||||||
Form: resultFrom,
|
Form: resultFrom,
|
||||||
UserForm: resultUserFrom,
|
UserForm: resultUserFrom,
|
||||||
@@ -482,7 +485,9 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if g.IsEmpty(msg.Messages) {
|
||||||
|
return nil, fmt.Errorf("msg is empty")
|
||||||
|
}
|
||||||
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -493,8 +498,6 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
//result := new(flowDto.TaskCallback)
|
|
||||||
//result.Text = "{\n \"content\": [\n {\n \"image\": \"https://dashscope-7c2c.oss-accelerate.aliyuncs.com/7d/8d/20260512/76483b06/306aac7b-915e-479d-94d4-adc3cf1d6f22.png?Expires=1779159512&OSSAccessKeyId=LTAI5tPxpiCM2hjmWrFXrym1&Signature=3a3KDmPNeO%2BVjHJbAV8t0R7UF6Q%3D\"\n },\n {\n \"image\": \"https://dashscope-7c2c.oss-accelerate.aliyuncs.com/7d/c9/20260512/76483b06/f8f3e9be-2920-48b8-93f5-acbf26e52b0c.png?Expires=1779159512&OSSAccessKeyId=LTAI5tPxpiCM2hjmWrFXrym1&Signature=li%2FpcoX5i7FJrk3PCpw5jrbWy2k%3D\"\n },\n {\n \"image\": \"https://dashscope-7c2c.oss-accelerate.aliyuncs.com/7d/89/20260512/76483b06/38d55abe-8230-4837-85d3-426265139be0.png?Expires=1779159512&OSSAccessKeyId=LTAI5tPxpiCM2hjmWrFXrym1&Signature=uNRV9RQY2O60frAtIg6JvCcVhDw%3D\"\n },\n {\n \"image\": \"https://dashscope-7c2c.oss-accelerate.aliyuncs.com/7d/82/20260512/76483b06/e100070d-2a79-4ec8-be72-105226854bab.png?Expires=1779159512&OSSAccessKeyId=LTAI5tPxpiCM2hjmWrFXrym1&Signature=7UCh7FmYt0%2FYxyItNoLELp7zPF0%3D\"\n }\n ]\n}"
|
|
||||||
mapTaskResult := gconv.Map(result.Text)
|
mapTaskResult := gconv.Map(result.Text)
|
||||||
|
|
||||||
imgs := []string{}
|
imgs := []string{}
|
||||||
@@ -548,7 +551,7 @@ func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
outputRes = append(outputRes, node.NodeFormField{
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
Field: fmt.Sprintf("%v:img_url:%d", nodeInput.Config.Id, i),
|
Field: fmt.Sprintf("%v:img_url:%d", nodeInput.Config.Id, i),
|
||||||
Value: fmt.Sprintf("%s%s", url, item),
|
Value: fmt.Sprintf("%s%s", url, item),
|
||||||
Label: fmt.Sprintf("图片_%d关联文案ID", i),
|
Label: fmt.Sprintf("图片_img_%d关联文案ID", i),
|
||||||
Type: "string",
|
Type: "string",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -874,113 +877,51 @@ func SummaryLambda(ctx context.Context, input any) (any, error) {
|
|||||||
// 把汇总结果存入当前节点的输出
|
// 把汇总结果存入当前节点的输出
|
||||||
g.Log().Info(ctx, fmt.Sprintf("结果汇总完成,汇总数据:%+v", summaryResult))
|
g.Log().Info(ctx, fmt.Sprintf("结果汇总完成,汇总数据:%+v", summaryResult))
|
||||||
|
|
||||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
err := gfdb.DB(ctx, public.DbNameBlackDeacon).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||||
Id: execInput.Global.ExecutionId,
|
flowInfo, err := flowDao.FlowExecutionDao.Get(ctx, &flowDto.GetFlowExecutionReq{
|
||||||
OutputParams: summaryResult,
|
SessionId: execInput.Global.SessionId,
|
||||||
}
|
})
|
||||||
executionReq.Status = flow.FlowExecutionStatusSuccess.Code()
|
if err != nil {
|
||||||
_, err := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: execInput.Global.ExecutionId,
|
||||||
|
OutputParams: summaryResult,
|
||||||
|
}
|
||||||
|
executionReq.Status = flow.FlowExecutionStatusSuccess.Code()
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
|
||||||
|
if flowInfo != nil {
|
||||||
|
var url string
|
||||||
|
url, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
createFileTempReq := make([]*fileDto.CreateFileTempReq, 0, len(flowInfo.OutputParams))
|
||||||
|
for _, fileUrl := range flowInfo.OutputParams {
|
||||||
|
m := gconv.Map(fileUrl)
|
||||||
|
for _, v := range m {
|
||||||
|
var createReq = new(fileDto.CreateFileTempReq)
|
||||||
|
createReq.BusinessId = flowInfo.SessionId
|
||||||
|
createReq.FileUrl = url + gconv.String(v)
|
||||||
|
createFileTempReq = append(createFileTempReq, createReq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(createFileTempReq) > 0 {
|
||||||
|
_, err = fileDao.FileTempDao.BatchInsert(ctx, createFileTempReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return execInput, err
|
return execInput, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//func SummaryLambda(ctx context.Context, input any) (any, error) {
|
|
||||||
// execInput, ok := input.(*flowDto.NodeExecutionInput)
|
|
||||||
// if !ok {
|
|
||||||
// return nil, fmt.Errorf("汇总节点入参类型错误,实际是 %T", input)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 1. 定义临时映射:按条目序号(如item_0)聚合html/img/text
|
|
||||||
// // key: 条目序号(如0/1/2), value: {html:"", img:"", text:""}
|
|
||||||
// itemMap := make(map[int]map[string]string)
|
|
||||||
// // 存储每个条目对应的时间戳(一个条目一个唯一时间戳)
|
|
||||||
// itemTimeMap := make(map[int]int64)
|
|
||||||
//
|
|
||||||
// // 2. 遍历已执行节点,解析输出字段并分组
|
|
||||||
// for _, nodeID := range execInput.Global.ExecutedNodes {
|
|
||||||
// nodeConfig := execInput.Global.ConfigMap[nodeID]
|
|
||||||
// if nodeConfig == nil || len(nodeConfig.OutputResult) == 0 {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 遍历节点的输出字段
|
|
||||||
// for _, field := range nodeConfig.OutputResult {
|
|
||||||
// var itemIndex int
|
|
||||||
// var fieldType string
|
|
||||||
// var fieldValue string
|
|
||||||
//
|
|
||||||
// // 匹配「条目HTML地址」字段(如item_html_url_0)
|
|
||||||
// if match := regexp.MustCompile(`item_html_url_(\d+)`).FindStringSubmatch(field.Field); len(match) == 2 {
|
|
||||||
// itemIndex, _ = strconv.Atoi(match[1])
|
|
||||||
// fieldType = "html"
|
|
||||||
// fieldValue = gconv.String(field.Value)
|
|
||||||
// } else if match := regexp.MustCompile(`img_url:(\d+)`).FindStringSubmatch(field.Field); len(match) == 2 {
|
|
||||||
// itemIndex, _ = strconv.Atoi(match[1])
|
|
||||||
// fieldType = "img"
|
|
||||||
// fieldValue = gconv.String(field.Value)
|
|
||||||
// } else if match := regexp.MustCompile(`text_url:(\d+)`).FindStringSubmatch(field.Field); len(match) == 2 {
|
|
||||||
// itemIndex, _ = strconv.Atoi(match[1])
|
|
||||||
// fieldType = "text"
|
|
||||||
// fieldValue = gconv.String(field.Value)
|
|
||||||
// } else {
|
|
||||||
// // 非目标字段,跳过
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 初始化条目映射(首次遇到该条目时)
|
|
||||||
// if _, exists := itemMap[itemIndex]; !exists {
|
|
||||||
// itemMap[itemIndex] = map[string]string{
|
|
||||||
// "html": "",
|
|
||||||
// "img": "",
|
|
||||||
// "text": "",
|
|
||||||
// }
|
|
||||||
// // 为该条目生成唯一时间戳(毫秒级)
|
|
||||||
// itemTimeMap[itemIndex] = time.Now().UnixMilli()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 填充该条目对应的字段值
|
|
||||||
// itemMap[itemIndex][fieldType] = fieldValue
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 3. 组装最终的汇总结构:[{内容N:{html:"",img:"",text:""},时间戳:xxx}, ...]
|
|
||||||
// var summaryResult []map[string]interface{}
|
|
||||||
// // 按条目序号排序(保证顺序一致)
|
|
||||||
// itemIndexes := make([]int, 0, len(itemMap))
|
|
||||||
// for idx := range itemMap {
|
|
||||||
// itemIndexes = append(itemIndexes, idx)
|
|
||||||
// }
|
|
||||||
// sort.Ints(itemIndexes)
|
|
||||||
//
|
|
||||||
// // 遍历排序后的条目,组装结构
|
|
||||||
// for _, idx := range itemIndexes {
|
|
||||||
// itemData := itemMap[idx]
|
|
||||||
// timeStamp := itemTimeMap[idx]
|
|
||||||
//
|
|
||||||
// // 单条目结构:{"内容X": {html:"",img:"",text:""}, "时间戳": xxx}
|
|
||||||
// itemResult := make(map[string]interface{})
|
|
||||||
// itemResult[fmt.Sprintf("内容%d", idx+1)] = map[string]string{
|
|
||||||
// "html": itemData["html"],
|
|
||||||
// "img": itemData["img"],
|
|
||||||
// "text": itemData["text"],
|
|
||||||
// }
|
|
||||||
// itemResult["时间戳"] = timeStamp
|
|
||||||
//
|
|
||||||
// summaryResult = append(summaryResult, itemResult)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 4. 打印调试&更新数据库
|
|
||||||
// g.Log().Info(ctx, fmt.Sprintf("结果汇总完成,汇总数据:%+v", summaryResult))
|
|
||||||
// executionReq := flowDto.UpdateFlowExecutionReq{
|
|
||||||
// Id: execInput.Global.ExecutionId,
|
|
||||||
// OutputParams: summaryResult,
|
|
||||||
// Status: flow.FlowExecutionStatusSuccess.Code(),
|
|
||||||
// }
|
|
||||||
// _, err := flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
|
||||||
//
|
|
||||||
// return execInput, err
|
|
||||||
//}
|
|
||||||
|
|
||||||
// VideoModelLambda 构建视频
|
// VideoModelLambda 构建视频
|
||||||
func VideoModelLambda(ctx context.Context, input any) (any, error) {
|
func VideoModelLambda(ctx context.Context, input any) (any, error) {
|
||||||
fmt.Println("VideoModelLambda:", input)
|
fmt.Println("VideoModelLambda:", input)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.com/red-future/common/utils"
|
||||||
@@ -17,7 +16,7 @@ import (
|
|||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetIsChatModel(ctx context.Context) (*flowDto.GetIsChatModelRes, error) {
|
func GetIsChatModel(ctx context.Context) (res *flowDto.GetIsChatModelRes, err error) {
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
if r := g.RequestFromCtx(ctx); r != nil {
|
if r := g.RequestFromCtx(ctx); r != nil {
|
||||||
for k, v := range r.Request.Header {
|
for k, v := range r.Request.Header {
|
||||||
@@ -26,13 +25,9 @@ func GetIsChatModel(ctx context.Context) (*flowDto.GetIsChatModelRes, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res := new(flowDto.GetIsChatModelRes)
|
res = new(flowDto.GetIsChatModelRes)
|
||||||
err := commonHttp.Get(ctx, "model-gateway/model/getIsChatModel", headers, res, nil)
|
err = commonHttp.Get(ctx, "model-gateway/model/getIsChatModel", headers, res, nil)
|
||||||
if err != nil {
|
return
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string, error) {
|
func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string, error) {
|
||||||
@@ -53,7 +48,7 @@ func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string,
|
|||||||
return res.TaskId, nil
|
return res.TaskId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (*flowDto.ComposeMessagesRes, error) {
|
func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (res *flowDto.ComposeMessagesRes, err error) {
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
if r := g.RequestFromCtx(ctx); r != nil {
|
if r := g.RequestFromCtx(ctx); r != nil {
|
||||||
for k, v := range r.Request.Header {
|
for k, v := range r.Request.Header {
|
||||||
@@ -62,13 +57,9 @@ func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (*flo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res := new(flowDto.ComposeMessagesRes)
|
res = new(flowDto.ComposeMessagesRes)
|
||||||
err := commonHttp.Post(ctx, "prompts-core/prompt/composeMessages", headers, res, &req)
|
err = commonHttp.Post(ctx, "prompts-core/prompt/composeMessages", headers, res, &req)
|
||||||
if err != nil {
|
return
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (any, error) {
|
func GatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (any, error) {
|
||||||
@@ -169,77 +160,3 @@ func Upload(ctx context.Context, req *dto.UploadFileBytesReq) (*dto.UploadFileBy
|
|||||||
g.Log().Infof(ctx, "[Upload] success url=%s size=%d", res.FileURL, res.FileSize)
|
g.Log().Infof(ctx, "[Upload] success url=%s size=%d", res.FileURL, res.FileSize)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildMergeHtml(texts []string, images []string) string {
|
|
||||||
html := strings.Builder{}
|
|
||||||
|
|
||||||
html.WriteString(`
|
|
||||||
<!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; }
|
|
||||||
body {
|
|
||||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
|
||||||
background: #fff;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
max-width: 960px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
/* 图片:完全贴边,无额外间距 */
|
|
||||||
.image-block {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.image-block img {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
/* 文案:极致紧凑 */
|
|
||||||
.text-block {
|
|
||||||
margin: 0;
|
|
||||||
padding: 16px; /* 仅保留内边距,不设外边距 */
|
|
||||||
line-height: 1.6;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #444;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 分割线:完全去掉,改用内边距自然分隔 */
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
`)
|
|
||||||
|
|
||||||
// 1. 先渲染图片(无任何上下边距,占满宽度)
|
|
||||||
if len(images) > 0 {
|
|
||||||
html.WriteString(`<div class="image-block">`)
|
|
||||||
for _, img := range images {
|
|
||||||
html.WriteString(fmt.Sprintf(`<img src="%s" alt="" />`, img))
|
|
||||||
}
|
|
||||||
html.WriteString(`</div>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 渲染文案(紧贴图片下方,仅用内边距留白)
|
|
||||||
if len(texts) > 0 {
|
|
||||||
html.WriteString(`<div class="text-block">`)
|
|
||||||
// 段落之间用 <br> 而不是 <br><br>,减少空行
|
|
||||||
html.WriteString(strings.Join(texts, "<br>"))
|
|
||||||
html.WriteString(`</div>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
html.WriteString(`
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`)
|
|
||||||
|
|
||||||
return html.String()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import (
|
|||||||
skillDto "ai-agent/workflow/model/dto/skill"
|
skillDto "ai-agent/workflow/model/dto/skill"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitea.com/red-future/common/beans"
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
@@ -34,25 +38,105 @@ func IsAdmin(ctx context.Context) (res bool, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *skillUserService) Create(ctx context.Context, req *skillDto.CreateSkillUserReq) (res *skillDto.CreateSkillUserRes, err error) {
|
func (s *skillUserService) Create(ctx context.Context, req *skillDto.CreateSkillUserReq) (res *skillDto.CreateSkillUserRes, err error) {
|
||||||
|
ext := strings.TrimPrefix(filepath.Ext(req.FileUrl), ".")
|
||||||
|
if ext != "zip" {
|
||||||
|
return nil, fmt.Errorf("文件格式不支持,请上传zip格式文件")
|
||||||
|
}
|
||||||
admin, err := IsAdmin(ctx)
|
admin, err := IsAdmin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var id int64
|
var id int64
|
||||||
if admin {
|
if admin {
|
||||||
|
var count int
|
||||||
|
count, err = skillDao.SkillTemplateDao.Count(ctx, &skillDto.GetSkillTemplateReq{
|
||||||
|
Name: req.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return nil, fmt.Errorf("技能名称 %s 已存在", req.Name)
|
||||||
|
}
|
||||||
id, err = skillDao.SkillTemplateDao.Insert(ctx, &skillDto.CreateSkillTemplateReq{
|
id, err = skillDao.SkillTemplateDao.Insert(ctx, &skillDto.CreateSkillTemplateReq{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Category: req.Category,
|
|
||||||
FileName: req.FileName,
|
FileName: req.FileName,
|
||||||
FileUrl: req.FileUrl,
|
FileUrl: req.FileUrl,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
var user *beans.User
|
||||||
|
user, err = utils.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var count int
|
||||||
|
count, err = skillDao.SkillUserDao.Count(ctx, &skillDto.GetSkillUserReq{
|
||||||
|
Name: req.Name,
|
||||||
|
Creator: user.UserName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return nil, fmt.Errorf("技能名称 %s 已存在", req.Name)
|
||||||
|
}
|
||||||
id, err = skillDao.SkillUserDao.Insert(ctx, req)
|
id, err = skillDao.SkillUserDao.Insert(ctx, req)
|
||||||
}
|
}
|
||||||
return &skillDto.CreateSkillUserRes{Id: id}, err
|
return &skillDto.CreateSkillUserRes{Id: id}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *skillUserService) Update(ctx context.Context, req *skillDto.UpdateSkillUserReq) (err error) {
|
||||||
|
ext := strings.TrimPrefix(filepath.Ext(req.FileUrl), ".")
|
||||||
|
if ext != "zip" {
|
||||||
|
return fmt.Errorf("文件格式不支持,请上传zip格式文件")
|
||||||
|
}
|
||||||
|
admin, err := IsAdmin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if admin {
|
||||||
|
var count int
|
||||||
|
count, err = skillDao.SkillTemplateDao.Count(ctx, &skillDto.GetSkillTemplateReq{
|
||||||
|
NotInId: req.Id,
|
||||||
|
Name: req.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return fmt.Errorf("技能名称 %s 已存在", req.Name)
|
||||||
|
}
|
||||||
|
_, err = skillDao.SkillTemplateDao.Update(ctx, &skillDto.UpdateSkillTemplateReq{
|
||||||
|
Id: req.Id,
|
||||||
|
Name: req.Name,
|
||||||
|
Description: req.Description,
|
||||||
|
FileName: req.FileName,
|
||||||
|
FileUrl: req.FileUrl,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
var user *beans.User
|
||||||
|
user, err = utils.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var count int
|
||||||
|
count, err = skillDao.SkillUserDao.Count(ctx, &skillDto.GetSkillUserReq{
|
||||||
|
NotInId: req.Id,
|
||||||
|
Name: req.Name,
|
||||||
|
Creator: user.UserName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return fmt.Errorf("技能名称 %s 已存在", req.Name)
|
||||||
|
}
|
||||||
|
_, err = skillDao.SkillUserDao.Update(ctx, req)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *skillUserService) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (err error) {
|
func (s *skillUserService) Delete(ctx context.Context, req *skillDto.DeleteSkillUserReq) (err error) {
|
||||||
admin, err := IsAdmin(ctx)
|
admin, err := IsAdmin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -68,6 +152,49 @@ func (s *skillUserService) Delete(ctx context.Context, req *skillDto.DeleteSkill
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *skillUserService) Get(ctx context.Context, req *skillDto.GetSkillUserReq) (res *skillDto.SkillUserVO, err error) {
|
||||||
|
admin, err := IsAdmin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if admin {
|
||||||
|
var list *entity.SkillTemplate
|
||||||
|
list, err = skillDao.SkillTemplateDao.Get(ctx, &skillDto.GetSkillTemplateReq{
|
||||||
|
Id: req.Id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = &skillDto.SkillUserVO{}
|
||||||
|
res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = gconv.Struct(list, &res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := utils.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Creator = user.UserName
|
||||||
|
list, err := skillDao.SkillUserDao.Get(ctx, &skillDto.GetSkillUserReq{
|
||||||
|
Id: req.Id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = &skillDto.SkillUserVO{}
|
||||||
|
res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = gconv.Struct(list, &res)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *skillUserService) List(ctx context.Context, req *skillDto.ListSkillReq) (res *skillDto.ListSkillUserRes, err error) {
|
func (s *skillUserService) List(ctx context.Context, req *skillDto.ListSkillReq) (res *skillDto.ListSkillUserRes, err error) {
|
||||||
admin, err := IsAdmin(ctx)
|
admin, err := IsAdmin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -128,3 +255,46 @@ func (s *skillUserService) ListUser(ctx context.Context, req *skillDto.ListSkill
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *skillUserService) GetUserOrTemplate(ctx context.Context, req *skillDto.GetSkillReq) (res *skillDto.SkillUserVO, err error) {
|
||||||
|
var list *entity.SkillTemplate
|
||||||
|
list, err = skillDao.SkillTemplateDao.Get(ctx, &skillDto.GetSkillTemplateReq{
|
||||||
|
Id: req.Id,
|
||||||
|
Name: req.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !g.IsEmpty(list) {
|
||||||
|
res = &skillDto.SkillUserVO{}
|
||||||
|
res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = gconv.Struct(list, &res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := utils.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Creator = user.UserName
|
||||||
|
var userList *entity.SkillUser
|
||||||
|
userList, err = skillDao.SkillUserDao.Get(ctx, &skillDto.GetSkillUserReq{
|
||||||
|
Id: req.Id,
|
||||||
|
Creator: user.UserName,
|
||||||
|
Name: req.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = &skillDto.SkillUserVO{}
|
||||||
|
res.ImgAddressPrefix, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = gconv.Struct(userList, &res)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user