Al bucket de dades d'AlpinaShop hi ha 8.000 ressenyes de clients escrites en text lliure, ja desidentificades amb Sensitive Data Protection a 04-07. Cinc anys de gent explicant què li va semblar una motxilla, si la jaqueta abriga, si la talla venia justa, si l'enviament va arribar trencat.
Ningú no les ha llegit. Ni una.
No per deixadesa: llegir 8.000 ressenyes a trenta segons cadascuna són gairebé setanta hores de feina, i en acabar tindries una impressió general que no podries creuar amb res. Les ressenyes existeixen, es mostren a la fitxa de producte, generen la puntuació mitjana en estrelles, i aquí s'acaba la seva vida útil. Tota la informació sobre per què un producte agrada o no agrada està tancada en un text que cap procés no toca.
La lliçó anterior va acabar construint un model des de zero, amb contenidors, GPU i tres setmanes d'A/B test. Aquesta comença amb el principi contrari, que és el que estalvia més diners a la pràctica: no entrenis el que ja està entrenat.
Contingut
- APIs preentrenades davant de models propis
- Què ofereix exactament l'API de Natural Language
scoreimagnitude: on tothom s'equivoca- Anàlisi d'entitats i sentiment d'entitats
- Classificació de contingut i anàlisi sintàctica
- Primera crida des de Python
- Processar les 8.000 ressenyes: lots, quotes i errors
- Cost real i com estimar-lo abans de començar
- De BigQuery a
opiniones_sentimientoi tornada - La pregunta de negoci: el mal sentiment prediu devolucions?
- Idiomes: el castellà, el català i el que cal comprovar
- Els límits reals: ironia, negació i argot de muntanya
- Validar amb una mostra etiquetada a mà
- Comparació honesta: API, Gemini o classificador propi
- La família completa: Translation, Speech-to-Text, Document AI
- Privadesa: què s'envia, què es desa i què diu el RGPD
- APIs preentrenades davant de models propis
Una API preentrenada és un model que algú ja va entrenar, amb moltes més dades i recursos dels que tu tindràs, exposat com a servei. Tu envies text i reps una resposta. No hi ha dades d'entrenament, no hi ha etiquetatge, no hi ha entrenament, no hi ha desplegament, no hi ha monitoratge de deriva.
| Criteri | API preentrenada | Model propi (AutoML o custom) |
|---|---|---|
| Dades necessàries | Cap | Centenars o milers d'exemples etiquetats |
| Temps fins a producció | Una tarda | Setmanes |
| Cost inicial | 0 | Etiquetatge + entrenament |
| Cost per ús | Per unitat processada | Endpoint o lots |
| Qualitat en tasques genèriques | Alta | Similar, amb molt més esforç |
| Qualitat en argot propi | Mitjana o baixa | Alta si hi ha dades |
| Manteniment | Cap | Reentrenament i vigilància |
| Control | Cap | Total |
La regla pràctica es pot formular en una pregunta: el meu problema és essencialment diferent del de qualsevol altra empresa? Detectar si un text en castellà és positiu o negatiu no ho és: és exactament el mateix problema per a AlpinaShop, per a una pizzeria i per a un banc. Saber si una ressenya es refereix a l'ajust de l'arnès o a la rigidesa de la sola sí que és específic.
I l'ordre de treball que se'n deriva és clar: comença sempre per l'API preentrenada. Si resol el problema, has acabat en una tarda. Si no el resol, ja saps exactament en què falla, i aquell coneixement és justament el que necessites per decidir si entrenar alguna cosa pròpia val la pena.
- Què ofereix exactament l'API de Natural Language
La Cloud Natural Language API exposa cinc funcions. Convé conèixer-les totes perquè tres d'elles s'ignoren sistemàticament i són molt útils.
| Funció | Què rep | Què retorna | Ús a AlpinaShop |
|---|---|---|---|
| Anàlisi de sentiment | Un text | score i magnitude del text i de cada frase |
Com de positiva és cada ressenya |
| Anàlisi d'entitats | Un text | Persones, llocs, productes, quantitats, amb rellevància | Què s'esmenta a les ressenyes |
| Sentiment d'entitats | Un text | Cada entitat amb el seu propi sentiment | "La motxilla bé, l'enviament fatal" |
| Classificació de contingut | Un text (mínim unes 20 paraules) | Categories d'una taxonomia general | Classificar textos llargs per tema |
| Anàlisi sintàctica | Un text | Testimonis, lemes, categories gramaticals, dependències | Normalitzar i extreure patrons |
La tercera —sentiment d'entitats— és la joia amagada i la que més valor té per a una botiga. Una ressenya real gairebé mai no és "bona" o "dolenta" a seques: és "la jaqueta és fantàstica però va trigar tres setmanes a arribar". El sentiment global d'aquell text surt proper a zero, cosa que és alhora certa i inútil. El sentiment per entitat separa que el producte agrada i que la logística no.
score i magnitude: on tothom s'equivoca
score i magnitude: on tothom s'equivocaAquest és l'apartat més important de la lliçó, i el que més malentesos genera en projectes reals.
L'anàlisi de sentiment retorna dos números, no un:
score: entre −1,0 i +1,0. Indica l'orientació emocional global: negativa, neutra o positiva.magnitude: de 0,0 a infinit. Indica la quantitat total de càrrega emocional del text, i no està normalitzada per longitud: un text llarg acumula més magnitud.
L'error universal és mirar només el score. I el problema és que un score proper a 0 té dos significats completament oposats, que només es distingeixen mirant la magnitude.
score |
magnitude |
Interpretació | Exemple |
|---|---|---|---|
| +0,8 | 0,9 | Clarament positiu | "Motxilla perfecta, molt còmoda." |
| −0,7 | 0,8 | Clarament negatiu | "Es va descosir al cap d'una setmana. Fatal." |
| 0,0 | 0,1 | Neutre de debò | "Motxilla de 40 litres, color blau." |
| 0,0 | 3,4 | Mixt, molt emocional | "El producte és magnífic, però l'atenció al client ha estat lamentable i l'enviament va trigar tres setmanes." |
Les dues últimes files són la clau. Totes dues tenen score 0. La primera és una descripció sense emoció. La segona és una ressenya intensa amb emocions fortes en les dues direccions que s'anul·len en promitjar-se.
I són casos que exigeixen accions oposades. La ressenya neutra no requereix res. La ressenya mixta conté un problema seriós d'atenció al client i de logística que cal atendre avui. Una anàlisi que només miri el score classificarà totes dues com a "neutres", ignorarà la segona, i l'equip conclourà que "la majoria de les ressenyes són neutres, aquí no hi ha res".
La manera correcta de classificar utilitza les dues dimensions:
CREATE OR REPLACE VIEW `alpinashop-datos.alpinashop_analitica.v_opiniones_clasificadas` AS
SELECT
opinion_id, sku, fecha, puntuacion, score, magnitude,
CASE
WHEN score >= 0.25 THEN 'positiva'
WHEN score <= -0.25 THEN 'negativa'
WHEN magnitude >= 1.5 THEN 'mixta' -- emocio alta, score baix
ELSE 'neutra'
END AS clasificacion
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento`;Els llindars 0,25 i 1,5 no són sagrats. Són un punt de partida raonable que cal calibrar contra una mostra etiquetada a mà —apartat 13—, exactament igual que el llindar de decisió de 05-02: és un ajust de negoci, no una constant universal.
La magnitude no és comparable entre textos de longituds molt diferents. Una ressenya de 300 paraules tindrà més magnitud que una de 20 encara que sigui menys intensa. Si cal comparar, convé normalitzar dividint pel nombre de frases, o almenys segmentar l'anàlisi per rangs de longitud.
I una precisió que evita conclusions absurdes: el sentiment no mesura veracitat ni gravetat. Un client molt educat que escriu "lamentablement el mosquetó va cedir durant una via" pot donar un score moderat, i és un incident de seguretat. El sentiment ordena i prioritza; no substitueix llegir el que és important.
- Anàlisi d'entitats i sentiment d'entitats
L'anàlisi d'entitats identifica el que s'esmenta al text i li assigna un tipus (PERSON, LOCATION, ORGANIZATION, CONSUMER_GOOD, EVENT, NUMBER, PRICE, OTHER) i una rellevància (salience) entre 0 i 1 que indica la seva importància dins del text.
El sentiment d'entitats combina totes dues coses. Per a la ressenya:
"La jaqueta és impermeable de debò i molt lleugera, però la cremallera s'encalla i l'enviament va trigar tres setmanes."
Un resultat plausible:
| Entitat | Tipus | Rellevància | score |
magnitude |
|---|---|---|---|---|
| jaqueta | CONSUMER_GOOD | 0,52 | +0,8 | 1,2 |
| cremallera | CONSUMER_GOOD | 0,24 | −0,6 | 0,7 |
| enviament | OTHER | 0,18 | −0,7 | 0,9 |
Això és accionable i el sentiment global no ho era. El sentiment global d'aquella ressenya rondaria 0 amb magnitud alta —"mixta"—, correcte però mut. El desglossament per entitat diu tres coses concretes: el producte compleix la seva promesa principal, hi ha un defecte de component que el proveïdor ha de corregir, i hi ha un problema logístic.
Agregant 8.000 ressenyes per entitat s'obté el que cap puntuació en estrelles no dóna: què falla exactament i amb quina freqüència.
-- Que s esmenta amb pitjor sentiment a les ressenyes de motxilles
SELECT
entidad,
COUNT(*) AS menciones,
ROUND(AVG(score), 3) AS score_medio,
ROUND(AVG(salience), 3) AS relevancia_media,
COUNTIF(score < -0.3) AS menciones_negativas
FROM `alpinashop-datos.alpinashop_analitica.opiniones_entidades` e
JOIN `alpinashop-datos.alpinashop_analitica.productos` p USING (sku)
WHERE p.categoria = 'motxilla'
GROUP BY entidad
HAVING menciones >= 20
ORDER BY score_medio ASC
LIMIT 20;El HAVING menciones >= 20 importa: una entitat esmentada tres vegades amb sentiment pèssim és una anècdota, no un patró. És la mateixa disciplina del soporte al recomanador heurístic de 05-01.
- Classificació de contingut i anàlisi sintàctica
Classificació de contingut assigna el text a categories d'una taxonomia general i jeràrquica (/Sports/Outdoors/Climbing & Mountaineering). Requereix textos amb una certa longitud —de l'ordre de vint paraules o més— i la seva taxonomia és general, no la de la teva botiga. Per a AlpinaShop té poc valor a les ressenyes, que són curtes, però sí que en té per classificar automàticament articles del blog o descripcions llargues.
Anàlisi sintàctica descompon el text en testimonis amb el seu lema, categoria gramatical i relació de dependència. Poques vegades es fa servir tal qual, però té dues aplicacions pràctiques molt concretes:
- Lematització: agrupar "pesa", "pesava", "pesat" sota el lema "pesar" abans de comptar freqüències. Sense això, un recompte de paraules es dispersa en variants.
- Extracció de patrons adjectiu-substantiu: "corretja incòmoda", "teixit resistent", "costura fluixa". Un recompte d'aquells parells sobre 8.000 ressenyes produeix un resum de defectes molt dens, i sense cap model entrenat.
- Primera crida des de Python
Preparació prèvia: habilitar l'API amb gcloud services enable language.googleapis.com --project=alpinashop-datos i crear el compte de servei sa-nlp-opiniones. Invocar l'API no requereix un rol específic; els permisos que cal concedir són els de lectura i escriptura a BigQuery (roles/bigquery.dataEditor).
I la crida:
from google.cloud import language_v2
client = language_v2.LanguageServiceClient()
text = ("La jaqueta es impermeable de debo i molt lleugera, "
"pero la cremallera s encalla i l enviament va trigar tres setmanes.")
document = language_v2.Document(
content=text,
type_=language_v2.Document.Type.PLAIN_TEXT,
language_code="ca", # forcar l idioma evita deteccions errones
)
r = client.analyze_sentiment(
request={"document": document,
"encoding_type": language_v2.EncodingType.UTF8})
print(f"Global -> score {r.document_sentiment.score:+.2f} "
f"magnitude {r.document_sentiment.magnitude:.2f}")
for frase in r.sentences: # desglossament per frase, sense cost extra
print(f" [{frase.sentiment.score:+.2f}] {frase.text.content}")
e = client.analyze_entities( # entitats: segona facturacio
request={"document": document,
"encoding_type": language_v2.EncodingType.UTF8})Tres detalls que importen més del que sembla:
language_code explícit. Si no s'indica, l'API detecta l'idioma. En textos curts la detecció falla sovint, i confondre el castellà amb el portuguès o amb el català degrada el resultat sense avisar de res. Si coneixes l'idioma, declara'l.
encoding_type=UTF8. Determina com es compten les posicions dels caràcters a la resposta. Amb accents, ç i ñ —és a dir, sempre— fer servir el valor incorrecte desplaça els desplaçaments que retorna l'API i trenca qualsevol lògica que extregui fragments.
L'anàlisi per frase (r.sentences) és gratuïta: ve a la mateixa resposta i a la mateixa crida. Desar-la permet localitzar exactament quina frase d'una ressenya llarga és la negativa, sense tornar a trucar.
- Processar les 8.000 ressenyes: lots, quotes i errors
L'API processa un document per crida. Vuit mil ressenyes són vuit mil crides, i aquí és on un script ingenu s'estavella.
Els tres problemes que cal resoldre: quotes (hi ha un límit de peticions per minut que, si se supera, retorna error 429), errors transitoris (503, talls de xarxa) i cost (cada crida compta).
import time, random
from concurrent.futures import ThreadPoolExecutor
from google.cloud import language_v2
from google.api_core import exceptions
client = language_v2.LanguageServiceClient()
def analitzar(opinio, max_intents=5):
"""Analitza una ressenya amb reintents i espera exponencial."""
doc = language_v2.Document(
content=opinio["texto"][:20000], # retallar textos anomals
type_=language_v2.Document.Type.PLAIN_TEXT,
language_code=opinio.get("idioma", "ca"),
)
for intent in range(max_intents):
try:
r = client.analyze_sentiment(
request={"document": doc,
"encoding_type": language_v2.EncodingType.UTF8})
return {
"opinion_id": opinio["opinion_id"],
"sku": opinio["sku"],
"score": round(r.document_sentiment.score, 4),
"magnitude": round(r.document_sentiment.magnitude, 4),
"n_frases": len(r.sentences),
"estado": "OK",
}
except exceptions.ResourceExhausted: # 429: quota
espera = (2 ** intent) + random.random()
time.sleep(espera)
except exceptions.ServiceUnavailable: # 503: transitori
time.sleep(1 + intent)
except exceptions.InvalidArgument as err: # text no processable
return {"opinion_id": opinio["opinion_id"], "sku": opinio["sku"],
"score": None, "magnitude": None, "n_frases": 0,
"estado": f"ERROR: {err.message[:120]}"}
return {"opinion_id": opinio["opinion_id"], "sku": opinio["sku"],
"score": None, "magnitude": None, "n_frases": 0,
"estado": "ERROR: reintents exhaurits"}
with ThreadPoolExecutor(max_workers=8) as pool:
resultats = list(pool.map(analitzar, opinions))Les decisions d'aquest codi, una a una:
Espera exponencial amb soroll (2 ** intent + random()). Si vuit fils reben un 429 alhora i tots reintenten al segon exacte, tornen a xocar. El component aleatori els desincronitza. És el mateix patró de reintents de Pub/Sub a 04-04.
Distingir tipus d'error. ResourceExhausted és quota i es reintenta esperant més. ServiceUnavailable és transitori i es reintenta ràpid. InvalidArgument és un text que l'API no pot processar —buit, en un idioma no admès, massa llarg— i reintentar-lo és temps i diners perduts: falla sempre igual.
Registrar la fallada en lloc d'avortar. El resultat sempre porta fila, amb estado. Que un procés de 8.000 documents mori al 7.400 perquè un venia buit és inacceptable. Al final es compta quants van fallar i per què.
max_workers=8, no 100. Amb massa concurrència s'esgota la quota constantment, tot entra en reintents i el procés acaba sent més lent a més de més car. Vuit fils és un punt de partida conservador que convé pujar mesurant.
Retallar el text. L'API té un límit de mida per document. Un text anòmal de 500 KB —que n'hi ha: algú enganxa alguna cosa per error— falla i consumeix quota. Tallar a 20.000 caràcters és una defensa barata.
- Cost real i com estimar-lo abans de començar
La facturació de l'API de Natural Language es fa per unitats de 1.000 caràcters, arrodonint cap amunt per document i per cada funció sol·licitada.
Les dues conseqüències pràctiques:
- Una ressenya de 150 caràcters factura 1 unitat, igual que una de 990. L'arrodoniment per document penalitza els textos curts.
- Demanar sentiment i entitats sobre el mateix text són dues facturacions, no una.
Estimació abans de gastar res, calculada en SQL sobre les dades reals:
SELECT
COUNT(*) AS documentos,
ROUND(AVG(LENGTH(texto)), 0) AS long_media,
MAX(LENGTH(texto)) AS long_maxima,
SUM(CEIL(LENGTH(texto) / 1000)) AS unidades_sentimiento,
SUM(CEIL(LENGTH(texto) / 1000)) * 2 AS unidades_con_entidades
FROM `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica`;Un resultat típic per a AlpinaShop: 8.000 ressenyes, longitud mitjana d'uns 240 caràcters, gairebé totes per sota de 1.000. Això són unes 8.000 unitats per a sentiment, o 16.000 si a més es demanen entitats.
Amb preus de l'ordre d'un o dos euros per cada 1.000 unitats —un ordre de magnitud, el preu vigent cal consultar-lo sempre a la documentació oficial, i sol haver-hi un tram gratuït mensual—, l'anàlisi completa de l'històric d'AlpinaShop costa de l'ordre de desenes d'euros, una sola vegada.
Posa aquell número al costat del cost d'entrenar un classificador propi: etiquetar 2.000 ressenyes a mà, entrenar, desplegar, mantenir. La comparació es respon sola, i és exactament l'argument de l'apartat 1.
I el flux incremental, que és el que fa sostenible la despesa: l'històric es processa una vegada; a partir d'aquí només s'analitzen les ressenyes noves, unes poques desenes al dia. El cost recurrent és pràcticament zero.
-- Nomes el que encara no s ha analitzat
SELECT o.opinion_id, o.sku, o.texto
FROM `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` o
LEFT JOIN `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` s
USING (opinion_id)
WHERE s.opinion_id IS NULL;
- De BigQuery a
opiniones_sentimiento i tornada
opiniones_sentimiento i tornadaL'arquitectura del procés, amb les peces que ja coneixes del mòdul 4:
flowchart LR
A[v_opiniones_analitica<br/>BigQuery] --> B[Proces Python<br/>lots + reintents]
B --> C[Natural Language API]
C --> B
B --> D[opiniones_sentimiento<br/>BigQuery]
D --> E[Creuament amb comandes<br/>i devolucions]
E --> F[Looker Studio]
G[Cloud Scheduler] --> H[Workflows] --> B
La taula de resultats, amb particionat i clustering com mana 04-01:
CREATE TABLE IF NOT EXISTS `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` (
opinion_id STRING NOT NULL,
sku STRING NOT NULL,
fecha DATE,
score FLOAT64,
magnitude FLOAT64,
n_frases INT64,
idioma STRING,
estado STRING,
modelo_version STRING, -- tracabilitat: que ha analitzat aixo
procesado_en TIMESTAMP
)
PARTITION BY fecha
CLUSTER BY sku;Les dues columnes que gairebé ningú no inclou i sempre acaben fent falta són modelo_version i procesado_en. Les APIs preentrenades s'actualitzen pel seu compte: el model que analitza els teus textos avui no és necessàriament el de fa un any. Si d'aquí a sis mesos els score mitjans es mouen, la primera pregunta serà "ha canviat el model o han canviat els clients?", i sense aquestes dues columnes és impossible respondre.
L'escriptura es fa amb insert_rows_json en lots d'unes 500 files, afegint a cada resultat modelo_version i procesado_en abans d'inserir, i comprovant sempre la llista d'errors que retorna la crida (que no llança excepció: si no la mires, les files rebutjades es perden en silenci).
L'execució periòdica s'enganxa a l'orquestrador que ja va triar AlpinaShop a 04-06: Cloud Scheduler dispara un Workflow que executa el procés incremental cada nit.
- La pregunta de negoci: el mal sentiment prediu devolucions?
Aquí és on l'anàlisi deixa de ser un exercici i comença a valer diners.
WITH sentimiento_sku AS (
SELECT
sku,
COUNT(*) AS n_opiniones,
ROUND(AVG(score), 3) AS score_medio,
ROUND(AVG(magnitude), 3) AS magnitude_media,
COUNTIF(score < -0.25) AS opiniones_negativas,
ROUND(100 * COUNTIF(score < -0.25) / COUNT(*), 1) AS pct_negativas
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento`
WHERE estado = 'OK'
GROUP BY sku
HAVING n_opiniones >= 15
),
devoluciones_sku AS (
SELECT
sku,
COUNT(*) AS unidades_vendidas,
COUNTIF(devuelto) AS unidades_devueltas,
ROUND(100 * COUNTIF(devuelto) / COUNT(*), 2) AS tasa_devolucion
FROM `alpinashop-datos.alpinashop_analitica.lineas_pedido`
WHERE fecha_pedido >= DATE_SUB(CURRENT_DATE(), INTERVAL 2 YEAR)
GROUP BY sku
HAVING unidades_vendidas >= 50
)
SELECT
s.sku, p.nombre, p.categoria,
s.n_opiniones, s.score_medio, s.pct_negativas,
d.unidades_vendidas, d.tasa_devolucion,
ROUND(d.unidades_devueltas * p.precio_medio, 0) AS coste_devoluciones_eur
FROM sentimiento_sku s
JOIN devoluciones_sku d USING (sku)
JOIN `alpinashop-datos.alpinashop_analitica.productos` p USING (sku)
ORDER BY d.tasa_devolucion DESC
LIMIT 30;I la correlació global, que és la que contesta la pregunta:
SELECT
COUNT(*) AS skus_analizados,
ROUND(CORR(score_medio, tasa_devolucion), 3) AS correlacion
FROM sentimiento_sku JOIN devoluciones_sku USING (sku);Com llegir el resultat, sense enganyar-se.
Si la correlació surt al voltant de −0,4, significa que a pitjor sentiment, més taxa de devolució, amb una relació moderada. Això ja és útil: el sentiment serveix com a senyal d'alerta primerenca. Un producte nou amb quinze ressenyes de sentiment dolent probablement generarà devolucions abans que les devolucions apareguin a les dades.
Si surt a prop de 0, la conclusió no és que l'anàlisi no valgui: és que les devolucions d'AlpinaShop s'expliquen per una altra cosa —el més probable en roba tècnica, la talla—, i això és també una troballa valuosa que canvia on cal actuar.
I les tres cauteles obligatòries:
- Correlació no és causalitat. Hi pot haver una variable de fons —la categoria— que expliqui totes dues: si la roba es retorna més i a més genera ressenyes més crítiques, la correlació apareix sense que una cosa causi l'altra. La comprovació és repetir l'anàlisi dins de cada categoria.
- Biaix de selecció en qui ressenya. Només escriu una part dels clients, i sol estar sobrerepresentada la gent molt contenta i la molt enfadada. El sentiment mitjà de les ressenyes no és el sentiment mitjà dels clients.
- El filtre
n_opiniones >= 15deixa fora la majoria del catàleg. Amb 2.400 SKU i 8.000 ressenyes, la mitjana és de tres ressenyes per producte: l'anàlisi per SKU només és fiable per als més venuts. Per a la resta, agregar per categoria o per família és l'única lectura honesta.
La sortida pràctica és una llista de treball, igual que a 05-02: els productes amb pitjor sentiment i més cost de devolucions, ordenats, perquè algú miri les ressenyes concretes i decideixi si cal parlar amb el proveïdor, corregir la fitxa o canviar la taula de talles.
- Idiomes: el castellà, el català i el que cal comprovar
L'API admet un conjunt ampli d'idiomes, però no totes les funcions admeten els mateixos idiomes ni amb la mateixa qualitat. És una font habitual de sorpreses.
| Aspecte | Situació pràctica |
|---|---|
| Castellà | Suport complet i qualitat alta en totes les funcions |
| Català | Cobertura menor que la del castellà; cal verificar-ho funció per funció a la documentació oficial |
| Detecció automàtica | Poc fiable en textos curts, que és justament el cas de les ressenyes |
| Textos barrejats | Una ressenya que alterna castellà i català dóna resultats inconsistents |
AlpinaShop és una pime catalana amb clients a tot Espanya, així que aquest punt no és teòric: part de les ressenyes seran en català, i algunes barrejaran tots dos idiomes a la mateixa frase.
L'estratègia sensata, en tres passos:
- Desar l'idioma declarat pel client al formulari de ressenya, si existeix. És la informació més fiable i és gratis.
- Si no existeix, detectar-lo una vegada i emmagatzemar-lo, en lloc de deixar que l'API l'endevini a cada crida.
- Comprovar la cobertura real abans de processar en massa: agafar 50 ressenyes en català, analitzar-les, i comparar amb la valoració humana. Si el resultat no és fiable, hi ha dues sortides raonables: traduir al castellà amb Cloud Translation abans d'analitzar —afegeix cost i una mica de soroll, però funciona— o utilitzar Gemini (05-06), que manega el català amb solvència.
I abans de res, un GROUP BY idioma sobre v_opiniones_analitica per saber quant hi ha de cada cosa: evita construir una solució complexa per al 2 % dels casos.
- Els límits reals: ironia, negació i argot de muntanya
Una lliçó honesta ha de dir on falla l'eina.
Ironia i sarcasme. "Genial, la tenda de campanya va aguantar perfectament… tres hores." El model veu "genial" i "perfectament" i probablement retorna un score positiu. La ironia requereix entendre la contradicció entre la forma i el contingut, i els models de sentiment clàssics no la capturen de forma fiable.
Negacions complexes. "No diria que sigui una mala motxilla, encara que tampoc no és que m'hagi encantat." Doble negació més matisació. El resultat serà una cosa propera a zero, que no és incorrecta però perd tot el matís.
Argot del domini. Aquest és el més traïdor, perquè falla silenciosament i amb textos perfectament normals.
| Frase | Lectura genèrica | Lectura de muntanya |
|---|---|---|
| "La motxilla pesa" | Negatiu | Depèn: en una d'expedició és esperable; en una de trail, un defecte greu |
| "El sac és just per a 0 graus" | Ambigu | Advertiment: no compleix el que promet |
| "Les botes són dures" | Negatiu | Positiu en botes de grampó: la rigidesa és el requisit |
| "El teixit cruix" | Neutre | Negatiu: indica membrana rígida i sorollosa |
| "Tècnica" | Neutre | Positiu: producte especialitzat |
La quarta i la cinquena files són el problema en la seva forma pura. La mateixa paraula té signe oposat segons el producte. Un model genèric no sap de grampons, i "dures" li sona malament sempre.
Això no invalida l'eina: l'acota. L'anàlisi de sentiment genèrica serveix per prioritzar i agregar —quines categories van pitjor, quins productes concentren queixes, com evoluciona el sentiment mes a mes—. No serveix per decidir automàticament sobre un producte concret sense que ningú no llegeixi res.
- Validar amb una mostra etiquetada a mà
Tot l'anterior porta a una sola conclusió operativa: cal mesurar quant encerta l'API sobre els teus textos. No sobre textos en general: sobre els teus.
El protocol, que costa unes tres hores i val per tota la lliçó:
- Mostrejar 200 ressenyes a l'atzar, estratificant per categoria de producte i per puntuació en estrelles, perquè la mostra no sigui tota de motxilles ni tota de cinc estrelles.
- Etiquetar-les a mà en quatre classes: positiva, negativa, neutra, mixta. Idealment dues persones de forma independent, per mesurar quant coincideixen entre elles: si dos humans només coincideixen en el 75 %, no li pots exigir el 95 % a la màquina.
- Comparar amb la classificació de l'API utilitzant els llindars de l'apartat 3.
- Ajustar els llindars per maximitzar la concordança. Pot ser que en els teus textos el tall correcte sigui 0,15 i no 0,25.
- Repetir la validació cada sis mesos, perquè el model subjacent canvia sense avisar.
-- Matriu de concordanca entre l etiquetatge huma i l API
SELECT
m.etiqueta_humana,
c.clasificacion AS etiqueta_api,
COUNT(*) AS casos
FROM `alpinashop-datos.alpinashop_analitica.muestra_etiquetada` m
JOIN `alpinashop-datos.alpinashop_analitica.v_opiniones_clasificadas` c
USING (opinion_id)
GROUP BY 1, 2
ORDER BY 1, casos DESC;Un resultat plausible sobre les ressenyes d'AlpinaShop: bona concordança en positives i negatives clares, i la majoria dels desacords concentrats a la frontera entre "neutra" i "mixta" —justament on l'apartat 3 avisava— i a les ressenyes amb argot tècnic.
Aquest exercici produeix dues coses de valor permanent. Una és el número que pots dir a direcció: "la classificació automàtica coincideix amb el criteri humà en el 82 % dels casos". L'altra és un conjunt de 200 ressenyes etiquetades que, si algun dia decideixes entrenar un classificador propi amb AutoML (05-02), ja és el teu punt de partida.
- Comparació honesta: API, Gemini o classificador propi
Tres maneres de resoldre el mateix problema el 2026:
| Criteri | Natural Language API | Gemini (05-06) | AutoML Text (05-02) |
|---|---|---|---|
| Dades pròpies | Cap | Cap | Centenars d'exemples etiquetats |
| Posada en marxa | Hores | Hores | Dies o setmanes |
| Sortida | Fixa: score, magnitude, entitats |
La que demanis al prompt | Les teves etiquetes |
| Argot del domini | No l'entén | Se li pot explicar al prompt | L'aprèn de les dades |
| Ironia | Malament | Bastant millor | Depèn dels exemples |
| Català | Cobertura limitada | Bona | Depèn de les dades |
| Cost per document | Baix i molt predictible | Més gran, per tokens | Baix després d'entrenar |
| Latència | Baixa | Més gran | Baixa |
| Determinisme | Alt: mateixa entrada, mateixa sortida | Variable | Alt |
Quan cadascuna, per a AlpinaShop:
Natural Language API per al processament massiu de l'històric i el flux diari. És barata, ràpida, predictible i dóna un número comparable en el temps. És l'elecció per a les 8.000 ressenyes.
Gemini quan la pregunta és més rica que "positiu o negatiu?". Per exemple: "classifica aquesta ressenya en producte / talla / enviament / atenció al client, indica el sentiment de cada aspecte i extreu el defecte concret si n'hi ha, retornant JSON". Això, que l'API no pot fer, Gemini ho fa amb un prompt i sense entrenar res. I entén la ironia i el català molt millor. A canvi, costa més per document, és més lent i no és determinista: la mateixa ressenya pot donar respostes lleugerament diferents. Es veu a 05-06.
AutoML Text només si es dóna una condició molt concreta: que existeixi una taxonomia pròpia i estable —"defecte de costura", "problema de talla", "retard logístic", "error de descripció"— i que compensi etiquetar mil exemples. Amb les 200 de l'apartat 13 ja hi ha mig camí fet.
I una combinació que sol ser la millor de les tres: utilitzar l'API per processar-ho tot de forma barata, i reservar Gemini per al subconjunt interessant —les ressenyes negatives i les mixtes, que seran uns centenars— demanant-li una anàlisi detallada per aspectes. Cost baix sobre el volum, alta qualitat on importa.
- La família completa: Translation, Speech-to-Text, Document AI
L'API de Natural Language és una de diverses APIs preentrenades que comparteixen filosofia, facturació per ús i absència total d'entrenament.
| API | Què fa | Ús possible a AlpinaShop |
|---|---|---|
| Cloud Translation | Tradueix entre idiomes | Traduir fitxes de producte al català i a l'anglès; homogeneïtzar ressenyes abans d'analitzar-les |
| Speech-to-Text | Transcriu àudio | Transcriure les trucades d'atenció al client i analitzar-les igual que les ressenyes |
| Text-to-Speech | Genera veu | Marginal aquí |
| Document AI | Extreu dades de documents | Factures i albarans de proveïdor (es detalla a 05-05) |
Cloud Translation té dues edicions: la bàsica, que tradueix text pla, i l'avançada, que permet glossaris i traducció per lots. El glossari importa molt en aquest domini: sense ell, "piolet" o "arnès" es poden traduir de forma incorrecta o inconsistent entre fitxes. Amb glossari, la terminologia queda fixada.
Speech-to-Text obre una possibilitat interessant: AlpinaShop té un telèfon d'atenció al client les converses del qual no deixen cap dada analitzable. Transcriure-les i passar-les per la mateixa anàlisi de sentiment donaria una segona font sobre els mateixos problemes. Amb un advertiment legal de primer ordre: gravar i transcriure trucades exigeix informar prèviament, tenir base legal i una política de conservació clara, i la transcripció conté dades personals en abundància. Abans de tocar res, passa per compliment normatiu i aplica la desidentificació de 04-07.
- Privadesa: què s'envia, què es desa i què diu el RGPD
Què s'envia. El text complet del document viatja a l'API. Encara que la infraestructura sigui dins de Google Cloud, el contingut surt del teu projecte i entra en un servei gestionat.
On es processa. Les APIs preentrenades ofereixen endpoints regionals per a determinades funcions i idiomes. Si la residència de les dades a la UE és un requisit, cal verificar a la documentació oficial quins endpoints regionals hi ha disponibles per a la funció i l'idioma concrets, i configurar-los explícitament. No suposis que pel fet de tenir el projecte a europe-west1 el processament passa allà.
Què es desa. La política vigent de Google Cloud per a les APIs de predicció és no utilitzar les dades dels clients per entrenar els seus models, i hi ha compromisos contractuals al respecte. És un punt que cal verificar als termes vigents i documentar al registre de tractaments: no és una cosa que es pugui donar per sabuda.
El risc específic del text lliure. Aquest és el punt crític i val la pena dir-lo amb claredat: un camp de text lliure és el lloc on acaben les dades personals que ningú no esperava. Un client escriu el seu nom, el seu telèfon perquè el truquin, l'adreça on es va deixar el paquet, o el nom d'una altra persona. Cap validació de formulari no ho evita.
AlpinaShop ja va fer el que calia a 04-07: les ressenyes es desidentifiquen amb Sensitive Data Protection abans de quedar disponibles per a anàlisi, substituint cada troballa pel seu tipus ([EMAIL_ADDRESS], [PERSON_NAME]), cosa que preserva l'estructura i el sentiment del text. I l'anàlisi d'aquesta lliçó s'executa sobre v_opiniones_analitica, la vista desidentificada, mai sobre la taula original. Aquest és el control que fa que la resta sigui defensable.
Amb l'advertiment de sempre: la desidentificació automàtica no és infal·lible. Un client que escrigui "sóc el que va comprar la motxilla blava el dimarts a la botiga de Sabadell" no serà detectat per cap tipus predefinit i continua sent potencialment reidentificable.
Recomanació expressa. Abans de processar en massa text de clients, un professional de compliment normatiu o el DPD ha de determinar: la base legal del tractament analític de les ressenyes i si la finalitat està coberta per la informació donada en recollir-les; si l'enviament del text a l'API constitueix una comunicació de dades que requereixi informació addicional; els requisits de residència de les dades i quins endpoints regionals els compleixen; el termini de conservació dels textos i dels resultats; i la suficiència de la desidentificació aplicada. Aquesta lliçó descriu controls tècnics i no constitueix assessorament jurídic. Totes les dades són fictícies.
Sobre l'AI Act europeu: analitzar sentiment de ressenyes sobre productes per millorar el catàleg se situa raonablement en un nivell de risc baix. Convé assenyalar, tanmateix, que el reglament preveu restriccions específiques per a sistemes de reconeixement d'emocions aplicats a persones en contextos com el laboral o l'educatiu. Analitzar el to d'un text sobre una motxilla no és això, però la frontera importa: si demà algú proposés aplicar la mateixa anàlisi a les comunicacions de l'equip d'atenció al client per avaluar-ne el rendiment, l'enquadrament legal canviaria per complet. Qualsevol ús que apunti a persones i no a productes requereix revisió legal prèvia.
Errors Habituals i Consells
Mirar només el score. L'error d'aquesta lliçó. Un score de 0 amb magnitude de 3,4 és una ressenya intensa i mixta, no una ressenya neutra, i són les que més informació contenen.
No declarar l'idioma. La detecció automàtica falla en textos curts i degrada el resultat sense avisar.
Comparar magnitude entre textos de longituds molt diferents. No està normalitzada: un text llarg acumula més magnitud encara que sigui menys intens.
Reintentar els errors InvalidArgument. Un text que l'API no pot processar fallarà sempre igual. Reintentar-lo costa temps i quota.
Llançar 100 fils. Esgota la quota, dispara els reintents i acaba sent més lent i més car que anar amb vuit.
Demanar totes les funcions "per si de cas". Cada funció factura per separat. Demana sentiment i entitats si faràs servir totes dues; si no, només una.
Analitzar SKU amb tres ressenyes. Amb 8.000 ressenyes i 2.400 productes, la mitjana és de tres per SKU. Per a la majoria del catàleg, l'única lectura honesta és per categoria.
Oblidar modelo_version i procesado_en. Sense elles és impossible distingir un canvi en els clients d'un canvi en el model del proveïdor.
Consell: desa sempre el sentiment per frase. Ve gratis a la mateixa resposta i permet localitzar la frase problemàtica d'una ressenya llarga sense tornar a trucar.
Consell: valida amb 200 ressenyes etiquetades a mà abans d'ensenyar cap número a direcció. És la diferència entre "el sentiment mitjà és 0,31" i "la classificació coincideix amb el criteri humà en el 82 % dels casos, i falla sobretot en ironia i en argot tècnic".
Exercicis
Exercici 1
La Lucía presenta a direcció que "el 71 % de les ressenyes d'AlpinaShop són neutres" i conclou que els clients són indiferents. Diagnostica què ha pogut passar, quina consulta faries per comprovar-ho, i què li proposaries presentar en lloc d'això.
Exercici 2
Dissenya el procés complet per analitzar les ressenyes noves cada nit: arquitectura, taula de destinació, control de cost i què fer quan una ressenya falla. Indica quins serveis de mòduls anteriors reutilitzes.
Exercici 3
L'anàlisi mostra que el producte BOT-3391 (bota de muntanya rígida) té un sentiment mitjà de −0,18, dels pitjors del catàleg, però la seva taxa de devolució és del 2,1 %, molt per sota de la mitjana del 6,4 %. Explica la contradicció aparent i proposa com investigar-la.
Solucions
Solució 1
Diagnòstic: gairebé amb seguretat, està classificant només per score i ignorant la magnitude.
L'apartat 3 explica el mecanisme exacte. Les ressenyes mixtes —"el producte genial, l'enviament horrible"— tenen els dos sentiments anul·lant-se i produeixen un score proper a 0. Si el criteri és "neutra si el score és entre −0,25 i +0,25", totes aquelles ressenyes intenses cauen al sac de neutres.
Una causa secundària possible: si l'idioma no es va declarar i part de les ressenyes són en català, la detecció pot haver fallat i haver retornat valors poc discriminants.
Consulta per comprovar-ho:
SELECT
CASE WHEN ABS(score) < 0.25 THEN 'score_neutre' ELSE 'score_polaritzat' END AS grupo,
CASE WHEN magnitude < 0.6 THEN 'baixa'
WHEN magnitude < 1.5 THEN 'mitjana'
ELSE 'alta' END AS emocion,
COUNT(*) AS opiniones,
ROUND(AVG(puntuacion), 2) AS estrellas_medias,
ROUND(AVG(LENGTH(texto)), 0) AS long_media
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` s
JOIN `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` o USING (opinion_id)
WHERE estado = 'OK'
GROUP BY grupo, emocion
ORDER BY grupo, emocion;Què esperar. Si dins de score_neutre hi ha un bloc gran amb emoció alta, aquí hi ha la resposta: no són neutres, són mixtes. I la dada que ho confirma de forma independent és estrellas_medias: si aquell grup té una mitjana de 2,8 estrelles i textos llargs, és evident que no són clients indiferents.
Què presentar en lloc d'això:
- La classificació en quatre classes —positiva, negativa, neutra, mixta— amb la vista de l'apartat 3. És molt probable que les "neutres" reals baixin del 71 % a un 25-30 %.
- El desglossament de les mixtes per entitat, que és la informació accionable: "a les ressenyes mixtes, el producte té sentiment mitjà +0,6 i l'enviament −0,5". Això no diu que els clients siguin indiferents: diu que el producte agrada i la logística falla, que és una conclusió amb accions associades.
- La validació amb 200 ressenyes etiquetades a mà, amb la frase d'honestedat corresponent: "la classificació automàtica coincideix amb el criteri humà en el X % dels casos".
La lliçó de fons: un número mal interpretat porta a la conclusió de negoci més equivocada possible —"als clients els és igual"— quan les dades diuen justament el contrari.
Solució 2
Arquitectura, reutilitzant el del mòdul 4:
flowchart LR
A[Cloud Scheduler<br/>03:30 diari] --> B[Workflows]
B --> C[Consulta incremental<br/>a BigQuery]
C --> D[Cloud Run Job<br/>proces Python]
D --> E[Natural Language API]
E --> D
D --> F[opiniones_sentimiento]
D --> G[opiniones_fallidas]
B --> H[Comprovacio de qualitat]
H -->|fallada| I[Alerta a gcp-datos@]
Serveis reutilitzats: Cloud Scheduler i Workflows com a orquestrador (04-06, decisió ja presa davant de Composer), BigQuery com a origen i destinació (04-01) amb la vista desidentificada de 04-07, Cloud Run com a executor del procés (detall a 07-02), Cloud Monitoring per a l'alerta (06-04) i Secret Manager si calgués alguna credencial (03-06).
Per què Cloud Run Job i no una funció: el procés pot trigar diversos minuts amb reintents, i un treball de Cloud Run admet execucions llargues sense les restriccions de temps d'una funció.
Selecció incremental, la consulta de l'apartat 8, amb un topall de seguretat:
SELECT o.opinion_id, o.sku, o.fecha, o.texto, o.idioma
FROM `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` o
LEFT JOIN `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` s
USING (opinion_id)
WHERE s.opinion_id IS NULL
LIMIT 5000; -- topall de seguretat: si alguna cosa es desmadra, no es dispara el costEl LIMIT 5000 és deliberat. Si per un error de dades apareguessin 400.000 ressenyes sense processar, el topall evita una factura inesperada. El que sobri es processarà la nit següent, i la comprovació de qualitat avisarà que la cua creix.
Taula de destinació: la de l'apartat 9, particionada per fecha i agrupada per sku, amb modelo_version i procesado_en.
Què fer quan una ressenya falla:
| Tipus de fallada | Acció |
|---|---|
429 quota |
Reintent amb espera exponencial i soroll, fins a 5 vegades |
503 transitori |
Reintent ràpid |
InvalidArgument |
No reintentar. Fila amb estado='ERROR: ...' |
| Text buit o < 10 caràcters | Filtrar abans de trucar; no gasta quota |
| Reintents exhaurits | Fila amb estat d'error; el procés següent no el reintenta automàticament |
La clau: cada ressenya llegida produeix una fila, amb resultat o amb error. Així opinion_id IS NULL continua significant "no processat" i no "va fallar i es reintentarà eternament", que és com es construeix un bucle infinit de cost.
Control de cost:
- Filtrar textos trivials abans de trucar (
LENGTH(texto) >= 10). LIMIT 5000com a topall dur.- Demanar només sentiment al flux diari; l'anàlisi d'entitats es reserva per a les ressenyes negatives i mixtes, que són una fracció.
- Etiqueta de facturació
centro-coste:analiticai alerta de pressupost (01-04).
Comprovació de qualitat al Workflow, que bloqueja si alguna cosa va malament:
SELECT
COUNTIF(estado = 'OK') AS ok,
COUNTIF(estado != 'OK') AS fallidas,
SAFE_DIVIDE(COUNTIF(estado != 'OK'), COUNT(*)) AS tasa_fallo
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento`
WHERE DATE(procesado_en) = CURRENT_DATE();Si tasa_fallo > 0.05, el Workflow marca fallada i alerta gcp-datos@. És la mateixa disciplina de qualitat que bloqueja el pipeline nocturn a 04-07.
Solució 3
No hi ha contradicció. Hi ha dues explicacions plausibles, i totes dues són bones notícies mal explicades.
Explicació 1 (la més probable): l'argot del domini. És exactament el cas de la taula de l'apartat 12. Una bota de muntanya rígida genera ressenyes com "són duríssimes", "costa caminar-hi en pla", "molt rígides", "pesen". El model genèric llegeix "dures", "costa", "pesen" i retorna sentiment negatiu. Per a una bota compatible amb grampó, la rigidesa és el requisit funcional, no un defecte. El client que escriu "són duríssimes" està descrivint amb satisfacció que el producte fa el que promet.
I les devolucions ho confirmen: qui compra aquest producte sap què compra i se'l queda.
Explicació 2: la queixa és sobre el procés d'adaptació, no sobre el producte. Les botes rígides requereixen un període de rodatge incòmode. Les ressenyes poden ser negatives sobre aquella experiència —"els primers dies van ser un suplici"— i positives sobre el resultat final. El sentiment global capta la part negativa.
Com investigar-ho, en tres passos:
Pas 1 — Llegir. Treure les 20 ressenyes més negatives del SKU i llegir-les. Costa quinze minuts i moltes vegades resol el cas. Cap anàlisi automàtica no substitueix això.
SELECT o.texto, s.score, s.magnitude, o.puntuacion
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` s
JOIN `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` o USING (opinion_id)
WHERE s.sku = 'BOT-3391' AND s.estado = 'OK'
ORDER BY s.score ASC LIMIT 20;Pas 2 — Contrastar amb les estrelles. La puntuació numèrica és una etiqueta humana que ja existeix i és gratuïta:
SELECT
ROUND(AVG(o.puntuacion), 2) AS estrellas_medias,
ROUND(AVG(s.score), 3) AS score_medio,
ROUND(CORR(o.puntuacion, s.score), 3) AS correlacion_sku,
COUNT(*) AS n
FROM `alpinashop-datos.alpinashop_analitica.opiniones_sentimiento` s
JOIN `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` o USING (opinion_id)
WHERE s.sku = 'BOT-3391' AND s.estado = 'OK';Aquest és el pas decisiu. Si les estrelles mitjanes són 4,3 i el score mitjà és −0,18, el veredicte és inequívoc: el problema és de l'anàlisi, no del producte. Els clients estan contents i el model ho està llegint a l'inrevés.
Pas 3 — Comparar dins de la categoria. Repetir la consulta anterior agrupant per categoria i subcategoria amb HAVING opiniones >= 30, ordenant per correlació ascendent. Si totes les botes rígides del catàleg mostren el mateix desajust entre estrelles i score, no és un cas aïllat: és un biaix sistemàtic del model en aquella categoria. Les categories amb correlació baixa o negativa entre estrelles i score són aquelles on l'anàlisi genèrica no és de fiar.
Què fer amb la troballa:
- Curt termini: no fer servir el
scoreabsolut per comparar entre categories. Comparar cada producte contra la mitjana de la seva categoria, no contra la mitjana global. Unscorede −0,18 en una categoria la mitjana de la qual és −0,22 és en realitat dels millors. - Mitjà termini: fer servir Gemini per a les categories problemàtiques (05-06), explicant-li el context al prompt: "Aquestes són ressenyes sobre botes de muntanya rígides. En aquest context, 'dures', 'rígides' i 'pesades' poden ser descripcions positives del rendiment tècnic. Classifica el sentiment real del client." Això arregla el problema sense entrenar res.
- Llarg termini: si el problema és extens, entrenar un classificador propi amb AutoML Text (05-02) utilitzant les estrelles com a etiqueta feble i una mostra validada a mà. Aquí sí que compensaria.
I la lliçó general: el millor detector de fallades de l'anàlisi de sentiment és una etiqueta humana que ja tens. Les estrelles eren a la base de dades des del principi. Creuar la sortida d'un model amb un senyal humà independent és la comprovació més barata i més eficaç que existeix.
Conclusió
Has aplicat el principi que més diners estalvia en aprenentatge automàtic aplicat: no entrenis el que ja està entrenat. Vuit mil ressenyes que portaven cinc anys sense que ningú no les llegís estan ara analitzades, creuades amb les vendes i disponibles a BigQuery, per unes desenes d'euros i sense ni un minut d'entrenament.
Coneixes les cinc funcions de l'API de Natural Language —sentiment, entitats, sentiment d'entitats, classificació de contingut i sintaxi— i per què la tercera és la més valuosa per a una botiga: una ressenya real gairebé mai no és bona o dolenta a seques, és "el producte genial, l'enviament horrible", i només el desglossament per entitat converteix això en una cosa accionable.
I sobretot entens score i magnitude, que és on s'equivoca gairebé tothom. Un score de 0 amb magnitude de 0,1 és un text descriptiu sense emoció; un score de 0 amb magnitude de 3,4 és una ressenya intensa amb un problema seriós a dins. Confondre'ls porta a la conclusió més equivocada possible —"als clients els és igual"— justament quan les dades diuen el contrari.
Has muntat el processament de les 8.000 ressenyes amb el que cal perquè un procés d'aquest tipus sobrevisqui a la realitat: espera exponencial amb soroll per a les quotes, distinció entre errors reintentables i definitius, una fila de resultat per cada document llegit encara que falli, concurrència moderada i retall defensiu de textos anòmals. Saps estimar el cost abans de gastar-lo amb una consulta SQL, i per què l'arrodoniment per document i per funció és el que de debò determina la factura.
Els resultats viuen a opiniones_sentimiento, particionada i agrupada, amb modelo_version i procesado_en —les dues columnes que permeten distingir, d'aquí a sis mesos, si va canviar el model o van canviar els clients—. I el procés incremental nocturn s'enganxa a Cloud Scheduler i Workflows, l'orquestrador que AlpinaShop ja va triar a 04-06, amb topall de seguretat i comprovació de qualitat que bloqueja si la taxa de fallada es dispara.
Has respost la pregunta de negoci creuant sentiment amb devolucions, i saps llegir el resultat amb les tres cauteles: correlació no és causalitat, qui ressenya no és una mostra representativa, i amb tres ressenyes per SKU de mitjana l'única lectura honesta per a la majoria del catàleg és per categoria.
I coneixes els límits reals, dits sense adorns: la ironia se li escapa, les negacions complexes es dilueixen, i l'argot de muntanya li juga males passades —"dures" és un defecte en unes vambes i una virtut en unes botes de grampó—. Per això el protocol de validar amb 200 ressenyes etiquetades a mà no és opcional: és el que converteix "el sentiment mitjà és 0,31" en "coincideix amb el criteri humà en el 82 % dels casos, i falla en ironia i argot tècnic". I tens el truc més barat de tots: creuar la sortida del model amb les estrelles que els clients ja havien posat.
Tens la comparació honesta entre l'API, Gemini i un classificador propi, amb la combinació que sol guanyar —l'API per al volum, Gemini per al subconjunt interessant—, i saps que Translation, Speech-to-Text i Document AI comparteixen la mateixa filosofia. I tens el marc de privadesa clar: l'anàlisi corre sobre la vista desidentificada de 04-07, el text lliure és on acaben les dades personals que ningú no esperava, la residència de les dades cal verificar-la per funció i idioma, i qualsevol ús que apunti a persones en lloc de a productes canvia l'enquadrament legal per complet.
Queda una pregunta del mòdul 4 sense respondre, i és la més voluminosa: 60 GB d'imatges a alpinashop-catalogo. AutoML les va classificar per categoria a 05-02, però de cada foto se'n pot extreure moltíssim més del que hi ha: quins objectes hi apareixen i on, quin text porta imprès, quins colors hi dominen, si és apta per publicar-se. I hi ha un problema nou: els clients comencen a pujar les seves pròpies fotos a les ressenyes, i ningú no les està moderant.
A 05-05, l'API de visió, apliques el mateix principi a les imatges. Veuràs les funcions de Cloud Vision —etiquetes, objectes amb requadre, OCR, logotips, punts de referència, colors dominants, SafeSearch i detecció web—, processaràs els 60 GB en massa amb asyncBatchAnnotate controlant el cost per miler d'imatges, i les convertiràs en quatre coses concretes: el text alternatiu d'accessibilitat que avui no existeix, el filtre per color de la botiga, la moderació automàtica de les fotos de clients i la detecció de les fitxes que no compleixen l'estàndard del catàleg. Amb l'arquitectura per esdeveniments sobre el topic imagenes-subidas, i amb l'advertiment legal més seriós del mòdul, que arriba quan en una imatge apareix una cara.
Curs de Google Cloud Platform (GCP)
Mòdul 1: Introducció a Google Cloud Platform
- Què és Google Cloud Platform?
- Configuració del teu compte de GCP
- Descripció general de la consola de GCP
- Projectes, jerarquia de recursos i facturació
- Regions, zones i model de responsabilitat compartida
- Cloud Shell i la CLI de gcloud
Mòdul 2: Serveis principals de GCP
- Compute Engine: màquines virtuals a Google Cloud
- Cloud Storage: emmagatzematge d'objectes
- Cloud SQL: bases de dades relacionals gestionades
- App Engine: plataforma com a servei
- Google Kubernetes Engine (GKE)
- Bases de dades NoSQL: Firestore, Bigtable i Spanner
- Com triar el servei de còmput adequat
Mòdul 3: Xarxes i seguretat
- Xarxes VPC
- Balanceig de càrrega al núvol
- Cloud CDN
- Gestió d'identitat i accés (IAM)
- Cloud Armor
- Secrets i xifratge: Secret Manager i Cloud KMS
- Cloud DNS, certificats TLS i publicació segura de serveis
Mòdul 4: Dades i anàlisi
- BigQuery: el magatzem de dades analític
- Cloud Dataflow: processament de dades per lots i en temps real
- Cloud Dataproc: Spark i Hadoop gestionats
- Cloud Pub/Sub: missatgeria asíncrona
- Cloud Data Fusion: integració de dades sense codi
- Orquestració de pipelines amb Cloud Composer i Workflows
- Govern de les dades i taulers amb Dataplex i Looker Studio
Mòdul 5: Aprenentatge automàtic i IA
- Vertex AI: la plataforma d'aprenentatge automàtic de GCP
- AutoML: models a mida sense escriure codi
- TensorFlow a GCP: entrenament i servei de models
- API de llenguatge natural
- API de visió
- IA generativa a Vertex AI: models Gemini i incrustacions
- MLOps: del model al producte amb Vertex AI Pipelines
Mòdul 6: DevOps i monitoratge
- Cloud Build: integració contínua a GCP
- Cloud Source Repositories i gestió del codi font
- Cloud Functions: funcions sense servidor
- Cloud Monitoring (abans Stackdriver): mètriques, taulers i alertes
- Cloud Deployment Manager i infraestructura com a codi nativa
- Cloud Logging i Cloud Trace: registres, traces i diagnòstic
- Terraform a GCP: infraestructura com a codi a la pràctica
Mòdul 7: Temes avançats de GCP
- Híbrid i multinúvol amb Anthos
- Computació sense servidor amb Cloud Run
- Xarxes avançades: VPC compartida, aparellament i connectivitat híbrida
- Bones pràctiques de seguretat
- Gestió i optimització de costos
- Fiabilitat: SLO, alta disponibilitat i recuperació de desastres
- Govern a escala: organització, polítiques i auditoria
