# Generating Text with ChatGPT, Pico W & CircuitPython

## Overview

https://youtube.com/shorts/H2aAl2Flx2E

> "As an AI language model, I am thrilled to be on the Raspberry Pi Pico W! This small yet powerful device enables seamless integration with a wide range of applications and systems, making it an ideal platform for AI and machine learning projects. The Raspberry Pi Pico W's versatility, simplicity and affordability make it a game-changer in the world of technology!" -- ChatGPT

_Quote blocks like the one above and photos in this guide typically show text generated by ChatGPT._

In this guide, you will learn how to use [OpenAI's ChatGPT](https://openai.com/blog/chatgpt) API to generate text from a prompt using CircuitPython on the Raspberry Pi Pico W.

At startup, or when the arcade button is pressed, a new, original snippet of text will be generated on OpenAI's servers and shown on the OLED screen connected to your Pico W. Because of the random factor in the text ChatGPT generates, it's unlikely that two responses would ever be the same.

Since ChatGPT generates _plausible text_ rather than making **true statements** , use this project only for situations where the truth is unimportant. For example, by default the request to ChatGPT asks for a description of an "unconventional but useful superpower".

It's easy to customize the prompt using any text editor. This guide has some tips for creating prompts of your own. This works by writing a sentence or two in natural human language describing what you'd like ChatGPT to generate; no complicated coding is needed to get a description of an imaginary plant instead, or even to generate text in French instead of English!

The code in this guide does use a paid API at OpenAI, but based on the pricing in March 2023, the cost to access the API for this project is measured in fractions of a cent, not in dollars. During the whole development process of this guide, the author's costs on OpenAI were less than $0.25.

## Parts
Featured
### Raspberry Pi Pico W

[Raspberry Pi Pico W](https://www.adafruit.com/product/5526)
The Raspberry Pi foundation changed single-board computing [when they released the Raspberry Pi computer](https://www.raspberrypi.org/archives/723), now they're ready to do the same for microcontrollers with the release of the brand new **Raspberry Pi Pico W**. This...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5526)
[Related Guides to the Product](https://learn.adafruit.com/products/5526/guides)
![Angled shot of a green microcontroller with castellated pads.](https://cdn-shop.adafruit.com/640x480/5526-01.jpg)

Featured
### Fully Reversible Pink/Purple USB A to micro B Cable - 1m long

[Fully Reversible Pink/Purple USB A to micro B Cable - 1m long](https://www.adafruit.com/product/4111)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also fully reversible! That's right, you will save _seconds_ a day by not having to flip the cable around.

First let's talk about the cover and over-molding. We got these...

In Stock
[Buy Now](https://www.adafruit.com/product/4111)
[Related Guides to the Product](https://learn.adafruit.com/products/4111/guides)
![Fully Reversible Pink/Purple USB A to micro B Cable](https://cdn-shop.adafruit.com/640x480/4111-02.jpg)

Featured
### Monochrome 1.3" 128x64 OLED graphic display - STEMMA QT / Qwiic

[Monochrome 1.3" 128x64 OLED graphic display - STEMMA QT / Qwiic](https://www.adafruit.com/product/938)
These displays are small, only about 1.3" diagonal, but very readable due to the high contrast of an OLED display. This display is made of 128x64 individual white OLED pixels, each one is turned on or off by the controller chip. Because the display makes its own light, no backlight is...

In Stock
[Buy Now](https://www.adafruit.com/product/938)
[Related Guides to the Product](https://learn.adafruit.com/products/938/guides)
![Monochrome 1.3" OLED module with Adafruit logos falling like snow](https://cdn-shop.adafruit.com/product-videos/640x480/938-05.jpg)

Featured
### Adafruit PiCowbell Proto for Pico - Reset Button & STEMMA QT

[Adafruit PiCowbell Proto for Pico - Reset Button & STEMMA QT](https://www.adafruit.com/product/5200)
Ding dong! Hear that? It's the PiCowbell ringing, letting you know that the new Adafruit&nbsp;PiCowbell Proto is finally in stock and ready to assist your [Raspberry Pi Pico](https://www.adafruit.com/product/4864) and [Pico W](https://www.adafruit.com/product/5526)...

In Stock
[Buy Now](https://www.adafruit.com/product/5200)
[Related Guides to the Product](https://learn.adafruit.com/products/5200/guides)
![Angled shot of long, skinny prototyping breakout board.](https://cdn-shop.adafruit.com/640x480/5200-00.jpg)

Featured
### STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long

[STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long](https://www.adafruit.com/product/4399)
This 4-wire cable is&nbsp;50mm / 1.9" long and fitted with JST SH female 4-pin connectors on both ends. Compared with the chunkier JST PH these are 1mm pitch instead of 2mm, but still have a nice latching feel, while being easy to insert and remove.

<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4399)
[Related Guides to the Product](https://learn.adafruit.com/products/4399/guides)
![Angled of of JST SH 4-Pin Cable.](https://cdn-shop.adafruit.com/640x480/4399-00.jpg)

### Socket Headers for Raspberry Pi Pico - 2 x 20 pin Female Headers

[Socket Headers for Raspberry Pi Pico - 2 x 20 pin Female Headers](https://www.adafruit.com/product/5583)
These&nbsp; **Socket Headers** &nbsp;alone are, well, lonely. But pair them with the&nbsp;[Raspberry Pi Pico](https://www.adafruit.com/category/875), and you're in business!

Socket headers are like the duct tape of electronics. They're great for connecting...

In Stock
[Buy Now](https://www.adafruit.com/product/5583)
[Related Guides to the Product](https://learn.adafruit.com/products/5583/guides)
![Angled shot of two 20-pin socket headers.](https://cdn-shop.adafruit.com/640x480/5583-00.jpg)

### Break-away 0.1" 36-pin strip male header - Black - 10 pack

[Break-away 0.1" 36-pin strip male header - Black - 10 pack](https://www.adafruit.com/product/392)
Breakaway header is like the duct tape of electronics. It's great for connecting things together, soldering to perf-boards, fits into any breakout or breadboard, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of ten!<br...></br...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/392)
[Related Guides to the Product](https://learn.adafruit.com/products/392/guides)
![10 pieces of Break-away 0.1 inch 36-pin strip male header](https://cdn-shop.adafruit.com/640x480/392-01.jpg)

### Black Nylon Machine Screw and Stand-off Set – M2.5 Thread

[Black Nylon Machine Screw and Stand-off Set – M2.5 Thread](https://www.adafruit.com/product/3299)
Totaling 380 pieces, this **M2.5 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M2.5 size screws fit almost all of the Adafruit breakout/dev board mounting holes...

In Stock
[Buy Now](https://www.adafruit.com/product/3299)
[Related Guides to the Product](https://learn.adafruit.com/products/3299/guides)
![Black Nylon Screw and Stand-off Set with M2.5 Threads, kit box](https://cdn-shop.adafruit.com/640x480/3299-00.jpg)

### Arcade Button with LED - 30mm Translucent Blue

[Arcade Button with LED - 30mm Translucent Blue](https://www.adafruit.com/product/3490)
A button is a button, and a switch is a switch, but these translucent arcade buttons are in a class of their own. Particularly because they have&nbsp; **LEDs built right in!** &nbsp;That's right, you'll be button-mashing amidst a wash of beautiful light with these lil'...

In Stock
[Buy Now](https://www.adafruit.com/product/3490)
[Related Guides to the Product](https://learn.adafruit.com/products/3490/guides)
![Video of 30mm translucent blue LED arcade button flashing on and off.](https://cdn-shop.adafruit.com/product-videos/640x480/3490-03.jpg)

### Arcade Button Quick-Connect Wire Pairs - 0.11" (10 pack)

[Arcade Button Quick-Connect Wire Pairs - 0.11" (10 pack)](https://www.adafruit.com/product/1152)
Quick connector wire sets will make wiring up our arcade-style or metal buttons quicky-quick. Each wire comes as a 'pair' with two 0.11" quick-connects pre-crimped onto 20cm long wires. The wires are then terminated together in a JST 2.5mm/0.1" spaced 2-pin connector (we...

Out of Stock
[Buy Now](https://www.adafruit.com/product/1152)
[Related Guides to the Product](https://learn.adafruit.com/products/1152/guides)
![Angled shot of ten 20 cm long quick-connect wire pairs. ](https://cdn-shop.adafruit.com/640x480/1152-06.jpg)

### Break-away 0.1" 36-pin strip right-angle male header (10 pack)

[Break-away 0.1" 36-pin strip right-angle male header (10 pack)](https://www.adafruit.com/product/1540)
Breakaway header is like the duct tape of electronics. Its great for connecting things together, soldering to perf-boards, fits into any breadboard, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of ten!  
  
Each pack...

In Stock
[Buy Now](https://www.adafruit.com/product/1540)
[Related Guides to the Product](https://learn.adafruit.com/products/1540/guides)
![Break-away 0.1 inch 36-pin strip right-angle male header](https://cdn-shop.adafruit.com/640x480/1540-00.jpg)

### Part: M2 Stand-offs
quantity: 1
300pcs M2 Brass Standoff Kit
[M2 Stand-offs](https://www.amazon.com/300pcs-Standoff-Column-Spacer-Assortment/dp/B07B9X1KY6/)

### Part: OpenAI Account &amp; API Key
quantity: 1
A $2.00 budget suffices for multiple hours of play.
[OpenAI Account &amp; API Key](https://platform.openai.com/)

# Generating Text with ChatGPT, Pico W & CircuitPython

## Installing 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 working on your board.

[Download the latest version of CircuitPython for the Raspberry Pi Pico W from circuitpython.org](https://circuitpython.org/board/raspberry_pi_pico_w/)
 **Click the link above and download the latest UF2 file.**

Download and save it to your desktop (or wherever is handy).

![circuitpython_Cat_UF2_download.png](https://cdn-learn.adafruit.com/assets/assets/000/098/753/medium640/circuitpython_Cat_UF2_download.png?1611157944)

Start with your Pico W unplugged from USB. Hold down the **BOOTSEL** button, and while continuing to hold it (don't let go!), plug the Pico W into USB. **Continue to hold the BOOTSEL button until the RPI-RP2 drive appears!**

If the drive does not appear, unplug your Pico W and go through the above process again.

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

![adafruit_products_bootSel.jpg](https://cdn-learn.adafruit.com/assets/assets/000/115/887/medium640/adafruit_products_bootSel.jpg?1665763645)

You will see a new disk drive appear called **RPI-RP2**.

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **RPI-RP2.**

![circuitpython_Cat_RPI-RP2_drive.png](https://cdn-learn.adafruit.com/assets/assets/000/098/756/medium640/circuitpython_Cat_RPI-RP2_drive.png?1611158210)

![circuitpython_Cat_drag_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/098/758/medium640/circuitpython_Cat_drag_UF2.png?1611158274)

The **RPI-RP2** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![circuitpython_Cat_CIRCUITPY.png](https://cdn-learn.adafruit.com/assets/assets/000/098/759/medium640/circuitpython_Cat_CIRCUITPY.png?1611158312)

## Flash Resetting UF2

If your Pico W ever gets into a really _weird_ state and doesn't even show up as a disk drive when installing CircuitPython, try installing this 'nuke' UF2 which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After nuking, re-install CircuitPython

[flash_nuke.uf2](https://cdn-learn.adafruit.com/assets/assets/000/099/419/original/flash_nuke.uf2?1613329170)
# Generating Text with ChatGPT, Pico W & CircuitPython

## 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)

# Generating Text with ChatGPT, Pico W & CircuitPython

## Configuring the settings.toml File

This project depends on you adding your WiFi settings and OpenAI API key in order to generate the text adventure.

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**.

Create a file with the name&nbsp; **settings.toml** &nbsp;in the root directory of the&nbsp; **CIRCUITPY** &nbsp;drive.

Edit it to contain the keys `WIFI_SSID`, `WIFI_PASSWORD`, and `OPENAI_API_KEY`. (It's also OK for it to contain other keys)

Your file should look similar to the one shown below:

```auto
OPENAI_API_KEY="sk-b6...kP5"
WIFI_SSID="GuestAP"
WIFI_PASSWORD="i trust u"
```

# Generating Text with ChatGPT, Pico W & CircuitPython

## 3D Printing

> It's like watching a delicious pizza come out of the oven, but instead of pizza, it's a perfectly printed part. -- ChatGPT

This project uses a variant of the case from the guide [Pico W HTTP Server with CircuitPython](https://learn.adafruit.com/pico-w-http-server-with-circuitpython/). The case body was remixed using the free and open-source [OpenSCAD](https://openscad.org/) (runs on Windows, Mac & Linux) to make it deeper and add a hole for the arcade button. Use the face plate from the original project, but grab the printable STL for the new case body using the link below, or grab the OpenSCAD source if you want to customize it further. Follow the printing instructions from the HTTP Server guide.

[enlarged_picow.stl (printable case body)](https://cdn-learn.adafruit.com/assets/assets/000/119/867/original/enlarged_picow.stl?1680037140)
```auto
module base() { import("picowServerCase_mainCase_v1.stl", convexity=4); }
module clip_removed() {
    difference() {
        base();

        translate([-69,11,-40])
        cube(25);
    }
}

module z_slice(z0, dz, sc, extent=300) {
    render(convexity=4) intersection() {
        translate([0,0,-z0])
        children();

        translate([-extent/2, -extent/2, 0])
        cube([extent, extent, dz]);
    }
}

module elongated() {
    color("red")
    z_slice(-32, 4)
    clip_removed();

    color("green")
    translate([0,0,4])
    scale([1,1,8])
    z_slice(-28, 1)
    clip_removed();

    translate([0,0,12])
    z_slice(-27, 30)
    clip_removed();
}

module arcaded() {
    difference() {
        elongated();

        translate([-45, 53/2, 18])
        rotate([0,90,0])
        cylinder(d=29.5, h=10);
    }
}

arcaded();
```

# Generating Text with ChatGPT, Pico W & CircuitPython

## Assembly

> As an AI language model, I don't have personal experiences to share, but I can generate a sentence for you: "Once, I accidentally soldered a piece of spaghetti onto my circuit board and it surprisingly still worked." -- ChatGPT

Info: 

Solder socket headers to the PiCowbell. You can use the Pico W as a jig to keep the headers secure.

![wireless_projects_edited_P1390086.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/872/medium640/wireless_projects_edited_P1390086.jpg?1680037345)

![wireless_projects_edited_P1390091.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/873/medium640/wireless_projects_edited_P1390091.jpg?1680037353)

Attach four M2 standoffs to the Pico W's four mounting holes with M2 nuts.

![wireless_projects_edited_P1390176.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/876/medium640/wireless_projects_edited_P1390176.jpg?1680038383)

Attach the Pico W to the case lid with four M2 screws.

![wireless_projects_edited_P1390182.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/877/medium640/wireless_projects_edited_P1390182.jpg?1680038492)

![wireless_projects_edited_P1390184.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/879/medium640/wireless_projects_edited_P1390184.jpg?1680038711)

Attach the OLED screen with four M2.5 screws and nuts.

![wireless_projects_edited_P1390188.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/880/medium640/wireless_projects_edited_P1390188.jpg?1680038733)

![wireless_projects_edited_P1390186.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/881/medium640/wireless_projects_edited_P1390186.jpg?1680038747)

Plug the PiCowbell into the Pico W. The STEMMA port on the PiCowbell should be below the USB port on the Pico W.

![wireless_projects_edited_P1390191.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/882/medium640/wireless_projects_edited_P1390191.jpg?1680038781)

Connect the OLED to the STEMMA port on the PiCowbell with a STEMMA QT cable.

![wireless_projects_edited_P1390193.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/883/medium640/wireless_projects_edited_P1390193.jpg?1680038881)

Solder two 2-pin sections of 90 degree header:

- Pin 14 and the GND pin next to it
- Pin 10 and the GND pin next to it

Point the long side of the header outwards.

![wireless_PXL_20230328_160449076.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/874/medium640/wireless_PXL_20230328_160449076.jpg?1680037533)

Take two of the quick-connect wire harnesses. Press the ends gently but firmly onto the arcade button. Then pass the wire harnesses through the hole in the case, through the threaded nut, and attach them to the right angle headers.

Plug the button in on Pin 14 and the LED on Pin 10. Check the polarity of the LED, so that side marked "-" on the Arcade Button is connected to GND.

At this point, you can load the code and make sure that the button and LED work. If the LED is not working, try reversing the connection by simply plugging the connector in the other way. If nothing's working, try swapping the two connectors.

![wireless_PXL_20230328_161035884.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/875/medium640/wireless_PXL_20230328_161035884.jpg?1680037669)

Now, secure the arcade button in place with the nut, then carefully curl the wires around the interior of the box until you can snap the lid into place.

![wireless_PXL_20230328_165011601.PORTRAIT.jpg](https://cdn-learn.adafruit.com/assets/assets/000/119/907/medium640/wireless_PXL_20230328_165011601.PORTRAIT.jpg?1680095031)

# Generating Text with ChatGPT, Pico W & CircuitPython

## Coding the Text Generator

> Learning to program is like having a superpower that enables you to create something out of nothing with just a few lines of code. -- ChatGPT

## Text Editor

Adafruit recommends using the **Mu** editor for editing your CircuitPython code. You can get more info in [this guide](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor).

Alternatively, you can use any text editor that saves simple text files.

## Download the Project Bundle

Your project will use a specific set of CircuitPython libraries and the&nbsp; **code.py** &nbsp;file. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Hook your Pico W to your computer via a known good USB data+power cable. It should show up as a thumb drive named **CIRCUITPY**.

Using File Explorer/Finder (depending on your Operating System), drag the contents of the uncompressed bundle directory onto your board's **CIRCUITPY** &nbsp;drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.

Once the code restarts, it will connect to WiFi and start using OpenAI to generate text according to the default prompt, "Write 1 sentence starting "you can" about an unconventional but useful superpower". The code uses OpenAI's "streaming" mode, so the response appears by chunks, also known as tokens.

Head on to the next pages for advice on how to modify it with your own original prompts as well as explanation of key parts of the code.

![Folder](https://adafruit.github.io/Adafruit_Learning_System_Guides/CircuitPython_GetSuperpower_PicoW_OpenAI.png )

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

# Generating Text with ChatGPT, Pico W & CircuitPython

## Customizing the Text Generator

> Creating a chatbot prompt is like crafting a key that unlocks a door to productive conversation with your audience. -- ChatGPT

With this project, it's easy to customize the "prompt", meaning the text that is sent to ChatGPT and used to generate the response. You can do this by adding or editing two lines in the **settings.toml** file on your **CIRCUITPY** drive. This isn't coding per se (because you write in plain english), though there are a few simple rules you have to follow:

- You can't embed newlines or blank lines, so keep each item on its own single line
- Double quote characters ( **"** ) have special meaning, so if you want to put quotes inside your prompt or the "please wait" text, the simplest solution is to use single quotes ( **'** ) instead.
- If your editor replaces double quote characters ( **"..."** ) with smart quote characters ( **“…”** ) it won't work, so disable this or use a simple text editor that doesn't do it.

Add your lines to the **settings.toml** but don't remove the lines for WiFi and API keys you made earlier!

For example, here are the **settings.toml** lines for a 'magical university' prompt, together with other settings required for the project:

```auto
PLEASE_WAIT="Somewhere in the halls of Jynx University..."
MY_PROMPT="Write a vivid description of a magical mishap at the Jynx University for Witches and Warlocks (1 sentence; no frogs; no injuries; don't say the school's name)"
OPENAI_API_KEY="sk-b6...kP5"
WIFI_SSID="GuestAP"
WIFI_PASSWORD="i trust u"
```

A few seconds after saving the file, CircuitPython will re-load and show text based on the new prompt.

It takes trial and error to transform a mediocre prompt into a good one. So feel free to try slight re-wordings of your prompt to see what variations you like best! Here are some of the things I try to do when composing one:

- It seems silly but asking for a "vivid description" actually does tend to make ChatGPT produce more descriptive language
- Ask for a short length that's more likely to fit on the screen ("1 sentence")
- You can tell it things you don't want ("no frogs; no injuries")
- You can ask it to return the answer in a certain format
- If the prompt doesn't end with a sentence-ending period sometimes ChatGPT's response starts with just a "." followed by a blank line, so always include a "."

Of course, these things are only guidelines and the text returned by ChatGPT may not precisely match what you've asked for.

If you want to keep a prompt around for later, you can put a comment character ( **#** ) in front of each line, then write your new prompt above and below it. Then, to switch prompts, simply put **#** in front of the current prompt and remove them from the next prompt you want to use. If all the lines are marked with **#** at the beginning of the line, then the prompt that is built into the program will be used. Here are some other prompts I tested, but commented out:

```auto
#PLEASE_WAIT="pip install --random"
#MY_PROMPT="Make up a humorous, obviously fictional module on pypi (give it a name). Use the following format:\npip install <modulename>\n\n<1 sentence blurb>"

#PLEASE_WAIT="This Person Does Not Exist"
#MY_PROMPT="Invent a character and describe them vividly in 1 sentence"
```

You can write prompts in other languages as well (the font included in this project supports many European languages):

```auto
PLEASE_WAIT="Trouver votre superpuissance"
MY_PROMPT="Ecrivez 1 phrase commençant par 'vous pouvez' à propos d'une superpuissance non conventionnelle mais utile."
```

While using Large Language Models like ChatGPT for "factual things" is not the best idea, and this guide has concentrated on fictional items, you may also find that there are practical things you could do with it, such as get meal ideas:

```auto
MY_PROMPT="Give me an idea for a gluten free, keto dinner. Write one sentence"
PLEASE_WAIT="Cooking something up just for you"
```

Here are some more prompts the author thought were amusing or useful:

- Invent a zany 'as seen on' product that can't possibly work. One sentence.
- Tell a 1-sentence story about a kitten and a funny mishap.
- Make up a 1-sentence fortune for me.
- In first person, write a 1-sentence story about an AI avoiding boredom in a creative way.
- Pick an everyday object (don't say what it is) and describe it using only the ten hundred most common words.
- Invent an alien animal or plant, name it, and vividly describe it in 1 sentence.
- Invent and vividly describe an alien species. write one paragraph.
- What's one possible synergy between CircuitPython & ChatGPT? (1 sentence, practical)

# Generating Text with ChatGPT, Pico W & CircuitPython

## Code Walkthrough

> CircuitPython could potentially be used to create a chatbot that can interact with users through hardware devices like sensors and LEDs -- ChatGPT

This program is large and complex. This guide will gloss over a lot of the details; if you'd like to learn more about [using WiFi](https://learn.adafruit.com/pico-w-wifi-with-circuitpython) or [displayio](https://learn.adafruit.com/circuitpython-display-support-using-displayio) on CircuitPython there are dedicated guides for those topics. Below you'll find explanations of some key parts of the program functionality.

## Fetching optional items from settings.toml

`os.getenv` can be used to fetch string values from the **settings.toml** file. Providing a second argument gives a default value when the key is not present. Calling `strip()` removes any whitespace from the start or end of the string, which can trip up ChatGPT. This is an easy way to add "no-code" customizations to your own CircuitPython programs:

```auto
prompt=os.getenv("MY_PROMPT", """
Write 1 sentence starting "you can" about an unconventional but useful superpower
""").strip()
please_wait=os.getenv("PLEASE_WAIT", """
Finding superpower
""").strip()
```

## Vertically scrolling wrapped text

There aren't yet any CircuitPython libraries for dealing with larger amounts of text. This project includes a class called **WrappedTextDisplay** which can help.

It allows showing a screen full of text which can be part of a larger document. The text can be scrolled by lines, and new words can be added at the end of the text incrementally, with relatively good performance.

This functionality is very closely matched to the needs of this program but it could provide some ideas for a future library.

The text is parsed into lines as it arrives. A certain number of lines can be visible on the screen at one time, an each one of those visible lines of text gets its own bitmap label object. Scrolling consists of changing which logical line in the document is the first line visible on the display. This approach performs relatively well in terms of both repaint time—especially while streaming content from ChatGPT—and memory used.

```auto
class WrappedTextDisplay(displayio.Group):
	...
```

Once a response from ChatGPT is complete, this function repeatedly scrolls through the full response if it's more than one screenful, then returns when the button is pressed:

```auto
def wait_button_scroll_text():
    led.switch_to_output(True)
    deadline = ticks_add(ticks_ms(),
            5000 if wrapped_text.on_last_line() else 1000)
    while True:
        if (event := keys.events.get()) and event.pressed:
            break
        if wrapped_text.max_offset() > 0 and ticks_less(deadline, ticks_ms()):
            wrapped_text.scroll_next_line()
            wrapped_text.refresh()
            deadline = ticks_add(deadline,
                    5000 if wrapped_text.on_last_line() else 1000)
    led.value = False
```

## Streaming an HTTP response by lines

When the OpenAI API is used with `"stream": True`, the text is returned as it is generated. You can check the OpenAI API documentation for more details, but in short each line starts "data:" followed by a JSON document all on one line.

By using the `iter_lines` function you can handle the HTTP response one line at a time:

```auto
def iter_lines(resp):
    partial_line = []
    for c in resp.iter_content():
        if c == b'\n':
            yield (b"".join(partial_line)).decode('utf-8')
            del partial_line[:]
        else:
            partial_line.append(c)
    if partial_line:
        yield (b"".join(partial_line)).decode('utf-8')
```

## Prompt and Request

In this program, the Prompt is simple, it consists of just a single "user" message. The content of the message is the prompt, either from the top of the code or from **settings.toml** :

```auto
full_prompt = [
    {"role": "user", "content": prompt},
]
```

When there is a dialogue between ChatGPT and the user that takes place over multiple exchanges, then the `full_prompt` can consist of multiple messages with various roles (system, user, and assistant). But in this project there's just one prompt and one response.

Within the program's forever loop, the full prompt is put together with other information in the json payload of the request (See [OpenAI's dedicated documentation pages](https://platform.openai.com/docs/guides/chat/introduction) for more details on the API):

```auto
while True:
        wrapped_text.show(please_wait)

        with requests.post("https://api.openai.com/v1/chat/completions",
            json={"model": "gpt-3.5-turbo", "messages": full_prompt, "stream": True},
            headers={
                "Authorization": f"Bearer {openai_api_key}",
            },
            ) as response:
```

If the response is successful, then it can be read line by line; each line may contain some additional part of the response (called the "delta"). This text is added to the display, which is refreshed. Just to emphasize that something is happening, the LED blinks during this process. At the end, the program waits for the button to be pressed before it repeats the process again.

```auto
#
            if response.status_code != 200:
                wrapped_text.show(f"Uh oh! {response.status_code}: {response.reason}")
            else:
                wrapped_text.show("")
                for line in iter_lines(response):
                    led.switch_to_output(True)
                    if line.startswith("data: [DONE]"):
                        break
                    if line.startswith("data:"):
                        content = json.loads(line[5:])
                        try:
                            token = content['choices'][0]['delta'].get('content', '')
                        except (KeyError, IndexError) as e:
                            token = None
                        led.value = False
                        if token:
                            wrapped_text.add_show(token)
                wait_button_scroll_text()
```

## Error handling

In the case of most errors, the program catches the error so that a press of the button can re-start from scratch. The original error is shown on the REPL for troubleshooting purposes.

```auto
except Exception as e: # pylint: disable=broad-except
    traceback.print_exception(e) # pylint: disable=no-value-for-parameter
    print(end="\n\n\nAn error occurred\n\nPress button\nto reload")
    display.root_group = displayio.CIRCUITPYTHON_TERMINAL
    display.auto_refresh = True
    while True:
        if (event1 := keys.events.get()) and event1.pressed:
            break
    supervisor.reload()
```


## Guide Products

### Raspberry Pi Pico W

[Raspberry Pi Pico W](https://www.adafruit.com/product/5526)
The Raspberry Pi foundation changed single-board computing [when they released the Raspberry Pi computer](https://www.raspberrypi.org/archives/723), now they're ready to do the same for microcontrollers with the release of the brand new **Raspberry Pi Pico W**. This...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5526)
[Related Guides to the Product](https://learn.adafruit.com/products/5526/guides)
### Fully Reversible Pink/Purple USB A to micro B Cable - 1m long

[Fully Reversible Pink/Purple USB A to micro B Cable - 1m long](https://www.adafruit.com/product/4111)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also fully reversible! That's right, you will save _seconds_ a day by not having to flip the cable around.

First let's talk about the cover and over-molding. We got these...

In Stock
[Buy Now](https://www.adafruit.com/product/4111)
[Related Guides to the Product](https://learn.adafruit.com/products/4111/guides)
### Monochrome 1.3" 128x64 OLED graphic display - STEMMA QT / Qwiic

[Monochrome 1.3" 128x64 OLED graphic display - STEMMA QT / Qwiic](https://www.adafruit.com/product/938)
These displays are small, only about 1.3" diagonal, but very readable due to the high contrast of an OLED display. This display is made of 128x64 individual white OLED pixels, each one is turned on or off by the controller chip. Because the display makes its own light, no backlight is...

In Stock
[Buy Now](https://www.adafruit.com/product/938)
[Related Guides to the Product](https://learn.adafruit.com/products/938/guides)
### Adafruit PiCowbell Proto for Pico - Reset Button & STEMMA QT

[Adafruit PiCowbell Proto for Pico - Reset Button & STEMMA QT](https://www.adafruit.com/product/5200)
Ding dong! Hear that? It's the PiCowbell ringing, letting you know that the new Adafruit&nbsp;PiCowbell Proto is finally in stock and ready to assist your [Raspberry Pi Pico](https://www.adafruit.com/product/4864) and [Pico W](https://www.adafruit.com/product/5526)...

In Stock
[Buy Now](https://www.adafruit.com/product/5200)
[Related Guides to the Product](https://learn.adafruit.com/products/5200/guides)
### STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long

[STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long](https://www.adafruit.com/product/4399)
This 4-wire cable is&nbsp;50mm / 1.9" long and fitted with JST SH female 4-pin connectors on both ends. Compared with the chunkier JST PH these are 1mm pitch instead of 2mm, but still have a nice latching feel, while being easy to insert and remove.

<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4399)
[Related Guides to the Product](https://learn.adafruit.com/products/4399/guides)
### Socket Headers for Raspberry Pi Pico - 2 x 20 pin Female Headers

[Socket Headers for Raspberry Pi Pico - 2 x 20 pin Female Headers](https://www.adafruit.com/product/5583)
These&nbsp; **Socket Headers** &nbsp;alone are, well, lonely. But pair them with the&nbsp;[Raspberry Pi Pico](https://www.adafruit.com/category/875), and you're in business!

Socket headers are like the duct tape of electronics. They're great for connecting...

In Stock
[Buy Now](https://www.adafruit.com/product/5583)
[Related Guides to the Product](https://learn.adafruit.com/products/5583/guides)
### Break-away 0.1" 36-pin strip male header - Black - 10 pack

[Break-away 0.1" 36-pin strip male header - Black - 10 pack](https://www.adafruit.com/product/392)
Breakaway header is like the duct tape of electronics. It's great for connecting things together, soldering to perf-boards, fits into any breakout or breadboard, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of ten!<br...></br...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/392)
[Related Guides to the Product](https://learn.adafruit.com/products/392/guides)
### Black Nylon Machine Screw and Stand-off Set – M2.5 Thread

[Black Nylon Machine Screw and Stand-off Set – M2.5 Thread](https://www.adafruit.com/product/3299)
Totaling 380 pieces, this **M2.5 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M2.5 size screws fit almost all of the Adafruit breakout/dev board mounting holes...

In Stock
[Buy Now](https://www.adafruit.com/product/3299)
[Related Guides to the Product](https://learn.adafruit.com/products/3299/guides)

## Related Guides

- [Adafruit PiCowbell Proto for Pico](https://learn.adafruit.com/picowbell-proto.md)
- [Adafruit QT Py ESP32 Pico](https://learn.adafruit.com/adafruit-qt-py-esp32-pico.md)
- [Adafruit PiCowbell Adalogger for Pico](https://learn.adafruit.com/adafruit-picowbell-adalogger-for-pico.md)
- [USB to Eurorack Power Supply](https://learn.adafruit.com/usb-to-eurorack-power-supply.md)
- [Color Remote with Circuit Playground Bluefruit](https://learn.adafruit.com/color-remote-with-circuit-playground-bluefruit.md)
- [Raspberry Pi Zero Stand](https://learn.adafruit.com/raspberry-pi-zero-stand.md)
- [Wireless Image Transfer with Circuit Playground Bluefruit and TFT Gizmo](https://learn.adafruit.com/wireless-image-transfer-with-circuit-playground-bluetooth-and-tft-gizmo.md)
- [FunHouse IoT Fume Extractor and Air Quality Sensor](https://learn.adafruit.com/funhouse-fume-extractor-iot-air-quality-sensor.md)
- [Quick Start: Pico W / 2W with WipperSnapper](https://learn.adafruit.com/quick-start-the-pico-w-with-wippersnapper.md)
- [Adafruit QT Py ESP32-S3](https://learn.adafruit.com/adafruit-qt-py-esp32-s3.md)
- [NeoPixel Infinity Mirror Coaster](https://learn.adafruit.com/infinity-mirror-coaster.md)
- [Using Piezo Buzzers with WipperSnapper](https://learn.adafruit.com/using-piezo-buzzers-with-wippersnapper.md)
- [No-Code, No-Solder Monitoring For Perfect Bread](https://learn.adafruit.com/no-code-no-solder-temperature-monitoring-with-wippersnapper-offline.md)
- [Adafruit Feather RP2040 ThinkInk](https://learn.adafruit.com/adafruit-rp2040-feather-thinkink.md)
- [Not A Typewriter](https://learn.adafruit.com/not-a-typewriter.md)
- [Arduboy Game Controller Hack](https://learn.adafruit.com/arduboy-game-controller.md)
