Hands-on · Paso 5 de 10
Natural Language: análisis de sentimientos
Clasifica el tono de cualquier texto en positivo, negativo o neutral con NLTagger.
En esta demo crearás una app que analiza el sentimiento de cualquier texto en español, inglés u otros idiomas soportados. Usaremos NLTagger con el esquema .sentimentScore: una API de una sola línea que devuelve un valor entre -1.0 (muy negativo) y 1.0 (muy positivo).
Arquitectura de la demo
La app tiene un campo de texto, un botón de análisis y una visualización del resultado con color (rojo para negativo, verde para positivo, gris para neutral).
Flujo de análisis: el texto pasa por NLTagger y se clasifica según el rango del score de sentimiento.
import SwiftUI
import NaturalLanguage
struct SentimentAnalysisView: View {
@State private var inputText: String = ""
@State private var sentiment: SentimentResult = .neutral
enum SentimentResult: Equatable {
case neutral
case positive(Double)
case negative(Double)
var label: String {
switch self {
case .neutral: return "Neutral"
case .positive(let score): return "Positivo (\(String(format: "%.2f", score)))"
case .negative(let score): return "Negativo (\(String(format: "%.2f", score)))"
}
}
var color: Color {
switch self {
case .neutral: return .gray
case .positive: return .green
case .negative: return .red
}
}
}
var body: some View {
VStack(spacing: 24) {
Text("Análisis de sentimientos")
.font(.largeTitle)
.fontWeight(.bold)
TextEditor(text: $inputText)
.frame(height: 120)
.padding(8)
.background(Color(.systemGray6))
.cornerRadius(12)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(Color(.systemGray4), lineWidth: 1)
)
Button(action: analyze) {
Label("Analizar", systemImage: "text.bubble.magnifyingglass")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
.background(Color.accentColor)
.foregroundColor(.white)
.cornerRadius(12)
}
HStack(spacing: 12) {
Circle()
.fill(sentiment.color)
.frame(width: 16, height: 16)
Text(sentiment.label)
.font(.title2)
.fontWeight(.semibold)
}
.padding(.vertical, 16)
.padding(.horizontal, 24)
.background(sentiment.color.opacity(0.15))
.cornerRadius(12)
Spacer()
}
.padding()
}
func analyze() {
guard !inputText.isEmpty else {
sentiment = .neutral
return
}
let tagger = NLTagger(tagSchemes: [.sentimentScore])
tagger.string = inputText
let (tag, _) = tagger.tag(at: inputText.startIndex, unit: .paragraph, scheme: .sentimentScore)
let score = Double(tag?.rawValue ?? "0") ?? 0.0
if score > 0.1 {
sentiment = .positive(score)
} else if score < -0.1 {
sentiment = .negative(score)
} else {
sentiment = .neutral
}
}
}
SentimentAnalysisView.swift
Cómo interpretar el score
NLTagger devuelve un NLTag cuyo rawValue es un string numérico. No es un enum, así que debes convertirlo a Double.
| Rango de score | Interpretación |
|---|---|
| 1.0 | Muy positivo |
| 0.1 ... 1.0 | Positivo |
| -0.1 ... 0.1 | Neutral |
| -1.0 ... -0.1 | Negativo |
| -1.0 | Muy negativo |
Variante: análisis por oración
Si necesitas granularidad mayor, itera por oraciones en lugar de analizar todo el texto como un único párrafo.
func analyzeBySentences(_ text: String) -> [(String, Double)] {
let tagger = NLTagger(tagSchemes: [.sentimentScore])
tagger.string = text
var results: [(String, Double)] = []
tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .sentence, scheme: .sentimentScore, options: []) { tag, range in
let sentence = String(text[range])
let score = Double(tag?.rawValue ?? "0") ?? 0.0
results.append((sentence, score))
return true
}
return results
}
SentenceAnalyzer.swift
Esta variante es útil para resúmenes de reseñas largas o para detectar qué parte de un mensaje cambia de tono.
Variante: detección de idioma automática
Antes de analizar el sentimiento, puedes detectar el idioma del texto. Esto permite mostrar etiquetas localizadas o elegir modelos específicos si más adelante usas Core ML.
func detectLanguage(for text: String) -> String? {
let tagger = NLTagger(tagSchemes: [.language])
tagger.string = text
let (tag, _) = tagger.tag(at: text.startIndex, unit: .paragraph, scheme: .language)
return tag?.rawValue // "es", "en", "fr", etc.
}
LanguageDetector.swift
Puntos clave para el hackathon
- Idiomas soportados: el análisis de sentimiento funciona mejor en inglés, pero también soporta español y otros idiomas principales. Prueba con frases de tu dominio antes de la demo final.
- Privacidad total: el texto nunca sale del dispositivo. Esto es ideal para apps de salud mental, diarios personales o feedback interno.
- Combinación con Foundation Models: si el score es neutral pero el texto es largo, puedes pasar el texto a un
LanguageModelSessionpara un análisis más profundo (ver demo de Foundation Models).
Recursos relacionados
Cuando hayas leído el texto, marca la lección para seguir el progreso.