Qualche giorno fa il mio amico Marco Lancellotti ha iniziato a pubblicare su YouTube alcuni video per mostrare come utilizzare le API di OpenAi per creare un generatore di immagini in PHP/Laravel e così ho provato a fare qualcosa di simile in Flutter: ne è venuto fuori il progetto che vi presento in questo articolo.
Che cosa è OpenAi
OpenAi è un'azienda creata da Elon Musk con l'intento di utilizzare l'intelligenza artificiale per analizzare e comprendere il testo scritto dagli umani, tramite complessi algoritmi di machine learning. OpenAi è oggi attiva in vari settori oltre alla comprensione del testo: è perfettamente in grado di scrivere notizie false con uno stile che sembra in tutto e per tutto quello di uno scrittore umano e allo stesso modo è capace di produrre immagini realistiche a partire da una semplice descrizione testuale.
In questo progetto utilizzeremo proprio la capacità di produrre immagini. Per farlo, occorre che l'utente possa digitare una descrizione dell'immagine desiderata e che sia possibile poi interrogare le API di OpenAi per ottenere il risultato desiderato.
Il progetto base
Creiamo un nuovo progetto e sostituiamo il codice standard nel file main.dart con questo.
Il widget OpenAiImage
Creiamo ora il nostro widget stateful principale OpenAiImage:
class OpenAiImage extends StatefulWidget { const OpenAiImage({super.key});
@override State<OpenAiImage> createState() => _OpenAiImageState();}
class _OpenAiImageState extends State<OpenAiImage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Flutter OpenAi test"), ), body: ...... , ); }
e inseriamo nel body una casella di testo ed un pulsante, utilizzando una layout semplice a colonna:
per ottenere un risultato simile a questo:
Le API di OpenAi
Per utilizzare le API rese disponibile da OpenAi occorre registrarsi su questo sito (la registrazione è gratuita) selezionare dal menu a tendina associato al profilo la voce "View API keys" e generare una chiave (fate attenzione, la chiave viene mostrata una sola volta e poi non più, quindi prendete nota). Come accennavo, la registrazione è gratuita, ma l'utilizzo della API è a pagamento: fortunatamente per noi, c'è un credito bonus iniziale di 18 dollari con cui fare un po' di prove, terminato il quale, occorre attivare un piano a pagamento.
Ottenuta la chiave, creiamo un file nel nostro progetto in cui memorizzarla (e ricordiamo di inserire questo file tra quelli da non sincronizzare con Git, per evitare di esporre la nostra chiave nella repo che pubblicheremo). Nel mio caso ho creato un file openai_key.dart con questa semplice riga:
e aggiungiamo l'import di questo file in testa al file main.dart:
L'interrogazione delle API
Gli esempi riportati dalla documentazione online di OpenAi, mostrano che per l'utilizzo è necessario effettuare una richiesta HTTP passando i parametri di interrogazione con il metodo POST. Per questo, occorre innanzitutto aggiungere al nostro progetto un package che ci permette di interagire con un web service. Da terminale, digitiamo il seguente comando:
Gestiamo il risultato
Aggiungiamo ora la chiamata di questa funzione al nostro pulsante, dopo aver introdotto una nuova variabile di stato in cui memorizzare l'url dell'immagine che otterremo dall'API:
onPressed: () { getImage(textController.value.toString()).then((value) { result = json.decode(value.body)['data'][0]['url']; }).whenComplete(() { setState(() {}); }); }, child: const Text("Genera")),
come argomento passeremo il value.toString() ottenuto dal controller associato al TextField e nel ramo .then() della chiamata asincrona assegniamo il risultato. Ricordiamoci che questo ramo verrà eseguito quando la chiamata è andata a buon fine e la risposta è pronta (per valorizzare result, teniamo conto che la risposta ci viene fornita in formato json e che presenta la struttura vista sopra). Quando la chiamata è stata completata, aggiorniamo lo stato del nostro widget.
Esponiamo il risultato come immagine
Per esporre l'immagine di cui abbiamo ottenuto l'URL dall'interrogazione dell'API, possiamo creare una semplice card (ho copiato e modificato quella che ho ho utilizzato in questo mio precedente progetto: Utilizzo delle immagini in Flutter ):
che può essere aggiunta ora al nostro widget Column principale:
Considerando che la chiamata è asincrona, per completare e migliorare la visualizzazione, possiamo pensare di introdurre un indicatore che ci permetta di capire che l'app sta girando e che è in attesa di una risposta dal web service. Introduciamo quindi una nuova variabile di stato che ci permetta di capire quando la procedura è in attesa di un risultato:
e modifichiamo il pulsante in questo modo:
Ora dopo il click, la variabile isLoading è posta a true e riportata a false solo dopo il completamento della chiamata. Al posto di richiamare semplicemente la funzione imageCard, aggiungiamo una condizione ternaria che tenga conto della variabile introdotta:
Questa modifica (e l'aggiornamento dello stato inserito nel pulsante, sia prima, sia dopo la chiamata asincrona) permette di mostrare un indicatore di progresso durante l'attesa e di non mostrare nulla se l'url non è valorizzato.
Non ci resta che racchiudere il body della nostra app in un SingleChildScrollView ed eventualmente aggiungere il giusto padding, per completare il lavoro.
Commenti
Posta un commento