Sentiment Analysis with Tensorflow.js A quick port of the official example to Observable, using Googleโs pre-trained example model. The model was trained against 25,000 film reviews from IMDB, labeled either positive (1), or negative (0).
mutable positivity = 0.5
sentiment = { let mood = (() => { if (positivity > 0.9) return '๐'; if (positivity > 0.8) return '๐'; if (positivity > 0.6) return '๐'; if (positivity > 0.4) return '๐'; if (positivity > 0.2) return '๐'; if (positivity > 0.1) return '๐ฆ'; return '๐ฑ'; })(); return html`<span style="font-size: 50px;">${mood}</span>`; }
viewof text = textarea({cols: 80, rows: 10, placeholder: "Type a positive or negative comment. Longer โreviewsโ seem to work better than short ones...", value: review && review.review})
Or, try a random Metacritic review of a recent, controversial film:
viewof randomReview = button("Random review of โThe Last Jediโ")
Tensorflow.js bits
predict = { const trimmed = text.trim().toLowerCase().replace(/(\.|\,|\!)/g, '').split(' '); const inputBuffer = tf.buffer([1, metadata.max_len], "float32"); trimmed.forEach((word, i) => inputBuffer.set(metadata.word_index[word] + metadata.index_from, 0, i)); const input = inputBuffer.toTensor(); const predictOut = model.predict(input); mutable positivity = predictOut.dataSync()[0]; predictOut.dispose(); return predictOut; }
model = { return this || await tf.loadModel("https://storage.googleapis.com/tfjs-models/tfjs/sentiment_cnn_v1/model.json") }
metadata = (await fetch("https://storage.googleapis.com/tfjs-models/tfjs/sentiment_cnn_v1/metadata.json")).json()
tf = require("@tensorflow/tfjs@0.8.0")
import {button, textarea} from "@jashkenas/inputs"
Metacritic reviews bits
review = { randomReview; if (!this) return true; return reviews[Math.floor(Math.random() * reviews.length)]; }
tljReviews = ({text: await (await fetch("https://gist.githubusercontent.com/jashkenas/ee5b07c30b99b23a6d5baf1675542bce/raw/03f093bc6d7d5d349307c84db61deb187edf1c90/last-jedi-user-reviews.html")).text()})
tljHTML = { const doc = document.implementation.createHTMLDocument(); const div = doc.createElement("div"); div.innerHTML = await tljReviews.text; doc.body.appendChild(div); return doc; }
reviews = { const reviews = tljHTML.querySelectorAll(".review"); return Array.from(reviews).map(el => { return { score: +el.querySelector(".metascore_w").innerText, review: (el.querySelector(".blurb_expanded") || el.querySelector(".review_body")).innerText.trim() }; }); }