diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/AmongusText.java b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/AmongusText.java new file mode 100644 index 000000000..b9f887d05 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/AmongusText.java @@ -0,0 +1,133 @@ +package dev.sheldan.abstracto.imagegeneration.command; + +import dev.sheldan.abstracto.core.command.UtilityModuleDefinition; +import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; +import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +import dev.sheldan.abstracto.core.command.config.HelpInfo; +import dev.sheldan.abstracto.core.command.config.Parameter; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig; +import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.templating.model.AttachedFile; +import dev.sheldan.abstracto.core.templating.model.MessageToSend; +import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.core.utils.FileService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefinition; +import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames; +import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class AmongusText extends AbstractConditionableCommand { + + public static final String TEXT_PARAMETER_KEY = "text"; + + @Autowired + private ImageGenerationService imageGenerationService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ChannelService channelService; + + @Autowired + private FileService fileService; + + @Autowired + private InteractionService interactionService; + + @Autowired + private SlashCommandParameterService slashCommandParameterService; + + private static final String AMONGUS_TEXT_EMBED_TEMPLATE_KEY = "amongusText_response"; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + String text = (String) commandContext.getParameters().getParameters().get(0); + File amongusTextImage = imageGenerationService.getAmongusTextImage(text); + MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object()); + // template support does not support binary files + AttachedFile file = AttachedFile + .builder() + .file(amongusTextImage) + .fileName("amongus.png") + .build(); + messageToSend.getAttachedFiles().add(file); + return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) + .thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CompletableFuture executeSlash(SlashCommandInteractionEvent event) { + event.deferReply().queue(); + String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER_KEY, event, String.class); + File amongusTextImage = imageGenerationService.getAmongusTextImage(text); + MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object()); + // template support does not support binary files + AttachedFile file = AttachedFile + .builder() + .file(amongusTextImage) + .fileName("amongus.png") + .build(); + messageToSend.getAttachedFiles().add(file); + return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(messageToSend, event.getHook())) + .thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + Parameter memberParameter = Parameter + .builder() + .name(TEXT_PARAMETER_KEY) + .type(String.class) + .remainder(true) + .templated(true) + .build(); + parameters.add(memberParameter); + + HelpInfo helpInfo = HelpInfo + .builder() + .templated(true) + .build(); + + SlashCommandConfig slashCommandConfig = SlashCommandConfig + .builder() + .enabled(true) + .rootCommandName(ImageGenerationSlashCommandNames.IMAGE_GENERATION) + .groupName("memes") + .commandName("amongustext") + .build(); + + return CommandConfiguration.builder() + .name("amongusText") + .module(UtilityModuleDefinition.UTILITY) + .templated(true) + .supportsEmbedException(true) + .async(true) + .slashCommandConfig(slashCommandConfig) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureDefinition getFeature() { + return ImageGenerationFeatureDefinition.IMAGE_GENERATION; + } +} diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java index 148ed7580..0444b24c0 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java @@ -1,7 +1,9 @@ package dev.sheldan.abstracto.imagegeneration.service; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.exception.RequestException; import dev.sheldan.abstracto.core.service.HttpService; +import dev.sheldan.abstracto.imagegeneration.exception.AmongusTextRequestException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -22,6 +24,9 @@ public class ImageGenerationServiceBean implements ImageGenerationService { @Value("${abstracto.feature.imagegeneration.bonk.url}") private String bonkUrl; + @Value("${abstracto.feature.imagegeneration.amongusText.url}") + private String amongusTextUrl; + @Autowired private HttpService httpService; @@ -52,4 +57,15 @@ public class ImageGenerationServiceBean implements ImageGenerationService { } } + @Override + public File getAmongusTextImage(String text) { + try { + return httpService.downloadFileToTempFile(amongusTextUrl.replace("{1}", text)); + } catch (IOException e) { + throw new AbstractoRunTimeException(String.format("Failed to download amongus text with error %s", text, e.getMessage())); + } catch (RequestException exception) { + throw new AmongusTextRequestException(text, exception.getErrorMessage()); + } + } + } diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties index 75f5ca648..ee3f32a3e 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties @@ -8,4 +8,6 @@ abstracto.feature.imagegeneration.pat.url=http://${PRIVATE_REST_API_HOST}:${PRIV abstracto.feature.imagegeneration.pat.imagesize=128 abstracto.feature.imagegeneration.bonk.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/bonk/file.gif?url={1} -abstracto.feature.imagegeneration.bonk.imagesize=128 \ No newline at end of file +abstracto.feature.imagegeneration.bonk.imagesize=128 + +abstracto.feature.imagegeneration.amongusText.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/amogus/text?text={1} diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/collection.xml b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/collection.xml new file mode 100644 index 000000000..121b5aadf --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/collection.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/command.xml b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/command.xml new file mode 100644 index 000000000..caabc4207 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/command.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/data.xml b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/data.xml new file mode 100644 index 000000000..c048f6f53 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.22/seedData/data.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/imageGeneration-changeLog.xml b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/imageGeneration-changeLog.xml index 87fbbc4b6..444299db8 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/imageGeneration-changeLog.xml +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/imageGeneration-changeLog.xml @@ -8,4 +8,5 @@ http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" > + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/exception/AmongusTextRequestException.java b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/exception/AmongusTextRequestException.java new file mode 100644 index 000000000..4df41aef0 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/exception/AmongusTextRequestException.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.imagegeneration.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException; +import dev.sheldan.abstracto.imagegeneration.model.exception.AmongusTextRequestExceptionModel; + +public class AmongusTextRequestException extends AbstractoTemplatableException { + private final AmongusTextRequestExceptionModel model; + + public AmongusTextRequestException(String inputText, String errorMessage) { + this.model = AmongusTextRequestExceptionModel + .builder() + .inputText(inputText) + .errorMessage(errorMessage) + .build(); + } + + @Override + public String getTemplateName() { + return "amongusText_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/model/exception/AmongusTextRequestExceptionModel.java b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/model/exception/AmongusTextRequestExceptionModel.java new file mode 100644 index 000000000..f60227cf0 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/model/exception/AmongusTextRequestExceptionModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.imagegeneration.model.exception; + +import lombok.Builder; +import lombok.Getter; + +import java.io.Serializable; + +@Getter +@Builder +public class AmongusTextRequestExceptionModel implements Serializable { + private String inputText; + private String errorMessage; +} diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java index 654fed0d6..b6ae32432 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java @@ -6,4 +6,5 @@ public interface ImageGenerationService { File getTriggeredGif(String imageUrl); File getPatGif(String imageUrl); File getBonkGif(String imageUrl); + File getAmongusTextImage(String text); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/HttpServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/HttpServiceBean.java index 4a0a35484..4d48d127c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/HttpServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/HttpServiceBean.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.service; +import dev.sheldan.abstracto.core.exception.RequestException; import dev.sheldan.abstracto.core.utils.FileService; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -25,6 +26,13 @@ public class HttpServiceBean implements HttpService { Request request = new Request.Builder().url(url).get().build(); File tempFile = fileService.createTempFile(Math.random() + ""); Response execute = client.newCall(request).execute(); + if(!execute.isSuccessful()) { + throw RequestException + .builder() + .errorMessage(execute.body().string()) + .httpCode(execute.code()) + .build(); + } fileService.writeBytesToFile(tempFile, execute.body().bytes()); return tempFile; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/RequestException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/RequestException.java new file mode 100644 index 000000000..165381b0c --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/RequestException.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.core.exception; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class RequestException extends RuntimeException { + private String errorMessage; // we just assume the body will be a plain text instead + private Integer httpCode; +} diff --git a/python/components/image-gen/python/endpoints/amogus.py b/python/components/image-gen/python/endpoints/amogus.py new file mode 100644 index 000000000..44c9cb777 --- /dev/null +++ b/python/components/image-gen/python/endpoints/amogus.py @@ -0,0 +1,85 @@ +from __main__ import app + +from PIL import Image, ImageOps +from flask import request +import logging +import math +import re +import random + +from utils import flask_utils + +vertical_padding = 5 +horizontal_padding = 5 + +max_chars = 2000 +chars_per_row = 50 + + +space_width = 80 + +character_height = 120 + + +@app.route('/memes/amogus/text') +def generate_amogus_text(): + text = request.args.get('text', type=str) + if text is None: + return 'no text', 400 + if len(text) > max_chars: + return f'too long text, max {max_chars}', 400 + text = text.lower() + text = re.sub(r'[^a-z!\\? ]', "", text) + if len(text) == 0: + return 'No valid characters found.', 400 + logging.info(f'Rendering amogus text.') + image_cache = {} + images_to_use = [] + + try: + for character in text: + if character == ' ': + images_to_use.append(None) + continue + # manual correction for filenames + if character == '?': + character = 'zq' + if character == '!': + character = 'zx' + chosen_sub_image = random.randint(1, 3) + cache_key = f'{character}{chosen_sub_image}' + if cache_key not in image_cache: + character_image = Image.open(f'resources/img/amogus/crewmate-{character}{chosen_sub_image}.png').__enter__() + old_character_width, old_character_height = character_image.size + character_ratio = old_character_height / character_height + desired_width = int(old_character_width * character_ratio) + resized_character_image = ImageOps.contain(character_image, (desired_width, character_height)) + image_cache[cache_key] = resized_character_image + image_to_use = resized_character_image + else: + image_to_use = image_cache[cache_key] + images_to_use.append(image_to_use) + # the line length is defined by the amount of characters, not once a certain width is reached + lines = [images_to_use[i:i + chars_per_row] for i in range(0, len(images_to_use), chars_per_row)] + # calculate the length of each line, and then take the widest one + line_widths = [sum(image_to_use.size[0] + horizontal_padding if image_to_use is not None else space_width for image_to_use in character_line) for character_line in lines] + canvas_width = max(line_widths) + row_count = math.ceil(len(text) / chars_per_row) + canvas_height = row_count * (character_height + vertical_padding) + drawing_board = Image.new('RGBA', (canvas_width, canvas_height), (0, 0, 0, 0)) + start_x = 0 + start_y = 0 + for index, image_to_use in enumerate(images_to_use): + if index > 0 and (index % chars_per_row) == 0: + start_y += character_height + vertical_padding + start_x = 0 + if image_to_use is not None: + drawing_board.paste(image_to_use, (start_x, start_y), image_to_use) + start_x += image_to_use.size[0] + horizontal_padding + else: + start_x += space_width + finally: + for cached_image in image_cache.values(): + cached_image.__exit__(None, None, None) + return flask_utils.serve_pil_image(drawing_board) + diff --git a/python/components/image-gen/resources/img/amogus/crewmate-a1.png b/python/components/image-gen/resources/img/amogus/crewmate-a1.png new file mode 100644 index 000000000..d4e5888c6 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-a1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-a2.png b/python/components/image-gen/resources/img/amogus/crewmate-a2.png new file mode 100644 index 000000000..00a26229c Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-a2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-a3.png b/python/components/image-gen/resources/img/amogus/crewmate-a3.png new file mode 100644 index 000000000..dc21c2f67 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-a3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-b1.png b/python/components/image-gen/resources/img/amogus/crewmate-b1.png new file mode 100644 index 000000000..87edcdbb6 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-b1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-b2.png b/python/components/image-gen/resources/img/amogus/crewmate-b2.png new file mode 100644 index 000000000..2d4658375 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-b2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-b3.png b/python/components/image-gen/resources/img/amogus/crewmate-b3.png new file mode 100644 index 000000000..5e4aad984 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-b3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-c1.png b/python/components/image-gen/resources/img/amogus/crewmate-c1.png new file mode 100644 index 000000000..5846e10c7 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-c1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-c2.png b/python/components/image-gen/resources/img/amogus/crewmate-c2.png new file mode 100644 index 000000000..01d5cd05e Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-c2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-c3.png b/python/components/image-gen/resources/img/amogus/crewmate-c3.png new file mode 100644 index 000000000..65c05d61b Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-c3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-d1.png b/python/components/image-gen/resources/img/amogus/crewmate-d1.png new file mode 100644 index 000000000..d18190291 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-d1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-d2.png b/python/components/image-gen/resources/img/amogus/crewmate-d2.png new file mode 100644 index 000000000..002fc9480 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-d2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-d3.png b/python/components/image-gen/resources/img/amogus/crewmate-d3.png new file mode 100644 index 000000000..f04eb33c6 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-d3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-e1.png b/python/components/image-gen/resources/img/amogus/crewmate-e1.png new file mode 100644 index 000000000..1660f6c26 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-e1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-e2.png b/python/components/image-gen/resources/img/amogus/crewmate-e2.png new file mode 100644 index 000000000..40fb16b78 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-e2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-e3.png b/python/components/image-gen/resources/img/amogus/crewmate-e3.png new file mode 100644 index 000000000..7b7748ad2 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-e3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-f1.png b/python/components/image-gen/resources/img/amogus/crewmate-f1.png new file mode 100644 index 000000000..64d1e9eab Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-f1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-f2.png b/python/components/image-gen/resources/img/amogus/crewmate-f2.png new file mode 100644 index 000000000..90532111c Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-f2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-f3.png b/python/components/image-gen/resources/img/amogus/crewmate-f3.png new file mode 100644 index 000000000..123d9e815 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-f3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-g1.png b/python/components/image-gen/resources/img/amogus/crewmate-g1.png new file mode 100644 index 000000000..8793598fd Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-g1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-g2.png b/python/components/image-gen/resources/img/amogus/crewmate-g2.png new file mode 100644 index 000000000..d0d17c4f5 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-g2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-g3.png b/python/components/image-gen/resources/img/amogus/crewmate-g3.png new file mode 100644 index 000000000..1af979911 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-g3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-h1.png b/python/components/image-gen/resources/img/amogus/crewmate-h1.png new file mode 100644 index 000000000..9a6768746 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-h1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-h2.png b/python/components/image-gen/resources/img/amogus/crewmate-h2.png new file mode 100644 index 000000000..c3a4a5cd3 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-h2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-h3.png b/python/components/image-gen/resources/img/amogus/crewmate-h3.png new file mode 100644 index 000000000..019c32882 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-h3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-i1.png b/python/components/image-gen/resources/img/amogus/crewmate-i1.png new file mode 100644 index 000000000..fb697502b Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-i1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-i2.png b/python/components/image-gen/resources/img/amogus/crewmate-i2.png new file mode 100644 index 000000000..804eca26d Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-i2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-i3.png b/python/components/image-gen/resources/img/amogus/crewmate-i3.png new file mode 100644 index 000000000..58c3ee9a7 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-i3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-j1.png b/python/components/image-gen/resources/img/amogus/crewmate-j1.png new file mode 100644 index 000000000..b4d27a93c Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-j1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-j2.png b/python/components/image-gen/resources/img/amogus/crewmate-j2.png new file mode 100644 index 000000000..1a2f2ed3d Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-j2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-j3.png b/python/components/image-gen/resources/img/amogus/crewmate-j3.png new file mode 100644 index 000000000..b50aee47d Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-j3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-k1.png b/python/components/image-gen/resources/img/amogus/crewmate-k1.png new file mode 100644 index 000000000..268d02d3e Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-k1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-k2.png b/python/components/image-gen/resources/img/amogus/crewmate-k2.png new file mode 100644 index 000000000..244162e4b Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-k2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-k3.png b/python/components/image-gen/resources/img/amogus/crewmate-k3.png new file mode 100644 index 000000000..77ccfc70a Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-k3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-l1.png b/python/components/image-gen/resources/img/amogus/crewmate-l1.png new file mode 100644 index 000000000..ef1b32652 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-l1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-l2.png b/python/components/image-gen/resources/img/amogus/crewmate-l2.png new file mode 100644 index 000000000..3749c20b5 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-l2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-l3.png b/python/components/image-gen/resources/img/amogus/crewmate-l3.png new file mode 100644 index 000000000..71186ab07 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-l3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-m1.png b/python/components/image-gen/resources/img/amogus/crewmate-m1.png new file mode 100644 index 000000000..0af9a9f73 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-m1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-m2.png b/python/components/image-gen/resources/img/amogus/crewmate-m2.png new file mode 100644 index 000000000..e781872a3 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-m2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-m3.png b/python/components/image-gen/resources/img/amogus/crewmate-m3.png new file mode 100644 index 000000000..3f002f038 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-m3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-n1.png b/python/components/image-gen/resources/img/amogus/crewmate-n1.png new file mode 100644 index 000000000..4533a3e8b Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-n1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-n2.png b/python/components/image-gen/resources/img/amogus/crewmate-n2.png new file mode 100644 index 000000000..60f98f359 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-n2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-n3.png b/python/components/image-gen/resources/img/amogus/crewmate-n3.png new file mode 100644 index 000000000..83bb695af Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-n3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-o1.png b/python/components/image-gen/resources/img/amogus/crewmate-o1.png new file mode 100644 index 000000000..6cf5963c1 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-o1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-o2.png b/python/components/image-gen/resources/img/amogus/crewmate-o2.png new file mode 100644 index 000000000..335063ad4 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-o2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-o3.png b/python/components/image-gen/resources/img/amogus/crewmate-o3.png new file mode 100644 index 000000000..99cfcc21d Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-o3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-p1.png b/python/components/image-gen/resources/img/amogus/crewmate-p1.png new file mode 100644 index 000000000..71f0fbf59 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-p1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-p2.png b/python/components/image-gen/resources/img/amogus/crewmate-p2.png new file mode 100644 index 000000000..ba1960fb9 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-p2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-p3.png b/python/components/image-gen/resources/img/amogus/crewmate-p3.png new file mode 100644 index 000000000..b5485cdbe Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-p3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-q1.png b/python/components/image-gen/resources/img/amogus/crewmate-q1.png new file mode 100644 index 000000000..81df3a9c7 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-q1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-q2.png b/python/components/image-gen/resources/img/amogus/crewmate-q2.png new file mode 100644 index 000000000..3aeab5f22 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-q2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-q3.png b/python/components/image-gen/resources/img/amogus/crewmate-q3.png new file mode 100644 index 000000000..c0f71085a Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-q3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-r1.png b/python/components/image-gen/resources/img/amogus/crewmate-r1.png new file mode 100644 index 000000000..465d6d233 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-r1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-r2.png b/python/components/image-gen/resources/img/amogus/crewmate-r2.png new file mode 100644 index 000000000..42af78381 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-r2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-r3.png b/python/components/image-gen/resources/img/amogus/crewmate-r3.png new file mode 100644 index 000000000..4f0d84b54 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-r3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-s1.png b/python/components/image-gen/resources/img/amogus/crewmate-s1.png new file mode 100644 index 000000000..5610bad2e Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-s1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-s2.png b/python/components/image-gen/resources/img/amogus/crewmate-s2.png new file mode 100644 index 000000000..3ae567097 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-s2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-s3.png b/python/components/image-gen/resources/img/amogus/crewmate-s3.png new file mode 100644 index 000000000..3cc068fc9 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-s3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-t1.png b/python/components/image-gen/resources/img/amogus/crewmate-t1.png new file mode 100644 index 000000000..00649ee75 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-t1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-t2.png b/python/components/image-gen/resources/img/amogus/crewmate-t2.png new file mode 100644 index 000000000..bba538460 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-t2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-t3.png b/python/components/image-gen/resources/img/amogus/crewmate-t3.png new file mode 100644 index 000000000..963a8ec47 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-t3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-u1.png b/python/components/image-gen/resources/img/amogus/crewmate-u1.png new file mode 100644 index 000000000..c9c906d8e Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-u1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-u2.png b/python/components/image-gen/resources/img/amogus/crewmate-u2.png new file mode 100644 index 000000000..a1d83c50f Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-u2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-u3.png b/python/components/image-gen/resources/img/amogus/crewmate-u3.png new file mode 100644 index 000000000..96cffb178 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-u3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-v1.png b/python/components/image-gen/resources/img/amogus/crewmate-v1.png new file mode 100644 index 000000000..3b76269c3 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-v1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-v2.png b/python/components/image-gen/resources/img/amogus/crewmate-v2.png new file mode 100644 index 000000000..d88ac61ab Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-v2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-v3.png b/python/components/image-gen/resources/img/amogus/crewmate-v3.png new file mode 100644 index 000000000..1a027c3ce Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-v3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-w1.png b/python/components/image-gen/resources/img/amogus/crewmate-w1.png new file mode 100644 index 000000000..53179a00a Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-w1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-w2.png b/python/components/image-gen/resources/img/amogus/crewmate-w2.png new file mode 100644 index 000000000..03db51832 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-w2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-w3.png b/python/components/image-gen/resources/img/amogus/crewmate-w3.png new file mode 100644 index 000000000..eea772aa3 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-w3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-x1.png b/python/components/image-gen/resources/img/amogus/crewmate-x1.png new file mode 100644 index 000000000..a8badb4f7 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-x1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-x2.png b/python/components/image-gen/resources/img/amogus/crewmate-x2.png new file mode 100644 index 000000000..f558afc74 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-x2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-x3.png b/python/components/image-gen/resources/img/amogus/crewmate-x3.png new file mode 100644 index 000000000..f493e9d6b Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-x3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-y1.png b/python/components/image-gen/resources/img/amogus/crewmate-y1.png new file mode 100644 index 000000000..ea410e32c Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-y1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-y2.png b/python/components/image-gen/resources/img/amogus/crewmate-y2.png new file mode 100644 index 000000000..c5be4c992 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-y2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-y3.png b/python/components/image-gen/resources/img/amogus/crewmate-y3.png new file mode 100644 index 000000000..94667c344 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-y3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-z1.png b/python/components/image-gen/resources/img/amogus/crewmate-z1.png new file mode 100644 index 000000000..995cbdff0 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-z1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-z2.png b/python/components/image-gen/resources/img/amogus/crewmate-z2.png new file mode 100644 index 000000000..cf0fe8903 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-z2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-z3.png b/python/components/image-gen/resources/img/amogus/crewmate-z3.png new file mode 100644 index 000000000..6e0e46dbd Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-z3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zq1.png b/python/components/image-gen/resources/img/amogus/crewmate-zq1.png new file mode 100644 index 000000000..f1de866ee Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zq1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zq2.png b/python/components/image-gen/resources/img/amogus/crewmate-zq2.png new file mode 100644 index 000000000..f7de7dfff Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zq2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zq3.png b/python/components/image-gen/resources/img/amogus/crewmate-zq3.png new file mode 100644 index 000000000..719aabfa1 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zq3.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zx1.png b/python/components/image-gen/resources/img/amogus/crewmate-zx1.png new file mode 100644 index 000000000..a62c9b004 Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zx1.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zx2.png b/python/components/image-gen/resources/img/amogus/crewmate-zx2.png new file mode 100644 index 000000000..9cafd999d Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zx2.png differ diff --git a/python/components/image-gen/resources/img/amogus/crewmate-zx3.png b/python/components/image-gen/resources/img/amogus/crewmate-zx3.png new file mode 100644 index 000000000..68db18ffe Binary files /dev/null and b/python/components/image-gen/resources/img/amogus/crewmate-zx3.png differ