Compare commits

...

58 Commits

Author SHA1 Message Date
bx1834938347-prog
c18bd4372f Merge branch 'wwq' 2025-12-12 10:19:50 +08:00
bx1834938347-prog
0a14025092 feat:ai生成图文新增选择分辨率 2025-12-12 09:51:56 +08:00
bx1834938347-prog
92c6089096 feat:更改模型 2025-12-11 14:28:03 +08:00
bx1834938347-prog
d53ace3306 style:ai生成图文 2025-12-09 14:56:17 +08:00
bx1834938347-prog
5f9aad3732 feat:调整prompt 2025-12-09 09:48:26 +08:00
bx1834938347-prog
16c6bae7d1 Merge branch 'dev' into wwq 2025-12-09 09:33:21 +08:00
bx1834938347-prog
8398fc4a6f Update imageContentProcessor.go 2025-12-08 17:10:23 +08:00
bx1834938347-prog
2413a185a2 feat:ai生成图文 2025-12-08 16:54:30 +08:00
bx1834938347-prog
5fe4be61b9 feat:ai生成图文 2025-12-08 14:12:38 +08:00
bx1834938347-prog
cfe6f2b756 style :ai生成图文 2025-12-08 11:18:44 +08:00
bx1834938347-prog
0518b547d8 Update generateImageToText.go 2025-12-08 09:02:36 +08:00
bx1834938347-prog
dea013471a feat:ai生成图文 2025-12-05 19:12:09 +08:00
bx1834938347-prog
a68502d957 feat:ai生成图文 2025-12-05 17:06:10 +08:00
bx1834938347-prog
19fc4c0f77 Update imageContentProcessor.go 2025-12-05 16:23:03 +08:00
bx1834938347-prog
eae2db4942 feat:ai生成图文 2025-12-05 16:19:29 +08:00
bx1834938347-prog
0d45477f93 feat:ai生成图文 2025-12-05 15:46:21 +08:00
bx1834938347-prog
a093ab9e9c feat:ai生成图文 2025-12-05 15:12:11 +08:00
bx1834938347-prog
a60132086d feat:ai生成图文 2025-12-05 14:24:50 +08:00
bx1834938347-prog
b152fbe01b feat:ai生成图片 2025-12-05 14:16:48 +08:00
bx1834938347-prog
796ebd33b9 Update imageContentProcessor.go 2025-12-05 10:59:14 +08:00
bx1834938347-prog
7379c0b84e Update imageContentProcessor.go 2025-12-05 10:52:25 +08:00
bx1834938347-prog
b6c071fcec feat:修改ai生成图文 2025-12-05 10:43:23 +08:00
bx1834938347-prog
665c3e3b6a Update imageContentProcessor.go 2025-12-05 10:27:50 +08:00
bx1834938347-prog
6b63afbdff feat:ai生成图文 2025-12-05 10:21:51 +08:00
bx1834938347-prog
eb33d725eb feat:ai生成图文 2025-12-05 09:02:44 +08:00
bx1834938347-prog
d9233a0606 Update imageContentProcessor.go 2025-12-04 15:44:44 +08:00
bx1834938347-prog
b9259f1300 feat:ai生成图文 2025-12-04 15:25:40 +08:00
bx1834938347-prog
a753595b12 feat:ai批量生成图文 2025-12-04 14:59:19 +08:00
bx1834938347-prog
2eae0aa1a5 feat:新增ai批量生成图文 2025-12-04 11:18:35 +08:00
jiaji.H
2feceb8be7 Merge branch 'feat-hjj-filebrowser#Saas3' 2025-12-01 14:13:08 +08:00
jiaji.H
cba61d3f07 Updata:更新数据 2025-12-01 14:12:59 +08:00
jiaji.H
b5084d7299 Updata:解决冲突 2025-12-01 14:08:30 +08:00
jiaji.H
9f2ff6a440 Updata:更新素材库错误推送 2025-12-01 13:55:58 +08:00
jiaji.H
91a7668afd Updata:更新逻辑 2025-12-01 13:40:48 +08:00
jiaji.H
389aabac31 Updata:更新逻辑 2025-12-01 13:38:13 +08:00
jiaji.H
6d947e21cc Updata:更新逻辑 2025-12-01 13:36:08 +08:00
jiaji.H
4c9bd2d0e8 Updata:更新我的文件列表查询 2025-12-01 13:32:53 +08:00
jiaji.H
28ac17d51a Updata:增加分页 2025-12-01 13:30:53 +08:00
jiaji.H
b1d3fbabf4 Updata:更新pb文件 2025-12-01 13:08:53 +08:00
jiaji.H
76c955838e Updata:更新pb文件 2025-12-01 11:59:43 +08:00
jiaji.H
c13b0d9d71 Updata:更新pb文件 2025-12-01 11:43:25 +08:00
cjy
7cb1553174 Merge branch 'feat-cjy-taskBench2'
# Conflicts:
#	api/bundle/bundle.pb.go
#	api/bundle/bundle_triple.pb.go
2025-12-01 10:24:28 +08:00
cjy
ccc553850c feat: 增加一个接口 2025-12-01 10:12:21 +08:00
cjy
26825e6ebf Merge branch 'feat-cjy-taskBench2' 2025-11-29 13:05:53 +08:00
cjy
e46787512c Merge branch 'feat-cjy-taskBench2' of https://gitea-net.fontree.cn/fiee/fonchain-fiee into feat-cjy-taskBench2 2025-11-29 11:06:15 +08:00
cjy
5ecb8c5a3a feat: 导出增加4个字段 2025-11-29 11:06:12 +08:00
cjy
95c805efec feat: 导出增加4个字段 2025-11-29 11:04:59 +08:00
cjy
315911dc2d Merge branch 'feat-cjy-taskBench2'
# Conflicts:
#	api/bundle/bundle.pb.go
#	api/bundle/bundle_triple.pb.go
2025-11-28 16:06:33 +08:00
cjy
6c729bb8bd feat: 增加删除最近指派人 2025-11-28 15:31:25 +08:00
jiaji.H
488eee0e9b Updata 2025-11-28 15:00:58 +08:00
jiaji.H
8992b0c048 Merge branch 'feat-hjj-CastWork#' 2025-11-28 14:48:26 +08:00
jiaji.H
b86381b0b7 Updata更新列宽 2025-11-28 14:45:22 +08:00
jiaji.H
f3fd2ddcac Updata:调整艺人账号导出列表 2025-11-28 14:37:48 +08:00
cjy
cf1a4e45db Merge branch 'feat-cjy-taskBench2' 2025-11-27 20:19:43 +08:00
cjy
3847142b91 fix:把 待 改成 可 2025-11-27 20:17:37 +08:00
jiaji.H
b20b2c4e3f Updata:调整错误提示 2025-11-27 17:58:54 +08:00
c0a1f135cd Merge branch 'feature-userinfo-daiyb' 2025-11-27 17:50:05 +08:00
47b4750d6e 脚本审批ID 2025-11-27 17:49:46 +08:00
28 changed files with 5767 additions and 2496 deletions

File diff suppressed because it is too large Load Diff

View File

@ -530,10 +530,23 @@ func (this *TaskAssignRequest) Validate() error {
func (this *UpdatePendingCountRequest) Validate() error {
return nil
}
func (this *AddHiddenTaskAssigneeRequest) Validate() error {
return nil
}
func (this *RecentAssignRecordsRequest) Validate() error {
return nil
}
func (this *RecentAssigneeItem) Validate() error {
return nil
}
func (this *RecentAssignRecordsResponse) Validate() error {
for _, item := range this.OperatorList {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("OperatorList", err)
}
}
}
return nil
}
func (this *EmployeeTaskQueryRequest) Validate() error {
@ -639,6 +652,22 @@ func (this *PendingUploadBreakdownResponse) Validate() error {
}
return nil
}
func (this *PendingAssignRequest) Validate() error {
return nil
}
func (this *PendingAssignItem) Validate() error {
return nil
}
func (this *PendingAssignResponse) Validate() error {
for _, item := range this.Items {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Items", err)
}
}
}
return nil
}
func (this *ArtistBundleBalanceRequest) Validate() error {
return nil
}

View File

@ -105,7 +105,10 @@ type BundleClient interface {
GetPendingTaskLayout(ctx context.Context, in *GetPendingTaskLayoutReq, opts ...grpc_go.CallOption) (*GetPendingTaskLayoutResp, common.ErrorWithAttachment)
SetPendingTaskLayout(ctx context.Context, in *SetPendingTaskLayoutReq, opts ...grpc_go.CallOption) (*SetPendingTaskLayoutResp, common.ErrorWithAttachment)
GetPendingUploadBreakdown(ctx context.Context, in *PendingUploadBreakdownRequest, opts ...grpc_go.CallOption) (*PendingUploadBreakdownResponse, common.ErrorWithAttachment)
GetPendingAssign(ctx context.Context, in *PendingAssignRequest, opts ...grpc_go.CallOption) (*PendingAssignResponse, common.ErrorWithAttachment)
RevertTaskCompletionByUUIDItem(ctx context.Context, in *RevertTaskCompletionByUUIDItemRequest, opts ...grpc_go.CallOption) (*ComResponse, common.ErrorWithAttachment)
AddHiddenTaskAssignee(ctx context.Context, in *AddHiddenTaskAssigneeRequest, opts ...grpc_go.CallOption) (*ComResponse, common.ErrorWithAttachment)
// 数据指标
MetricsBusiness(ctx context.Context, in *MetricsBusinessReq, opts ...grpc_go.CallOption) (*MetricsBusinessResp, common.ErrorWithAttachment)
MetricsOperatingCreate(ctx context.Context, in *MetricsOperatingCreateReq, opts ...grpc_go.CallOption) (*MetricsOperatingCreateResp, common.ErrorWithAttachment)
MetricsOperatingStatus(ctx context.Context, in *MetricsOperatingStatusReq, opts ...grpc_go.CallOption) (*MetricsOperatingStatusResp, common.ErrorWithAttachment)
@ -189,7 +192,9 @@ type BundleClientImpl struct {
GetPendingTaskLayout func(ctx context.Context, in *GetPendingTaskLayoutReq) (*GetPendingTaskLayoutResp, error)
SetPendingTaskLayout func(ctx context.Context, in *SetPendingTaskLayoutReq) (*SetPendingTaskLayoutResp, error)
GetPendingUploadBreakdown func(ctx context.Context, in *PendingUploadBreakdownRequest) (*PendingUploadBreakdownResponse, error)
GetPendingAssign func(ctx context.Context, in *PendingAssignRequest) (*PendingAssignResponse, error)
RevertTaskCompletionByUUIDItem func(ctx context.Context, in *RevertTaskCompletionByUUIDItemRequest) (*ComResponse, error)
AddHiddenTaskAssignee func(ctx context.Context, in *AddHiddenTaskAssigneeRequest) (*ComResponse, error)
MetricsBusiness func(ctx context.Context, in *MetricsBusinessReq) (*MetricsBusinessResp, error)
MetricsOperatingCreate func(ctx context.Context, in *MetricsOperatingCreateReq) (*MetricsOperatingCreateResp, error)
MetricsOperatingStatus func(ctx context.Context, in *MetricsOperatingStatusReq) (*MetricsOperatingStatusResp, error)
@ -630,12 +635,24 @@ func (c *bundleClient) GetPendingUploadBreakdown(ctx context.Context, in *Pendin
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetPendingUploadBreakdown", in, out)
}
func (c *bundleClient) GetPendingAssign(ctx context.Context, in *PendingAssignRequest, opts ...grpc_go.CallOption) (*PendingAssignResponse, common.ErrorWithAttachment) {
out := new(PendingAssignResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetPendingAssign", in, out)
}
func (c *bundleClient) RevertTaskCompletionByUUIDItem(ctx context.Context, in *RevertTaskCompletionByUUIDItemRequest, opts ...grpc_go.CallOption) (*ComResponse, common.ErrorWithAttachment) {
out := new(ComResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/RevertTaskCompletionByUUIDItem", in, out)
}
func (c *bundleClient) AddHiddenTaskAssignee(ctx context.Context, in *AddHiddenTaskAssigneeRequest, opts ...grpc_go.CallOption) (*ComResponse, common.ErrorWithAttachment) {
out := new(ComResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/AddHiddenTaskAssignee", in, out)
}
func (c *bundleClient) MetricsBusiness(ctx context.Context, in *MetricsBusinessReq, opts ...grpc_go.CallOption) (*MetricsBusinessResp, common.ErrorWithAttachment) {
out := new(MetricsBusinessResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -753,7 +770,10 @@ type BundleServer interface {
GetPendingTaskLayout(context.Context, *GetPendingTaskLayoutReq) (*GetPendingTaskLayoutResp, error)
SetPendingTaskLayout(context.Context, *SetPendingTaskLayoutReq) (*SetPendingTaskLayoutResp, error)
GetPendingUploadBreakdown(context.Context, *PendingUploadBreakdownRequest) (*PendingUploadBreakdownResponse, error)
GetPendingAssign(context.Context, *PendingAssignRequest) (*PendingAssignResponse, error)
RevertTaskCompletionByUUIDItem(context.Context, *RevertTaskCompletionByUUIDItemRequest) (*ComResponse, error)
AddHiddenTaskAssignee(context.Context, *AddHiddenTaskAssigneeRequest) (*ComResponse, error)
// 数据指标
MetricsBusiness(context.Context, *MetricsBusinessReq) (*MetricsBusinessResp, error)
MetricsOperatingCreate(context.Context, *MetricsOperatingCreateReq) (*MetricsOperatingCreateResp, error)
MetricsOperatingStatus(context.Context, *MetricsOperatingStatusReq) (*MetricsOperatingStatusResp, error)
@ -978,9 +998,15 @@ func (UnimplementedBundleServer) SetPendingTaskLayout(context.Context, *SetPendi
func (UnimplementedBundleServer) GetPendingUploadBreakdown(context.Context, *PendingUploadBreakdownRequest) (*PendingUploadBreakdownResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPendingUploadBreakdown not implemented")
}
func (UnimplementedBundleServer) GetPendingAssign(context.Context, *PendingAssignRequest) (*PendingAssignResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPendingAssign not implemented")
}
func (UnimplementedBundleServer) RevertTaskCompletionByUUIDItem(context.Context, *RevertTaskCompletionByUUIDItemRequest) (*ComResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RevertTaskCompletionByUUIDItem not implemented")
}
func (UnimplementedBundleServer) AddHiddenTaskAssignee(context.Context, *AddHiddenTaskAssigneeRequest) (*ComResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddHiddenTaskAssignee not implemented")
}
func (UnimplementedBundleServer) MetricsBusiness(context.Context, *MetricsBusinessReq) (*MetricsBusinessResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method MetricsBusiness not implemented")
}
@ -3057,6 +3083,35 @@ func _Bundle_GetPendingUploadBreakdown_Handler(srv interface{}, ctx context.Cont
return interceptor(ctx, in, info, handler)
}
func _Bundle_GetPendingAssign_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(PendingAssignRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("GetPendingAssign", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Bundle_RevertTaskCompletionByUUIDItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(RevertTaskCompletionByUUIDItemRequest)
if err := dec(in); err != nil {
@ -3086,6 +3141,35 @@ func _Bundle_RevertTaskCompletionByUUIDItem_Handler(srv interface{}, ctx context
return interceptor(ctx, in, info, handler)
}
func _Bundle_AddHiddenTaskAssignee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(AddHiddenTaskAssigneeRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("AddHiddenTaskAssignee", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Bundle_MetricsBusiness_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(MetricsBusinessReq)
if err := dec(in); err != nil {
@ -3547,10 +3631,18 @@ var Bundle_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "GetPendingUploadBreakdown",
Handler: _Bundle_GetPendingUploadBreakdown_Handler,
},
{
MethodName: "GetPendingAssign",
Handler: _Bundle_GetPendingAssign_Handler,
},
{
MethodName: "RevertTaskCompletionByUUIDItem",
Handler: _Bundle_RevertTaskCompletionByUUIDItem_Handler,
},
{
MethodName: "AddHiddenTaskAssignee",
Handler: _Bundle_AddHiddenTaskAssignee_Handler,
},
{
MethodName: "MetricsBusiness",
Handler: _Bundle_MetricsBusiness_Handler,

File diff suppressed because it is too large Load Diff

View File

@ -1107,6 +1107,12 @@ func (m *UpdateWorkImageReq) validate(all bool) error {
// no validation rules for Source
// no validation rules for LineNo
// no validation rules for Remark
// no validation rules for Success
if len(errors) > 0 {
return UpdateWorkImageReqMultiError(errors)
}
@ -4106,6 +4112,282 @@ var _ interface {
ErrorName() string
} = ArtistInfoRespValidationError{}
// Validate checks the field values on ImportWorkBatchReq with the rules
// defined in the proto definition for this message. If any rules are
// violated, the first error encountered is returned, or nil if there are no violations.
func (m *ImportWorkBatchReq) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on ImportWorkBatchReq with the rules
// defined in the proto definition for this message. If any rules are
// violated, the result is a list of violation errors wrapped in
// ImportWorkBatchReqMultiError, or nil if none found.
func (m *ImportWorkBatchReq) ValidateAll() error {
return m.validate(true)
}
func (m *ImportWorkBatchReq) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
for idx, item := range m.GetImageWorks() {
_, _ = idx, item
if all {
switch v := interface{}(item).(type) {
case interface{ ValidateAll() error }:
if err := v.ValidateAll(); err != nil {
errors = append(errors, ImportWorkBatchReqValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
case interface{ Validate() error }:
if err := v.Validate(); err != nil {
errors = append(errors, ImportWorkBatchReqValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
}
} else if v, ok := interface{}(item).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
return ImportWorkBatchReqValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
}
}
}
}
if len(errors) > 0 {
return ImportWorkBatchReqMultiError(errors)
}
return nil
}
// ImportWorkBatchReqMultiError is an error wrapping multiple validation errors
// returned by ImportWorkBatchReq.ValidateAll() if the designated constraints
// aren't met.
type ImportWorkBatchReqMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m ImportWorkBatchReqMultiError) Error() string {
msgs := make([]string, 0, len(m))
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m ImportWorkBatchReqMultiError) AllErrors() []error { return m }
// ImportWorkBatchReqValidationError is the validation error returned by
// ImportWorkBatchReq.Validate if the designated constraints aren't met.
type ImportWorkBatchReqValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e ImportWorkBatchReqValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e ImportWorkBatchReqValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e ImportWorkBatchReqValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e ImportWorkBatchReqValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e ImportWorkBatchReqValidationError) ErrorName() string {
return "ImportWorkBatchReqValidationError"
}
// Error satisfies the builtin error interface
func (e ImportWorkBatchReqValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sImportWorkBatchReq.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = ImportWorkBatchReqValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = ImportWorkBatchReqValidationError{}
// Validate checks the field values on ImportWorkBatchResp with the rules
// defined in the proto definition for this message. If any rules are
// violated, the first error encountered is returned, or nil if there are no violations.
func (m *ImportWorkBatchResp) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on ImportWorkBatchResp with the rules
// defined in the proto definition for this message. If any rules are
// violated, the result is a list of violation errors wrapped in
// ImportWorkBatchRespMultiError, or nil if none found.
func (m *ImportWorkBatchResp) ValidateAll() error {
return m.validate(true)
}
func (m *ImportWorkBatchResp) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
for idx, item := range m.GetImageWorks() {
_, _ = idx, item
if all {
switch v := interface{}(item).(type) {
case interface{ ValidateAll() error }:
if err := v.ValidateAll(); err != nil {
errors = append(errors, ImportWorkBatchRespValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
case interface{ Validate() error }:
if err := v.Validate(); err != nil {
errors = append(errors, ImportWorkBatchRespValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
}
} else if v, ok := interface{}(item).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
return ImportWorkBatchRespValidationError{
field: fmt.Sprintf("ImageWorks[%v]", idx),
reason: "embedded message failed validation",
cause: err,
}
}
}
}
// no validation rules for SuccessCount
// no validation rules for FailCount
if len(errors) > 0 {
return ImportWorkBatchRespMultiError(errors)
}
return nil
}
// ImportWorkBatchRespMultiError is an error wrapping multiple validation
// errors returned by ImportWorkBatchResp.ValidateAll() if the designated
// constraints aren't met.
type ImportWorkBatchRespMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m ImportWorkBatchRespMultiError) Error() string {
msgs := make([]string, 0, len(m))
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m ImportWorkBatchRespMultiError) AllErrors() []error { return m }
// ImportWorkBatchRespValidationError is the validation error returned by
// ImportWorkBatchResp.Validate if the designated constraints aren't met.
type ImportWorkBatchRespValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e ImportWorkBatchRespValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e ImportWorkBatchRespValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e ImportWorkBatchRespValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e ImportWorkBatchRespValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e ImportWorkBatchRespValidationError) ErrorName() string {
return "ImportWorkBatchRespValidationError"
}
// Error satisfies the builtin error interface
func (e ImportWorkBatchRespValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sImportWorkBatchResp.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = ImportWorkBatchRespValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = ImportWorkBatchRespValidationError{}
// Validate checks the field values on OAuthAccountReq with the rules defined
// in the proto definition for this message. If any rules are violated, the
// first error encountered is returned, or nil if there are no violations.
@ -5536,6 +5818,8 @@ func (m *GetVideoScriptResp) validate(all bool) error {
// no validation rules for Remark
// no validation rules for ApprovalID
if len(errors) > 0 {
return GetVideoScriptRespMultiError(errors)
}

View File

@ -45,6 +45,7 @@ type CastClient interface {
DelWork(ctx context.Context, in *DelWorkReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
WorkInfo(ctx context.Context, in *WorkInfoReq, opts ...grpc_go.CallOption) (*WorkInfoResp, common.ErrorWithAttachment)
ArtistInfo(ctx context.Context, in *ArtistInfoReq, opts ...grpc_go.CallOption) (*ArtistInfoResp, common.ErrorWithAttachment)
ImportWorkBatch(ctx context.Context, in *ImportWorkBatchReq, opts ...grpc_go.CallOption) (*ImportWorkBatchResp, common.ErrorWithAttachment)
OAuthAccount(ctx context.Context, in *OAuthAccountReq, opts ...grpc_go.CallOption) (*OAuthAccountResp, common.ErrorWithAttachment)
OAuthCodeToToken(ctx context.Context, in *OAuthCodeToTokenReq, opts ...grpc_go.CallOption) (*OAuthCodeToTokenResp, common.ErrorWithAttachment)
RefreshToken(ctx context.Context, in *RefreshTokenReq, opts ...grpc_go.CallOption) (*RefreshTokenResp, common.ErrorWithAttachment)
@ -88,6 +89,7 @@ type CastClientImpl struct {
DelWork func(ctx context.Context, in *DelWorkReq) (*emptypb.Empty, error)
WorkInfo func(ctx context.Context, in *WorkInfoReq) (*WorkInfoResp, error)
ArtistInfo func(ctx context.Context, in *ArtistInfoReq) (*ArtistInfoResp, error)
ImportWorkBatch func(ctx context.Context, in *ImportWorkBatchReq) (*ImportWorkBatchResp, error)
OAuthAccount func(ctx context.Context, in *OAuthAccountReq) (*OAuthAccountResp, error)
OAuthCodeToToken func(ctx context.Context, in *OAuthCodeToTokenReq) (*OAuthCodeToTokenResp, error)
RefreshToken func(ctx context.Context, in *RefreshTokenReq) (*RefreshTokenResp, error)
@ -216,6 +218,12 @@ func (c *castClient) ArtistInfo(ctx context.Context, in *ArtistInfoReq, opts ...
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ArtistInfo", in, out)
}
func (c *castClient) ImportWorkBatch(ctx context.Context, in *ImportWorkBatchReq, opts ...grpc_go.CallOption) (*ImportWorkBatchResp, common.ErrorWithAttachment) {
out := new(ImportWorkBatchResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ImportWorkBatch", in, out)
}
func (c *castClient) OAuthAccount(ctx context.Context, in *OAuthAccountReq, opts ...grpc_go.CallOption) (*OAuthAccountResp, common.ErrorWithAttachment) {
out := new(OAuthAccountResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -344,6 +352,7 @@ type CastServer interface {
DelWork(context.Context, *DelWorkReq) (*emptypb.Empty, error)
WorkInfo(context.Context, *WorkInfoReq) (*WorkInfoResp, error)
ArtistInfo(context.Context, *ArtistInfoReq) (*ArtistInfoResp, error)
ImportWorkBatch(context.Context, *ImportWorkBatchReq) (*ImportWorkBatchResp, error)
OAuthAccount(context.Context, *OAuthAccountReq) (*OAuthAccountResp, error)
OAuthCodeToToken(context.Context, *OAuthCodeToTokenReq) (*OAuthCodeToTokenResp, error)
RefreshToken(context.Context, *RefreshTokenReq) (*RefreshTokenResp, error)
@ -420,6 +429,9 @@ func (UnimplementedCastServer) WorkInfo(context.Context, *WorkInfoReq) (*WorkInf
func (UnimplementedCastServer) ArtistInfo(context.Context, *ArtistInfoReq) (*ArtistInfoResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ArtistInfo not implemented")
}
func (UnimplementedCastServer) ImportWorkBatch(context.Context, *ImportWorkBatchReq) (*ImportWorkBatchResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportWorkBatch not implemented")
}
func (UnimplementedCastServer) OAuthAccount(context.Context, *OAuthAccountReq) (*OAuthAccountResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method OAuthAccount not implemented")
}
@ -966,6 +978,35 @@ func _Cast_ArtistInfo_Handler(srv interface{}, ctx context.Context, dec func(int
return interceptor(ctx, in, info, handler)
}
func _Cast_ImportWorkBatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportWorkBatchReq)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("ImportWorkBatch", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Cast_OAuthAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(OAuthAccountReq)
if err := dec(in); err != nil {
@ -1559,6 +1600,10 @@ var Cast_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "ArtistInfo",
Handler: _Cast_ArtistInfo_Handler,
},
{
MethodName: "ImportWorkBatch",
Handler: _Cast_ImportWorkBatch_Handler,
},
{
MethodName: "OAuthAccount",
Handler: _Cast_OAuthAccount_Handler,

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc v3.20.3
// protoc-gen-go v1.31.0
// protoc v5.26.0
// source: files.proto
package files
@ -25,9 +25,12 @@ type FileListReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` // 目标文件夹路径
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"` // 用户空间的路径
Sorting *Sorting `protobuf:"bytes,3,opt,name=sorting,proto3" json:"sorting,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"` // 目标文件夹路径
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"` // 用户空间的路径
Sorting *Sorting `protobuf:"bytes,3,opt,name=sorting,proto3" json:"sorting"`
Page int32 `protobuf:"varint,4,opt,name=page,proto3" json:"page"`
PageSize int32 `protobuf:"varint,5,opt,name=pageSize,proto3" json:"pageSize"`
Total int32 `protobuf:"varint,6,opt,name=total,proto3" json:"total"`
}
func (x *FileListReq) Reset() {
@ -83,21 +86,42 @@ func (x *FileListReq) GetSorting() *Sorting {
return nil
}
func (x *FileListReq) GetPage() int32 {
if x != nil {
return x.Page
}
return 0
}
func (x *FileListReq) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *FileListReq) GetTotal() int32 {
if x != nil {
return x.Total
}
return 0
}
type Items struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"`
Modified string `protobuf:"bytes,5,opt,name=modified,proto3" json:"modified,omitempty"`
ModTime int64 `protobuf:"varint,6,opt,name=modTime,proto3" json:"modTime,omitempty"`
Mode string `protobuf:"bytes,7,opt,name=mode,proto3" json:"mode,omitempty"`
IsDir bool `protobuf:"varint,8,opt,name=isDir,proto3" json:"isDir,omitempty"`
IsSymlink bool `protobuf:"varint,9,opt,name=isSymlink,proto3" json:"isSymlink,omitempty"`
Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size"`
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension"`
Modified string `protobuf:"bytes,5,opt,name=modified,proto3" json:"modified"`
ModTime int64 `protobuf:"varint,6,opt,name=modTime,proto3" json:"modTime"`
Mode string `protobuf:"bytes,7,opt,name=mode,proto3" json:"mode"`
IsDir bool `protobuf:"varint,8,opt,name=isDir,proto3" json:"isDir"`
IsSymlink bool `protobuf:"varint,9,opt,name=isSymlink,proto3" json:"isSymlink"`
Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type"`
}
func (x *Items) Reset() {
@ -207,8 +231,8 @@ type Sorting struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
By string `protobuf:"bytes,1,opt,name=by,proto3" json:"by,omitempty"`
Asc bool `protobuf:"varint,2,opt,name=asc,proto3" json:"asc,omitempty"`
By string `protobuf:"bytes,1,opt,name=by,proto3" json:"by"`
Asc bool `protobuf:"varint,2,opt,name=asc,proto3" json:"asc"`
}
func (x *Sorting) Reset() {
@ -262,20 +286,23 @@ type FileListResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Items []*Items `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
NumDirs int32 `protobuf:"varint,2,opt,name=numDirs,proto3" json:"numDirs,omitempty"`
NumFiles int32 `protobuf:"varint,3,opt,name=numFiles,proto3" json:"numFiles,omitempty"`
Sorting *Sorting `protobuf:"bytes,4,opt,name=sorting,proto3" json:"sorting,omitempty"`
Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"`
Extension string `protobuf:"bytes,8,opt,name=extension,proto3" json:"extension,omitempty"`
Modified string `protobuf:"bytes,9,opt,name=modified,proto3" json:"modified,omitempty"`
ModTime int64 `protobuf:"varint,10,opt,name=modTime,proto3" json:"modTime,omitempty"`
Mode string `protobuf:"bytes,11,opt,name=mode,proto3" json:"mode,omitempty"`
IsDir bool `protobuf:"varint,12,opt,name=isDir,proto3" json:"isDir,omitempty"`
IsSymlink bool `protobuf:"varint,13,opt,name=isSymlink,proto3" json:"isSymlink,omitempty"`
Type string `protobuf:"bytes,14,opt,name=type,proto3" json:"type,omitempty"`
Items []*Items `protobuf:"bytes,1,rep,name=items,proto3" json:"items"`
NumDirs int32 `protobuf:"varint,2,opt,name=numDirs,proto3" json:"numDirs"`
NumFiles int32 `protobuf:"varint,3,opt,name=numFiles,proto3" json:"numFiles"`
Sorting *Sorting `protobuf:"bytes,4,opt,name=sorting,proto3" json:"sorting"`
Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path"`
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name"`
Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size"`
Extension string `protobuf:"bytes,8,opt,name=extension,proto3" json:"extension"`
Modified string `protobuf:"bytes,9,opt,name=modified,proto3" json:"modified"`
ModTime int64 `protobuf:"varint,10,opt,name=modTime,proto3" json:"modTime"`
Mode string `protobuf:"bytes,11,opt,name=mode,proto3" json:"mode"`
IsDir bool `protobuf:"varint,12,opt,name=isDir,proto3" json:"isDir"`
IsSymlink bool `protobuf:"varint,13,opt,name=isSymlink,proto3" json:"isSymlink"`
Type string `protobuf:"bytes,14,opt,name=type,proto3" json:"type"`
Page int32 `protobuf:"varint,15,opt,name=page,proto3" json:"page"`
PageSize int32 `protobuf:"varint,16,opt,name=pageSize,proto3" json:"pageSize"`
Total int32 `protobuf:"varint,17,opt,name=total,proto3" json:"total"`
}
func (x *FileListResp) Reset() {
@ -408,13 +435,34 @@ func (x *FileListResp) GetType() string {
return ""
}
func (x *FileListResp) GetPage() int32 {
if x != nil {
return x.Page
}
return 0
}
func (x *FileListResp) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *FileListResp) GetTotal() int32 {
if x != nil {
return x.Total
}
return 0
}
type CreateReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
}
func (x *CreateReq) Reset() {
@ -506,8 +554,8 @@ type DeleteReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
}
func (x *DeleteReq) Reset() {
@ -599,9 +647,9 @@ type UploadReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content"`
}
func (x *UploadReq) Reset() {
@ -700,9 +748,9 @@ type SearchReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Query string `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Query string `protobuf:"bytes,3,opt,name=query,proto3" json:"query"`
}
func (x *SearchReq) Reset() {
@ -763,7 +811,7 @@ type SearchResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Items []*SearchResp_Nested `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
Items []*SearchResp_Nested `protobuf:"bytes,1,rep,name=items,proto3" json:"items"`
}
func (x *SearchResp) Reset() {
@ -810,9 +858,9 @@ type TusCreateReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Override bool `protobuf:"varint,3,opt,name=override,proto3" json:"override,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Override bool `protobuf:"varint,3,opt,name=override,proto3" json:"override"`
}
func (x *TusCreateReq) Reset() {
@ -873,8 +921,8 @@ type TusCreateResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UploadLength int64 `protobuf:"varint,1,opt,name=uploadLength,proto3" json:"uploadLength,omitempty"`
UploadOffset int64 `protobuf:"varint,2,opt,name=uploadOffset,proto3" json:"uploadOffset,omitempty"`
UploadLength int64 `protobuf:"varint,1,opt,name=uploadLength,proto3" json:"uploadLength"`
UploadOffset int64 `protobuf:"varint,2,opt,name=uploadOffset,proto3" json:"uploadOffset"`
}
func (x *TusCreateResp) Reset() {
@ -928,10 +976,10 @@ type TusUploadReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
UploadOffset int64 `protobuf:"varint,3,opt,name=uploadOffset,proto3" json:"uploadOffset,omitempty"`
Content []byte `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
UploadOffset int64 `protobuf:"varint,3,opt,name=uploadOffset,proto3" json:"uploadOffset"`
Content []byte `protobuf:"bytes,4,opt,name=content,proto3" json:"content"`
}
func (x *TusUploadReq) Reset() {
@ -999,7 +1047,7 @@ type TusUploadResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UploadOffset int64 `protobuf:"varint,1,opt,name=uploadOffset,proto3" json:"uploadOffset,omitempty"`
UploadOffset int64 `protobuf:"varint,1,opt,name=uploadOffset,proto3" json:"uploadOffset"`
}
func (x *TusUploadResp) Reset() {
@ -1046,10 +1094,10 @@ type ResumableTransferReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
Length int64 `protobuf:"varint,4,opt,name=length,proto3" json:"length,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset"`
Length int64 `protobuf:"varint,4,opt,name=length,proto3" json:"length"`
}
func (x *ResumableTransferReq) Reset() {
@ -1117,7 +1165,7 @@ type ResumableTransferResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content"`
}
func (x *ResumableTransferResp) Reset() {
@ -1164,8 +1212,8 @@ type FileInfoReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
}
func (x *FileInfoReq) Reset() {
@ -1219,16 +1267,16 @@ type FileInfoResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"`
Modified string `protobuf:"bytes,5,opt,name=modified,proto3" json:"modified,omitempty"`
Mode string `protobuf:"bytes,6,opt,name=mode,proto3" json:"mode,omitempty"`
ModTime int64 `protobuf:"varint,7,opt,name=modTime,proto3" json:"modTime,omitempty"`
IsDir bool `protobuf:"varint,8,opt,name=isDir,proto3" json:"isDir,omitempty"`
IsSymlink bool `protobuf:"varint,9,opt,name=isSymlink,proto3" json:"isSymlink,omitempty"`
Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size"`
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension"`
Modified string `protobuf:"bytes,5,opt,name=modified,proto3" json:"modified"`
Mode string `protobuf:"bytes,6,opt,name=mode,proto3" json:"mode"`
ModTime int64 `protobuf:"varint,7,opt,name=modTime,proto3" json:"modTime"`
IsDir bool `protobuf:"varint,8,opt,name=isDir,proto3" json:"isDir"`
IsSymlink bool `protobuf:"varint,9,opt,name=isSymlink,proto3" json:"isSymlink"`
Type string `protobuf:"bytes,10,opt,name=type,proto3" json:"type"`
}
func (x *FileInfoResp) Reset() {
@ -1338,9 +1386,9 @@ type PreviewReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` // 预览大小 0256x256, 1:1080x1080
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size"` // 预览大小 0256x256, 1:1080x1080
}
func (x *PreviewReq) Reset() {
@ -1401,9 +1449,9 @@ type PreviewResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName,omitempty"`
ModTime int64 `protobuf:"varint,3,opt,name=modTime,proto3" json:"modTime,omitempty"`
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content"`
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName"`
ModTime int64 `protobuf:"varint,3,opt,name=modTime,proto3" json:"modTime"`
}
func (x *PreviewResp) Reset() {
@ -1464,12 +1512,12 @@ type ActionReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Action string `protobuf:"bytes,3,opt,name=action,proto3" json:"action,omitempty"`
Destination string `protobuf:"bytes,4,opt,name=destination,proto3" json:"destination,omitempty"`
Override bool `protobuf:"varint,5,opt,name=override,proto3" json:"override,omitempty"`
Rename bool `protobuf:"varint,6,opt,name=rename,proto3" json:"rename,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Action string `protobuf:"bytes,3,opt,name=action,proto3" json:"action"`
Destination string `protobuf:"bytes,4,opt,name=destination,proto3" json:"destination"`
Override bool `protobuf:"varint,5,opt,name=override,proto3" json:"override"`
Rename bool `protobuf:"varint,6,opt,name=rename,proto3" json:"rename"`
}
func (x *ActionReq) Reset() {
@ -1589,10 +1637,10 @@ type DirDownloadReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Files []string `protobuf:"bytes,3,rep,name=files,proto3" json:"files,omitempty"`
Algo string `protobuf:"bytes,4,opt,name=algo,proto3" json:"algo,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
Files []string `protobuf:"bytes,3,rep,name=files,proto3" json:"files"`
Algo string `protobuf:"bytes,4,opt,name=algo,proto3" json:"algo"`
}
func (x *DirDownloadReq) Reset() {
@ -1660,7 +1708,7 @@ type DirDownloadResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content"`
}
func (x *DirDownloadResp) Reset() {
@ -1707,8 +1755,8 @@ type UsageReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath,omitempty"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path"`
UserSpacePath string `protobuf:"bytes,2,opt,name=userSpacePath,proto3" json:"userSpacePath"`
}
func (x *UsageReq) Reset() {
@ -1762,8 +1810,8 @@ type UsageResp struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
Used int64 `protobuf:"varint,2,opt,name=used,proto3" json:"used,omitempty"`
Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"`
Used int64 `protobuf:"varint,2,opt,name=used,proto3" json:"used"`
}
func (x *UsageResp) Reset() {
@ -1817,11 +1865,11 @@ type SearchResp_Nested struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsDir bool `protobuf:"varint,1,opt,name=isDir,proto3" json:"isDir,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"`
ModTime int64 `protobuf:"varint,5,opt,name=modTime,proto3" json:"modTime,omitempty"`
IsDir bool `protobuf:"varint,1,opt,name=isDir,proto3" json:"isDir"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path"`
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name"`
Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size"`
ModTime int64 `protobuf:"varint,5,opt,name=modTime,proto3" json:"modTime"`
}
func (x *SearchResp_Nested) Reset() {
@ -1895,234 +1943,243 @@ var File_files_proto protoreflect.FileDescriptor
var file_files_proto_rawDesc = []byte{
0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x22, 0x71, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74,
0x69, 0x6c, 0x65, 0x73, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73,
0x74, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72,
0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28,
0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x0e, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x52,
0x07, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08,
0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xf3,
0x01, 0x0a, 0x05, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18,
0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52,
0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65,
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x69, 0x73, 0x44, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44,
0x69, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b,
0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x74, 0x79, 0x70, 0x65, 0x22, 0x2b, 0x0a, 0x07, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12,
0x0e, 0x0a, 0x02, 0x62, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x62, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x73,
0x63, 0x22, 0xc4, 0x03, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
0x73, 0x70, 0x12, 0x22, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52,
0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x44, 0x69, 0x72,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x44, 0x69, 0x72, 0x73,
0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x05, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x07,
0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73,
0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12,
0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69,
0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07,
0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d,
0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73,
0x44, 0x69, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72,
0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x0d, 0x20,
0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05,
0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69,
0x7a, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69,
0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x11, 0x20, 0x01, 0x28,
0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x45, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65,
0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22,
0x0c, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x45, 0x0a,
0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65,
0x50, 0x61, 0x74, 0x68, 0x22, 0x0c, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65,
0x73, 0x70, 0x22, 0x5f, 0x0a, 0x09, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x12,
0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70,
0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65,
0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72,
0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e,
0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x22, 0x0c, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73,
0x70, 0x22, 0x5b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x12, 0x12,
0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,
0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50,
0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53,
0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72,
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xb2,
0x01, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2e, 0x0a,
0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x2e,
0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x74, 0x0a,
0x06, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20,
0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64,
0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x54,
0x69, 0x6d, 0x65, 0x22, 0x64, 0x0a, 0x0c, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53,
0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a,
0x07, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07,
0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xf3, 0x01, 0x0a, 0x05, 0x49, 0x74, 0x65, 0x6d,
0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d,
0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d,
0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69,
0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x18, 0x08,
0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69,
0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,
0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2b, 0x0a,
0x07, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x62, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x62, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, 0x18,
0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x73, 0x63, 0x22, 0xfe, 0x02, 0x0a, 0x0c, 0x46,
0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x05, 0x69,
0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12,
0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x44, 0x69, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x07, 0x6e, 0x75, 0x6d, 0x44, 0x69, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x75, 0x6d,
0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6e, 0x75, 0x6d,
0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53,
0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12,
0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70,
0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65,
0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64,
0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64,
0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d,
0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x18, 0x0c, 0x20, 0x01,
0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53,
0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73,
0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x45, 0x0a, 0x09, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x22, 0x0c, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
0x22, 0x45, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70,
0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22, 0x0c, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x5f, 0x0a, 0x09, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52,
0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70,
0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75,
0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63,
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x0c, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64,
0x52, 0x65, 0x73, 0x70, 0x22, 0x5b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61,
0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73,
0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71,
0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72,
0x79, 0x22, 0xb2, 0x01, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70,
0x12, 0x2e, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x18, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
0x73, 0x70, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
0x1a, 0x74, 0x0a, 0x06, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73,
0x44, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72,
0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d,
0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x64, 0x0a, 0x0c, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73,
0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68,
0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x08, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0x57, 0x0a, 0x0d,
0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a,
0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f,
0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x86, 0x01, 0x0a, 0x0c, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c,
0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73,
0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68,
0x12, 0x22, 0x0a, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66,
0x66, 0x73, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x33,
0x0a, 0x0d, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12,
0x22, 0x0a, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x22, 0x80, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c,
0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04,
0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,
0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74,
0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61,
0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16,
0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x31, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61,
0x62, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12,
0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x47, 0x0a, 0x0b, 0x46, 0x69, 0x6c,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x22, 0xfa, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x65, 0x73, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12,
0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a,
0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64,
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72,
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x1c, 0x0a,
0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08,
0x52, 0x09, 0x69, 0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74,
0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22,
0x5a, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70,
0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x5d, 0x0a, 0x0b, 0x50,
0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f,
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e,
0x74, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x09, 0x41,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08,
0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65,
0x22, 0x0c, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x74,
0x0a, 0x0e, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a,
0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0x57, 0x0a, 0x0d, 0x54, 0x75, 0x73,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x70,
0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x22,
0x0a, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73,
0x65, 0x74, 0x22, 0x86, 0x01, 0x0a, 0x0c, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64,
0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53,
0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x22, 0x0a,
0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x33, 0x0a, 0x0d, 0x54,
0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c,
0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x22, 0x80, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74,
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a,
0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50,
0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c,
0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6c, 0x65, 0x6e,
0x67, 0x74, 0x68, 0x22, 0x31, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63,
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x47, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e,
0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65,
0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22,
0xfa, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70,
0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63,
0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65,
0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x67, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x61, 0x6c, 0x67, 0x6f, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f,
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f,
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f,
0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x64,
0x54, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x18, 0x08, 0x20,
0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73,
0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69,
0x73, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5a, 0x0a, 0x0a,
0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65,
0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x5d, 0x0a, 0x0b, 0x50, 0x72, 0x65, 0x76,
0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x22, 0x44, 0x0a, 0x08, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a,
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x6d, 0x6f, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x09, 0x41, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65,
0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12,
0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x76, 0x65,
0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6f, 0x76, 0x65,
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x0c, 0x0a,
0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x74, 0x0a, 0x0e, 0x44,
0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x24, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70,
0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22, 0x35, 0x0a, 0x09, 0x55, 0x73, 0x61, 0x67, 0x65,
0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20,
0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73,
0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x32, 0xcb,
0x05, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12,
0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74,
0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a,
0x04, 0x61, 0x6c, 0x67, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x67,
0x6f, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64,
0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x44,
0x0a, 0x08, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65,
0x50, 0x61, 0x74, 0x68, 0x22, 0x35, 0x0a, 0x09, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73,
0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x32, 0xcb, 0x05, 0x0a, 0x04,
0x46, 0x69, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x2e, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71,
0x1a, 0x13, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73,
0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f,
0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x46,
0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a,
0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f,
0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12,
0x2f, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00,
0x12, 0x2f, 0x0a, 0x06, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22,
0x00, 0x12, 0x38, 0x0a, 0x09, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13,
0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x09, 0x54,
0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x13, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x2e, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52,
0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62,
0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06,
0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73,
0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a,
0x06, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x38,
0x0a, 0x09, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
0x1a, 0x14, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x09, 0x54, 0x75, 0x73, 0x55,
0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x13, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x75,
0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x2e, 0x54, 0x75, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70,
0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x76, 0x69,
0x65, 0x77, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69,
0x65, 0x77, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x50, 0x72,
0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x41,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x41, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b,
0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x2e, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52,
0x65, 0x71, 0x1a, 0x16, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x44, 0x69, 0x72, 0x44, 0x6f,
0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2c,
0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0f, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e,
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08,
0x2e, 0x2f, 0x3b, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x72, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73,
0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12,
0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52,
0x65, 0x71, 0x1a, 0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69,
0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b, 0x44, 0x69, 0x72,
0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x2e, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a,
0x16, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x44, 0x69, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x05, 0x55,
0x73, 0x61, 0x67, 0x65, 0x12, 0x0f, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x61,
0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x55, 0x73,
0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x3b,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -1,194 +0,0 @@
syntax = "proto3";
package files;
option go_package = "./;files";
service File {
rpc List(FileListReq) returns (FileListResp) {} //
rpc Info(FileInfoReq) returns (FileInfoResp) {} //
rpc Create(CreateReq) returns (CreateResp) {} //
rpc Delete(DeleteReq) returns (DeleteResp) {} //
rpc Search(searchReq) returns (searchResp) {} //
rpc Upload(UploadReq) returns (UploadResp) {} //
rpc TusCreate(TusCreateReq) returns (TusCreateResp) {
} //
rpc TusUpload(TusUploadReq) returns (TusUploadResp) {
} //
rpc ResumableTransfer(ResumableTransferReq) returns (ResumableTransferResp) {
} // grpc实现
rpc Preview(PreviewReq) returns (PreviewResp) {} //
rpc Action(ActionReq) returns (ActionResp) {} //
rpc DirDownload(DirDownloadReq) returns (stream DirDownloadResp) {
} //
rpc Usage(UsageReq) returns (UsageResp) {} //使
}
message FileListReq {
string path = 1; //
string userSpacePath = 2; //
Sorting sorting = 3;
}
message Items {
string path = 1;
string name = 2;
int64 size = 3;
string extension = 4;
string modified = 5;
int64 modTime = 6;
string mode = 7;
bool isDir = 8;
bool isSymlink = 9;
string type = 10;
}
message Sorting {
string by = 1;
bool asc = 2;
}
message FileListResp {
repeated Items items = 1;
int32 numDirs = 2;
int32 numFiles = 3;
Sorting sorting = 4;
string path = 5;
string name = 6;
int64 size = 7;
string extension = 8;
string modified = 9;
int64 modTime = 10;
string mode = 11;
bool isDir = 12;
bool isSymlink = 13;
string type = 14;
}
message CreateReq {
string path = 1;
string userSpacePath = 2;
}
message CreateResp {}
message DeleteReq {
string path = 1;
string userSpacePath = 2;
}
message DeleteResp {}
message UploadReq {
string path = 1;
string userSpacePath = 2;
bytes content = 3;
}
message UploadResp {}
message searchReq {
string path = 1;
string userSpacePath = 2;
string query = 3;
}
message searchResp {
message Nested {
bool isDir = 1;
string path = 2;
string name = 3;
int64 size = 4;
int64 modTime = 5;
}
repeated Nested items = 1;
}
message TusCreateReq {
string path = 1;
string userSpacePath = 2;
bool override = 3;
}
message TusCreateResp {
int64 uploadLength = 1;
int64 uploadOffset = 2;
}
message TusUploadReq {
string path = 1;
string userSpacePath = 2;
int64 uploadOffset = 3;
bytes content = 4;
}
message TusUploadResp { int64 uploadOffset = 1; }
message ResumableTransferReq {
string path = 1;
string userSpacePath = 2;
int64 offset = 3;
int64 length = 4;
}
message ResumableTransferResp { bytes content = 1; }
message FileInfoReq {
string path = 1;
string userSpacePath = 2;
}
message FileInfoResp {
string path = 1;
string name = 2;
int64 size = 3;
string extension = 4;
string modified = 5;
string mode = 6;
int64 modTime = 7;
bool isDir = 8;
bool isSymlink = 9;
string type = 10;
}
message PreviewReq {
string path = 1;
string userSpacePath = 2;
uint32 size = 3; // 0256x256, 1:1080x1080
}
message PreviewResp {
bytes content = 1;
string fileName = 2;
int64 modTime = 3;
}
message ActionReq {
string path = 1;
string userSpacePath = 2;
string action = 3;
string destination = 4;
bool override = 5;
bool rename = 6;
}
message ActionResp {}
message DirDownloadReq {
string path = 1;
string userSpacePath = 2;
repeated string files = 3;
string algo = 4;
}
message DirDownloadResp { bytes content = 1; }
message UsageReq {
string path = 1;
string userSpacePath = 2;
}
message UsageResp {
int64 total = 1;
int64 used = 2;
}

View File

@ -1,14 +1,13 @@
// Code generated by protoc-gen-go-triple. DO NOT EDIT.
// versions:
// - protoc-gen-go-triple v1.0.8
// - protoc v3.20.3
// - protoc-gen-go-triple v1.0.5
// - protoc v5.26.0
// source: files.proto
package files
import (
context "context"
constant1 "dubbo.apache.org/dubbo-go/v3/common/constant"
protocol "dubbo.apache.org/dubbo-go/v3/protocol"
dubbo3 "dubbo.apache.org/dubbo-go/v3/protocol/dubbo3"
invocation "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
@ -595,13 +594,6 @@ func _File_Action_Handler(srv interface{}, ctx context.Context, dec func(interfa
func _File_DirDownload_Handler(srv interface{}, stream grpc_go.ServerStream) error {
_, ok := srv.(dubbo3.Dubbo3GrpcService)
ctx := stream.Context()
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
stream.(grpc_go.CtxSetterStream).SetContext(context.WithValue(ctx, constant1.AttachmentKey, invAttachment))
invo := invocation.NewRPCInvocation("DirDownload", nil, nil)
if !ok {
fmt.Println(invo)

View File

@ -18,7 +18,7 @@ AccessKeyId = "${OSS_AK}"
AccessKeySecret = "${OSS_SK}"
Endpoint = "${OSS_ENDPOINTT}"
BucketName = "${OSS_BUCKETNAME}"
BaseDir = "fontree-fiee-test"
BaseDir = "fonchain-main"
CdnHost = "${OSS_CDN}"
[redis]
RedisDB = "2"

View File

@ -27,7 +27,6 @@ dubbo:
protocol: tri
retries: 0
interface: com.fontree.microservices.fiee.bundle # must be compatible with grpc or dubbo-java
SecFilingsClientImpl:
CastClientImpl:
protocol: tri
retries: 0
interface: com.fontree.microservices.fiee.SecFiling
interface: com.fontree.microservices.fiee.multicast

View File

@ -197,6 +197,14 @@ func NewRouter() *gin.Engine {
importRoute.POST("data/publish3", imports.ImportPublishV3)
importRoute.POST("data/publish4", imports.ImportPublishV4)
importRoute.POST("data/confirm", imports.WorkConfirm)
importRoute.POST("image-content/import", imports.ImageContentImport) // AI生成内容并导入系统
importRoute.GET("image-content/result", imports.ImageContentGetResult) // 获取导入结果
importRoute.GET("image-content/result/excel", imports.ImageContentGetResultExcel) // 导出错误的excel
importRoute.GET("generate/photo/test", imports.Test)
importRoute.GET("generate/photo/test1", imports.Test1)
importRoute.GET("generate/photo/test2", imports.Test2)
}
//静态文件
r.StaticFS("/api/fiee/static", http.Dir("./runtime"))

View File

@ -73,6 +73,12 @@ func TaskBenchRouter(r *gin.RouterGroup) {
// 查询艺人待上传列表并导出Excel
taskBenchRoute.POST("pending-upload-list-download", taskbench.GetArtistUploadStatsListDownload)
// 添加隐藏任务指派人
taskBenchRoute.POST("hide", taskbench.AddHiddenTaskAssignee)
// 查询待指派数据
taskBenchRoute.POST("pending-data-list", taskbench.GetPendingAssign)
}
// 员工任务相关路由需要App登录验证

View File

@ -170,7 +170,7 @@ func MetricsArtistAccountExport(ctx *gin.Context) {
utils.CheckDirPath("./runtime/"+fmt.Sprint(userInfo.ID), true)
sheet := "Sheet1"
f := excelize.NewFile()
headers := []string{"序号", "艺人", "用户编号", "DM账号", "DM账号昵称", "Instagram账号", "Instagram账号昵称", "TikTok账号", "TikTok账号昵称"}
headers := []string{"序号", "艺人", "用户编号", "DM账号名", "Instagram账号名", "TikTok账号名"}
for i, h := range headers {
col, _ := excelize.ColumnNumberToName(i + 1)
cell := col + "1"
@ -196,14 +196,11 @@ func MetricsArtistAccountExport(ctx *gin.Context) {
_ = write(2, it.ArtistName)
_ = write(3, it.UserNum)
_ = write(4, it.DmAccount)
_ = write(5, it.DmNickname)
_ = write(6, it.InstagramAccount)
_ = write(7, it.InstagramNickname)
_ = write(8, it.TiktokAccount)
_ = write(9, it.TiktokNickname)
_ = write(5, it.InstagramAccount)
_ = write(6, it.TiktokAccount)
}
// 可选:设置列宽,使表格更美观
_ = f.SetColWidth(sheet, "A", "AZ", 15)
_ = f.SetColWidth(sheet, "A", "AZ", 18)
// 保存文件
if err := f.SaveAs(filePath); err != nil {

View File

@ -137,7 +137,7 @@ func HandShelf(c *gin.Context) {
}
res, err := service.BundleProvider.HandShelf(context.Background(), &req)
if err != nil {
service.Error(c, errors.New(common.HandShelfFailed))
service.Error(c, err)
return
}
service.Success(c, res)

View File

@ -103,6 +103,24 @@ const (
BalanceMetricsExportFailed = "服务使用明细数据导出失败"
)
//素材库
const (
FileListFailed = "素材库列表查询失败"
FileUsageFailed = "素材库使用情况查询失败"
GetFileInfoFailed = "素材库文件信息查询失败"
CreateFileFailed = "素材库文件创建失败"
DeleteFileFailed = "素材库文件删除失败"
SearchFileFailed = "素材库文件搜索失败"
UploadFileFailed = "素材库文件上传失败"
TusCreateFailed = "素材库文件创建失败"
TusUploadFailed = "素材库文件上传失败"
PreviewFileFailed = "素材库文件预览失败"
ActionFailed = "素材库文件操作失败"
DirDownloadFailed = "素材库文件下载失败"
InvalidUploadOffset = "无效的上传偏移量"
ERROR_OPEN_FILE = "打开文件错误"
)
//官网
const (
CreateSecFilingFailed = "创建官方信息失败"

View File

@ -3,9 +3,9 @@ package file
import (
"bytes"
"errors"
"fmt"
"fonchain-fiee/api/files"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/bundle/common"
"io"
"net/http"
"net/url"
@ -24,7 +24,7 @@ func Raw(ctx *gin.Context) {
w.Header().Set("Cache-Control", "private")
rs, err := newGrpcReaderSeeker(getUserSpacePath(ctx), ctx.Param("path"))
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.FileListFailed))
return
}
if r.URL.Query().Get("inline") == "true" {
@ -40,6 +40,8 @@ func List(ctx *gin.Context) {
path := ctx.DefaultQuery("path", "/")
sortBy := ctx.DefaultQuery("sortBy", "name")
sortAsc, _ := strconv.ParseBool(ctx.DefaultQuery("sortAsc", "true"))
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "100000"))
resp, err := service.FilesProvider.List(ctx, &files.FileListReq{
Path: path,
UserSpacePath: getUserSpacePath(ctx),
@ -47,9 +49,11 @@ func List(ctx *gin.Context) {
By: sortBy,
Asc: sortAsc,
},
Page: int32(page),
PageSize: int32(pageSize),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.FileListFailed))
return
}
service.Success(ctx, resp)
@ -62,7 +66,7 @@ func Usage(ctx *gin.Context) {
UserSpacePath: getUserSpacePath(ctx),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.FileUsageFailed))
return
}
service.Success(ctx, resp)
@ -74,7 +78,7 @@ func Info(ctx *gin.Context) {
UserSpacePath: getUserSpacePath(ctx),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.GetFileInfoFailed))
return
}
service.Success(ctx, resp)
@ -89,7 +93,7 @@ func Create(ctx *gin.Context) {
req.UserSpacePath = getUserSpacePath(ctx)
resp, err := service.FilesProvider.Create(ctx, &req)
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.CreateFileFailed))
return
}
service.Success(ctx, resp)
@ -101,7 +105,7 @@ func Delete(ctx *gin.Context) {
UserSpacePath: getUserSpacePath(ctx),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.DeleteFileFailed))
return
}
service.Success(ctx, resp)
@ -114,7 +118,7 @@ func Search(ctx *gin.Context) {
Query: ctx.Query("query"),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.SearchFileFailed))
return
}
service.Success(ctx, resp)
@ -128,7 +132,7 @@ func Upload(ctx *gin.Context) {
}
b, err := io.ReadAll(ctx.Request.Body)
if !ok {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.ERROR_OPEN_FILE))
return
}
resp, err := service.FilesProvider.Upload(ctx, &files.UploadReq{
@ -137,7 +141,7 @@ func Upload(ctx *gin.Context) {
Content: b,
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.UploadFileFailed))
return
}
service.Success(ctx, resp)
@ -152,7 +156,7 @@ func TusCreate(ctx *gin.Context) {
req.UserSpacePath = getUserSpacePath(ctx)
resp, err := service.FilesProvider.TusCreate(ctx, &req)
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.TusCreateFailed))
return
}
service.Success(ctx, resp)
@ -166,24 +170,24 @@ func TusUpload(ctx *gin.Context) {
}
uploadOffset, err := getUploadOffset(ctx.Request)
if err != nil {
service.Error(ctx, fmt.Errorf("invalid upload offset: %w", err))
service.Error(ctx, errors.New(common.ERROR_OPEN_FILE))
return
}
mf, err := ctx.MultipartForm()
if err != nil {
service.Error(ctx, fmt.Errorf("invalid upload offset: %w", err))
service.Error(ctx, errors.New(common.ERROR_OPEN_FILE))
return
}
f, err := mf.File["file"][0].Open()
if err != nil {
service.Error(ctx, fmt.Errorf("invalid upload offset: %w", err))
service.Error(ctx, errors.New(common.ERROR_OPEN_FILE))
return
}
defer f.Close()
b, err := io.ReadAll(f)
// b, err := io.ReadAll(ctx.Request.Body)
if !ok {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.ERROR_OPEN_FILE))
return
}
resp, err := service.FilesProvider.TusUpload(ctx, &files.TusUploadReq{
@ -193,7 +197,7 @@ func TusUpload(ctx *gin.Context) {
UserSpacePath: getUserSpacePath(ctx),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.TusUploadFailed))
return
}
ctx.Writer.Header().Set("Upload-Offset", strconv.FormatInt(resp.UploadOffset, 10))
@ -212,7 +216,7 @@ func Preview(ctx *gin.Context) {
Size: uint32(size),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.PreviewFileFailed))
return
}
ctx.Writer.Header().Set("Cache-Control", "private")
@ -228,7 +232,7 @@ func Action(ctx *gin.Context) {
req.UserSpacePath = getUserSpacePath(ctx)
resp, err := service.FilesProvider.Action(ctx, &req)
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.ActionFailed))
return
}
service.Success(ctx, resp)
@ -245,12 +249,12 @@ func DirDownload(ctx *gin.Context) {
UserSpacePath: getUserSpacePath(ctx),
})
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.DirDownloadFailed))
return
}
header, err := stream.Header()
if err != nil {
service.Error(ctx, err)
service.Error(ctx, errors.New(common.DirDownloadFailed))
return
}
@ -267,7 +271,7 @@ func DirDownload(ctx *gin.Context) {
func getUploadOffset(r *http.Request) (int64, error) {
uploadOffset, err := strconv.ParseInt(r.Header.Get("Upload-Offset"), 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid upload offset: %w", err)
return 0, errors.New(common.InvalidUploadOffset)
}
return uploadOffset, nil
}

View File

@ -0,0 +1,140 @@
package imports
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
// 配置结构增强
type Aiconfig struct {
APIKey string
BaseURL string
Image2ImageURL string
TextGenerationURL string
TextToImageURL string
TextToImageModel string
TaskQueryURL string
ImageModel string
TextModel string
DefaultSize string
Timeout int
SaveDir string
MaxTokens int
Temperature float64
TopP float64
}
// 完整的AI生成器
type AiGenerator struct {
cfg Aiconfig
client *http.Client
}
const (
DefaultAPIKey = "sk-5ae9df5d3bcf4755ad5d12012058a2e7"
DefaultBaseURL = "https://dashscope.aliyuncs.com"
DefaultTextToImageURL = "/api/v1/services/aigc/text2image/image-synthesis" //文生图
DefaultTextToImageModel = "wan2.5-t2i-preview"
DefaultImage2ImageURL = "/api/v1/services/aigc/image2image/image-synthesis" //图生图
DefaultImageModel = "wan2.5-i2i-preview"
DefaultTextGenerationURL = "/api/v1/services/aigc/text-generation/generation" //文生文
DefaultTextModel = "qwen-turbo"
DefaultSize = "1024x1024"
DefaultTaskQueryURL = "/api/v1/tasks"
DefaultTimeout = 30
DefaultMaxTokens = 2000
DefaultTemperature = 0.8
DefaultTopP = 0.9
)
func NewAiGenerator() *AiGenerator {
cfg := &Aiconfig{
APIKey: DefaultAPIKey,
BaseURL: DefaultBaseURL,
Image2ImageURL: DefaultImage2ImageURL,
TextGenerationURL: DefaultTextGenerationURL,
TextToImageURL: DefaultTextToImageURL,
TextToImageModel: DefaultTextToImageModel,
TaskQueryURL: DefaultTaskQueryURL,
ImageModel: DefaultImageModel,
TextModel: DefaultTextModel,
DefaultSize: DefaultSize,
Timeout: DefaultTimeout,
MaxTokens: DefaultMaxTokens,
Temperature: DefaultTemperature,
TopP: DefaultTopP,
}
return &AiGenerator{
cfg: *cfg,
client: &http.Client{
Timeout: time.Duration(cfg.Timeout) * time.Second,
},
}
}
// 任务结果--------------------------------------------------------------------------
// ImageGenerationResponse 图片生成响应
type ImageGenerationResponse struct {
RequestID string `json:"request_id"`
Output Output `json:"output"`
Usage Usage `json:"usage"`
}
type Output struct {
TaskID string `json:"task_id"`
TaskStatus string `json:"task_status"`
SubmitTime string `json:"submit_time"`
ScheduledTime string `json:"scheduled_time"`
EndTime string `json:"end_time"`
Results []Result `json:"results"`
TaskMetrics TaskMetrics `json:"task_metrics"`
}
type Result struct {
URL string `json:"url,omitempty"`
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
type TaskMetrics struct {
Total int `json:"TOTAL"`
Succeeded int `json:"SUCCEEDED"`
Failed int `json:"FAILED"`
}
type Usage struct {
ImageCount int `json:"image_count"`
}
func (g *AiGenerator) GetTaskDetail(taskID string) (*ImageGenerationResponse, error) {
url := fmt.Sprintf("%s/api/v1/tasks/%s", g.cfg.BaseURL, taskID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
httpReq.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := g.client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API错误: %d", resp.StatusCode)
}
var imageGenerationResponse ImageGenerationResponse
if err := json.NewDecoder(resp.Body).Decode(&imageGenerationResponse); err != nil {
return nil, fmt.Errorf("任务详情解析失败: %v", err)
}
return &imageGenerationResponse, nil
}

View File

@ -0,0 +1,92 @@
package imports
//
//import (
// "bytes"
// "encoding/json"
// "fmt"
// "net/http"
//)
//
////------------------------------------------图生图
//
//type Image2ImageRequest struct {
// Model string `json:"model"`
// Input ImageInput `json:"input"`
// Params ImageParams `json:"parameters"`
//}
//
//type ImageInput struct {
// Images []string `json:"images"`
// Prompt string `json:"prompt"` // 可选的条件文本
//}
//
//type ImageParams struct {
// Size string `json:"size,omitempty"` // 输出尺寸
// Strength float64 `json:"strength"` // 重绘强度0-1
// N int `json:"n,omitempty"` // 生成数量
//}
//
//type ImageResponse struct {
// Output struct {
// TaskID string `json:"task_id"`
// Results []struct {
// URL string `json:"url"`
// } `json:"results"`
// } `json:"output"`
// RequestID string `json:"request_id"`
//}
//
//// Image2image 图生图
//func (g *AiGenerator) Image2image(imagePath string, prompt string, strength float64, size string, n int) (*ImageResponse, error) {
// if g.cfg.APIKey == "" {
// return nil, fmt.Errorf("API密钥未配置")
// }
//
// // 构建请求
// req := Image2ImageRequest{
// Model: g.cfg.ImageModel,
// Input: ImageInput{
// Images: []string{imagePath},
// Prompt: prompt,
// },
// Params: ImageParams{
// Size: size,
// Strength: strength,
// N: n,
// },
// }
//
// url := g.cfg.BaseURL + g.cfg.Image2ImageURL
// jsonData, err := json.Marshal(req)
// if err != nil {
// return nil, err
// }
//
// httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
// if err != nil {
// return nil, err
// }
//
// httpReq.Header.Set("Content-Type", "application/json")
// httpReq.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
// httpReq.Header.Set("X-DashScope-Async", "enable")
//
// resp, err := g.client.Do(httpReq)
// if err != nil {
// return nil, err
// }
// defer resp.Body.Close()
//
// // 解析响应
// var result ImageResponse
// if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
// return nil, fmt.Errorf("响应解析失败: %v", err)
// }
//
// if resp.StatusCode != http.StatusOK {
// return nil, fmt.Errorf("API错误: %d", resp.StatusCode)
// }
//
// return &result, nil
//}

View File

@ -0,0 +1,346 @@
package imports
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"net/http"
"strings"
"time"
)
// 使用OpenAI兼容格式
type ChatCompletionRequest struct {
Model string `json:"model"`
Messages []ChatMessage `json:"messages"`
MaxTokens int `json:"max_tokens,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
TopK float64 `json:"top_k,omitempty"`
PresencePenalty float64 `json:"presence_penalty,omitempty"`
Seed int `json:"seed,omitempty"`
}
type ChatMessage struct {
Role string `json:"role"`
Content []Content `json:"content"`
}
type Content struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ImageURL struct {
URL string `json:"url"`
} `json:"image_url,omitempty"`
}
type ChatCompletionResponse struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
Error struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}
// 图生文:根据图片生成标题和内容
func (g *AiGenerator) GenerateTitleAndContentFromImage(imageURL, titleRequire, contentRequire string) (string, string, error) {
// 构建提示词
prompt := fmt.Sprintf(`请分析这张图片并生成内容
图片分析要求
1. 标题要求%s
2. 内容要求%s
请严格按照以下格式返回不要有任何额外文字
标题{生成的标题}
内容{生成的内容}`, titleRequire, contentRequire)
// 发送聊天请求
response, err := g.chatWithImage(imageURL, prompt)
if err != nil {
return "", "", err
}
// 解析响应
title, content := parseTitleAndContent(response)
return title, content, nil
}
func (g *AiGenerator) chatWithImage(imageURL, prompt string) (string, error) {
reqBody := ChatCompletionRequest{
Model: "qwen3-vl-plus",
Messages: []ChatMessage{
{
Role: "user",
Content: []Content{
{
Type: "image_url",
ImageURL: struct {
URL string `json:"url"`
}{
URL: imageURL,
},
},
{
Type: "text",
Text: prompt,
},
},
},
},
MaxTokens: 2000,
Temperature: 1.5,
TopP: 0.9,
TopK: 99,
PresencePenalty: 1.5,
Seed: generateSeed(),
}
// 使用兼容模式接口
url := g.cfg.BaseURL + "/compatible-mode/v1/chat/completions"
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("JSON序列化失败: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
req.Header.Set("X-DashScope-Session-Id", fmt.Sprintf("session-%d", time.Now().UnixNano()))
resp, err := g.client.Do(req)
if err != nil {
return "", fmt.Errorf("API请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败: %v", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body))
}
var result ChatCompletionResponse
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("JSON解析失败: %v, 响应: %s", err, string(body))
}
// 检查API错误
if result.Error.Message != "" {
return "", fmt.Errorf("API返回错误: %s", result.Error.Message)
}
if len(result.Choices) == 0 {
return "", errors.New("AI未生成有效响应")
}
response := strings.TrimSpace(result.Choices[0].Message.Content)
return response, nil
}
func generateSeed() int {
rand.Seed(time.Now().UnixNano()) // 使用当前时间戳作为种子
return rand.Intn(2147483647) // 生成一个在 [0, 231-1] 范围内的随机数
}
// 解析标题和内容
func parseTitleAndContent(response string) (string, string) {
var title, content string
lines := strings.Split(response, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "标题:") {
title = strings.TrimPrefix(line, "标题:")
} else if strings.HasPrefix(line, "内容:") {
content = strings.TrimPrefix(line, "内容:")
}
}
return strings.TrimSpace(title), strings.TrimSpace(content)
}
// 文本生成文本(聊天模式)
func (g *AiGenerator) GenerateTitleAndContentFromText(titleRequire, contentRequire string) (string, string, error) {
// 构建提示词
prompt := fmt.Sprintf(`请根据以下要求生成内容
生成要求
1. 标题要求%s
2. 内容要求%s
请严格按照以下格式返回不要有任何额外文字
标题{生成的标题}
内容{生成的内容}`,
titleRequire,
contentRequire,
)
// 发送聊天请求
response, err := g.chatWithText(prompt)
if err != nil {
return "", "", err
}
// 解析响应
title, content := parseTitleAndContent(response)
return title, content, nil
}
// 文本聊天(纯文本生成)
func (g *AiGenerator) chatWithText(prompt string) (string, error) {
reqBody := ChatCompletionRequest{
Model: "qwen-max", // 使用文本模型
Messages: []ChatMessage{
{
Role: "user",
Content: []Content{
{
Type: "text",
Text: prompt,
},
},
},
},
MaxTokens: 2000,
Temperature: 1.9,
TopP: 1.0,
TopK: 99,
PresencePenalty: 1.0,
Seed: generateSeed(),
}
url := g.cfg.BaseURL + "/compatible-mode/v1/chat/completions"
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("JSON序列化失败: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
req.Header.Set("X-DashScope-Session-Id", fmt.Sprintf("session-%d", time.Now().UnixNano()))
resp, err := g.client.Do(req)
if err != nil {
return "", fmt.Errorf("API请求失败: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败: %v", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body))
}
var result ChatCompletionResponse
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("JSON解析失败: %v, 响应: %s", err, string(body))
}
if result.Error.Message != "" {
return "", fmt.Errorf("API返回错误: %s", result.Error.Message)
}
if len(result.Choices) == 0 {
return "", errors.New("AI未生成有效响应")
}
response := strings.TrimSpace(result.Choices[0].Message.Content)
return response, nil
}
//func (g *AiGenerator) GenerateImageFromText(prompt, size string, n int) (string, error) {
// // 构建图片生成提示词
// imagePrompt := fmt.Sprintf(`请根据以下描述生成图片:
//
//图片描述:%s
//生成数量:%d张
//图片尺寸:%s
//
//请直接生成图片,不要返回任何文字描述。`,
// prompt, n, size)
//
// // 使用文生图API
// result, err := g.TextToImage(imagePrompt, size, n)
// if err != nil {
// return "", err
// }
//
// return result.Output.TaskID, nil
//}
// 文本生成图像
//func (g *AiGenerator) TextToImage(prompt, size string, n int) (ImageGenerationResponse, error) {
// // 构建图像生成请求
// reqBody := map[string]interface{}{
// "prompt": prompt,
// "n": n,
// "size": size,
// "response_format": "url", // 假设返回的格式为图像 URL可以根据实际 API 调整
// }
//
// // 使用图像生成接口
// url := g.cfg.BaseURL + "/v1/images/generations"
// jsonData, err := json.Marshal(reqBody)
// if err != nil {
// return ImageGenerationResponse{}, fmt.Errorf("JSON序列化失败: %v", err)
// }
//
// req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
// if err != nil {
// return ImageGenerationResponse{}, fmt.Errorf("创建请求失败: %v", err)
// }
//
// req.Header.Set("Content-Type", "application/json")
// req.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
//
// resp, err := g.client.Do(req)
// if err != nil {
// return ImageGenerationResponse{}, fmt.Errorf("API请求失败: %v", err)
// }
// defer resp.Body.Close()
//
// // 读取响应体
// body, err := io.ReadAll(resp.Body)
// if err != nil {
// return ImageGenerationResponse{}, fmt.Errorf("读取响应失败: %v", err)
// }
//
// if resp.StatusCode != http.StatusOK {
// return ImageGenerationResponse{}, fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body))
// }
//
// // 解析图像生成响应
// var result ImageGenerationResponse
// if err := json.Unmarshal(body, &result); err != nil {
// return ImageGenerationResponse{}, fmt.Errorf("JSON解析失败: %v, 响应: %s", err, string(body))
// }
//
// if len(result.Data) == 0 {
// return ImageGenerationResponse{}, errors.New("未生成任何图像")
// }
//
// return result, nil
//}

View File

@ -0,0 +1,100 @@
package imports
//
//import (
// "bytes"
// "encoding/json"
// "fmt"
// "net/http"
//)
//
//// ----------------------------文生文
//
//// 文本生成请求结构
//type TextGenerationRequest struct {
// Model string `json:"model"`
// Input TextInput `json:"input"`
// Params TextParams `json:"parameters"`
//}
//
//type TextInput struct {
// Messages []Message `json:"messages"`
//}
//
//type TextParams struct {
// ResultFormat string `json:"result_format,omitempty"` // 结果格式
// MaxTokens int `json:"max_tokens,omitempty"` // 最大token数
// Temperature float64 `json:"temperature,omitempty"` // 温度参数
// TopP float64 `json:"top_p,omitempty"` // 核采样参数
//}
//
//type TextResponse struct {
// Output struct {
// Text string `json:"text"`
// FinishReason string `json:"finish_reason"`
// } `json:"output"`
// Usage struct {
// InputTokens int `json:"input_tokens"`
// OutputTokens int `json:"output_tokens"`
// TotalTokens int `json:"total_tokens"`
// } `json:"usage"`
// RequestID string `json:"request_id"`
//}
//
//// GenerateText 生成文本
//func (g *AiGenerator) GenerateText(prompt string) (*TextResponse, error) {
// if g.cfg.APIKey == "" {
// return nil, fmt.Errorf("API密钥未配置")
// }
//
// // 构建请求
// req := TextGenerationRequest{
// Model: g.cfg.TextModel,
// Input: TextInput{
// Messages: []Message{
// {
// Role: "user",
// Content: prompt,
// },
// },
// },
// Params: TextParams{
// ResultFormat: "message",
// MaxTokens: g.cfg.MaxTokens,
// Temperature: g.cfg.Temperature,
// TopP: g.cfg.TopP,
// },
// }
//
// url := g.cfg.BaseURL + g.cfg.TextGenerationURL
// jsonData, err := json.Marshal(req)
// if err != nil {
// return nil, err
// }
//
// httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
// if err != nil {
// return nil, err
// }
//
// httpReq.Header.Set("Content-Type", "application/json")
// httpReq.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
//
// resp, err := g.client.Do(httpReq)
// if err != nil {
// return nil, err
// }
// defer resp.Body.Close()
//
// // 解析响应
// var result TextResponse
// if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
// return nil, fmt.Errorf("文本生成响应解析失败: %v", err)
// }
//
// if resp.StatusCode != http.StatusOK {
// return nil, fmt.Errorf("API错误: %d", resp.StatusCode)
// }
//
// return &result, nil
//}

View File

@ -0,0 +1,120 @@
package imports
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// 修正后的文生图请求结构
type TextToImageRequest struct {
Model string `json:"model"`
Input TextToImageInput `json:"input"`
Params TextToImageParameters `json:"parameters"` // 修正字段名
}
type TextToImageInput struct {
Prompt string `json:"prompt"`
NegativePrompt string `json:"negative_prompt"`
}
type TextToImageParameters struct {
Size string `json:"size,omitempty"`
N int `json:"n,omitempty"`
NegativePrompt string `json:"negative_prompt,omitempty"`
Steps int `json:"steps,omitempty"`
Scale float64 `json:"scale,omitempty"`
Style string `json:"style,omitempty"`
Seed int `json:"seed,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
}
type TextToImageResponse struct {
Output struct {
TaskID string `json:"task_id"`
TaskStatus string `json:"task_status"` // 添加任务状态字段
Results []struct {
URL string `json:"url"`
} `json:"results"`
} `json:"output"`
RequestID string `json:"request_id"`
Code string `json:"code,omitempty"` // 错误代码
Message string `json:"message,omitempty"` // 错误信息
}
// 修正后的文生图函数
func (g *AiGenerator) TextToImage(prompt string, size string, n int) (*TextToImageResponse, error) {
if g.cfg.APIKey == "" {
return nil, fmt.Errorf("API密钥未配置")
}
// 构建请求
req := TextToImageRequest{
Model: g.cfg.TextToImageModel,
Input: TextToImageInput{
Prompt: prompt,
NegativePrompt: "低质量、残缺、人物正脸、多余的手指、乱码字符和文字、比例不良丶场景以国内场景为主",
//NegativePrompt: "人物正脸",
},
Params: TextToImageParameters{
Size: size,
N: n,
Seed: generateSeed(),
NegativePrompt: "低质量、残缺、人物正脸、多余的手指、乱码字符和文字、比例不良、场景以国内场景为主",
},
}
url := g.cfg.BaseURL + g.cfg.TextToImageURL
jsonData, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("JSON序列化失败: %v", err)
}
// 打印请求信息用于调试
fmt.Printf("请求URL: %s\n", url)
fmt.Printf("请求体: %s\n", string(jsonData))
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("创建请求失败: %v", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
httpReq.Header.Set("X-DashScope-Async", "enable")
resp, err := g.client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("API请求失败: %v", err)
}
defer resp.Body.Close()
// 读取完整响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
fmt.Printf("响应状态: %d\n", resp.StatusCode)
fmt.Printf("响应体: %s\n", string(body))
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body))
}
// 解析响应
var result TextToImageResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("响应解析失败: %v, 原始响应: %s", err, string(body))
}
// 检查任务状态
if result.Output.TaskStatus == "FAILED" {
return nil, fmt.Errorf("图片生成失败: %s", result)
}
return &result, nil
}

View File

@ -0,0 +1,116 @@
package imports
//
//import (
// "bytes"
// "encoding/json"
// "fmt"
// "io"
// "net/http"
//)
//
//// Message 结构体定义
//type Message struct {
// Role string `json:"role"`
// Content string `json:"content"`
//}
//
//// 同步文本生成请求
//type SyncTextGenerationRequest struct {
// Model string `json:"model"`
// Input SyncTextInput `json:"input"`
// Parameters SyncTextGenerationParams `json:"parameters"`
//}
//
//type SyncTextInput struct {
// Messages []Message `json:"messages"`
//}
//
//type SyncTextGenerationParams struct {
// ResultFormat string `json:"result_format,omitempty"`
// MaxTokens int `json:"max_tokens,omitempty"`
// Temperature float64 `json:"temperature,omitempty"`
// TopP float64 `json:"top_p,omitempty"`
// TopK int `json:"top_k,omitempty"`
// Seed int64 `json:"seed,omitempty"`
//}
//
//// 同步文本生成响应
//type SyncTextGenerationResponse struct {
// Output struct {
// Choices []struct {
// Message Message `json:"message"`
// } `json:"choices"`
// Text string `json:"text"`
// FinishReason string `json:"finish_reason"`
// } `json:"output"`
// Usage struct {
// InputTokens int `json:"input_tokens"`
// OutputTokens int `json:"output_tokens"`
// TotalTokens int `json:"total_tokens"`
// } `json:"usage"`
// RequestID string `json:"request_id"`
//}
//
//// 同步文本生成URL
//const DefaultSyncTextGenerationURL = "/api/v1/services/aigc/text-generation/generation"
//
//// 同步生成文本
//func (g *AiGenerator) GenerateTextSync(prompt string) (*SyncTextGenerationResponse, error) {
// if g.cfg.APIKey == "" {
// return nil, fmt.Errorf("API密钥未配置")
// }
//
// // 构建请求
// req := SyncTextGenerationRequest{
// Model: g.cfg.TextModel,
// Input: SyncTextInput{
// Messages: []Message{
// {
// Role: "user",
// Content: prompt,
// },
// },
// },
// Parameters: SyncTextGenerationParams{
// ResultFormat: "message",
// MaxTokens: g.cfg.MaxTokens,
// Temperature: g.cfg.Temperature,
// TopP: g.cfg.TopP,
// },
// }
//
// url := g.cfg.BaseURL + DefaultSyncTextGenerationURL
// jsonData, err := json.Marshal(req)
// if err != nil {
// return nil, fmt.Errorf("JSON序列化失败: %v", err)
// }
//
// httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
// if err != nil {
// return nil, fmt.Errorf("创建请求失败: %v", err)
// }
//
// httpReq.Header.Set("Content-Type", "application/json")
// httpReq.Header.Set("Authorization", "Bearer "+g.cfg.APIKey)
// // 注意:这里不设置 X-DashScope-Async 头,使用同步模式
//
// resp, err := g.client.Do(httpReq)
// if err != nil {
// return nil, fmt.Errorf("API请求失败: %v", err)
// }
// defer resp.Body.Close()
//
// if resp.StatusCode != http.StatusOK {
// body, _ := io.ReadAll(resp.Body)
// return nil, fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body))
// }
//
// // 解析响应
// var result SyncTextGenerationResponse
// if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
// return nil, fmt.Errorf("响应解析失败: %v", err)
// }
//
// return &result, nil
//}

View File

@ -0,0 +1,118 @@
package imports
import (
"errors"
"fmt"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/utils"
"sort"
"time"
"github.com/gin-gonic/gin"
)
func ImageContentGetResult(c *gin.Context) {
processor := GetBatchProcessorReadOnly()
if processor == nil {
service.Success(c, gin.H{
"status": 0,
"status_description": StatusMap[0],
"message": "暂无执行中的任务",
})
return
}
currentStatus := processor.getStatus()
switch currentStatus {
case StatusIdle:
service.Success(c, gin.H{
"status": currentStatus,
"status_description": StatusMap[currentStatus],
"message": "暂无执行中的任务",
})
return
case StatusProcessing:
completed, pending, total, completedTasks, failedTasks := processor.getTaskStatistics()
service.Success(c, gin.H{
"status": currentStatus,
"status_description": StatusMap[currentStatus],
"message": "任务执行中,请稍后",
"total_tasks": total,
"pending_tasks": pending,
"failed_tasks": len(failedTasks), //失败数量
"success_tasks": len(completedTasks), //成功数量
"progress": fmt.Sprintf("%.1f%%", float64(completed)/float64(total)*100),
"completed_tasks": completed,
"completed_rate": float64(completed) / float64(total) * 100,
})
return
case StatusCompleted:
completed, pending, total, completedTasks, failedTasks := processor.getTaskStatistics()
service.Success(c, gin.H{
"status": currentStatus,
"status_description": StatusMap[currentStatus],
"message": "所有任务已完成",
"total_tasks": total,
"failed_tasks": len(failedTasks), //失败数量
"success_tasks": len(completedTasks), //成功数量
"success_rate": fmt.Sprintf("%.1f%%", float64(len(completedTasks))/float64(total)*100),
"pending_tasks": pending,
"completed_tasks": completed,
"completed_rate": float64(completed) / float64(total) * 100,
}, "任务完成")
return
}
}
func ImageContentGetResultExcel(c *gin.Context) {
processor := GetBatchProcessorReadOnly()
if processor == nil {
service.Error(c, errors.New("任务未开始或者任务在处理中"))
return
}
currentStatus := processor.getStatus()
switch currentStatus {
case StatusCompleted:
_, _, _, _, failedTasks := processor.getTaskStatistics()
if len(failedTasks) > 0 {
if err := returnExcel(failedTasks, c); err != nil {
service.Error(c, errors.New("生成错误报告失败"))
return
}
return
} else {
service.Error(c, errors.New("没有错误"))
}
case StatusIdle, StatusProcessing:
service.Error(c, errors.New("任务未开始或者任务在处理中"))
return
}
}
func returnExcel(failedTasks []*Task, c *gin.Context) error {
titleList := []string{
"行数", "艺术家", "编号", "错误信息", "任务ID", "开始时间",
}
var dataList []interface{}
for _, task := range failedTasks {
data := []interface{}{
task.Data.LineNum + 1,
task.Data.ArtistName,
task.Data.SubNum,
getErrorMessage(task.Error),
task.TaskId,
task.StartTime.Format("2006-01-02 15:04:05"),
}
dataList = append(dataList, &data)
}
sort.Slice(failedTasks, func(i, j int) bool {
return failedTasks[i].Data.LineNum < failedTasks[j].Data.LineNum
})
content, err := utils.ToExcelByType(titleList, dataList, "slice", "")
if err != nil {
return fmt.Errorf("生成Excel失败: %v", err)
}
utils.ResponseXls(c, content, fmt.Sprintf("失败任务报告_%s.xlsx", time.Now().Format("20060102150405")))
return nil
}

View File

@ -0,0 +1,339 @@
package imports
import (
"errors"
"fmt"
"fonchain-fiee/pkg/config"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/utils"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/fonchain_enterprise/utils/objstorage"
"github.com/xuri/excelize/v2"
"github.com/gin-gonic/gin"
)
const (
fail string = "操作失败"
)
type excelData struct {
ArtistName string //艺人 必须字段
SubNum string //用户编号 必须字段
TikTok string
Instagram string
Youtube string
Desc string //艺人简介
TitleRequire string //标题要求 必须字段
ContentRequire string //内容要求 必须字段
PhotoRequire string //图片要求 必须字段
PhotoUrl string //画作地址
PhotoNum int //图片数量 必须字段
LineNum int
Title string //标题
Content string //内容
MediaAccountUuids []string
MediaAccountNames []string
PhotoDpi string
}
type publishImageReq struct {
ArtistName string //艺人
SubNum string //用户编号
Title string //标题
Content string //内容
TikTok string
Instagram string
GeneratePhotoUrl []string //生成图片地址
MediaAccountUuids []string
MediaAccountNames []string
}
func getErrorMessage(err error) string {
if err == nil {
return ""
}
return err.Error()
}
func ImageContentImport(c *gin.Context) {
processor := GetOrCreateBatchProcessor()
currentStatus := processor.getStatus()
switch currentStatus {
case StatusProcessing: //进行中
service.Error(c, errors.New("当前有任务正在执行中,请先查看执行进度"))
return
case StatusIdle, StatusCompleted: //空闲状态,完成可以执行下一次导入
}
defer func() {
if r := recover(); r != nil {
service.Error(c, errors.New("操作失败"))
}
}()
// 导入excel
excelFile, err := c.FormFile("excel")
if err != nil {
service.Error(c, errors.New("缺少excel文件"))
return
}
// 创建临时文件
tempDir := "tmp"
if err = os.MkdirAll(tempDir, 0755); err != nil {
service.Error(c, errors.New("创建临时目录失败"))
return
}
defer os.RemoveAll(tempDir)
// 保存excel
excelPath := filepath.Join(tempDir, "excel.xlsx")
if err = c.SaveUploadedFile(excelFile, excelPath); err != nil {
service.Error(c, errors.New("保存excel文件失败"))
return
}
// 读取excel
readExcelResult, err := readExcel(excelPath)
if err != nil {
service.Error(c, fmt.Errorf("读取excel失败: %v", err))
return
}
if len(readExcelResult) == 0 {
service.Error(c, errors.New("请检查excel文件"))
return
}
//设置全局状态为进行中
processor.setStatus(StatusProcessing)
//设置请求间隔
qps := 10
interval := time.Second / time.Duration(qps)
for i, v := range readExcelResult {
if i > 0 {
time.Sleep(interval)
}
if err := processor.submitTask(&v); err != nil {
task := &Task{
Data: &v,
TaskId: i,
Error: err,
StartTime: time.Now(),
}
processor.taskIdFindTask[v.LineNum] = task
processor.taskIdFindTaskStatus[v.LineNum] = true
}
}
//开始轮询
processor.startPolling()
service.Success(c, gin.H{
"message": "导入成功",
"total": len(readExcelResult),
})
}
func readExcel(excelPath string) ([]excelData, error) {
//打开excel
f, err := excelize.OpenFile(excelPath)
if err != nil {
return nil, err
}
defer f.Close()
//读取第一页
sheetName := f.GetSheetName(0)
if sheetName == "" {
return nil, errors.New("excel文件中没有工作表")
}
//读取数据
rows, err := f.GetRows(sheetName)
if err != nil {
return nil, fmt.Errorf("读取工作表失败: %v", err)
}
if len(rows) <= 1 {
return nil, errors.New("excel文件没有数据行只有表头或为空")
}
var result []excelData
for i := 1; i < len(rows); i++ { // 从第2行开始跳过表头
row := rows[i]
if len(row) == 0 {
continue
}
artistName := getCellValue(f, sheetName, i, 0)
if artistName == "" {
return nil, fmt.Errorf("第%d行应该有艺人名称", i+1)
}
subNum := getCellValue(f, sheetName, i, 1)
if subNum == "" {
return nil, fmt.Errorf("第%d行应该有编号", i+1)
}
tikTok := getCellValue(f, sheetName, i, 2)
if tikTok == "" {
return nil, fmt.Errorf("第%d行应该有tiktok账号昵称", i+1)
}
instagram := getCellValue(f, sheetName, i, 3)
if instagram == "" {
return nil, fmt.Errorf("第%d行应该有ins账号昵称", i+1)
}
desc := getCellValue(f, sheetName, i, 4)
titleRequire := getCellValue(f, sheetName, i, 5)
if titleRequire == "" {
return nil, fmt.Errorf("第%d行应该有标题要求", i+1)
}
contentRequire := getCellValue(f, sheetName, i, 6)
if contentRequire == "" {
return nil, fmt.Errorf("第%d行应该有内容要求", i+1)
}
photoRequire := getCellValue(f, sheetName, i, 7)
photoUrl := getCellValue(f, sheetName, i, 8)
photoNumStr := getCellValue(f, sheetName, i, 9)
photoDpi := getCellValue(f, sheetName, i, 10)
var num int
if photoUrl == "" { //如果没有关联画作,数量必须有,需求必须有
//需求必须有
if photoRequire == "" {
return nil, fmt.Errorf("第%d行应该有图片需求", i+1)
}
//转换成功
photoNum, err := strconv.Atoi(strings.TrimSpace(photoNumStr))
if err != nil {
return nil, fmt.Errorf("第%d行图片数量格式错误: '%s',必须是整数", i+1, photoNumStr)
}
// 数量大于
if photoNum <= 0 {
return nil, fmt.Errorf("第%d行图片数量必须大于0当前值: %d", i+1, photoNum)
}
num = photoNum
}
data := excelData{
ArtistName: artistName,
SubNum: subNum,
TikTok: tikTok,
Instagram: instagram,
Desc: desc,
TitleRequire: titleRequire,
ContentRequire: contentRequire,
PhotoRequire: photoRequire,
PhotoUrl: photoUrl,
PhotoNum: num,
LineNum: i, //行数
PhotoDpi: photoDpi,
}
result = append(result, data)
}
return result, nil
}
func getCellValue(f *excelize.File, sheetName string, rowIndex, colIndex int) string {
colName, _ := excelize.ColumnNumberToName(colIndex + 1)
cell := fmt.Sprintf("%s%d", colName, rowIndex+1)
value, err := f.GetCellValue(sheetName, cell)
if err != nil {
log.Printf("读取单元格 %s 失败: %v", cell, err)
return ""
}
return strings.TrimSpace(value)
}
func Test1(c *gin.Context) {
// 创建临时目录
tempDir := "tmp"
if err := os.MkdirAll(tempDir, 0755); err != nil {
}
defer os.RemoveAll(tempDir) // 程序结束时清理整个目录
// 生成唯一文件名
fileName := fmt.Sprintf("%d.jpg", time.Now().Unix())
// 构建文件路径
imgPath := filepath.Join(tempDir, fileName)
// 创建文件
file, err := os.Create(imgPath)
if err != nil {
}
defer file.Close()
log.Printf("文件创建在: %s", imgPath)
// 下载图片到文件
resp, err := http.Get("https://e-cdn.fontree.cn/fontree-fiee/tmp/unzipped/9.23-04/邬小明/90_1758873144.jpg")
if err != nil {
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
}
// 复制到文件
_, err = io.Copy(file, resp.Body)
if err != nil {
}
file.Sync()
fileBytes, err := os.ReadFile(imgPath)
if err != nil {
}
// 上传到桶
BOSClient, err := objstorage.NewOSS(
config.ConfigData.Oss.AccessKeyId,
config.ConfigData.Oss.AccessKeySecret,
config.ConfigData.Oss.Endpoint,
)
_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, fileName, fileBytes)
if err != nil {
return
}
url := fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, fileName)
log.Printf("图片上传成功: %s -> %s", fileName, url)
service.Success(c)
}
func Test(c *gin.Context) {
err := publishImage(publishImageReq{
ArtistName: "荣小松",
SubNum: "FE00062",
Title: "test",
Content: "test",
GeneratePhotoUrl: []string{"0221", "2"},
})
if err != nil {
return
}
service.Success(c)
}
func Test2(c *gin.Context) {
titleList := []string{
"1",
}
var dataList []interface{}
data := []string{
"123123",
}
dataList = append(dataList, &data)
content, err := utils.ToExcelByType(titleList, dataList, "slice", "")
if err != nil {
service.Error(c, err)
return
}
utils.ResponseXls(c, content, "1")
}

View File

@ -0,0 +1,746 @@
package imports
import (
"context"
"errors"
"fmt"
"fonchain-fiee/api/accountFiee"
apiCast "fonchain-fiee/api/cast"
"fonchain-fiee/pkg/config"
"fonchain-fiee/pkg/service"
"io"
"log"
"math/rand"
"net/http"
"os"
"path/filepath"
"strconv"
"sync"
"time"
"github.com/fonchain_enterprise/utils/objstorage"
"go.uber.org/zap"
)
type TaskStatus string
const (
TaskPending TaskStatus = "PENDING" //任务排队中
TaskRunning TaskStatus = "RUNNING" //任务处理中
TaskSuccessful TaskStatus = "SUCCESSFUL" //任务执行成功
TaskFailed TaskStatus = "FAILED" //任务执行失败
TaskCancelled TaskStatus = "CANCELLED" //任务已经取消
TaskCanceled TaskStatus = "UNKNOWN" //任务不存在
)
var (
batchProcessor *BatchProcessor
batchProcessorMutex sync.Mutex
)
const (
StatusIdle = 0 // 空闲中(可执行新任务)
StatusProcessing = 1 // 处理中(只能读取进度)
StatusCompleted = 2 // 已完成(可读取结果)
)
var StatusMap = map[int]string{StatusIdle: "空闲中", StatusProcessing: "处理中", StatusCompleted: "已完成"}
type BatchProcessor struct {
mu sync.RWMutex
taskIdFindTask map[int]*Task //IdFind任务
taskIdFindTaskStatus map[int]bool //IdFind任务状态
taskIdFindSubTaskStatus map[int]map[string]TaskStatus //IdFind子任务状态
pollInterval time.Duration //间隔时间
status int //全局实例状态
}
type Task struct {
StartTime time.Time //任务开始时间
EndTime time.Time //任务结束时间
RetryCount int //重试次数todo暂未使用
TaskId int //任务唯一标识
Data *excelData //导入的初始任务数据
Status TaskStatus //统一千文的错误
Error error //任务调度中的报错
//子任务
SubTaskStatus map[string]TaskStatus //子任务-状态
RequiredCount int //子任务-需要成功的数量
SuccessCount int //子任务-成功数量
FailedCount int //子任务-失败数量
//生成的内容
Title string //生成的标题
Content string //生成的内容
Urls []string //生成的地址
}
// GetBatchProcessorReadOnly 获取只读实例
func GetBatchProcessorReadOnly() *BatchProcessor {
return batchProcessor
}
// GetOrCreateBatchProcessor 获取实例
func GetOrCreateBatchProcessor() *BatchProcessor {
batchProcessorMutex.Lock()
defer batchProcessorMutex.Unlock()
if batchProcessor == nil || batchProcessor.status == StatusCompleted {
batchProcessor = &BatchProcessor{
taskIdFindTask: make(map[int]*Task),
taskIdFindTaskStatus: make(map[int]bool),
taskIdFindSubTaskStatus: make(map[int]map[string]TaskStatus),
pollInterval: 100 * time.Millisecond,
status: StatusIdle,
}
}
return batchProcessor
}
// 设置任务状态
func (p *BatchProcessor) setStatus(status int) {
p.mu.Lock()
defer p.mu.Unlock()
p.status = status
}
// GetStatus 获取当前状态
func (p *BatchProcessor) getStatus() int {
p.mu.RLock()
defer p.mu.RUnlock()
return p.status
}
// GetTaskStatistics 获取实例相关信息
func (p *BatchProcessor) getTaskStatistics() (completed, pending, total int, completedTasks, failedTasks []*Task) {
p.mu.RLock()
defer p.mu.RUnlock()
total = len(p.taskIdFindTask)
for _, task := range p.taskIdFindTask {
if p.taskIdFindTaskStatus[task.TaskId] { //是否转换成功
completed++
if task.Status == TaskSuccessful && task.Error == nil { //转换成功 并且 发布成功
completedTasks = append(completedTasks, task)
} else if task.Status == TaskFailed || task.Error != nil { //转换失败 或者 发布失败
failedTasks = append(failedTasks, task)
}
} else {
pending++
}
}
return completed, pending, total, completedTasks, failedTasks
}
func (p *BatchProcessor) recordSubTaskStatus(taskID int, subTaskID string, status TaskStatus) {
if _, exists := p.taskIdFindSubTaskStatus[taskID]; !exists {
p.taskIdFindSubTaskStatus[taskID] = make(map[string]TaskStatus)
}
p.taskIdFindSubTaskStatus[taskID][subTaskID] = status
// 更新主任务状态
if task, exists := p.taskIdFindTask[taskID]; exists {
switch status {
case TaskSuccessful:
task.SuccessCount++
task.SubTaskStatus[subTaskID] = TaskSuccessful
case TaskFailed:
task.FailedCount++
task.SubTaskStatus[subTaskID] = TaskFailed
case TaskPending:
task.SubTaskStatus[subTaskID] = TaskPending
}
// 检查任务完成状态
p.checkTaskCompletion(taskID)
}
}
// 检查任务是否完成
func (p *BatchProcessor) checkTaskCompletion(taskID int) {
task, exists := p.taskIdFindTask[taskID]
if !exists {
return
}
// 检查是否所有子任务都完成
if task.SuccessCount+task.FailedCount >= len(p.taskIdFindSubTaskStatus[taskID]) {
// 子任务都完成,判断成功数量
if task.SuccessCount >= task.RequiredCount {
// 成功数量满足要求
task.Status = TaskSuccessful
zap.L().Info("任务完成", zap.Int("taskID", taskID), zap.String("status", "success"))
} else {
// 成功数量不满足要求,但所有子任务完成
task.Status = TaskFailed
zap.L().Warn("任务部分成功", zap.Int("taskID", taskID), zap.Int("success", task.SuccessCount), zap.Int("required", task.RequiredCount))
}
task.EndTime = time.Now()
p.taskIdFindTaskStatus[taskID] = true
} else {
zap.L().Info("任务正在进行中", zap.Int("taskID", taskID), zap.String("status", "in progress"))
}
}
// IsAllCompleted 获取任务是否全部完成
func (p *BatchProcessor) IsAllCompleted() bool {
p.mu.RLock()
defer p.mu.RUnlock()
if len(p.taskIdFindTaskStatus) == 0 {
return true
}
// 检查是否所有任务都标记为完成
for _, completed := range p.taskIdFindTaskStatus {
if !completed {
return false
}
}
return true
}
// 获取未完成的任务列表
func (p *BatchProcessor) getIncompleteTasks() []int {
p.mu.RLock()
defer p.mu.RUnlock()
var incomplete []int
for taskID, completed := range p.taskIdFindTaskStatus {
if !completed {
incomplete = append(incomplete, taskID)
}
}
return incomplete
}
// 开始轮询
func (p *BatchProcessor) startPolling() {
go func() {
ticker := time.NewTicker(p.pollInterval)
defer ticker.Stop()
for range ticker.C {
if p.IsAllCompleted() {
p.setStatus(StatusCompleted)
zap.L().Info("所有任务已完成,停止轮询")
break
}
for taskId, isAccomplish := range p.taskIdFindTaskStatus { // 遍历 inProgress 中的任务
if !isAccomplish { // 如果任务未完成
for subTaskId, taskIdTaskStates := range p.taskIdFindSubTaskStatus[taskId] { // 遍历该任务的子任务状态
if taskIdTaskStates == TaskPending { // 如果子任务是待处理状态
if err := p.updateTask(taskId, subTaskId); err != nil {
zap.L().Error("批量更新任务状态失败: %v", zap.Error(err))
continue
}
}
}
}
continue
}
}
}()
}
// 提交一个任务
func (p *BatchProcessor) submitTask(req *excelData) error {
// 获取用户信息
list, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{
Name: req.ArtistName,
SubNum: req.SubNum,
})
if err != nil {
return fmt.Errorf("获取用户信息失败: %s", err.Error())
}
if len(list.UserList) == 0 {
return fmt.Errorf("未找到用户信息: %s", req.ArtistName)
}
// 获取用户详细信息
_, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
ID: list.UserList[0].Id,
Domain: "app",
})
if err != nil {
return fmt.Errorf("获取用户详细信息失败: %s", err.Error())
}
// 获取 TikTok 自媒体账号
accountListTikTok, err := service.CastProvider.MediaUserList(context.Background(), &apiCast.MediaUserListReq{
ArtistVal: req.ArtistName,
PlatformID: 1,
Page: 1,
PageSize: 10,
ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
})
if err != nil {
return fmt.Errorf("获取 TikTok 账号失败: %s", err.Error())
}
if accountListTikTok == nil || len(accountListTikTok.Data) == 0 {
return fmt.Errorf("tiktok自媒体账号数量为0")
}
// 查找 TikTok 账号
tiktokFound := false
for _, user := range accountListTikTok.Data {
if user.PlatformUserName == req.TikTok {
req.MediaAccountNames = append(req.MediaAccountNames, user.PlatformUserName)
req.MediaAccountUuids = append(req.MediaAccountUuids, user.MediaAccountUuid)
tiktokFound = true
break
}
}
if !tiktokFound {
return fmt.Errorf("未找到匹配的TikTok账号: %s", req.TikTok)
}
// 获取 Instagram 自媒体账号
accountListIns, err := service.CastProvider.MediaUserList(context.Background(), &apiCast.MediaUserListReq{
ArtistVal: req.ArtistName,
PlatformID: 3,
Page: 1,
PageSize: 10,
ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
})
if err != nil {
return fmt.Errorf("获取 Instagram 账号失败: %s", err.Error())
}
if accountListIns == nil || len(accountListIns.Data) == 0 {
return fmt.Errorf("ins自媒体账号数量为0")
}
// 查找 Instagram 账号
insFound := false
for _, user := range accountListIns.Data {
if user.PlatformUserName == req.Instagram {
req.MediaAccountNames = append(req.MediaAccountNames, user.PlatformUserName)
req.MediaAccountUuids = append(req.MediaAccountUuids, user.MediaAccountUuid)
insFound = true
break
}
}
if !insFound {
return fmt.Errorf("未找到匹配的Instagram账号: %s", req.Instagram)
}
switch {
case req.PhotoUrl == "": // 如果没有提供照片 URL生成标题和内容
// 生成标题和内容
title, content, err := p.generateTitleAndContent(req)
if err != nil {
zap.L().Error("生成标题和内容失败: %v", zap.Error(err))
return fmt.Errorf("生成标题失败")
}
req.Title = title
req.Content = content
// 请求生成图片
taskIds := make([]string, 0, req.PhotoNum)
for i := 0; i < req.PhotoNum; i++ {
taskId, err := p.generateImage(req)
if err != nil {
zap.L().Error("生成图片失败: %v", zap.Error(err))
p.recordSubTaskStatus(req.LineNum, taskId, TaskFailed)
return fmt.Errorf("生成图片失败")
}
taskIds = append(taskIds, taskId)
p.recordSubTaskStatus(req.LineNum, taskId, TaskPending)
}
// 创建并保存任务
task := &Task{
Data: req,
TaskId: req.LineNum,
Status: TaskPending,
Title: title,
Content: content,
StartTime: time.Now(),
SubTaskStatus: make(map[string]TaskStatus),
RequiredCount: req.PhotoNum, // 需要成功的图片数量
SuccessCount: 0,
FailedCount: 0,
}
p.taskIdFindTask[req.LineNum] = task
p.taskIdFindTaskStatus[req.LineNum] = false
case req.PhotoUrl != "": //如果有图片
task := &Task{
Data: req,
TaskId: req.LineNum,
Status: TaskPending,
StartTime: time.Now(),
RequiredCount: 1, // 单张图片只需要成功1次
SuccessCount: 0,
FailedCount: 0,
SubTaskStatus: make(map[string]TaskStatus),
}
p.recordSubTaskStatus(req.LineNum, strconv.Itoa(req.LineNum), TaskPending)
p.taskIdFindTask[req.LineNum] = task
p.taskIdFindTaskStatus[req.LineNum] = false
}
return nil
}
// 更新任务
func (p *BatchProcessor) updateTask(id int, taskId string) (err error) {
p.mu.Lock()
defer p.mu.Unlock()
// 任务不存在直接返回
task, exists := p.taskIdFindTask[id]
if !exists {
return fmt.Errorf("任务ID %d 不存在", id)
}
switch {
case task.Data.PhotoUrl != "": // 如果有图片 URL生成标题和内容并发布
// 生成标题和内容
title, content, err := p.generateTitleAndContent(task.Data)
if err != nil { //生成标题失败
task.Status = TaskFailed
p.taskIdFindTaskStatus[id] = true
task.EndTime = time.Now()
task.Error = fmt.Errorf("生成标题和内容失败: %s", err.Error())
p.recordSubTaskStatus(id, taskId, TaskFailed)
zap.L().Error("生成标题和内容失败: %v", zap.Error(err))
return err
}
task.Title = title
task.Content = content
// 发布内容
if err = publishImage(publishImageReq{
ArtistName: task.Data.ArtistName,
SubNum: task.Data.SubNum,
Title: task.Title,
Content: task.Content,
TikTok: task.Data.TikTok,
Instagram: task.Data.Instagram,
GeneratePhotoUrl: []string{task.Data.PhotoUrl},
MediaAccountUuids: task.Data.MediaAccountUuids,
MediaAccountNames: task.Data.MediaAccountNames,
}); err != nil { //发布失败
task.Status = TaskFailed
p.taskIdFindTaskStatus[id] = true
task.EndTime = time.Now()
task.Error = fmt.Errorf("发布内容失败: %s", err.Error())
zap.L().Error("发布内容失败: %v", zap.Error(err))
p.recordSubTaskStatus(id, taskId, TaskFailed)
return err
}
//操作成功
p.recordSubTaskStatus(id, taskId, TaskSuccessful)
case task.Data.PhotoUrl == "": // 如果没有图片 URL处理图片生成结果
getTaskDetailRes, err := NewAiGenerator().GetTaskDetail(taskId)
if err != nil { //获取图片结果失败
zap.L().Error("查看图片生成结果失败: %v", zap.Error(err))
task.Error = fmt.Errorf("查看图片生成结果失败")
//task.Status = TaskFailed
//p.inProgress[id] = true
//task.EndTime = time.Now()
p.recordSubTaskStatus(id, taskId, TaskFailed)
return err
}
switch getTaskDetailRes.Output.TaskStatus {
case "SUCCEEDED":
if task.Status != TaskSuccessful {
//上传图片
urls := make([]string, len(getTaskDetailRes.Output.Results))
for i, v := range getTaskDetailRes.Output.Results {
urls[i] = v.URL
}
uploadedURLs, err := downloadAndUploadImages(urls)
if err != nil { //图片上传失败
zap.L().Error("图片上传失败: %v", zap.Error(err))
task.Error = fmt.Errorf("图片上传失败")
//task.Status = TaskFailed
//p.inProgress[id] = true
//task.EndTime = time.Now()
p.recordSubTaskStatus(id, taskId, TaskFailed)
return err
}
task.Urls = append(task.Urls, uploadedURLs...)
p.recordSubTaskStatus(id, taskId, TaskSuccessful)
}
case "FAILED": //第三方返回失败
if task.Status != TaskFailed {
zap.L().Error("第三方生成失败: %v", zap.Error(err))
task.Error = fmt.Errorf("生成失败")
//task.Status = TaskFailed
//p.inProgress[id] = true
//task.EndTime = time.Now()
p.recordSubTaskStatus(id, taskId, TaskFailed)
return err
}
}
p.checkTaskCompletion(id)
if p.taskIdFindTaskStatus[id] == true {
// 发布图文
if err = publishImage(publishImageReq{
ArtistName: task.Data.ArtistName,
SubNum: task.Data.SubNum,
Title: task.Title,
Content: task.Content,
TikTok: task.Data.TikTok,
Instagram: task.Data.Instagram,
MediaAccountUuids: task.Data.MediaAccountUuids,
MediaAccountNames: task.Data.MediaAccountNames,
GeneratePhotoUrl: task.Urls,
}); err != nil { //发布失败
zap.L().Error("发布内容失败: %v", zap.Error(err))
task.Error = fmt.Errorf("发布内容失败")
task.Status = TaskFailed
p.taskIdFindTaskStatus[id] = true
task.EndTime = time.Now()
return err
}
//处理成功
task.Status = TaskSuccessful
p.taskIdFindTaskStatus[id] = true
task.EndTime = time.Now()
}
}
return nil
}
// 批量上传图片
func downloadAndUploadImages(urls []string) ([]string, error) {
var uploadedURLs []string
for _, result := range urls {
if result == "" {
continue
}
// 下载并直接上传到桶
bucketURL, err := downloadAndUploadToBucket(result)
if err != nil {
log.Printf("图片上传失败 [%s]: %v", result, err)
continue
}
uploadedURLs = append(uploadedURLs, bucketURL)
log.Printf("图片上传成功: %s -> %s", result, bucketURL)
}
if len(uploadedURLs) == 0 {
return nil, errors.New("所有图片上传失败")
}
return uploadedURLs, nil
}
// 上传图片到桶里面
func downloadAndUploadToBucket(imageURL string) (string, error) {
// 创建临时目录
tempDir := "tmp"
if err := os.MkdirAll(tempDir, 0755); err != nil {
return "", fmt.Errorf("创建临时目录失败: %v", err)
}
defer os.RemoveAll(tempDir) // 程序结束时清理整个目录
rand.Seed(time.Now().UnixNano())
fileName := fmt.Sprintf("%d%04d.jpg", time.Now().Unix(), rand.Intn(10000))
// 构建文件路径
imgPath := filepath.Join(tempDir, fileName)
// 创建文件
file, err := os.Create(imgPath)
if err != nil {
return "", fmt.Errorf("创建文件失败: %v", err)
}
defer file.Close()
log.Printf("文件创建在: %s", imgPath)
// 下载图片到文件
resp, err := http.Get(imageURL)
if err != nil {
return "", fmt.Errorf("下载图片失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("下载失败,状态码: %d", resp.StatusCode)
}
// 复制到文件
_, err = io.Copy(file, resp.Body)
if err != nil {
return "", fmt.Errorf("保存文件失败: %v", err)
}
file.Sync()
fileBytes, err := os.ReadFile(imgPath)
if err != nil {
return "", fmt.Errorf("读取本地文件失败: %v", err)
}
BOSClient, err := objstorage.NewOSS(
os.Getenv(config.ConfigData.Oss.AccessKeyId),
os.Getenv(config.ConfigData.Oss.AccessKeySecret),
os.Getenv(config.ConfigData.Oss.Endpoint),
)
if BOSClient == nil {
return "", fmt.Errorf("上传文件失败: %v", err)
}
_, err = BOSClient.PutObjectFromBytes(os.Getenv(config.ConfigData.Oss.BucketName), fileName, fileBytes)
if err != nil {
return "", fmt.Errorf("上传文件失败: %v", err)
}
url := fmt.Sprintf("%s/%s", os.Getenv(config.ConfigData.Oss.CdnHost), fileName)
//上传到桶
//BOSClient, err := objstorage.NewOSS(
// config.ConfigData.Oss.AccessKeyId,
// config.ConfigData.Oss.AccessKeySecret,
// config.ConfigData.Oss.Endpoint,
//)
//if BOSClient == nil {
// return "", fmt.Errorf("上传文件失败: %v", err)
//}
//_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, fileName, fileBytes)
//if err != nil {
// return "", fmt.Errorf("上传文件失败: %v", err)
//}
//url := fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, fileName)
return url, nil
}
func (p *BatchProcessor) generateTitleAndContent(req *excelData) (string, string, error) {
if req.PhotoUrl != "" {
title, content, err := NewAiGenerator().GenerateTitleAndContentFromImage(
req.PhotoUrl,
req.TitleRequire,
req.ContentRequire,
)
if err != nil {
return "", "", fmt.Errorf("图生文失败: %v", err)
}
return title, content, nil
} else {
title, content, err := NewAiGenerator().GenerateTitleAndContentFromText(
req.TitleRequire,
req.ContentRequire,
)
if err != nil {
return "", "", fmt.Errorf("生成内容失败: %v", err)
}
return title, content, nil
}
}
func (p *BatchProcessor) generateImage(req *excelData) (string, error) {
prompt := fmt.Sprintf("请根据以下要求生成内容:%s\n", req.PhotoRequire)
if req.Title != "" {
prompt += fmt.Sprintf("1标题%s\n", req.Title) // 关联标题
}
if req.Content != "" {
prompt += fmt.Sprintf("2内容%s\n", req.Content) // 关联内容
}
if req.Desc != "" {
prompt += fmt.Sprintf("3艺人简介%s艺人简介的优先级要低只依据艺人简介的风格", req.Desc)
}
prompt += "\n请基于标题和内容生成单张图片高质量高分辨率。"
prompt += "\n要求不能出现:低质量、残缺、人物正脸、多余的手指、乱码字符和文字、比例不良,场景以国内场景为主"
if req.PhotoDpi == "" {
req.PhotoDpi = "720*1280"
}
result, err := NewAiGenerator().TextToImage(
prompt,
req.PhotoDpi,
1,
)
if err != nil {
return "", err
}
return result.Output.TaskID, nil
}
//func (p *BatchProcessor) StartPolling() {
// go func() {
// ticker := time.NewTicker(p.pollInterval) // 1秒间隔
// defer ticker.Stop()
//
// // 令牌桶控制每秒最多10个请求
// tokenBucket := make(chan struct{}, 10)
//
// // 每秒补充令牌
// go func() {
// refillTicker := time.NewTicker(time.Second)
// defer refillTicker.Stop()
//
// for {
// select {
// case <-refillTicker.C:
// // 每秒补充到10个令牌
// for i := 0; i < 10-len(tokenBucket); i++ {
// select {
// case tokenBucket <- struct{}{}:
// default:
// // 桶已满,跳过
// }
// }
// }
// }
// }()
//
// for range ticker.C {
// if p.IsAllCompleted() {
// p.SetStatus(StatusCompleted)
// zap.L().Info("所有任务已完成,停止轮询")
// ticker.Stop()
// break
// }
//
// // 获取未完成的任务
// incompleteTasks := p.getIncompleteTasks()
// if len(incompleteTasks) == 0 {
// continue
// }
//
// // 处理当前可用的任务最多10个
// processedCount := 0
// for _, taskID := range incompleteTasks {
// if processedCount >= 10 {
// break // 本秒已达到10个请求限制
// }
//
// select {
// case <-tokenBucket:
// // 获取到令牌,可以发送请求
// processedCount++
// go p.updateTaskWithToken(taskID, tokenBucket)
// default:
// // 没有令牌了,跳过
// break
// }
// }
//
// zap.L().Debug("本轮处理任务数量",
// zap.Int("processed", processedCount),
// zap.Int("remaining", len(incompleteTasks)-processedCount))
// }
// }()
//}
//
//// 使用令牌更新任务状态
//func (p *BatchProcessor) updateTaskWithToken(taskID string, tokenBucket chan struct{}) {
// defer func() {
// // 任务完成后不返还令牌,由定时器统一补充
// }()
//
// if err := p.UpdateTaskStatuses(taskID); err != nil {
// zap.L().Error("更新任务状态失败",
// zap.String("task_id", taskID),
// zap.Error(err))
// }
//}

View File

@ -0,0 +1,107 @@
package imports
import (
"context"
"fmt"
"fonchain-fiee/api/accountFiee"
apiCast "fonchain-fiee/api/cast"
"fonchain-fiee/pkg/service"
"strconv"
)
func publishImage(req publishImageReq) (err error) {
var infoResp *accountFiee.UserInfoResponse
list, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{
Name: req.ArtistName,
SubNum: req.SubNum,
})
if err != nil {
return fmt.Errorf("获取用户信息失败: %s", err.Error())
}
if len(list.UserList) == 0 {
return fmt.Errorf("未找到用户信息: %s", req.ArtistName)
}
if len(list.UserList) > 0 {
infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
ID: list.UserList[0].Id,
Domain: "app",
})
if err != nil {
return fmt.Errorf("获取用户信息失败: %s", err.Error())
}
}
//-----------------------------------------------------获取自媒体账号
//accountList, err := service.CastProvider.MediaUserList(context.Background(), &apiCast.MediaUserListReq{
// ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
// ArtistVal: req.ArtistName,
// Page: 1,
// PageSize: 10,
//})
//if err != nil {
// return fmt.Errorf("自媒体账号数量获取失败: %s,账号数量:%d", err.Error(), len(accountList.Data))
//}
//if accountList == nil || len(accountList.Data) == 0 {
// return fmt.Errorf("自媒体账号数量为0")
//}
//var mediaAccountUuids []string
//var mediaAccountNames []string
//platformIDs 1 tiktok 2youtube 3ins
//platformIDs := []apiCast.PlatformIDENUM{}
//for _, info := range accountList.Data {
// if info.ArtistName == req.TikTok || info.ArtistName == req.Instagram {
// mediaAccountUuids = append(mediaAccountUuids, info.MediaAccountUuid)
// mediaAccountNames = append(mediaAccountNames, info.PlatformUserName)
// platformIDs = append(platformIDs, apiCast.PlatformIDENUM(info.PlatformID))
// }
//}
//---------------------------------------------------发布
_, err = service.CastProvider.UpdateWorkImage(context.Background(), &apiCast.UpdateWorkImageReq{
Title: req.Title,
Content: req.Content,
Images: req.GeneratePhotoUrl,
MediaAccountUuids: req.MediaAccountUuids,
MediaAccountNames: req.MediaAccountNames,
PlatformIDs: []apiCast.PlatformIDENUM{1, 3},
PublishConfig1: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 1,
IsAI: 1,
PublicType: 1,
},
PublishConfig2: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 1,
IsAI: 1,
PublicType: 1,
},
PublishConfig3: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 1,
IsAI: 1,
PublicType: 1,
},
PublishConfig4: nil,
Action: "submit",
ArtistPhone: infoResp.TelNum,
ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
ArtistName: infoResp.Name,
ArtistPhoneAreaCode: infoResp.TelAreaCode,
WorkUuid: "",
Source: 2,
LineNo: 0,
Remark: "",
Success: false,
})
if err != nil {
return fmt.Errorf("发布"+req.ArtistName+"图文"+"失败: %s", err.Error())
}
return nil
}

View File

@ -182,6 +182,22 @@ func GetRecentAssignRecords(c *gin.Context) {
service.Success(c, res)
}
func AddHiddenTaskAssignee(c *gin.Context) {
var req bundle.AddHiddenTaskAssigneeRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
res, err := service.BundleProvider.AddHiddenTaskAssignee(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}
// GetEmployeeAssignedTasks 根据登录人信息查询被指派给该员工的任务
func GetEmployeeAssignedTasks(c *gin.Context) {
var req bundle.EmployeeTaskQueryRequest
@ -553,7 +569,7 @@ func GetArtistUploadStatsListDownload(c *gin.Context) {
}
titleList := []string{
"用户编号", "艺人", "手机号", "最近一次指派人", "待上传视频脚本数", "已上传视频脚本数", "待上传视频数", "已上传视频数", "已释放视频额度", "套餐视频总数", "增值视频总数", "上传图文数", "已上传图文数", "已释放图文额度", "套餐图文总数", "增值图文总数", "上传数据数", "已上传数据数", "已释放数据额度", "套餐数据总数", "增值数据总数", "进行中任务数", "已完成任务数",
"用户编号", "艺人", "手机号", "最近一次指派人", "可指派视频脚本数", "可上传视频脚本数", "已上传视频脚本数", "可指派视频数", "可上传视频数", "已上传视频数", "已释放视频额度", "套餐视频总数", "增值视频总数", "可指派图文数", "可上传图文数", "已上传图文数", "已释放图文额度", "套餐图文总数", "增值图文总数", "可指派数据数", "可上传数据数", "已上传数据数", "已释放数据额度", "套餐数据总数", "增值数据总数", "进行中任务数", "已完成任务数",
}
var dataList []interface{}
@ -563,18 +579,22 @@ func GetArtistUploadStatsListDownload(c *gin.Context) {
i.ArtistName,
i.TelNum,
i.LastTaskAssignee,
i.AllowVideoScriptCount,
i.PendingVideoScriptCount,
i.UploadedVideoScriptCount,
i.AllowVideoCount,
i.PendingVideoCount,
i.UploadedVideoCount,
i.ReleasedVideoTotal,
i.BundleVideoTotal,
i.IncreaseVideoTotal,
i.AllowPostCount,
i.PendingPostCount,
i.UploadedPostCount,
i.ReleasedPostTotal,
i.BundlePostTotal,
i.IncreasePostTotal,
i.AllowDataCount,
i.PendingDataAnalysisCount,
i.UploadedDataAnalysisCount,
i.ReleasedDataAnalysisTotal,
@ -659,3 +679,19 @@ func UpdateVideoScriptWithUUID(ctx *gin.Context) {
service.Success(ctx, resp)
return
}
func GetPendingAssign(c *gin.Context) {
var req bundle.PendingAssignRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
res, err := service.BundleProvider.GetPendingAssign(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}