Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# docker run -i --rm -p 8080:8080 -e GOOGLE_AI_API_KEY=your-api-key quarkus/playing-with-google-java-genai
#
###
FROM registry.access.redhat.com/ubi8/openjdk-17:1.18
FROM registry.access.redhat.com/ubi8/openjdk-21:1.20

ENV LANGUAGE='en_US:en'

Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,30 @@ The application provides several pre-configured templates for different use case

```bash
# Show help
mvn quarkus:dev -Dquarkus.args="--help"
quarkus dev -Dquarkus.args="--help"

# Generate image for a blog post (single author)
mvn quarkus:dev -Dquarkus.args="image --template-name generate-image-blog-post --title 'Introduction to DuckDB' --name 'John Doe' --photo images/people/john-doe.png -o output.png"
quarkus dev -Dquarkus.args="image --template-name generate-image-blog-post --title=IntroductiontoDuckDB --name=John_Doe --photo=images/people/john-doe.png -o output.png"

# Generate image for a blog post (2 authors)
mvn quarkus:dev -Dquarkus.args="image --template-name generate-image-2-blog-post --title 'Exploring Firebase Studio' --name 'Alice Smith' --name2 'Bob Johnson' --photo images/people/alice.png --photo2 images/people/bob.png -o output.png"
quarkus dev -Dquarkus.args="image --template-name generate-image-2-blog-post --title=Exploring_Firebas_Studio --name=Alice-Smith --name2=Bob_Johnson --photo=images/people/alice.png --photo2 images/people/bob.png -o output.png"

# Generate image for a conference speaker
mvn quarkus:dev -Dquarkus.args="image --template-name generate-image-speaker-event --title 'My Great Talk' --name 'Speaker Name' --photo images/people/speaker.png --conf-photo images/logos/conference.png -o output.png"
quarkus dev -Dquarkus.args="image --template-name generate-image-speaker-event --title=My_Great_Talk --name=Speaker_Name --photo=images/people/speaker.png --conf-photo=images/logos/conference.png -o output.png"

# Generate image for a conference with 2 speakers
mvn quarkus:dev -Dquarkus.args="image --template-name generate-image-2-speaker-event --title 'Firebase Studio' --name 'Benjamin Bourgeois' --name2 'Jean-Phi Baconnais' --photo images/people/benjamin-bourgeois.png --photo2 images/people/jeanphi-baconnais.png --conf-photo images/logos/conference.png -o output.png"
quarkus dev -Dquarkus.args="image --template-name generate-image-2-speaker-event --title=Firebase_Studio --name=Speaker_1 --name2=Speaker_2 --photo images/people/peolple1.png --photo2=images/people/people2.png --conf-photo=images/logos/conference.png -o output.png"

# Generate video
quarkus dev -Dquarkus.args="video --prompt 'Conference intro' --vertex"
```

### Running the Application

**Development Mode (with hot reload):**
**With CLI arguments:**

```bash
mvn quarkus:dev
quarkus dev -Dquarkus.args="--type image --prompt 'Your prompt here' --output result.png"
```

**Production mode:**
Expand Down Expand Up @@ -189,7 +192,7 @@ The application automatically detects and supports the following image formats:

For support and questions:

- Create an issue in the GitLab repository
- Create an issue in the GitHub repository
- Check the [Google AI documentation](https://ai.google.dev/docs)
- Review the [Quarkus guides](https://quarkus.io/guides/)

Expand Down
19 changes: 8 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<skipITs>true</skipITs>
<compiler-plugin.version>3.11.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<quarkus.platform.version>3.15.1</quarkus.platform.version>
<maven.compiler.release>25</maven.compiler.release>
<quarkus.platform.version>3.27.0</quarkus.platform.version>
<surefire-plugin.version>3.2.5</surefire-plugin.version>
</properties>
<dependencyManagement>
Expand Down Expand Up @@ -86,13 +86,19 @@
</goals>
</execution>
</executions>
<configuration>
<jvmArgs>--add-opens java.base/java.lang=ALL-UNNAMED</jvmArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<source>25</source>
<target>25</target>
<compilerArgs>
<arg>-parameters</arg>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
Expand Down Expand Up @@ -125,15 +131,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
Expand Down
39 changes: 38 additions & 1 deletion src/main/java/zenika/marketing/cli/GenerateImageCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public class GenerateImageCommand implements Runnable {
"generate-image-blog-post", this::generateImageBlogPost,
"generate-image-2-blog-post", this::generateImage2BlogPost,
"generate-image-speaker-event", this::generateImageSpeakerEvent,
"generate-image-2-speaker-event", this::generateImage2SpeakerEvent
"generate-image-2-speaker-event", this::generateImage2SpeakerEvent,
"generate-image-binome-speaker-event", this::generateImageBinomeSpeakerEvent
// generate-post-speaker-event
);

Expand Down Expand Up @@ -232,6 +233,42 @@ private void generateImage2SpeakerEvent(Template template) {
prepareCallGemini(template, content, completedPrompt);
}

private void generateImageBinomeSpeakerEvent(Template template) {
Content content = null;
config.setDefaultName(name != null ? name : config.getDefaultName());
config.setDefaultName2(name2 != null ? name2 : config.getDefaultName2());
config.setDefaultTitle(title != null ? title : config.getDefaultTitle());
config.setDefaultPhoto(photo);
config.setDefaultPhoto2(photo2);
config.setDefaultConfPhoto(confPhoto);

String completedPrompt = templateService.preparePrompt(template, config);

Path templateFile = Path.of(template.template());
Path zPhoto = Path.of(config.getDefaultPhoto());
Path zPhoto2 = Path.of(config.getDefaultPhoto2());
Path confPhoto = Path.of(config.getDefaultConfPhoto());

checkisFileExist(templateFile);
checkisFileExist(zPhoto);
checkisFileExist(zPhoto2);
checkisFileExist(confPhoto);

try {
content = Content.fromParts(
Part.fromBytes(Files.readAllBytes(templateFile), Utils.getMimeType(templateFile.toString())),
Part.fromBytes(Files.readAllBytes(zPhoto), Utils.getMimeType(zPhoto.toString())),
Part.fromBytes(Files.readAllBytes(zPhoto2), Utils.getMimeType(zPhoto2.toString())),
Part.fromBytes(Files.readAllBytes(confPhoto), Utils.getMimeType(confPhoto.toString())),
Part.fromText(completedPrompt));
} catch (IOException e) {
Log.error("❌ Error: " + e.getMessage(), e);
System.exit(1);
}

prepareCallGemini(template, content, completedPrompt);
}

private void prepareCallGemini(Template template, Content content, String prompt) {
config.setDefaultResultFilename(output != null ? output : config.getDefaultResultFilename());
config.setDefaultResultFilename(
Expand Down
111 changes: 39 additions & 72 deletions src/main/java/zenika/marketing/cli/GenerateVideoCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,61 @@
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import zenika.marketing.config.ConfigProperties;
import zenika.marketing.config.MODE_FEATURE;
import zenika.marketing.domain.Template;
import zenika.marketing.services.GeminiVideoServices;
import zenika.marketing.services.TemplateService;

@Command(
name = "video",
mixinStandardHelpOptions = true,
description = "Generate a video using Gemini AI."
)
@Command(name = "video", mixinStandardHelpOptions = true, description = "Generate a video using Gemini AI.")
public class GenerateVideoCommand implements Runnable {

@Inject
GeminiVideoServices geminiServices;
@Inject
GeminiVideoServices geminiServices;

@Inject
ConfigProperties config;
@Inject
ConfigProperties config;

@Inject
TemplateService templateService;
@Inject
TemplateService templateService;

@Option(
names = {"-o", "--output"},
description = "Output filename (default: ${DEFAULT-VALUE})"
)
String output;
@Option(names = { "-o", "--output" }, description = "Output filename")
String output;

@Option(
names = {"--template"},
description = "Path to template image"
)
String templatePath;
@Option(names = { "--photo" }, description = "Path to image to use")
String photo;

@Option(
names = {"-m", "--model"},
description = "Gemini model to use"
)
String model;
@Option(names = { "--template-name" }, description = "Name of the template to use", required = true)
String templateName;

@Option(
names = {"--template-name"},
description = "Name of the template to use",
required = true
)
String templateName;
@Option(names = { "--ratio" }, description = "Video aspect ratio (default: configured default)")
String videoRatio;

@Option(
names = {"--ratio"},
description = "Video aspect ratio (default: configured default)"
)
String videoRatio;
@Option(names = { "--resolution" }, description = "Video resolution (default: configured default)")
String videoResolution;

@Option(
names = {"--resolution"},
description = "Video resolution (default: configured default)"
)
String videoResolution;
public void run() {
try {
Template template = templateService.waitAValidTemplateByUser(templateName);
config.setDefaultPrompt(template.prompt());
String finalOutput = output != null ? output : config.getDefaultResultFilenameVideo();
config.setDefaultPhoto(photo != null ? photo : config.getDefaultPhoto());
config.setDefaultGeminiVeoModel(config.getDefaultGeminiVeoModel());
config.setDefaultVideoResolution(videoResolution != null ? videoResolution
: config.getDefaultVideoResolution());
config.setDefaultVideoRatio(videoRatio != null ? videoRatio : config.getDefaultVideoRatio());
config.setDefaultPhoto(photo);
config.setDefaultResultFilename(output != null ? output : config.getDefaultResultFilename());

@Override
public void run() {
try {
var template = templateService.waitAValidTemplateByUser(templateName);
String completedPrompt = templateService.preparePrompt(template, config);

// Check that the template is of type VIDEO
if (!template.type().equals(MODE_FEATURE.VIDEO)) {
Log.error("❌ Error: Template '" + templateName + "' is not a VIDEO template");
System.exit(1);
return;
}
Log.infof("-> generate Video %s", template.name());
Log.info("\uD83D\uDCDD \uD83D\uDC49 Prompt: \n \t " + completedPrompt + "\n");

String templatePrompt = template.prompt();
String finalOutput = output != null ? output : config.getDefaultResultFilename();
String finalTemplatePath = templatePath != null ? templatePath : config.getDefaultTemplatePath();
String finalModel = model != null ? model : config.getDefaultGeminiVeoModel();
String finalVideoRatio = videoRatio != null ? videoRatio : config.getDefaultVideoRatio();
String finalVideoResolution = videoResolution != null ? videoResolution : config.getDefaultVideoResolution();
geminiServices.generateVideo(finalOutput, config);
System.exit(0);

geminiServices.generateVideo(
finalModel,
templatePrompt,
finalOutput,
finalTemplatePath,
finalVideoRatio,
finalVideoResolution
);

} catch (Exception e) {
Log.error("❌ Error: " + e.getMessage(), e);
System.exit(1);
} catch (Exception e) {
Log.error("❌ Error: " + e.getMessage(), e);
System.exit(1);
}
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/zenika/marketing/config/ConfigProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public class ConfigProperties {
@ConfigProperty(name = "app.result.filename")
String defaultResultFilename;

@ConfigProperty(name = "app.result.filename.video")
String defaultResultFilenameVideo;

@ConfigProperty(name = "app.prompt")
String defaultPrompt;

String defaultTemplatePath;
Expand Down Expand Up @@ -101,6 +105,10 @@ public String getDefaultConfPhoto() {
return defaultConfPhoto;
}

public String getDefaultResultFilenameVideo() {
return defaultResultFilenameVideo;
}

public void setDefaultPhoto2(String defaultPhoto2) {
this.defaultPhoto2 = defaultPhoto2;
}
Expand Down Expand Up @@ -165,6 +173,10 @@ public void setDefaultConfPhoto(String defaultConfPhoto) {
this.defaultConfPhoto = defaultConfPhoto;
}

public void setDefaultResultFilenameVideo(String defaultResultFilenameVideo) {
this.defaultResultFilenameVideo = defaultResultFilenameVideo;
}

public String getFieldByValue(String field, ConfigProperties config) {
return switch (FIELDS_PROMPT.valueOf(field)) {
case NAME, NAME1 -> config.getDefaultName();
Expand Down
Loading