# OpenAI Image Descriptors with MEMENTO

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/128/499/medium800/camera_edited_P1440420.jpg?1709327292)

The old adage ["a picture is worth a thousand words"](https://en.wikipedia.org/wiki/A_picture_is_worth_a_thousand_words) asserts that a standalone image has the ability to express complex thoughts, views and feelings concurrently. In this project, you'll put that to the test by uploading the pictures you take with your MEMENTO camera to [OpenAI](https://platform.openai.com/overview) to request a description of the image with various prompts.&nbsp;

The MEMENTO is running CircuitPython code that lets you connect to WiFi, take a photo,&nbsp;[send the photo to OpenAI with their API](https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images) and then save the response as a text file. You can view the response after it is fetched on the MEMENTO display.

Six prompts are included to get you started and they range from utilitarian to silly:

1. Alt Text
2. Haiku
3. Translate Text to English
4. Cable Identifier
5. Describe the Image as an Alien Visitor
6. Is Anything Out of Place?

You can use the directional buttons on the MEMENTO to select your prompt before taking the photo and sending it to OpenAI.

![camera_choosePrompt.gif](https://cdn-learn.adafruit.com/assets/assets/000/128/501/medium640thumb/camera_choosePrompt.jpg?1709328167)

## Project Inspiration

The inspiration for this project came from the [Descriptive Camera project by Matt Richardson](https://mattrichardson.com/descriptive-camera). It was built in 2012 with a [BeagleBone](https://www.adafruit.com/product/1996) that connected to the [Amazon Mechanical Turk API](https://www.mturk.com/mturk/welcome). That API would outreach to people on the internet to complete tasks. In this case, it was asking those workers to create metadata manually for each photo submitted. Just over ten years later, and this process can now be automated and run without the need for a Linux OS.

## Thoughts on "AI"

Artificial intelligence is one of the most divisive issues of our time. The approach and mindset of this project is that at its core, AI is a tool that is only as good as the human giving input to it. You'll see that the prompts used in this project are worded in a way to try and achieve a result that is both useful and concise; with the keyword being try. Mistakes on the part of the API are entirely possible and responses should always be checked.

However, in general, the responses have been found to be accurate and, as a result, exciting, especially when considering how some of these more utilitarian prompts could be engineered in the future for accessibility applications.

## Parts
### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
![Video of a DIY camera on a lazy susan.](https://cdn-shop.adafruit.com/product-videos/640x480/5420-05.jpg)

### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
![Lithium Ion Polymer Battery 3.7v 420mAh with JST 2-PH connector and short cable](https://cdn-shop.adafruit.com/640x480/4236-04.jpg)

### 256MB Micro SD Memory Card

[256MB Micro SD Memory Card](https://www.adafruit.com/product/5251)
Add storage in a jiffy using this **256MB microSD card**. Preformatted to FAT32, so it works out of the packaging with our projects. Works great with any device in the Adafruit shop that uses microSD cards. Ideal for use with Feathers, data loggers, or small Linux SBCs (not good...

In Stock
[Buy Now](https://www.adafruit.com/product/5251)
[Related Guides to the Product](https://learn.adafruit.com/products/5251/guides)
![Angled shot of Small microSD card 256mb](https://cdn-shop.adafruit.com/640x480/5251-00.jpg)

### Pink and Purple Woven USB A to USB C Cable - 1 meter long

[Pink and Purple Woven USB A to USB C Cable - 1 meter long](https://www.adafruit.com/product/5153)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers, and more.&nbsp;&nbsp;[If you want something just like it but for Micro B, we...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5153)
[Related Guides to the Product](https://learn.adafruit.com/products/5153/guides)
![Angled shot of coiled pink and purple USB cable with USB A and USB C connectors.](https://cdn-shop.adafruit.com/640x480/5153-02.jpg)

# OpenAI Image Descriptors with MEMENTO

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Warning: Make sure you use CircuitPython 9.0.0 final or later. CircuitPython 9.0.0-beta.1 and earlier have a bug that can corrupt the fileystem.

```auto
import storage
storage.erase_filesystem()
```

Your board will reboot after running this.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_esp32s3_camera/)
Warning: As of CircuitPython 9, you'll need to create a folder called "sd" on your CIRCUITPY drive to mount the microSD card, if it's not already there.

[Follow these steps to create the /sd directory](https://learn.adafruit.com/adafruit-memento-camera-board/circuitpython-memento-starter-projects)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/126/734/medium800/adafruit_products_resetNeo.jpg?1702908010)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Double-click the **reset** button (highlighted in red above), and you will see the **RGB status LED(s)** turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

If you do not see the LED turning purple, you will need to reinstall the UF2 bootloader. See the **Factory Reset** page in this guide for details.

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **CAMERABOOT**. Drag the **adafruit-circuitpython-adafruit\_esp32s3\_camera-etc.uf2** file to **CAMERABOOT**.

![adafruit_products_cameraboot.png](https://cdn-learn.adafruit.com/assets/assets/000/126/740/medium640/adafruit_products_cameraboot.png?1702932896)

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# OpenAI Image Descriptors with MEMENTO

## Create an account with OpenAI

Info: 

In your web browser, visit [https://platform.openai.com/](https://platform.openai.com/)

Click the "sign up" link. Then, you can use your e-mail to sign up, or an existing Google or Microsoft account.

OpenAI may require additional steps such as e-mail or phone verification before you can log in to your account.

![circuitpython_Screenshot_2023-03-08_08-43-40.png](https://cdn-learn.adafruit.com/assets/assets/000/119/295/medium640/circuitpython_Screenshot_2023-03-08_08-43-40.png?1678286661)

Once you have completed the verification process and logged in, you will next create an API key. Use the menu in the far upper right corner (probably labeled "Personal") and then select "View API Keys".

![circuitpython_ksnip_20230308-084810.png](https://cdn-learn.adafruit.com/assets/assets/000/119/296/medium640/circuitpython_ksnip_20230308-084810.png?1678286921)

Then, create a fresh API key by clicking "Create new secret key".

![circuitpython_ksnip_20230308-084917.png](https://cdn-learn.adafruit.com/assets/assets/000/119/298/medium640/circuitpython_ksnip_20230308-084917.png?1678287073)

Save this secret key in the file **settings.toml** on the **CIRCUITPY** drive in a line that looks like

```
OPENAI\_API\_KEY="sk-b6...kP5"
```

This file also requires your WiFI credentials, see the next page of the guide for the details.

![circuitpython_ksnip_20230308-084955.png](https://cdn-learn.adafruit.com/assets/assets/000/119/299/medium640/circuitpython_ksnip_20230308-084955.png?1678287111)

At the time of writing, OpenAI provides a free credit with new accounts. After the free credit is used or expires, you'll need to enter a credit card in your billing information to keep using the service.

Using the project tends to cost a few cents per session at most, and it's easy to limit your monthly bill to a pre-set amount such as $8.00.

To set a hard usage limit per month, visit the "Usage Limits" section of the OpenAI website.

![circuitpython_ksnip_20230310-085720.png](https://cdn-learn.adafruit.com/assets/assets/000/119/338/medium640/circuitpython_ksnip_20230310-085720.png?1678460269)

![circuitpython_ksnip_20230310-085702.png](https://cdn-learn.adafruit.com/assets/assets/000/119/339/medium640/circuitpython_ksnip_20230310-085702.png?1678460280)

Warning: 

This graph shows the author's usage costs while developing and playtesting an app, a total of $1.27 in API calls.

![circuitpython_Screenshot_2023-03-09_09-29-01.png](https://cdn-learn.adafruit.com/assets/assets/000/119/311/medium640/circuitpython_Screenshot_2023-03-09_09-29-01.png?1678375759)

# OpenAI Image Descriptors with MEMENTO

## Configuring settings.toml and the OpenAI Prompts

This project depends on you adding your WiFi settings, OpenAI API key and text prompts to your board's **settings.toml** file. The text prompts are available in a text file in the **Project Bundle**.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/MEMENTO/MEMENTO_OpenAI_Image_Descriptor/memento_openai_prompts.txt

Plug your CircuitPython board into your computer via a known good data + power USB cable. Your board should show up as a thumb drive in your File Explorer / Finder (depending on your operating system) named **CIRCUITPY**.

Edit the **settings.toml** file to contain the following keys:

- `CIRCUITPY_WIFI_SSID`
- `CIRCUITPY_WIFI_PASSWORD`
- `OPENAI_API_KEY`
- `ALT_TEXT_PROMPT`
- `HAIKU_PROMPT`
- `CABLE_PROMPT`
- `TRANSLATE_PROMPT`
- `ALIEN_PROMPT`
- `WEIRD_PROMPT`

Your file should look similar to the one shown below:

```auto
CIRCUITPY_WIFI_SSID = "YOUR-SSID-HERE"
CIRCUITPY_WIFI_PASSWORD = "YOUR-PASSWORD-HERE"
OPENAI_API_KEY="YOUR-OPENAI-KEY-HERE"
ALT_TEXT_PROMPT="Please describe what is in this image. The description should be in the style of alt text used on social media sites like Mastodon. Avoid talking about the quality of the image. Avoid talking about the background of the image. Only describe the main subject."
HAIKU_PROMPT="Please identify the main subject of the image and write a haiku about it. It should be a poem that consists of three lines, with five syllables in the first line, seven in the second, and five in the third. It does not need to rhyme. Only return the haiku, no image description is necessary. Please insert a * between each line instead of a comma (,)."
CABLE_PROMPT="This image features a type of cable connector. Please specifically identify the cable connection. You should describe the category of the cable and the specific type. For example, if you see a USB cable, you should also say whether it is type A, type mini B, etc. If you are not sure what type of cable connector it is, please state that and make your best inference. The response should be concise, no more than two sentences. You do not need to describe the general appearance of the image."
TRANSLATE_PROMPT="This image has text that is not in English. Please translate it to English. Only return the translated text in English. For example, if the text reads hola (hello in Spanish), then return hello (translated to English). No further explanation is necessary. If you are not sure on how to translate a word(s) then please return the text as seen in the image. You do not need to describe the image."
ALIEN_PROMPT="Describe this image as if you are a friendly alien visiting from another world in our galaxy. You have no context for society on Earth. Your descriptions are cute, inquisitive and concise (2-3 sentences). You do not need to comment on the quality of the image."
WEIRD_PROMPT="Take in the full image as context. Is there anything in the image that is out of the ordinary or interesting? For example, if the image is of a backyard, do you see any animals or objects that catch your eye? You do not need to comment on the quality of the image. Please keep responses brief and concise, between one to two sentences. If you do not see anything out of the ordinary for the context of the image or anything particularly interesting, please return: Nothing to see here."
```

## About the Prompts

The text prompts were written to try and cover a wide range of possibilities. You'll see a recurring theme of asking OpenAI to be concise and to not comment on the image quality. These were consistent issues that popped up when constructing a prompt and should be considered if you write your own prompts. The main takeaway for writing prompts in general is that you should not assume any context on the part of OpenAI. If there is an important caveat or need for your prompt, then you should include it. The more detail, the better.

### Alt Text Prompt

The alt text prompt is the most general prompt included. It returns a brief description of the image. Mastodon was included as a reference point because of that social media network's commitment to accessibility and the prolific use of alt text on the site.

### Haiku Prompt

This is one of the sillier prompts included. It requests a haiku be written about the main subject of the image. The guidelines on what a haiku is is included because it was initially returning responses that had too many syllables to be a haiku. The `*` separator is requested so that it can be used as a line break in the CircuitPython code when the response is displayed on the MEMENTO screen.

### Cable Identifier Prompt

This is an attempt at a machine learning-style response. It asks OpenAI to identify a cable connection, such as a USB-A cable or a TRS audio cable.&nbsp;

### Translation Prompt

This prompt asks that any text in the image be translated to English. It was tested using common phrases in multiple languages via Google translate on a computer screen, language flashcards, product directions and hand written notes to check if it was a viable idea.

### Alien Prompt

This prompt is purely for entertainment. It asks that the image be described from the point of view of an alien visiting from outer space. Guidelines were included to make sure that the responses were wholesome, such as noting that the alien is friendly and that the descriptions are cute and inquisitive.

### Is Anything Out of Place? Prompt

Like the cable identifier prompt, this prompt attempts a pseudo-machine learning result by asking for OpenAI to determine if anything is interesting in the image based on the context of the image. An application for this could be a wildlife camera or monitoring for packages being delivered on a porch.

# OpenAI Image Descriptors with MEMENTO

## CircuitPython Code

Warning: The OpenAI API may change over time. If you get errors when submitting a request, check their API for any changes that may not be reflected in the code embedded here.

Once you've finished setting up your MEMENTO with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.

To do this, click on the **Download Project Bundle** button in the window below. It will download to your computer as a zipped folder.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/MEMENTO/MEMENTO_OpenAI_Image_Descriptor/code.py

## Upload the Code and Libraries to MEMENTO

After downloading the Project Bundle, plug your MEMENTO into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called **CIRCUITPY**. Unzip the folder and copy the following items to the MEMENTO's **CIRCUITPY** drive:

- **lib** folder
- **code.py**

Your MEMENTO **CIRCUITPY** drive should look like this after copying the **lib** folder and the **code.py** file.

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/MEMENTO_MEMENTO_OpenAI_Image_Descriptor.png )

## Add Your **settings.toml** File

As of CircuitPython 8.0.0, there is support for [Environment Variables](https://docs.circuitpython.org/en/latest/docs/environment.html). Environment variables are stored in a **settings.toml** file. Similar to **secrets.py** , the **settings.toml** file separates your sensitive information from your main **code.py** file. Add your **settings.toml** file as described in the [Configuring settings.toml and the OpenAI Prompts](https://learn.adafruit.com/openai-image-descriptors-with-memento/configuring-settings-toml-and-the-openai-prompts) earlier in this guide. You'll need to include your `OPENAI_API_KEY`,&nbsp;`CIRCUITPY_WIFI_SSID`, `CIRCUITPY_WIFI_PASSWORD` and the OpenAI text prompts.

[Configuring settings.toml and the OpenAI Prompts Guide Page](https://learn.adafruit.com/openai-image-descriptors-with-memento/configuring-settings-toml-and-the-openai-prompts)
## Manage Your OpenAI Account

If you've confirmed that all of your information is correct in **settings.toml** and you get a `KeyError` when you send the image to OpenAI, then you probably need to add a credit card to your OpenAI account. The vision model is not available to free tier accounts.

## How the CircuitPython Code Works

At the top of the code are some user configurable parameters. The first is `text_scale`. This is the scale of the **terminalio** font used to display the returned text from OpenAI on the display. Next are the prompt imports from the **settings.toml** file. The prompts are added to the `prompts` array. The `prompt_labels` array has `string` labels for each prompt that is shown on the display when it is selected.

```python
# scale for displaying returned text from OpenAI
text_scale = 2

# OpenAI key and prompts from settings.toml
openai_api_key = os.getenv("OPENAI_API_KEY")
alt_text_prompt = os.getenv("ALT_TEXT_PROMPT")
haiku_prompt = os.getenv("HAIKU_PROMPT")
cable_prompt = os.getenv("CABLE_PROMPT")
translate_prompt = os.getenv("TRANSLATE_PROMPT")
alien_prompt = os.getenv("ALIEN_PROMPT")
weird_prompt = os.getenv("WEIRD_PROMPT")

prompts = [alt_text_prompt,
           haiku_prompt,
           cable_prompt,
           translate_prompt,
           alien_prompt,
           weird_prompt]
num_prompts = len(prompts)
prompt_index = 0
prompt_labels = ["ALT_TEXT", "HAIKU", "CABLE_IDENTIFIER", "TRANSLATE", "ALIEN", "WEIRD?"]
```

## Functions

A few functions are used in the loop. `encode_image()` takes the JPEG image file from the microSD card and encodes it as Base64. This encoding is required for OpenAI.

```python
# encode jpeg to base64 for OpenAI
def encode_image(image_path):
    with open(image_path, 'rb') as image_file:
        image_data = image_file.read()
        base64_encoded_data = binascii.b2a_base64(image_data).decode('utf-8').rstrip()
        return base64_encoded_data
```

The `view_text()` function displays the returned description from OpenAI on the MEMENTO screen. It uses `wrap_text_to_lines` to have it fit on the screen.

```python
# view returned text on MEMENTO screen
def view_text(the_text):
    rectangle = vectorio.Rectangle(pixel_shader=palette, width=240, height=240, x=0, y=0)
    pycam.splash.append(rectangle)
    the_text = "\n".join(wrap_text_to_lines(the_text, 20))
    if prompt_index == 1:
        the_text = the_text.replace("*", "\n")
    text_area = label.Label(terminalio.FONT, text=the_text,
                            color=0xFFFFFF, x=2, y=10, scale=text_scale)
    pycam.splash.append(text_area)
    pycam.display.refresh()
```

The `send_img()` function passes the JPEG image to the `encode_image()` function. A request is sent to the OpenAI API. When it is returned, it is formatted as JSON. The returned description is saved as a text file with the same name as the image. The prompt used is also included in the file name. After the file is saved, the response text is shown on the MEMENTO display using the `view_text()` function.

```python
# send image to OpenAI, print the returned text and save it as a text file
def send_img(img, prompt):
    base64_image = encode_image(img)
    headers = {
      "Content-Type": "application/json",
      "Authorization": f"Bearer {openai_api_key}"
    }
    payload = {
      "model": "gpt-4-vision-preview",
      "messages": [
        {
          "role": "user",
          "content": [
            {
              "type": "text",
              "text": f"{prompt}"
            },
            {
              "type": "image_url",
              "image_url": {
                "url": f"data:image/jpeg;base64,{base64_image}"
              }
            }
          ]
        }
      ],
      "max_tokens": 300
    }
    response = requests.post("https://api.openai.com/v1/chat/completions",
                             headers=headers, json=payload)
    json_openai = response.json()
    print(json_openai['choices'][0]['message']['content'])
    alt_text_file = img.replace('jpg', 'txt')
    alt_text_file = alt_text_file[:11] + f"_{prompt_labels[prompt_index]}" + alt_text_file[11:]
    if prompt_index == 5:
        alt_text_file = alt_text_file.replace("?", "")
    with open(alt_text_file, "a") as fp:
        fp.write(json_openai['choices'][0]['message']['content'])
        fp.flush()
        time.sleep(1)
        fp.close()
    view_text(json_openai['choices'][0]['message']['content'])
```

The `load_image()` function opens and displays an image from the microSD card. It is placed in the same position on the display as the camera preview.

```python
# view images on sd card to re-send to OpenAI
def load_image(bit, file):
    bit.fill(0b00000_000000_00000)
    decoder.open(file)
    decoder.decode(bit, scale=0, x=0, y=0)
    pycam.blit(bit, y_offset=32)
    pycam.display.refresh()
```

## WiFi and Camera Initialization

The MEMENTO connects to your WiFi network and then instantiates `pycam` as a `PyCamera` device. `mode`, `effect` and `resolution` are set. You can try higher resolutions but `320x240` seemed to be plenty of pixels for OpenAI to discern from and it keeps API token usage low.

```auto
print()
print("Connecting to WiFi")
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
print("Connected to WiFi")
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

pycam = adafruit_pycamera.PyCamera()
pycam.mode = 0  # only mode 0 (JPEG) will work in this example

# Resolution of 320x240 is plenty for OpenAI
pycam.resolution = 1  # 0-12 preset resolutions:
#                      0: 240x240, 1: 320x240, 2: 640x480, 3: 800x600, 4: 1024x768,
#                      5: 1280x720, 6: 1280x1024, 7: 1600x1200, 8: 1920x1080, 9: 2048x1536,
#                      10: 2560x1440, 11: 2560x1600, 12: 2560x1920
# pycam.led_level = 1  # 0-4 preset brightness levels
# pycam.led_color = 0  # 0-7  preset colors: 0: white, 1: green, 2: yellow, 3: red,
#                                          4: pink, 5: blue, 6: teal, 7: rainbow
pycam.effect = 0  # 0-7 preset FX: 0: normal, 1: invert, 2: b&amp;w, 3: red,
#                                  4: green, 5: blue, 6: sepia, 7: solarize
```

All of the images on the microSD card are added to the `all_images` array. The images are then sorted by number so that they can be accessed in the order that they were photographed.

```python
# sort image files by numeric order
all_images = [
    f"/sd/{filename}"
    for filename in os.listdir("/sd")
    if filename.lower().endswith(".jpg")
    ]
all_images.sort(key=lambda f: int(''.join(filter(str.isdigit, f))))
```

## Prompt Labels

The default `PyCamera` display text at the bottom of the screen is covered with a **vectorio** `Rectangle` so that the prompt label text can be shown on the screen. These two elements are added to the `pycam` display group.

```python
# add label for selected prompt
rect = vectorio.Rectangle(pixel_shader=palette, width=240, height=20, x=0, y=0)
prompt_txt = label.Label(
            terminalio.FONT, text=prompt_labels[prompt_index], color=0xFF0055, x=10, y=15, scale=2
        )
# pylint: disable=protected-access
pycam._botbar.append(rect)
pycam._botbar.append(prompt_txt)
# pylint: enable=protected-access
pycam.display.refresh()
```

## The Loop

In the loop, a long press on the shutter button lets you autofocus on your subject. A short press takes a photo and saves it to the microSD card. After saving, it converts the JPEG image to Base64, uploads it to OpenAI with the selected prompt and returns the description. The response is saved as a text file that matches the image name.

```python
if pycam.shutter.long_press:
      pycam.autofocus()
if pycam.shutter.short_count:
      try:
        pycam.display_message("snap", color=0x00DD00)
        pycam.capture_jpeg()
        pycam.live_preview_mode()
      except TypeError as exception:
        pycam.display_message("Failed", color=0xFF0000)
        time.sleep(0.5)
        pycam.live_preview_mode()
      except RuntimeError as exception:
        pycam.display_message("Error\nNo SD Card", color=0xFF0000)
        time.sleep(0.5)
      all_images = [
              f"/sd/{filename}"
              for filename in os.listdir("/sd")
              if filename.lower().endswith(".jpg")
            ]
      all_images.sort(key=lambda f: int(''.join(filter(str.isdigit, f))))
      the_image = all_images[-1]
      pycam.display_message("OpenAI..", color=0x00DD00)
      send_img(the_image, prompts[prompt_index])
      view = True
```

## States with OK and Select

There is a state called `view` that is set to `True` after a response from OpenAI is received. When `view` is `True`, it means that the response is displayed as a label on the MEMENTO. To clear the text, the OK button needs to be pressed.

The second possible state is called `new_prompt`. This is toggled by the select button. It allows you to view the images on the microSD card. You can send the image to OpenAI for an additional response.

```python
if pycam.select.fell:
     if not new_prompt:
     	file_index = -1
      	new_prompt = True
      	filename = all_images[file_index]
      	load_image(bitmap, filename)
    else:
      	new_prompt = False
      	pycam.display.refresh()

if pycam.ok.fell:
  	if view:
    	pycam.splash.pop()
    	pycam.splash.pop()
    	pycam.display.refresh()
    	view = False
    if new_prompt:
      	pycam.display_message("OpenAI..", color=0x00DD00)
      	send_img(filename, prompts[prompt_index])
      	new_prompt = False
      	view = True
```

## Directional Buttons

By default, the directional buttons let you choose the different prompts from your list. If `new_prompt` is `True`, then the left and right buttons control scrolling thru your photos on the microSD card.

```python
if pycam.up.fell:
    prompt_index = (prompt_index - 1) % num_prompts
    prompt_txt.text = prompt_labels[prompt_index]
    pycam.display.refresh()

if pycam.down.fell:
	prompt_index = (prompt_index + 1) % num_prompts
    prompt_txt.text = prompt_labels[prompt_index]
    pycam.display.refresh()

if pycam.right.fell:
	if new_prompt:
        file_index = (file_index - -1) % -len(all_images)
        filename = all_images[file_index]
        load_image(bitmap, filename)
	else:
		prompt_index = (prompt_index + 1) % num_prompts
		prompt_txt.text = prompt_labels[prompt_index]
		pycam.display.refresh()

if pycam.left.fell:
	if new_prompt:
		file_index = (file_index + -1) % -len(all_images)
		filename = all_images[file_index]
		load_image(bitmap, filename)
	else:
		prompt_index = (prompt_index - 1) % num_prompts
		prompt_txt.text = prompt_labels[prompt_index]
		pycam.display.refresh()
```

# OpenAI Image Descriptors with MEMENTO

## Use

![](https://cdn-learn.adafruit.com/assets/assets/000/128/500/medium800/camera_edited_P1440440.jpg?1709327308)

In the bottom left corner of the screen, you'll see the currently selected text prompt for OpenAI. You can use the **directional buttons** to scroll thru the list.

![camera_choosePrompt.gif](https://cdn-learn.adafruit.com/assets/assets/000/128/502/medium640thumb/camera_choosePrompt.jpg?1709328192)

When you take a picture with the shutter button, it will send the image to OpenAI. The response is shown on the MEMENTO display. You'll press the **OK button** to go back to the camera app.

![camera_endView.gif](https://cdn-learn.adafruit.com/assets/assets/000/128/503/medium640thumb/camera_endView.jpg?1709328375)

If you've confirmed that all of your information is correct in **settings.toml** and you get a `KeyError` when you send the image to OpenAI then you probably need to add a credit card to your OpenAI account. The vision model is not available to free tier accounts.

The response from OpenAI is saved as a text file so that you can reference it later.

![camera_files.png](https://cdn-learn.adafruit.com/assets/assets/000/128/469/medium640/camera_files.png?1709320007)

If you want to send an image to OpenAI again or with a different prompt, you can press the **Select button**. This will let you view the images from the microSD card and scroll thru them with the **left and right directional buttons**. You can change prompts with the **up and down buttons**. You'll send the image to OpenAI with the **OK button**.

![camera_sendAgain.gif](https://cdn-learn.adafruit.com/assets/assets/000/128/504/medium640thumb/camera_sendAgain.jpg?1709328535)

# OpenAI Image Descriptors with MEMENTO

## Favorite Images and Descriptors Gallery

Here are some favorite responses from OpenAI and the images that inspired them.

## Alt Text Prompt
> A small orange plastic dinosaur toy posed as if nibbling on a teal LEGO brick.

![camera_img0070.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/485/medium640/camera_img0070.jpg?1709321448)

> A cow-shaped casing encompassing electronic components with visible circuit boards and connectors.

![camera_img0120.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/476/medium640/camera_img0120.jpg?1709320652)

## Alien Prompt
> Greetings! I have discovered a small Earth creature with a smooth fur covering and enchanting, round ocular units that gleam. It seems to be camouflaged in the shadows, except for its gaze which pierces the dimness.

![camera_img0117.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/479/medium640/camera_img0117.jpg?1709320874)

> Oh, what an adorable little creature with perky ears and a paw raised high! It seems to wear a wide smile and has patterns on its body that might mean something special to the Earth dwellers.

![camera_img0090.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/480/medium640/camera_img0090.jpg?1709321054)

## Translation Prompt
This is a picture of a Spanish flashcard.

> Sentence creator  
> On a sheet of paper or acrylic board, write the beginnings of the sentences.  
> Here are some ideas:  
> I ate\_\_\_\_\_\_  
> I caressed\_\_\_\_\_\_  
> I put on\_\_\_\_\_\_
> 
> Read aloud the words you wrote and invite your child to finish the sentence.

![camera_img0053.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/470/medium640/camera_img0053.jpg?1709320146)

This was instructions on product packaging in French.

> Turn on the LEDs, adjust the brightness, set the color, and more

![camera_img0111.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/478/medium640/camera_img0111.jpg?1709320773)

## Cable Identifier Prompt
> This is a USB cable with a Micro-B connector.

![camera_img0044.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/481/medium640/camera_img0044.jpg?1709321157)

> This image features various TRS (Tip, Ring, Sleeve) connectors, commonly known as audio jacks. They appear to include both 1/4 inch (6.35mm) and 1/8 inch (3.5mm) sizes.

![camera_img0119.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/482/medium640/camera_img0119.jpg?1709321202)

## Haiku Prompt
> Tiny figures stand,  
> Above the screen they watch close,  
> Silent guardians.

![camera_img0075.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/471/medium640/camera_img0075.jpg?1709320300)

> Black feline rests high,  
> Atop the rainbow's calm arc,  
> Dreams whisker-twitch deep.

![camera_img0036.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/483/medium640/camera_img0036.jpg?1709321256)

## Is Anything Out of Place? Prompt
> Nothing to see here.

![camera_img0121.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/484/medium640/camera_img0121.jpg?1709321351)

> The bunch of bananas with a barcode seems out of place on a cluttered desk among items like a keyboard and a pen.

![camera_img0094.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/473/medium640/camera_img0094.jpg?1709320420)

> A black cat is lying on a bed with a striped toy beside it.

![camera_img0109.jpg](https://cdn-learn.adafruit.com/assets/assets/000/128/477/medium640/camera_img0109.jpg?1709320729)


## Featured Products

### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
### Pink and Purple Woven USB A to USB C Cable - 1 meter long

[Pink and Purple Woven USB A to USB C Cable - 1 meter long](https://www.adafruit.com/product/5153)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers, and more.&nbsp;&nbsp;[If you want something just like it but for Micro B, we...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5153)
[Related Guides to the Product](https://learn.adafruit.com/products/5153/guides)
### 256MB Micro SD Memory Card

[256MB Micro SD Memory Card](https://www.adafruit.com/product/5251)
Add storage in a jiffy using this **256MB microSD card**. Preformatted to FAT32, so it works out of the packaging with our projects. Works great with any device in the Adafruit shop that uses microSD cards. Ideal for use with Feathers, data loggers, or small Linux SBCs (not good...

In Stock
[Buy Now](https://www.adafruit.com/product/5251)
[Related Guides to the Product](https://learn.adafruit.com/products/5251/guides)
### 8GB Class 10 SD/MicroSD Memory Card - SD Adapter Included

[8GB Class 10 SD/MicroSD Memory Card - SD Adapter Included](https://www.adafruit.com/product/2692)
Add mega-storage in a jiffy using this 8 GB micro-SD card. It comes with a SD adapter so you can use it with any of our shields or adapters! Preformatted to FAT so it works out of the box with our projects. Tested and works great with our [Wave...](http://www.adafruit.com/products/94)

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2692)
[Related Guides to the Product](https://learn.adafruit.com/products/2692/guides)

## Related Guides

- [Adafruit MEMENTO Camera Board](https://learn.adafruit.com/adafruit-memento-camera-board.md)
- [AdaBox 021](https://learn.adafruit.com/adabox021.md)
- [MEMENTO Wireless Remote with TouchOSC](https://learn.adafruit.com/memento-wireless-remote.md)
- [Face Tracking Robot with MEMENTO](https://learn.adafruit.com/face-tracking-robot-with-memento.md)
- [Memento Photo Capture with itsaSNAP](https://learn.adafruit.com/memento-photo-capture-with-itsasnap.md)
- [DIY IoT Doorbell Camera with MEMENTO](https://learn.adafruit.com/diy-iot-doorbell-camera-with-memento.md)
- [Remote Shutter Button for MEMENTO](https://learn.adafruit.com/memento-shutter.md)
- [ePaper Camera](https://learn.adafruit.com/epaper-camera.md)
- [3D Printed Camera Case for MEMENTO](https://learn.adafruit.com/memento-3d-case.md)
- [IoT Bird Feeder with Camera](https://learn.adafruit.com/iot-window-bird-feeder-with-camera.md)
- [MEMENTO Focus Stacking](https://learn.adafruit.com/memento-focus-stacking.md)
- [BLE Cat Thermal Printer with MEMENTO](https://learn.adafruit.com/ble-cat-thermal-printer-with-memento.md)
- [Set up Web Workflow on the Adafruit MEMENTO](https://learn.adafruit.com/set-up-web-workflow-on-the-adafruit-memento.md)
- [Facial Detection and Recognition with MEMENTO](https://learn.adafruit.com/facial-detection-and-recognition-with-memento.md)
- [NeoTrellis Game](https://learn.adafruit.com/neotrellis-box-game.md)
