Skip to content

Instantly share code, notes, and snippets.

@jxxcarlson
Created May 11, 2023 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jxxcarlson/62f67f60a941b50c6e615f8bb9aaa386 to your computer and use it in GitHub Desktop.
Save jxxcarlson/62f67f60a941b50c6e615f8bb9aaa386 to your computer and use it in GitHub Desktop.
The code needed in an Elm + Lamdera app to use OpenAI's API to generate images

Intro

The code below is the core functionality used in the app gpt-lab.lamdera.app. It is based on choonkeat/elm-openai, which I highly recommend. The other reference is the api-reference/images part of OpenAI's docs.

— jxxcarlson

Data flow

The data flow goes like this:

Send the following command from frontend with your prompt and the number of images to be generated:

Lamdera.sendToBackend (AskGPTForGeneratedImages 
    model.inputPrompt 
    model.imagesPerPrompt)

In clause AskGPTForGeneratedImages of Backend.updateFromFrontend, function generateImages (see below) is called. It requests image urls from OpenAI. This function uses the library choonkeat/elm-openai. Function generateImages has to be called from the backend to keep it away from bad people.

OpenAI's response is processed at clause GotGeneratedImagesAtBE in Backend.update. It sends the urls received to the frontend where they are captured at clause GotImageUrls in Frontend.updateFromBackend. The type is GotImageUrls (List String)

Function generateImages

-- Imports rom Choonkeat's library:
import OpenAI
import OpenAI.Image

generateImages : Lamdera.ClientId -> String -> Int -> Task String ( OpenAI.Image.Output, Lamdera.ClientId )
generateImages clientId userInput n =
    let
        cfg =
            { organizationId = "MY-ORGANIZATIONAL-ID"
            , apiKey = Env.gptLabAPIKey
            , baseUrl = Nothing -- defaults to "https://api.openai.com/v1"
            }
    in
    OpenAI.Image.create
        { prompt = userInput
        , n = Just n
        , size = Just OpenAI.Image.Size1024x1024
        , response_format = Just OpenAI.Image.ImageURL
        , user = Nothing
        }
        |> OpenAI.withConfig cfg
        |> Http.task
        |> Task.mapError Ext.Http.errorString
        |> Task.map (\result -> ( result, clientId ))

Clause AskGPTForGeneratedImages

AskGPTForGeneratedImages prompt imagesToGenerate ->
   ( model, 
   Task.attempt GotGeneratedImagesAtBE 
      (AI.Image.generateImages clientId prompt imagesToGenerate) )

Clause GotGeneratedImagesAtBE

This is a clause in Backend.update. It sends the image urls received from OpenAI to the frontene:

GotGeneratedImagesAtBE result ->
  case result of
    Err errMessage ->
      ( model, Cmd.none )

    Ok imageData ->
      case imageData of
        ( OpenAI.Image.ImageURLOutput _ imageUrls, clientId ) ->
            ( model, 
              Lamdera.sendToFrontend 
                clientId 
                (GotImageUrls (imageUrls |> List.map Url.toString)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment