Skip to content

Commit ae8ff0b

Browse files
committed
fix: remove x-wf-file_name in convert
1 parent a7d0eee commit ae8ff0b

File tree

10 files changed

+255
-38
lines changed

10 files changed

+255
-38
lines changed

backend/api/handler/coze/workflow_service_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,7 +2454,7 @@ func TestStartNodeDefaultValues(t *testing.T) {
24542454
result, _ := r.openapiSyncRun(idStr, input)
24552455
assert.Equal(t, result, map[string]any{
24562456
"ts": "2025-07-09 21:43:34",
2457-
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image?x-wf-file_name=20250317-154742.jpeg",
2457+
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image",
24582458
"str": "str",
24592459
"object": map[string]any{
24602460
"a": "1",
@@ -2478,7 +2478,7 @@ func TestStartNodeDefaultValues(t *testing.T) {
24782478
result, _ := r.openapiSyncRun(idStr, input)
24792479
assert.Equal(t, result, map[string]any{
24802480
"ts": "2025-07-09 21:43:34",
2481-
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image?x-wf-file_name=20250317-154742.jpeg",
2481+
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image",
24822482
"str": "str",
24832483
"object": map[string]any{
24842484
"a": "1",
@@ -2503,7 +2503,7 @@ func TestStartNodeDefaultValues(t *testing.T) {
25032503
result, _ := r.openapiSyncRun(idStr, input)
25042504
assert.Equal(t, result, map[string]any{
25052505
"ts": "2025-07-09 21:43:34",
2506-
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image?x-wf-file_name=20250317-154742.jpeg",
2506+
"files": "http://imagex.fanlv.fun/tos-cn-i-1heqlfnr21/e81acc11277f421390770618e24e01ce.jpeg~tplv-1heqlfnr21-image.image",
25072507
"str": "value",
25082508
"object": map[string]any{
25092509
"a": "1",

backend/api/model/crossdomain/workflow/workflow.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type ExecuteConfig struct {
5656
ConversationHistorySchemaMessages []*schema.Message
5757
SectionID *int64
5858
MaxHistoryRounds *int32
59+
InputFileFields map[string]*FileInfo
5960
}
6061

6162
type ExecuteMode string
@@ -91,3 +92,9 @@ const (
9192
BizTypeAgent BizType = "agent"
9293
BizTypeWorkflow BizType = "workflow"
9394
)
95+
96+
type FileInfo struct {
97+
FileURL string `json:"file_url"`
98+
FileName string `json:"file_name"`
99+
FileExtension string `json:"file_extension"`
100+
}

backend/domain/workflow/entity/vo/node.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package vo
1919
import (
2020
"errors"
2121
"fmt"
22-
2322
"github.com/cloudwego/eino/compose"
2423
"github.com/cloudwego/eino/schema"
2524

@@ -44,8 +43,14 @@ type Reference struct {
4443
}
4544

4645
type FieldSource struct {
47-
Ref *Reference `json:"ref,omitempty"`
48-
Val any `json:"val,omitempty"`
46+
Ref *Reference `json:"ref,omitempty"`
47+
Val any `json:"val,omitempty"`
48+
FileExtra *FileExtra `json:"file_extra,omitempty"`
49+
}
50+
51+
type FileExtra struct {
52+
FileName *string `json:"file_name,omitempty"`
53+
FileNames []string `json:"file_names,omitempty"`
4954
}
5055

5156
type TypeInfo struct {
@@ -66,6 +71,11 @@ type NamedTypeInfo struct {
6671
Properties []*NamedTypeInfo `json:"properties,omitempty"`
6772
}
6873

74+
// type FileInfo struct {
75+
// FileURL string `json:"file_url"`
76+
// FileName string `json:"file_name"`
77+
// FileExtension string `json:"file_extension"`
78+
// }
6979
type ErrorLevel string
7080

7181
const (

backend/domain/workflow/internal/canvas/adaptor/canvas_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,20 @@ func TestKnowledgeDeleter(t *testing.T) {
731731
UserID: 123,
732732
})
733733

734+
defer mockey.Mock(execute.GetExeCtx).Return(&execute.Context{
735+
RootCtx: execute.RootCtx{
736+
ExeCfg: workflowModel.ExecuteConfig{
737+
InputFileFields: map[string]*workflowModel.FileInfo{
738+
"https://p26-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/5264fa1295da4a6483cd236b1316c454.pdf~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1782379180&x-signature=mlaXPIk9VJjOXu87xGaRmNRg9%2BA%3D": &workflowModel.FileInfo{
739+
FileName: "1706.03762v7.pdf",
740+
FileURL: "https://p26-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/5264fa1295da4a6483cd236b1316c454.pdf~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1782379180&x-signature=mlaXPIk9VJjOXu87xGaRmNRg9%2BA%3D",
741+
FileExtension: ".pdf",
742+
},
743+
},
744+
},
745+
},
746+
}).Build().UnPatch()
747+
734748
workflowSC, err := CanvasToWorkflowSchema(ctx, c)
735749
assert.NoError(t, err)
736750

backend/domain/workflow/internal/canvas/convert/type_convert.go

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ package convert
1818

1919
import (
2020
"fmt"
21+
2122
"strconv"
2223
"strings"
2324

2425
einoCompose "github.com/cloudwego/eino/compose"
2526

2627
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
2728
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
29+
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
2830
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
2931
"github.com/coze-dev/coze-studio/backend/types/errno"
3032
)
@@ -180,7 +182,10 @@ func CanvasBlockInputToFieldInfo(b *vo.BlockInput, path einoCompose.FieldPath, p
180182
if value == nil {
181183
return nil, fmt.Errorf("input %v has no value, type= %s", path, b.Type)
182184
}
183-
185+
var fileExtra *vo.FileExtra
186+
isFileAssistType := func(assistType vo.AssistType) bool {
187+
return assistType >= vo.AssistTypeDefault && assistType <= vo.AssistTypeVoice
188+
}
184189
switch value.Type {
185190
case vo.BlockInputValueTypeObjectRef:
186191
sc := b.Schema
@@ -214,7 +219,6 @@ func CanvasBlockInputToFieldInfo(b *vo.BlockInput, path einoCompose.FieldPath, p
214219
if content == nil {
215220
return nil, fmt.Errorf("input %v is literal but has no value, type= %s", path, b.Type)
216221
}
217-
218222
switch b.Type {
219223
case vo.VariableTypeObject:
220224
m := make(map[string]any)
@@ -223,11 +227,43 @@ func CanvasBlockInputToFieldInfo(b *vo.BlockInput, path einoCompose.FieldPath, p
223227
}
224228
content = m
225229
case vo.VariableTypeList:
226-
l := make([]any, 0)
227-
if err = sonic.UnmarshalString(content.(string), &l); err != nil {
228-
return nil, err
230+
switch content.(type) {
231+
case string:
232+
if _, ok := content.(string); ok {
233+
l := make([]any, 0)
234+
if err = sonic.UnmarshalString(content.(string), &l); err != nil {
235+
return nil, err
236+
}
237+
content = l
238+
}
239+
case []string:
240+
content = content.([]string)
241+
case []any:
242+
content = content.([]any)
243+
default:
244+
return nil, fmt.Errorf("unsupported variable type fot list: %s", b.Type)
245+
}
246+
eleSchema, err := vo.ParseVariable(b.Schema)
247+
if err != nil {
248+
return nil, fmt.Errorf("can not parse schema from %v", b.Schema)
249+
}
250+
251+
if isFileAssistType(eleSchema.AssistType) {
252+
rawMeta, ok := b.Value.RawMeta.(map[string]any)
253+
if ok {
254+
filenames, ok := rawMeta["fileName"].([]any)
255+
if !ok {
256+
return nil, fmt.Errorf("can not get filename from %v", rawMeta)
257+
}
258+
fileExtra = &vo.FileExtra{
259+
FileNames: make([]string, 0, len(filenames)),
260+
}
261+
for _, filename := range filenames {
262+
fileExtra.FileNames = append(fileExtra.FileNames, filename.(string))
263+
}
264+
}
265+
229266
}
230-
content = l
231267
case vo.VariableTypeInteger:
232268
switch content.(type) {
233269
case string:
@@ -268,13 +304,27 @@ func CanvasBlockInputToFieldInfo(b *vo.BlockInput, path einoCompose.FieldPath, p
268304
default:
269305
return nil, fmt.Errorf("unsupported variable type for boolean: %s", b.Type)
270306
}
307+
case vo.VariableTypeString:
308+
if isFileAssistType(b.AssistType) {
309+
rawMeta, ok := b.Value.RawMeta.(map[string]any)
310+
if ok {
311+
filename, ok := rawMeta["fileName"].(string)
312+
if !ok {
313+
return nil, fmt.Errorf("can not get filename from %v", rawMeta)
314+
}
315+
fileExtra = &vo.FileExtra{
316+
FileName: ptr.Of(filename),
317+
}
318+
}
319+
}
271320
default:
272321
}
273322
return []*vo.FieldInfo{
274323
{
275324
Path: path,
276325
Source: vo.FieldSource{
277-
Val: content,
326+
Val: content,
327+
FileExtra: fileExtra,
278328
},
279329
},
280330
}, nil
@@ -466,8 +516,8 @@ func SetInputsForNodeSchema(n *vo.Node, ns *schema.NodeSchema) error {
466516
if err != nil {
467517
return err
468518
}
469-
470519
ns.AddInputSource(sources...)
520+
471521
}
472522

473523
return nil

backend/domain/workflow/internal/compose/state.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func init() {
8585
_ = compose.RegisterSerializableType[*vo.TypeInfo]("type_info")
8686
_ = compose.RegisterSerializableType[vo.DataType]("data_type")
8787
_ = compose.RegisterSerializableType[vo.FileSubType]("file_sub_type")
88+
_ = compose.RegisterSerializableType[*workflowModel.FileInfo]("file_info")
8889
}
8990

9091
func (s *State) GetNodeCtx(key vo.NodeKey) (*execute.Context, bool, error) {

backend/domain/workflow/internal/nodes/convert.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23+
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
24+
"net/url"
25+
"path/filepath"
2326
"strconv"
2427
"strings"
2528

@@ -127,9 +130,23 @@ func ConvertInputs(ctx context.Context, in map[string]any, tInfo map[string]*vo.
127130
}
128131

129132
type convertOptions struct {
130-
skipUnknownFields bool
131-
failFast bool
132-
skipRequireCheck bool
133+
skipUnknownFields bool
134+
failFast bool
135+
skipRequireCheck bool
136+
collectFileFields map[string]*workflowModel.FileInfo
137+
notNeedTrimQueryFileName bool
138+
}
139+
140+
func WithCollectFileFields(fs map[string]*workflowModel.FileInfo) ConvertOption {
141+
return func(o *convertOptions) {
142+
o.collectFileFields = fs
143+
}
144+
}
145+
146+
func WithNotNeedTrimQueryFileName(b bool) ConvertOption {
147+
return func(o *convertOptions) {
148+
o.notNeedTrimQueryFileName = b
149+
}
133150
}
134151

135152
type ConvertOption func(*convertOptions)
@@ -161,15 +178,52 @@ func Convert(ctx context.Context, in any, path string, t *vo.TypeInfo, opts ...C
161178
return convert(ctx, in, path, t, options)
162179
}
163180

181+
func adaptorFileURL(in string) (string, *workflowModel.FileInfo, error) {
182+
u, err := url.Parse(in)
183+
if err != nil {
184+
return "", nil, err
185+
}
186+
query := u.Query()
187+
fileName := query.Get("x-wf-file_name")
188+
fileInfo := &workflowModel.FileInfo{
189+
FileName: fileName,
190+
FileExtension: filepath.Ext(fileName),
191+
}
192+
query.Del("x-wf-file_name")
193+
u.RawQuery = query.Encode()
194+
fileInfo.FileURL = u.String()
195+
return u.String(), fileInfo, nil
196+
}
197+
164198
func convert(ctx context.Context, in any, path string, t *vo.TypeInfo, options *convertOptions) (
165199
any, *ConversionWarnings, error) {
166200
if in == nil { // nil is valid for ALL types
167201
return nil, nil, nil
168202
}
169203

170204
switch t.Type {
171-
case vo.DataTypeString, vo.DataTypeFile, vo.DataTypeTime:
205+
case vo.DataTypeString, vo.DataTypeTime:
172206
return convertToString(ctx, in, path, options)
207+
case vo.DataTypeFile:
208+
ret, warns, err := convertToString(ctx, in, path, options)
209+
if err != nil {
210+
return nil, nil, err
211+
}
212+
if warns != nil {
213+
return ret, warns, nil
214+
}
215+
216+
fileURL, fileInfo, err := adaptorFileURL(ret.(string))
217+
if err != nil {
218+
return nil, nil, err
219+
}
220+
if options.collectFileFields != nil {
221+
options.collectFileFields[fileInfo.FileURL] = fileInfo
222+
}
223+
if options.notNeedTrimQueryFileName {
224+
return ret, nil, nil
225+
}
226+
return fileURL, nil, nil
173227
case vo.DataTypeInteger:
174228
return convertToInt64(ctx, in, path, options)
175229
case vo.DataTypeNumber:

backend/domain/workflow/internal/nodes/knowledge/knowledge_indexer.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
"net/url"
2423
"path/filepath"
24+
25+
"net/url"
2526
"strings"
2627

2728
"github.com/spf13/cast"
@@ -31,6 +32,7 @@ import (
3132
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
3233
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
3334
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
35+
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
3436
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
3537
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
3638
"github.com/coze-dev/coze-studio/backend/infra/contract/document/parser"
@@ -125,7 +127,7 @@ func (k *Indexer) Invoke(ctx context.Context, input map[string]any) (map[string]
125127
return nil, errors.New("knowledge is required")
126128
}
127129

128-
fileName, ext, err := parseToFileNameAndFileExtension(fileURL)
130+
fileName, ext, err := parseToFileNameAndFileExtension(ctx, fileURL)
129131

130132
if err != nil {
131133
return nil, err
@@ -153,23 +155,25 @@ func (k *Indexer) Invoke(ctx context.Context, input map[string]any) (map[string]
153155
return result, nil
154156
}
155157

156-
func parseToFileNameAndFileExtension(fileURL string) (string, parser.FileExtension, error) {
157-
158-
u, err := url.Parse(fileURL)
159-
if err != nil {
160-
return "", "", err
161-
}
162-
163-
fileName := u.Query().Get("x-wf-file_name")
164-
if len(fileName) == 0 {
165-
return "", "", errors.New("file name is required")
166-
}
167-
168-
fileExt := strings.ToLower(strings.TrimPrefix(filepath.Ext(fileName), "."))
169-
170-
ext, support := parser.ValidateFileExtension(fileExt)
158+
func parseToFileNameAndFileExtension(ctx context.Context, fileURL string) (string, parser.FileExtension, error) {
159+
inputFileFields := execute.GetExeCtx(ctx).ExeCfg.InputFileFields
160+
fileInfo, ok := inputFileFields[fileURL]
161+
if !ok {
162+
u, err := url.Parse(fileURL)
163+
if err != nil {
164+
return "", "", err
165+
}
166+
fileExt := filepath.Ext(strings.ToLower(strings.TrimPrefix(u.Path, ".")))
167+
ext, support := parser.ValidateFileExtension(fileExt)
168+
if !support {
169+
return "", "", fmt.Errorf("unsupported file type: %s", fileExt)
170+
}
171+
return u.Path, ext, nil
172+
}
173+
ext, support := parser.ValidateFileExtension(strings.ToLower(strings.TrimPrefix(fileInfo.FileExtension, ".")))
171174
if !support {
172-
return "", "", fmt.Errorf("unsupported file type: %s", fileExt)
175+
return "", "", fmt.Errorf("unsupported file type: %s", fileInfo.FileExtension)
173176
}
174-
return fileName, ext, nil
177+
return fileInfo.FileName, ext, nil
178+
175179
}

0 commit comments

Comments
 (0)