<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jesus Marin</title>
    <description>The latest articles on DEV Community by Jesus Marin (@chuymarin).</description>
    <link>https://dev.to/chuymarin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F616365%2F167a110c-4dcf-40c2-83aa-5d195fb9b297.png</url>
      <title>DEV Community: Jesus Marin</title>
      <link>https://dev.to/chuymarin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chuymarin"/>
    <language>en</language>
    <item>
      <title>DevBlog #2 Image generation using Dalle-2</title>
      <dc:creator>Jesus Marin</dc:creator>
      <pubDate>Thu, 20 Jul 2023 04:59:01 +0000</pubDate>
      <link>https://dev.to/chuymarin/devblog-2-image-generation-using-dalle-2-41ie</link>
      <guid>https://dev.to/chuymarin/devblog-2-image-generation-using-dalle-2-41ie</guid>
      <description>&lt;p&gt;Hello Everyone!&lt;/p&gt;

&lt;p&gt;This is the 2nd post of a series for my Development Blog, if you want to check my previous post click here: &lt;a href="https://dev.to/chuymarin/development-blog-1-4kg9"&gt;DevBlog #1 Autogenerated descriptions using OpenAI&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous post I used Python, AWS Lambda and OpenAI API to generate descriptions for TTRPG Terrains Table and store those descriptions in a DynamoDB Table, now we are going to use dalle-2 to generate images using the description as a prompt and store the iamges in AWS S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding generate image function
&lt;/h2&gt;

&lt;p&gt;For this function we are going to use &lt;code&gt;Image.create&lt;/code&gt; function from openai, by default it will return a url that shows the image, but for this case we are going to retrieve the image in &lt;code&gt;base64&lt;/code&gt; so that way we can store it directly in AWS S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import random
import boto3
import openai

terrains_table = [#code]

time_table = [#code]

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    # code

def generate_terrain_description(terrain, time):
    # code

def generate_terrain_image(description):
    openai.api_key = os.getenv("OPENAI_API_KEY")

    response = openai.Image.create(
        prompt=description,
        n=1,
        size="512x512",
        response_format="b64_json",
    )

    return response["data"][0]["b64_json"]

def create_terrain(terrain_id, time_id, name, time, description):
    # code

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        description = generate_terrain_description(terrain, time)
        imageBase64 = generate_terrain_image(description)
        item = create_terrain(terrain_id, time_id, terrain, time, description)

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point we just have the &lt;code&gt;base64&lt;/code&gt; value of the image stored in the &lt;code&gt;imageBase64&lt;/code&gt; variable, now we are going to save the image in AWS S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the S3 Bucket and Environment variable
&lt;/h2&gt;

&lt;p&gt;For this we just need to create a simple S3 bucket, no need to specify any properties or permissions as this is just for uploading the images.&lt;/p&gt;

&lt;p&gt;Then create a new environment variable named &lt;code&gt;BUCKET&lt;/code&gt; and assign the name of your S3 Bucket, as it will be used in the next function.&lt;/p&gt;

&lt;p&gt;Also, don't forget to add S3 permissions to your Lambda execution IAM Role, so that way your function will have the required permissions for uploading images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding upload image to s3 function
&lt;/h2&gt;

&lt;p&gt;For this function we are going to specofy the value of the Object Body and assign the value from &lt;code&gt;imageBase64&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import random
import boto3
import openai
import base64

terrains_table = [#code]

time_table = [#code]

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    # code

def generate_terrain_description(terrain, time):
    # code

def generate_terrain_image(description):
    # code

def upload_base64_to_s3(bucket, key, base_64_str):
    s3 = boto3.resource('s3')
    s3.Object(bucket, key).put(Body=base64.b64decode(base_64_str))
    return f'https://{bucket}.s3.amazonaws.com/{key}'

def create_terrain(terrain_id, time_id, name, time, description):
    # code

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        description = generate_terrain_description(terrain, time)
        imageBase64 = generate_terrain_image(description)
        item = create_terrain(terrain_id, time_id, terrain, time, description)
        bucket = os.getenv("BUCKET")
        key = f"terrains/{terrain}-{time}.png"
        image_url = upload_base64_to_s3(bucket, key, imageBase64)
        item = create_terrain(terrain_id, time_id, terrain, time, description, image_url)

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we've added a the &lt;code&gt;base64&lt;/code&gt; import and a new property in the &lt;code&gt;create_terrain&lt;/code&gt; function, so we need to update that function as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating create terrain function
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import random
import boto3
import openai
import base64

terrains_table = [#code]

time_table = [#code]

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    # code

def generate_terrain_description(terrain, time):
    # code

def generate_terrain_image(description):
    # code

def upload_base64_to_s3(bucket, key, base_64_str):
    # code

def create_terrain(terrain_id, time_id, name, time, description, image_url):
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Terrains')

    item = {
        'terrain_id': terrain_id,
        'time_id': time_id,
        'terrain': name,
        'time': time,
        'description': description,
        'image': image_url
    }

    response = table.put_item(Item=item)
    if response['ResponseMetadata']['HTTPStatusCode'] == 200:
        return item
    else:
        return None

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        description = generate_terrain_description(terrain, time)
        imageBase64 = generate_terrain_image(description)
        item = create_terrain(terrain_id, time_id, terrain, time, description)
        bucket = os.getenv("BUCKET")
        key = f"terrains/{terrain}-{time}.png"
        image_url = upload_base64_to_s3(bucket, key, imageBase64)
        item = create_terrain(terrain_id, time_id, terrain, time, description, image_url)

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we just need to add the &lt;code&gt;image_url&lt;/code&gt; property in the function definition and add a new &lt;code&gt;image_url&lt;/code&gt; value in the &lt;code&gt;item&lt;/code&gt; object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;If everything went well each time you test your Lambda function a new record will be stored in DynamoDB and store the image in S3, here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "terrain_id": 3,
 "time_id": 2,
 "description": "The night sky is illuminated by the stars and the moon, casting a pale light over the mountain range. The jagged peaks of the mountains are silhouetted against the night sky, creating a majestic and awe-inspiring sight. The air is crisp and cool, and the silence of the night is broken only by the occasional sound of a distant animal.",
 "image": "https://{your-s3-bucket}.s3.amazonaws.com/terrains/Mountains-night.png",
 "terrain": "Mountains",
 "time": "night"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image in this post was generated using the above criteria.&lt;/p&gt;

&lt;p&gt;That's all for this post, in the next one probably I'll do some refactor as the code can get bigger, and it is better to have it in separate files.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;p&gt;Cover generated using OpenAI Dalle-2&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
      <category>openai</category>
      <category>development</category>
    </item>
    <item>
      <title>DevBlog #1 Autogenerated descriptions using OpenAI</title>
      <dc:creator>Jesus Marin</dc:creator>
      <pubDate>Fri, 14 Jul 2023 04:37:34 +0000</pubDate>
      <link>https://dev.to/chuymarin/development-blog-1-4kg9</link>
      <guid>https://dev.to/chuymarin/development-blog-1-4kg9</guid>
      <description>&lt;p&gt;Hello Everyone!&lt;/p&gt;

&lt;p&gt;This is the first post of a series for my Development Blog, if you want to know what this is about you can check my previous article &lt;a href="https://dev.to/chuymarin/development-blog-0-55le"&gt;DevBlog #0 Introduction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;OSR TTRPG Games have a lot of reference tables, such as places, monsters, weapons, and in this article I'll try to make autogenerated content using OpenAI for a Terrains Table.&lt;/p&gt;

&lt;p&gt;I want to generate description of the following terrains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valley&lt;/li&gt;
&lt;li&gt;Forest&lt;/li&gt;
&lt;li&gt;Mountains&lt;/li&gt;
&lt;li&gt;Grasslands&lt;/li&gt;
&lt;li&gt;Desert&lt;/li&gt;
&lt;li&gt;Swamp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the description can vary depending on if it is day or night.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating RandomTableGenerator Lambda function
&lt;/h2&gt;

&lt;p&gt;For this I'm going to use a Lambda Function using Python, So I have created a function called: &lt;code&gt;RandomTableGenerator&lt;/code&gt; using Pyhton 3.8 version.&lt;/p&gt;

&lt;p&gt;For the purpose of this post I'm going to just use the default lambda handler: &lt;code&gt;lambda_function.lambda_handler&lt;/code&gt; that comes already in the lambda function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding roll dice function
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is to add a function that returns a random number and two variables to get the value of the dice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random

terrains_table = [
    "Valley",
    "Forest",
    "Mountains",
    "Grasslands",
    "Desert",
    "Swamp"
]

time_table = [
    "day",
    "night"
]

def roll_dice(number):
    result = random.randint(1, number)
    return result

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    print(terrain)
    print(time)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Terrains DynamoDB Table
&lt;/h2&gt;

&lt;p&gt;Now that we have the terrain value and time value, we are going to look in a DynamoDB table if the item already exists.&lt;/p&gt;

&lt;p&gt;For this I'm going to create a &lt;code&gt;Terrains&lt;/code&gt; DynamoDB Table using &lt;code&gt;terrain_id&lt;/code&gt; as the &lt;code&gt;partition_key&lt;/code&gt; and &lt;code&gt;time_id&lt;/code&gt; as the &lt;code&gt;sort_key&lt;/code&gt;, that way I can get the item using both values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding get terrain by time function
&lt;/h2&gt;

&lt;p&gt;Now we need to add the code to look for items and create items if those doesn't exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
import boto3

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Terrains')

    response = table.get_item(
        Key={
            'terrain_id': terrain_id,
            'time_id': time_id
        }
    )

    item = response.get('Item')
    if not item:
        return False

    return item


def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        # item doesn't exist

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding create terrain function
&lt;/h2&gt;

&lt;p&gt;Now we are going to create a new function for creating the item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
import boto3

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    # code

def create_terrain(terrain_id, time_id, name, time, description):
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Terrains')

    item = {
        'terrain_id': terrain_id,
        'time_id': time_id,
        'terrain': name,
        'time': time,
        'description': description
    }

    response = table.put_item(Item=item)
    if response['ResponseMetadata']['HTTPStatusCode'] == 200:
        return item
    else:
        return None

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    description = ""
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        item = create_terrain(terrain_id, time_id, name, time, description)

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok now if the item we are looking for doesn't exist it will create the item and return it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding OpenAI Lambda Layer
&lt;/h2&gt;

&lt;p&gt;In the next step we are going to generate some description based on our input using OpenAI.&lt;/p&gt;

&lt;p&gt;Note: OpenAI package is not availble in AWS Lambda, so what we need to to is to add a Lambda Layer containing the openai package and its dependencies, fortunately the GitHub User: &lt;a href="https://github.com/erenyasarkurt"&gt;erenyasarkurt&lt;/a&gt; (shootout to him) created a repository with releases of this lambda layet, you can find these release in the following GitHub Repo: &lt;a href="https://github.com/erenyasarkurt/OpenAI-AWS-Lambda-Layer"&gt;erenyasarkurt/OpenAI-AWS-Lambda-Layer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Download the release for your Python version and create a new layer in Lambda, after that update your Lambda function to use the layer.&lt;/p&gt;

&lt;p&gt;Now go to Configuration / Environment variables and create a new variable called &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; and add your key as the value.&lt;/p&gt;

&lt;p&gt;If you don't have an OpenAI API Key you can signup and create a key, you can also follow this &lt;a href="https://platform.openai.com/docs/introduction/overview"&gt;OpenAI Introduction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding generate terrain description function
&lt;/h2&gt;

&lt;p&gt;Now that we have our openai layer and our key in an environment variable, we can continue with the code.&lt;/p&gt;

&lt;p&gt;The next step is to create a new funcion that will generate a description based on the &lt;code&gt;terrain&lt;/code&gt; and &lt;code&gt;time&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import random
import boto3
import openai

def roll_dice(number):
    # code

def get_terrain_by_time(terrain_id, time_id):
    # code

def generate_terrain_description(terrain, time):
    openai_api_key = os.environ.get("OPENAI_API_KEY")
    prompt_template = """I am scene description Game Master. 
        You can give me description criteria and I will describe the scene only with the given description criteria.
        My answer will be a paragraph no longer than 4 lines and will use a description in a Game Master Syle.
        \n
        \nDescription criteria:
        \n- Terrain: _terrain_
        \n- Time of the day: _time_
        \n"""
    my_prompt = prompt_template.replace("_terrain_", terrain)
    my_prompt = my_prompt.replace("time", time)
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=my_prompt,
        temperature=0,
        max_tokens=100,
        top_p=1,
        frequency_penalty=0.0,
        presence_penalty=0.0,
        stop=["\n"]
    )
    return response.choices[0]["text"]

def create_terrain(terrain_id, time_id, name, time, description):
    # code

def lambda_handler(event, context):
    terrain_id = roll_dice(6)
    time_id = roll_dice(2)
    terrain = terrains_table[terrain_id -1]
    time = time_table[time_id -1]
    item = get_terrain_by_time(terrain_id, time_id)

    if not item:
        description = generate_terrain_description(terrain, time)
        item = create_terrain(terrain_id, time_id, terrain, time, description)

    return item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;If everything went well, you will have the following output in your Lambda function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "terrain_id": 2,
    "time_id": 2,
    "description": "The forest is shrouded in darkness, the only light coming from the stars and the moon. The trees stand tall and silent, their branches swaying gently in the night breeze. The air is still and the only sound is the occasional chirp of a night bird.",
    "terrain": "Forest",
    "time": "night"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that's all for this article, in the next one I plan to generate images using Dall-e-2 and adding all the code in a GitHub Repository.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;p&gt;Cover by &lt;a href="https://unsplash.com/@andrewtneel?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;@andrewtneel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
      <category>openai</category>
      <category>development</category>
    </item>
    <item>
      <title>DevBlog #0 Introduction</title>
      <dc:creator>Jesus Marin</dc:creator>
      <pubDate>Fri, 14 Jul 2023 03:45:22 +0000</pubDate>
      <link>https://dev.to/chuymarin/development-blog-0-55le</link>
      <guid>https://dev.to/chuymarin/development-blog-0-55le</guid>
      <description>&lt;p&gt;Hello Everyone!&lt;/p&gt;

&lt;p&gt;I'm a DevOps Engineer who is passionate about technology, and I've always wanted to start a development blog. I've had many different ideas, but nothing that I truly wanted to pursue.&lt;/p&gt;

&lt;p&gt;Recently, I've become interested in OSR (Old School Renaissance/Revival) TTRPG Books due to their art style and fantasy content. I've enjoyed video games such as Fallout, Diablo, and Disco Elysium, which have a rich amount of content and lore.&lt;/p&gt;

&lt;p&gt;I've been working on some game concepts to create a hybrid between a video game and a TTRPG. Therefore, I'm starting a series of development articles to document my progress.&lt;/p&gt;

&lt;p&gt;Next: &lt;a href="https://dev.to/chuymarin/development-blog-1-4kg9"&gt;DevBlog #1 Autogenerated descriptions using OpenAI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
    </item>
  </channel>
</rss>
