Skip to content

Commit 0a60357

Browse files
authored
feat(studio): init studio dsl2saa (#2270)
1 parent b1b0355 commit 0a60357

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+613
-131
lines changed

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/frontend/packages/main/src/pages/App/Workflow/index.tsx

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import {
7070
} from './types';
7171
import { getMCPNodeInputParams } from './utils';
7272
import { transformToBizData, transformToFlowData } from './utils/transform';
73+
import { convertDifyToSpringAI } from '@/services/difyConverter';
7374

7475
interface IProps {
7576
onSave: (data: IBizFlowData) => void;
@@ -81,12 +82,13 @@ interface IProps {
8182
interface IFlowBaseProps extends Omit<IProps, 'setActiveTab' | 'onSave'> {
8283
actionLoading: boolean;
8384
handlePublish: () => void;
85+
handleExportSAA: () => void;
8486
}
8587

8688
const lang = $i18n.getCurrentLanguage();
8789

8890
export const FlowBase = memo((props: IFlowBaseProps) => {
89-
const { actionLoading, init, appDetail, handlePublish } = props;
91+
const { actionLoading, init, appDetail, handlePublish, handleExportSAA } = props;
9092
const setShowTest = useWorkflowAppStore((state) => state.setShowTest);
9193
const { initDebug } = useInitDebug();
9294
const portal = useInnerLayout();
@@ -191,6 +193,13 @@ export const FlowBase = memo((props: IFlowBaseProps) => {
191193
</Button>
192194
<CheckListBtn />
193195
</Space.Compact>
196+
{/* 新增“导出SAA工程代码”按钮 */}
197+
<Button
198+
disabled={actionLoading}
199+
onClick={handleExportSAA}
200+
>
201+
导出SAA工程代码
202+
</Button>
194203
<Button
195204
disabled={actionLoading}
196205
onClick={() => {
@@ -274,6 +283,55 @@ export const FlowEditor = memo((props: IProps) => {
274283
});
275284
}, []);
276285

286+
const handleExportSAA = useCallback(async () => {
287+
if (!props.appDetail) return;
288+
289+
console.log(props.appDetail);
290+
291+
setActionLoading(true);
292+
try {
293+
// 准备请求参数
294+
const params = {
295+
dependencies: 'spring-ai-alibaba-graph,web,spring-ai-alibaba-starter-dashscope',
296+
appMode: 'workflow',
297+
dslDialectType: 'studio',
298+
type: 'maven-project',
299+
language: 'java',
300+
bootVersion: '3.5.0',
301+
baseDir: 'demo',
302+
groupId: 'com.example',
303+
artifactId: 'demo',
304+
name: 'demo',
305+
description: 'Demo project for Spring Boot',
306+
packageName: 'com.example.demo',
307+
packaging: 'jar',
308+
javaVersion: '17',
309+
dsl: JSON.stringify(props.appDetail),
310+
};
311+
312+
// 调用转换服务
313+
const response = await convertDifyToSpringAI(params);
314+
315+
// 处理 zip 文件下载
316+
const blob = response.data;
317+
const url = window.URL.createObjectURL(blob);
318+
const link = document.createElement('a');
319+
link.href = url;
320+
link.download = 'spring-ai-alibaba-demo.zip';
321+
document.body.appendChild(link);
322+
link.click();
323+
document.body.removeChild(link);
324+
window.URL.revokeObjectURL(url);
325+
326+
message.success('转换成功!项目文件已开始下载');
327+
} catch (error) {
328+
console.error('转换失败:', error);
329+
message.error(`转换失败:${error.message || '请重试'}`);
330+
} finally {
331+
setActionLoading(false); // 重置加载状态
332+
}
333+
}, [props.appDetail]);
334+
277335
const handleSave = useCallback(
278336
async (data: { nodes: IWorkFlowNode[]; edges: Edge[] }) => {
279337
setActionLoading(true);
@@ -413,6 +471,7 @@ export const FlowEditor = memo((props: IProps) => {
413471
appDetail={props.appDetail}
414472
actionLoading={actionLoading}
415473
handlePublish={handlePublish}
474+
handleExportSAA={handleExportSAA}
416475
init={props.init}
417476
/>
418477

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/frontend/packages/main/src/pages/Dify/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const DifyConverter: React.FC = () => {
6363
const params = {
6464
dependencies: 'spring-ai-alibaba-graph,web,spring-ai-alibaba-starter-dashscope',
6565
appMode: 'workflow',
66+
dslDialectType: 'dify',
6667
type: 'maven-project',
6768
language: 'java',
6869
bootVersion: '3.5.0',

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/frontend/packages/main/src/services/difyConverter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { request } from '@/request';
33
export interface DifyConvertParams {
44
dependencies: string;
55
appMode: string;
6+
dslDialectType: string;
67
type: string;
78
language: string;
89
bootVersion: string;

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/model/workflow/Edge.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public class Edge {
3333

3434
private Integer zIndex = 0;
3535

36+
// Temp field
37+
private boolean isDify = true;
38+
3639
public String getId() {
3740
return id;
3841
}
@@ -96,4 +99,13 @@ public Edge setzIndex(Integer zIndex) {
9699
return this;
97100
}
98101

102+
public boolean isDify() {
103+
return isDify;
104+
}
105+
106+
public Edge setDify(boolean isDify) {
107+
this.isDify = isDify;
108+
return this;
109+
}
110+
99111
}

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/model/workflow/NodeType.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,55 +20,58 @@
2020

2121
public enum NodeType {
2222

23-
START("start", "start"),
23+
START("start", "start", "Start"),
2424

25-
END("end", "end"),
25+
END("end", "end", "End"),
2626

27-
ANSWER("answer", "answer"),
27+
ANSWER("answer", "answer", "UNSUPPORTED"),
2828

29-
AGENT("agent", "agent"),
29+
AGENT("agent", "agent", "UNSUPPORTED"),
3030

31-
LLM("llm", "llm"),
31+
LLM("llm", "llm", "UNSUPPORTED"),
3232

33-
CODE("code", "code"),
33+
CODE("code", "code", "UNSUPPORTED"),
3434

35-
RETRIEVER("retriever", "knowledge-retrieval"),
35+
RETRIEVER("retriever", "knowledge-retrieval", "UNSUPPORTED"),
3636

37-
AGGREGATOR("aggregator", "variable-aggregator"),
37+
AGGREGATOR("aggregator", "variable-aggregator", "UNSUPPORTED"),
3838

39-
HUMAN("human", "unsupported"),
39+
HUMAN("human", "unsupported", "UNSUPPORTED"),
4040

41-
BRANCH("branch", "if-else"),
41+
BRANCH("branch", "if-else", "UNSUPPORTED"),
4242

43-
DOC_EXTRACTOR("document-extractor", "document-extractor"),
43+
DOC_EXTRACTOR("document-extractor", "document-extractor", "UNSUPPORTED"),
4444

45-
QUESTION_CLASSIFIER("question-classifier", "question-classifier"),
45+
QUESTION_CLASSIFIER("question-classifier", "question-classifier", "UNSUPPORTED"),
4646

47-
HTTP("http", "http-request"),
47+
HTTP("http", "http-request", "UNSUPPORTED"),
4848

49-
LIST_OPERATOR("list-operator", "list-operator"),
49+
LIST_OPERATOR("list-operator", "list-operator", "UNSUPPORTED"),
5050

51-
PARAMETER_PARSING("parameter-parsing", "parameter-extractor"),
51+
PARAMETER_PARSING("parameter-parsing", "parameter-extractor", "UNSUPPORTED"),
5252

53-
TOOL("tool", "tool"),
53+
TOOL("tool", "tool", "UNSUPPORTED"),
5454

55-
MCP("mcp", "unsupported"),
55+
MCP("mcp", "unsupported", "UNSUPPORTED"),
5656

57-
TEMPLATE_TRANSFORM("template-transform", "template-transform"),
57+
TEMPLATE_TRANSFORM("template-transform", "template-transform", "UNSUPPORTED"),
5858

59-
ITERATION("iteration", "iteration"),
59+
ITERATION("iteration", "iteration", "UNSUPPORTED"),
6060

61-
DIFY_ITERATION_START("__empty__", "iteration-start"),
61+
DIFY_ITERATION_START("__empty__", "iteration-start", "UNSUPPORTED"),
6262

63-
ASSIGNER("assigner", "assigner");
63+
ASSIGNER("assigner", "assigner", "UNSUPPORTED");
6464

6565
private final String value;
6666

6767
private final String difyValue;
6868

69-
NodeType(String value, String difyValue) {
69+
private final String studioValue;
70+
71+
NodeType(String value, String difyValue, String studioValue) {
7072
this.value = value;
7173
this.difyValue = difyValue;
74+
this.studioValue = studioValue;
7275
}
7376

7477
public String value() {
@@ -79,6 +82,10 @@ public String difyValue() {
7982
return this.difyValue;
8083
}
8184

85+
public String studioValue() {
86+
return this.studioValue;
87+
}
88+
8289
public static Optional<NodeType> fromValue(String value) {
8390
return Arrays.stream(NodeType.values()).filter(nodeType -> nodeType.value.equals(value)).findFirst();
8491
}
@@ -87,4 +94,10 @@ public static Optional<NodeType> fromDifyValue(String difyValue) {
8794
return Arrays.stream(NodeType.values()).filter(nodeType -> nodeType.difyValue.equals(difyValue)).findFirst();
8895
}
8996

97+
public static Optional<NodeType> fromStudioValue(String studioValue) {
98+
return Arrays.stream(NodeType.values())
99+
.filter(nodeType -> nodeType.studioValue.equals(studioValue))
100+
.findFirst();
101+
}
102+
90103
}

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/model/workflow/nodedata/EndNodeData.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public static Variable getDefaultOutputSchema() {
2828
return new Variable("output", VariableType.ARRAY_STRING.value());
2929
}
3030

31+
private String outputKey;
32+
33+
private String outputType;
34+
35+
private String textTemplate;
36+
3137
public String getOutputKey() {
3238
return outputKey;
3339
}
@@ -37,7 +43,21 @@ public EndNodeData setOutputKey(String outputKey) {
3743
return this;
3844
}
3945

40-
private String outputKey;
46+
public String getOutputType() {
47+
return outputType;
48+
}
49+
50+
public void setOutputType(String outputType) {
51+
this.outputType = outputType;
52+
}
53+
54+
public String getTextTemplate() {
55+
return textTemplate;
56+
}
57+
58+
public void setTextTemplate(String textTemplate) {
59+
this.textTemplate = textTemplate;
60+
}
4161

4262
public EndNodeData() {
4363
}

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/model/workflow/nodedata/StartNodeData.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ public class StartNodeData extends NodeData {
2525

2626
private List<StartInput> startInputs;
2727

28-
private String outputKey;
29-
3028
public StartNodeData() {
3129
}
3230

@@ -43,15 +41,6 @@ public StartNodeData setStartInputs(List<StartInput> startInputs) {
4341
return this;
4442
}
4543

46-
public String getOutputKey() {
47-
return outputKey;
48-
}
49-
50-
public StartNodeData setOutputKey(String outputKey) {
51-
this.outputKey = outputKey;
52-
return this;
53-
}
54-
5544
public static class StartInput {
5645

5746
private String label;

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/service/dsl/AbstractDSLAdapter.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
*/
1616
package com.alibaba.cloud.ai.studio.admin.generator.service.dsl;
1717

18+
import java.util.List;
1819
import java.util.Map;
1920
import java.util.stream.Collectors;
2021
import java.util.stream.Stream;
2122

2223
import com.alibaba.cloud.ai.studio.admin.generator.model.App;
2324
import com.alibaba.cloud.ai.studio.admin.generator.model.AppMetadata;
2425
import com.alibaba.cloud.ai.studio.admin.generator.model.chatbot.ChatBot;
26+
import com.alibaba.cloud.ai.studio.admin.generator.model.workflow.NodeData;
27+
import com.alibaba.cloud.ai.studio.admin.generator.model.workflow.NodeType;
2528
import com.alibaba.cloud.ai.studio.admin.generator.model.workflow.Workflow;
2629

2730
/**
@@ -31,6 +34,23 @@ public abstract class AbstractDSLAdapter implements DSLAdapter {
3134

3235
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractDSLAdapter.class);
3336

37+
protected final List<NodeDataConverter<? extends NodeData>> nodeDataConverters;
38+
39+
protected final Serializer serializer;
40+
41+
protected AbstractDSLAdapter(List<NodeDataConverter<? extends NodeData>> nodeDataConverters,
42+
Serializer serializer) {
43+
this.nodeDataConverters = nodeDataConverters;
44+
this.serializer = serializer;
45+
}
46+
47+
protected NodeDataConverter<? extends NodeData> getNodeDataConverter(NodeType nodeType) {
48+
return nodeDataConverters.stream()
49+
.filter(converter -> converter.supportNodeType(nodeType))
50+
.findFirst()
51+
.orElseThrow(() -> new IllegalArgumentException("invalid node type " + nodeType));
52+
}
53+
3454
@Override
3555
public App importDSL(String dsl) {
3656
log.info("dsl importing: {}", dsl);

spring-ai-alibaba-studio/spring-ai-alibaba-studio-server/spring-ai-alibaba-studio-server-admin/src/main/java/com/alibaba/cloud/ai/studio/admin/generator/service/dsl/DSLDialectType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public enum DSLDialectType {
2222

2323
DIFY("dify", ".yml"),
2424

25+
STUDIO("studio", ".json"),
26+
2527
CUSTOM("custom", ".yml");
2628

2729
private final String value;
@@ -37,7 +39,7 @@ public String fileExtension() {
3739
}
3840

3941
public static Optional<DSLDialectType> fromValue(String value) {
40-
return Arrays.stream(DSLDialectType.values()).filter(t -> t.value.equals(value)).findFirst();
42+
return Arrays.stream(DSLDialectType.values()).filter(t -> t.value.equalsIgnoreCase(value)).findFirst();
4143
}
4244

4345
DSLDialectType(String value, String fileExtension) {

0 commit comments

Comments
 (0)