Gerando Imagens Usando a API OpenAI a partir do Emacs

しむどん 2024-10-26

Nos últimos anos, com a evolução da IA, várias ferramentas e serviços surgiram. Como parte da utilização dessas tecnologias a partir do Emacs, anteriormente implementei uma extensão do Emacs para geração de texto usando a API da OpenAI. Essa extensão ainda é amplamente utilizada, mas não suportava a geração de imagens. No entanto, a própria API da OpenAI oferece um modelo e API para geração de imagens. Nesta ocasião, usaremos isso para enriquecer ainda mais a nossa experiência no GNU Emacs.

Verificando a API de Geração de Imagens

A API de geração de imagens da OpenAI gera imagens com base em textos fornecidos. Neste caso, utilizaremos o modelo "DALL-E 3". Para começar, vamos verificar o funcionamento da API de geração de imagens.

Aqui está um exemplo de requisição para chamar o endpoint de geração de imagens da OpenAI.

:ORIGIN = https://api.openai.com
:API_KEY := openai-api-key

POST :ORIGIN/v1/images/generations
Content-Type: application/json
Authorization: Bearer :API_KEY

{
  "model": "dall-e-3",
  "prompt": "pretty cat",
  "n": 1,
  "size": "1024x1024"
}
{
  "created": 1729945494,
  "data": [
    {
      "revised_prompt": "Create an image",
      "url": "https://example.com/DUMMY/img-NIXf.png?st=DUMMY&se=DUMMY&sp=r&sv=DUMMY&sr=DUMMY&rscd=inline&rsct=image/png&skoid=DUMMY&sktid=DUMMY&skt=DUMMY&ske=DUMMY&sks=DUMMY&skv=DUMMY&sig=DUMMY"
    }
  ]
}

// POST DUMMY/v1/images/generations
// HTTP/1.1 200 OK
// Date: Sat, 26 Oct 2024 12:24:54 GMT
// Content-Type: application/json
// Content-Length: 1140
// Connection: keep-alive
// openai-version: 2020-10-01
// access-control-allow-origin: *

Ao enviar essa requisição, a API retorna uma resposta JSON que inclui a URL da imagem gerada. O campo data.url contém a URL da imagem gerada, e você pode acessá-la para fazer o download da imagem.

Usando a partir do Emacs

Vamos escrever um código em Emacs Lisp para gerar imagens usando esta API.

;;; openai-image --- OpenAI API Imaging Utility -*- lexical-binding: t -*-

;; Copyright (C) 2024 TakesxiSximada

;; Author: TakesxiSximada <[email protected]>
;; Maintainer: TakesxiSximada <[email protected]>
;; Repository:
;; Version: 1
;; Package-Version: 20241027.0000
;; Package-Requires: ((emacs "28.0")
;; Date: 2024-10-27

;; This file is not part of GNU Emacs.

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;; https://platform.openai.com/docs/api-reference/images/create
;;
;; Request
;;
;; curl https://api.openai.com/v1/images/generations \
;;   -H "Content-Type: application/json" \
;;   -H "Authorization: Bearer $OPENAI_API_KEY" \
;;   -d '{
;;     "model": "dall-e-3",
;;     "prompt": "A cute baby sea otter",
;;     "n": 1,
;;     "size": "1024x1024"
;;   }'
;;
;; Response
;;
;; {
;;   "created": 1589478378,
;;   "data": [
;;     {
;;       "url": "https://..."
;;     },
;;     {
;;       "url": "https://..."
;;     }
;;   ]
;; }

;;; Code:

(defvar openai-image-previous-ai-prompt "")

;;;###autoload
(defun openai-image-create-and-view (ai-prompt)
  (interactive
   (list (string-trim (read-string-from-buffer "Open AI Image"
					       openai-image-previous-ai-prompt))))
  (when (not (string-empty-p ai-prompt))
    (setq openai-image-previous-ai-prompt ai-prompt)
    (make-process :name "*Open AI Image*"
		  :buffer (generate-new-buffer "*Open AI Image*")
		  :command `("curl" "https://api.openai.com/v1/images/generations"
			     "-X" "POST"
			     "-H" "Content-Type: application/json"
			     "-H" ,(format "Authorization: Bearer %s" openai-api-key)
			     "-d" ,(json-encode `(:model "dall-e-3" :n 1 :size "1024x1024" :prompt ,ai-prompt)))
		  :sentinel (lambda (process event)
			      (when (string-equal event "finished\n")
				(let ((resp (with-current-buffer (process-buffer process)
					      (goto-char 0)
					      (json-parse-buffer))))
				  (eww (gethash "url" (aref (gethash "data" resp) 0)))))))))

(provide 'openai-image)
;; openai-image.el ends here

openai-image.el

Neste bloco de código, estamos gerando uma imagem através da API da OpenAI e acessando a URL da imagem que está contida na resposta usando o eww.

O Emacs possui várias maneiras de enviar requisições HTTP1. Nesta implementação, utilizamos `make-process` para chamar o curl como um subprocesso. Embora seja uma abordagem bastante primitiva, ela evita que você se perca nos labirintos do Emacs Lisp, pois apenas utiliza funções básicas do Emacs.

O prompt (a string que será passada para a IA) é configurado para que a última solicitação serva como o valor padrão. Assim, você poderá ajustar a string para gerar a imagem da maneira que desejar.

Conclusão

Usamos o modelo de geração de imagens da OpenAI, "DALL-E 3", para gerar imagens a partir do GNU Emacs. Especificamente, implementamos um Emacs Lisp que chama a API usando curl e exibe a URL da imagem gerada. Também foram feitas considerações para a configuração inicial do prompt e ajustes nas imagens geradas. Isso facilita a criação de várias imagens. Minha experiência com o GNU Emacs ficou ainda mais enriquecida.


1

url-retrieve, request.el e plz, embora request.el e plz não sejam bibliotecas padrão.