Aplicando Análise de Sentimentos com CoreML no SwiftUI

Bianca Maciel
Apple Developer Academy | Mackenzie
5 min readJun 16, 2022

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 NaturalLanguage
class 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

--

--