Skip to content

Commit 7b5881d

Browse files
flowable processes doc maven plugin
1 parent 563e285 commit 7b5881d

17 files changed

Lines changed: 1072 additions & 0 deletions

File tree

components/data/data-processes/pom.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,20 @@
4747
<parent.pom.folder>../../../</parent.pom.folder>
4848
</properties>
4949

50+
<build>
51+
<plugins>
52+
<plugin>
53+
<groupId>org.eclipse.dirigible</groupId>
54+
<artifactId>flowable-bpmn-docs-maven-plugin</artifactId>
55+
<executions>
56+
<execution>
57+
<goals>
58+
<goal>generate</goal>
59+
</goals>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
</plugins>
64+
</build>
65+
5066
</project>

dependencies/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<description>Dirigible Dependencies</description>
1818

1919
<dependencyManagement>
20+
2021
<dependencies>
2122
<!-- Dependency versions of the top declared -->
2223
<!-- pom imports have higher precedence-->
@@ -161,4 +162,16 @@
161162
</dependency>
162163
</dependencies>
163164
</dependencyManagement>
165+
166+
<build>
167+
<pluginManagement>
168+
<plugins>
169+
<plugin>
170+
<groupId>org.eclipse.dirigible</groupId>
171+
<artifactId>flowable-bpmn-docs-maven-plugin</artifactId>
172+
<version>${project.version}</version>
173+
</plugin>
174+
</plugins>
175+
</pluginManagement>
176+
</build>
164177
</project>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Flowable docs maven plugin
2+
3+
## Usage
4+
5+
### Maven
6+
7+
- Add the following to the pom
8+
9+
```xml
10+
11+
<build>
12+
<plugins>
13+
<plugin>
14+
<groupId>org.eclipse.dirigible</groupId>
15+
<artifactId>flowable-bpmn-docs-maven-plugin</artifactId>
16+
<version>13.0.0-SNAPSHOT</version>
17+
<configuration>
18+
<bpmnDirectory>${project.basedir}/my-bpmns</bpmnDirectory>
19+
<outputDirectory>${project.build.directory}/ai-docs</outputDirectory>
20+
<geminiApiKey>${env.GEMINI_API_KEY}</geminiApiKey>
21+
</configuration>
22+
<executions>
23+
<execution>
24+
<goals>
25+
<goal>generate</goal>
26+
</goals>
27+
<phase>prepare-package</phase>
28+
</execution>
29+
</executions>
30+
</plugin>
31+
</plugins>
32+
</build>
33+
```
34+
35+
- Execute with the following
36+
37+
```shell
38+
mvn clean install -Dgemini.api.key=YOUR_KEY_HERE
39+
```
40+
41+
## Run the goal directly
42+
43+
- Using full coordinates:
44+
45+
```shell
46+
mvn flowable-docs:generate \
47+
-Dbpmn.dir=./custom-folder \
48+
-Dbpmn.output=./docs-output \
49+
-Dgemini.api.key=YOUR_API_KEY
50+
```
51+
52+
- Using the Goal Prefix (shorthand)
53+
54+
```shell
55+
mvn flowable-docs:generate -Dgemini.api.key=YOUR_API_KEY
56+
```
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xmlns="http://maven.apache.org/POM/4.0.0"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>org.eclipse.dirigible</groupId>
8+
<artifactId>dirigible-maven-plugins-parent</artifactId>
9+
<version>13.0.0-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
14+
<name>Flowable BPMN Docs Maven Plugin</name>
15+
<artifactId>flowable-bpmn-docs-maven-plugin</artifactId>
16+
<packaging>maven-plugin</packaging>
17+
18+
19+
<properties>
20+
<license.header.location>../../licensing-header.txt</license.header.location>
21+
<parent.pom.folder>../../</parent.pom.folder>
22+
</properties>
23+
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>dev.langchain4j</groupId>
28+
<artifactId>langchain4j-google-ai-gemini</artifactId>
29+
<version>1.11.0</version>
30+
</dependency>
31+
<!-- Flowable -->
32+
<dependency>
33+
<groupId>org.flowable</groupId>
34+
<artifactId>flowable-engine</artifactId>
35+
<version>${flowable.version}</version>
36+
</dependency>
37+
38+
<dependency>
39+
<groupId>org.flowable</groupId>
40+
<artifactId>flowable-bpmn-model</artifactId>
41+
<version>${flowable.version}</version>
42+
</dependency>
43+
44+
<!-- Markdown → HTML -->
45+
<dependency>
46+
<groupId>com.vladsch.flexmark</groupId>
47+
<artifactId>flexmark-all</artifactId>
48+
<version>0.64.8</version>
49+
</dependency>
50+
51+
<!-- HTML → PDF -->
52+
<dependency>
53+
<groupId>com.openhtmltopdf</groupId>
54+
<artifactId>openhtmltopdf-pdfbox</artifactId>
55+
<version>1.0.10</version>
56+
</dependency>
57+
58+
<dependency>
59+
<groupId>org.springframework.boot</groupId>
60+
<artifactId>spring-boot-starter-test</artifactId>
61+
<scope>test</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.junit.jupiter</groupId>
65+
<artifactId>junit-jupiter</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
</dependencies>
69+
70+
<build>
71+
<plugins>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-plugin-plugin</artifactId>
75+
<version>3.15.2</version>
76+
<configuration>
77+
<goalPrefix>flowable-docs</goalPrefix>
78+
</configuration>
79+
<executions>
80+
<execution>
81+
<goals>
82+
<goal>descriptor</goal>
83+
</goals>
84+
</execution>
85+
</executions>
86+
</plugin>
87+
</plugins>
88+
</build>
89+
90+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.eclipse.dirigible.flowable.bpmn.docs.ai;
2+
3+
import dev.langchain4j.data.message.ImageContent;
4+
import dev.langchain4j.data.message.SystemMessage;
5+
import dev.langchain4j.data.message.TextContent;
6+
import dev.langchain4j.data.message.UserMessage;
7+
import dev.langchain4j.model.chat.request.ChatRequest;
8+
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.time.Duration;
15+
import java.util.Base64;
16+
17+
public class GeminiBpmnDocGenerator {
18+
19+
private static final Logger LOGGER = LoggerFactory.getLogger(GeminiBpmnDocGenerator.class);
20+
21+
private static final String SYSTEM_PROMPT = "You are an expert BPMN Documentation Architect.";
22+
23+
private static final String BPMN_DOC_INSTRUCTIONS = """
24+
Analyze the attached BPMN XML file and the corresponding process diagram image.
25+
Generate a detailed technical documentation in Markdown (.md) format.
26+
27+
CRITICAL: At the very beginning of the document, add a section for the process digram which should be embedded \s
28+
using this exact syntax:
29+
![Process Diagram](data:image/jpeg;base64,${DIAGRAM_BASE64})
30+
31+
RULES:
32+
1. Describe the overall process flow.
33+
2. For USER TASKS: Include ID, Name, and Candidate Groups.
34+
3. For SERVICE TASKS: If '${JSTask}' is used, find the 'handler' file path.
35+
36+
Output strictly in Markdown.
37+
""";
38+
39+
private final String apiKey;
40+
41+
public GeminiBpmnDocGenerator(String apiKey) {
42+
this.apiKey = apiKey;
43+
}
44+
45+
public String generateBpmnDoc(Path bpmnFile, Path bpmnImage) throws Exception {
46+
try {
47+
// doc:
48+
// https://github.com/langchain4j/langchain4j/blob/main/docs/docs/integrations/language-models/google-ai-gemini.md
49+
GoogleAiGeminiChatModel.GoogleAiGeminiChatModelBuilder builder = GoogleAiGeminiChatModel.builder();
50+
GoogleAiGeminiChatModel model = builder.apiKey(apiKey)
51+
// .modelName("gemini-2.5-flash")
52+
.modelName("gemini-3-flash-preview")
53+
.timeout(Duration.ofMinutes(10))
54+
// .temperature(0.1) // Low temperature for consistent documentation
55+
// .logRequestsAndResponses(true)
56+
.maxRetries(2)
57+
.build();
58+
59+
// Prepare inputs
60+
String bpmnXml = Files.readString(bpmnFile);
61+
String base64Image = Base64.getEncoder()
62+
.encodeToString(Files.readAllBytes(bpmnImage));
63+
64+
// Construct the conversation
65+
ChatRequest request = ChatRequest.builder()
66+
.messages(
67+
// 1. SET THE ROLE (System Message)
68+
SystemMessage.from(SYSTEM_PROMPT),
69+
70+
// 2. SET THE DATA (Multimodal User Message)
71+
UserMessage.from(TextContent.from("BPMN XML:\n" + bpmnXml),
72+
ImageContent.from(base64Image, "image/png"),
73+
TextContent.from(BPMN_DOC_INSTRUCTIONS)))
74+
.build();
75+
76+
String aiResponse = model.chat(request)
77+
.aiMessage()
78+
.text();
79+
80+
return aiResponse.replace("${DIAGRAM_BASE64}", base64Image);
81+
} catch (Exception ex) {
82+
throw new IllegalStateException("Failed to generate AI markdown for bpmnFile: " + bpmnFile, ex);
83+
}
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.eclipse.dirigible.flowable.bpmn.docs.diagram;
2+
3+
import org.eclipse.dirigible.flowable.bpmn.docs.model.ProcessDoc;
4+
import org.eclipse.dirigible.flowable.bpmn.docs.parser.BpmnParser;
5+
import org.flowable.bpmn.model.BpmnModel;
6+
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
7+
8+
import java.io.File;
9+
import java.io.InputStream;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.StandardCopyOption;
13+
14+
public class DiagramRenderer {
15+
16+
public static Path renderProcess(File bpmnFile, ProcessDoc doc, File outDir) throws Exception {
17+
18+
BpmnModel model = BpmnParser.parseToBpmnModel(bpmnFile);
19+
20+
DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
21+
22+
try (InputStream jpgInputStream = diagramGenerator.generateJpgDiagram(model)) {
23+
Path imagePath = outDir.toPath()
24+
.resolve(doc.getProcessId() + ".jpg");
25+
Files.copy(jpgInputStream, imagePath, StandardCopyOption.REPLACE_EXISTING);
26+
return imagePath;
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.eclipse.dirigible.flowable.bpmn.docs.export;
2+
3+
import org.eclipse.dirigible.flowable.bpmn.docs.model.ElementDoc;
4+
import org.eclipse.dirigible.flowable.bpmn.docs.model.ProcessDoc;
5+
import org.eclipse.dirigible.flowable.bpmn.docs.model.SequenceDoc;
6+
7+
import java.io.IOException;
8+
9+
public class MarkdownExporter {
10+
11+
public static String export(ProcessDoc doc) throws IOException {
12+
13+
StringBuilder md = new StringBuilder();
14+
md.append("# ")
15+
.append(doc.getName())
16+
.append("\n\n");
17+
md.append("![Diagram](")
18+
.append(doc.getProcessId())
19+
.append(".jpg)\n\n");
20+
21+
md.append("## Elements\n");
22+
for (ElementDoc e : doc.getElements()) {
23+
md.append("### ")
24+
.append(e.getType())
25+
.append(": ")
26+
.append(e.getName())
27+
.append("\n");
28+
e.getMetadata()
29+
.forEach((k, v) -> md.append("- ")
30+
.append(k)
31+
.append(": ")
32+
.append(v)
33+
.append("\n"));
34+
md.append("\n");
35+
}
36+
37+
md.append("## Sequence Flows\n");
38+
for (SequenceDoc f : doc.getFlows()) {
39+
md.append("- ")
40+
.append(f.source())
41+
.append(" → ")
42+
.append(f.target())
43+
.append("\n");
44+
}
45+
46+
return md.toString();
47+
}
48+
}

0 commit comments

Comments
 (0)