Aplicando Análise de Sentimentos com CoreML no SwiftUI
Para muitas pessoas, mexer com Inteligência Artificial (IA) é algo impossível, uma tecnologia feita apenas para acadêmicos e não para meros mortais. Mas adivinha só: basta querer que você consegue aplicar!
O que é SwiftUI?
O SwiftUI é uma framework que traz para o usuário uma interação muito mais intuitiva para a criação das interfaces dos Apps. Entretanto, diferentemente do UIKit, ele ainda não possui tantas ferramentas preparadas para a sua utilização.
O que é CoreML?
O CoreML é uma biblioteca que permite ao desenvolvedor aplicar modelos de Machine Learning de maneira mais prática em seus Apps. Seu funcionamento basicamente "poupa" o desenvolvedor de se preocupar com a integração entre o modelo e o App.
Integrando o CoreML ao SwiftUI
Para entender na prática como funciona um App com CoreML, vou mostrar como apliquei em um projeto que enviei para o Swift Student Challenge 2022 (infelizmente eu perdi, mas o que vale é a experiência rsrs).
No meu projeto eu desenvolvi um ChatBot que conversa com o usuário e, com base em suas respostas, é feita uma recomendação de um prato tipicamente brasileiro. Para isso, a cada resposta dada à pergunta feita, é analisada o grau de sentimento (positivo, negativo ou neutro).
Para poupá-los de todo o código que desenvolvi para o ChatBot vou apenas mostrar a classe do SentimentIdentifier(), onde é feita toda a preparação para receber o modelo ML; e as partes da classe do ChatView onde é aplicado a predição.
CreateML
Primeiramente eu criei um modelo ML (por meio do CreateML) que consegue classificar um texto com uma predição entre -1 a 1 (-1 = negativo, 0 = neutro, 1 = positivo) e o adicionei ao código.
O arquivo em .csv que coloquei para a geração do modelo precisa necessariamente ter como título apenas: label e text.
SentimentIdentifier()
Em segundo lugar desenvolvi a classe SentimentIdentifier(), que se utiliza da predição dada pelo modelo e o seu grau de confiança (ou seja, o quanto ele tem certeza de que está prevendo certo) para “preparar” o modelo à resposta escrita pelo usuário.
Para garantir que a classe se utilize da mensagem enviada pelo usuário é preciso que ela herde de ObservableObject e tenha as variáveis de predição e confiança como @Published, para saber quando ocorre alguma alteração. E por se tratar de uma Análise de Sentimentos, não podemos esquecer de importar a biblioteca de processamento de linguagem natural.
Logo em seguida, criei uma variável do tipo MLModel( ) instanciando assim um modelo de Machine Learning e outra variável instanciando o preditor de sentimento como sendo de Linguagem Natural, por isso NLModel( ).
Iniciei a classe criando uma constante que é do tipo SentimentClassifier* e tive depois que relacionar o modelo que criei com ele. Junto disso, apliquei o modelo de Machine Learning ao modelo de Natural Language e o relacionei com o modelo preditor.
* O SentimentClassifier seria criado automaticamente pelo XCode ao adicionar o modelo de classificação de sentimentos, entretanto como tive que utilizar o Playground tive que criar na mão essa classe. Para saber mais sobre o que há nessa classe, olhe o meu GitHub no final do artigo.
O resultado disso está aqui abaixo:
import Foundation
import SwiftUI
import CoreML
import NaturalLanguageclass SentimentIdentifier: ObservableObject {
@Published var prediction = ""
@Published var confidence = 0.0
var model = MLModel()
var sentimentPredictor = NLModel()
init() {
do {
let sentiment_model = try SentimentClassifier(configuration: MLModelConfiguration()).model
self.model = sentiment_model
do {
let predictor = try NLModel(mlModel: model)
self.sentimentPredictor = predictor
} catch {
print(error)
}
} catch {
print(error)
}
}
func predict(_ text: String) {
self.prediction = sentimentPredictor.predictedLabel(for: text) ?? ""
let predictionSet = sentimentPredictor.predictedLabelHypotheses(for: text, maximumCount: 1)
self.confidence = predictionSet[prediction] ?? 0.0
}
}
ChatView()
Por fim, preparei o ChatView para acionar a predição toda vez que a resposta do usuário for enviada. Para isso, eu criei uma variável do tipo SentimentIdentifier() que é um @ObservedObject para se comunicar com a classe.
import Foundation
import SwiftUI
import NaturalLanguage struct ChatView: View {
@State var messageText = ""
@State private var messages: [String] = []
@FocusState private var keyboardIsFocused: Bool
var textView : UITextView!
@ObservedObject var identifier = SentimentIdentifier()
...
}
Assim que o usuário responde à alguma pergunta que o bot faz, ele logo responde algo com base na análise do sentimento sobre a resposta. Para isso, eu criei uma função que pega o resultado da predição e retorna uma mensagem baseada nesse sentimento (positivo, negativo ou neutro).
func getBotResponse(identifier: SentimentIdentifier, message: String) -> String {
if identifier.prediction == "positive" && conclusion2 {
if accuracy1 == 1 {
confidence1 = identifier.confidence + 1
print("confidence1: \(confidence1)")
accuracy1 = 0
}
if accuracy2 == 2 {
confidence2 = identifier.confidence + 1
print("confidence2: \(confidence2)")
accuracy2 = 0
}
if accuracy3 == 3 {
confidence3 = identifier.confidence + 1
print("confidence3: \(confidence3)")
accuracy3 = 0
}
return "That's great!"
} else if identifier.prediction == "negative" && conclusion2 {
if accuracy1 == 1 {
confidence1 = identifier.confidence - 1
print("confidence1: \(confidence1)")
accuracy1 = 0
}
if accuracy2 == 2 {
confidence2 = identifier.confidence - 1
print("confidence2: \(confidence2)")
accuracy2 = 0
}
if accuracy3 == 3 {
confidence3 = identifier.confidence - 1
print("confidence3: \(confidence3)")
accuracy3 = 0
}
return "Really? Okay..."
} else if identifier.prediction == "neutral" && conclusion2 {
if accuracy1 == 1 {
confidence1 = identifier.confidence
print("confidence1: \(confidence1)")
accuracy1 = 0
}
if accuracy2 == 2 {
confidence2 = identifier.confidence
print("confidence2: \(confidence2)")
accuracy2 = 0
}
if accuracy3 == 3 {
confidence3 = identifier.confidence
print("confidence3: \(confidence3)")
accuracy3 = 0
}
return "Okay, I respect your opinion."
}
else {
return "It was nice to meet you, bye bye!"
}
}
O código em si tem uma complexidade maior, e a plataforma do Playground é muito mais limitada para a geração de um App com análise de Sentimentos. Mas com esses pontos que levantei você já pode começar a desenvolver aplicativos poderosos e personalizados para o que procura.
Espero que tenha sido útil a minha experiência! Beijinhos
Link para o repositório no GitHub: https://github.com/BiancaMMatos/BubbleBot