Sentiment
How positive or negative English text is, by VADER: scores from -1 to 1 that understand not good, VERY good!!! and emoji, for reviews, tickets and feedback.
Version 1.0.0 · 3 functions · 1 crate
Functions
What use sentiment.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use sentiment_scores, sentiment_label from sentiment (Quillo 0.6).
sentiment_scores(text: str) → anyor an errorThe sentiment of text: { label, compound, positive, negative, neutral }. compound runs from -1 (most negative) to 1 (most positive); label is "positive" from 0.05, "negative" from -0.05, else "neutral"; the other three are the shares of the text that are each, adding up to 1. Best on short texts such as a review or a tweet; English only. Up to 100 KB.
sentiment_label(text: str) → stror an errorOnly the label: "positive", "negative" or "neutral".
sentiment_sentences(text: str) → listor an errorEach sentence of text with its scores, [{ sentence, label, compound }], for long feedback that praises one thing and complains of another.
Get it
$ quillo install sentiment # sentiment.qwer into this folder$ quillo install sentiment --example # and its example, sentiment.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/sentiment.qwer$ curl -O https://quillolang.org/plugins/files/sentiment.qweThen, in your program, all of it or only what you call:
use sentiment.qweruse sentiment_scores, sentiment_label from sentiment // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
vader_sentiment = "0.1"Example
// Product reviews sorted by how unhappy they are, so support answers the worst first.//// quillo run sentiment.qwe then open http://localhost:8080/reviewsuse "sentiment.qwer"let reviews = [ "Absolutely love it!!! Best purchase this year 😍", "It is not good. The strap broke after two days and nobody answered my emails.", "Arrived on Tuesday.", "The screen is great, but the battery is terrible.",]route GET /reviews = reviews | map((r) => { review: r, mood: sentiment_scores(r)? }) | sort_by((r) => r.mood.compound)route GET /mood ? { text: str } = sentiment_scores(text)?route GET /sentences = sentiment_sentences("The screen is great. But the battery is terrible!!! Shipping was fine.")?$ quillo run sentiment.qwe$ curl 'localhost:8080/reviews'$ curl 'localhost:8080/sentences'Source
//! How positive or negative English text is, for reviews, support tickets and feedback: VADER scores that understand "not good", "VERY good!!!" and emoji.//! version: 1.0.0//!//! [dependencies]//! vader_sentiment = "0.1"use serde_json::{json, Value};use std::sync::OnceLock;use vader_sentiment::SentimentIntensityAnalyzer;fn analyzer() -> &'static SentimentIntensityAnalyzer<'static> { static A: OnceLock<SentimentIntensityAnalyzer<'static>> = OnceLock::new(); A.get_or_init(SentimentIntensityAnalyzer::new)}fn round(x: f64) -> f64 { (x * 1000.0).round() / 1000.0}fn label(compound: f64) -> &'static str { if compound >= 0.05 { "positive" } else if compound <= -0.05 { "negative" } else { "neutral" }}fn scores(text: &str) -> Result<Value, String> { if text.len() > 100_000 { return Err("text up to 100 KB".into()); } let t = text.to_string(); // The analyzer is an old port; a panic in it becomes an error, not a failed request. let s = std::panic::catch_unwind(move || { let m = analyzer().polarity_scores(&t); (m.get("pos").copied().unwrap_or(0.0), m.get("neg").copied().unwrap_or(0.0), m.get("neu").copied().unwrap_or(0.0), m.get("compound").copied().unwrap_or(0.0)) }) .map_err(|_| "could not score this text".to_string())?; Ok(json!({ "label": label(s.3), "compound": round(s.3), "positive": round(s.0), "negative": round(s.1), "neutral": round(s.2) }))}/// The sentiment of `text`: `{ label, compound, positive, negative, neutral }`. `compound` runs from -1 (most negative) to 1 (most positive); `label` is "positive" from 0.05, "negative" from -0.05, else "neutral"; the other three are the shares of the text that are each, adding up to 1. Best on short texts such as a review or a tweet; English only. Up to 100 KB.pub fn sentiment_scores(text: &str) -> Result<Value, String> { scores(text)}/// Only the label: "positive", "negative" or "neutral".pub fn sentiment_label(text: &str) -> Result<String, String> { Ok(scores(text)?["label"].as_str().unwrap_or("neutral").to_string())}/// Each sentence of `text` with its scores, `[{ sentence, label, compound }]`, for long feedback that praises one thing and complains of another.pub fn sentiment_sentences(text: &str) -> Result<Vec<Value>, String> { if text.len() > 100_000 { return Err("text up to 100 KB".into()); } let mut out = Vec::new(); let mut start = 0; let chars: Vec<(usize, char)> = text.char_indices().collect(); for (i, &(at, c)) in chars.iter().enumerate() { let next_space = chars.get(i + 1).map_or(true, |&(_, n)| n.is_whitespace()); if (c == '.' || c == '!' || c == '?' || c == '\n') && next_space { let end = at + c.len_utf8(); // Keep "!!!" and "?!" with their sentence. if chars.get(i + 1).map_or(false, |&(_, n)| n == '!' || n == '?') { continue; } push(&mut out, &text[start..end])?; start = end; } } push(&mut out, &text[start..])?; Ok(out)}fn push(out: &mut Vec<Value>, s: &str) -> Result<(), String> { let s = s.trim(); if !s.is_empty() { let sc = scores(s)?; out.push(json!({ "sentence": s, "label": sc["label"], "compound": sc["compound"] })); } Ok(())}Related
lang.qwer · 1.0.0Which of 69 languages a text is in, its script and how sure: route tickets, tag posts, pick a spell-checker.6 views · 6 downloadsN-grams ngrams.qwer · 1.0.0N-grams and shingles: word and character n-grams, the phrases a text uses most, how alike two texts are by shared shingles despite typos, and near-duplicates found among thousands of texts with MinHash.6 views · 9 downloadsCase case.qwer · 1.0.0Text in snake_case, camelCase, PascalCase, kebab-case, CONSTANT_CASE, Title Case and Sentence case: column names as API keys and labels.7 views · 8 downloadsChinese words chinese_segment.qwer · 1.0.0Chinese text split into words for search indexes and counts, with parts of speech, and written in pinyin with tones, tone numbers or initials for sorting and finding names.7 views · 7 downloadsEmoji emoji.qwer · 1.0.0Emoji for chat and comments: :shortcodes: turned into emoji and back, emoji found with their names, stripped from subjects, and searched by name for a picker.7 views · 8 downloadsFuzzy search fuzzy.qwer · 1.0.0Rank names against what someone typed, typos and all, edit distances, and did-you-mean.7 views · 8 downloadsThread 0 posts
On Sentiment: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.