{"__browser":{"country":"US","device":"unknown_device","mobile":false,"name":"unknown browser","platform":"unknown_platform","version":"0"},"__constants":{},"__CPDATA":{"domain_iframe":"https://cdpn.io","environment":"production","host":"codepen.io","iframe_allow":"accelerometer *; ambient-light-sensor *; camera *; display-capture *; encrypted-media *; geolocation *; gyroscope *; microphone *; midi *; payment *; serial *; vr *; web-share *; xr-spatial-tracking *","iframe_sandbox":"allow-downloads allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation"},"__graphql":{"data":{"data":{"sessionUser":{"id":"VoDkNZ","name":"Captain Anonymous","title":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","currentContext":{"id":"VoDkNZ","title":"Captain Anonymous","name":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","username":"anon","__typename":"User"},"currentTeamId":null,"username":"anon","admin":false,"anon":true,"pro":false,"verified":false,"featureFlags":[],"teams":[],"__typename":"User"}}},"url":"https://codepen.io/graphql","api":"cprails"},"__user":{"anon":true,"base_url":"/anon/","cohorts":[],"current_team_hashid":null,"current_team_id":0,"hashid":"VoDkNZ","id":1,"itemType":"user","name":"Captain Anonymous","paid":false,"tier":0,"username":"anon","created_at":null,"email_verified":null,"collections_count":0,"collections_private_count":0,"followers_count":0,"followings_count":0,"pens_count":0,"pens_private_count":0,"projects_count":0,"projects_private_count":0},"__firebase":{"config":{"apiKey":"AIzaSyBgLAe7N_MdFpuVofMkcQLGwwhUu5tuxls","authDomain":"codepen-store-production.firebaseapp.com","databaseURL":"https://codepen-store-production.firebaseio.com","disabled":false,"projectId":"codepen-store-production"},"token":"eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsImNsYWltcyI6eyJvd25lcklkIjoiVm9Ea05aIiwiYWRtaW4iOmZhbHNlfSwiZXhwIjoxNzQ1ODU5Njg0LCJpYXQiOjE3NDU4NTYwODQsImlzcyI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInN1YiI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInVpZCI6IlZvRGtOWiJ9.IgX1DElogfsdAJOIDSCO_G-TO6twu6gBunZzzHyfCgLsELpQx3LXKpqOQiaP7p53jzRoz7jglAW0UCLzojiLP7aBue0W6YsEMUaNYpgQTHQUFCAfnRduaukrGUBHYcloI6UqbPaLSLo3bAUjzm6GwvJ_6XRHB4IIDCLhUVHwsc3ksHSt4OQHzZEUGQkJfePl5SnvXifKzU1uSUaotBU1BqrW0Ss4APviQSqbRQ0NV5gfmSSjCPynOmRwQKsA-6NP0h-9KlrRALn7ISOt01K7lr4NWruug9YI186o_QiyMqvVFwRObyffHiXt_uSElA9VfSgsnux_2sJ_UNuYQafLqA"},"__pay_stripe_public_key":"pk_live_2GndomDfiklqpSNQn8FrGuwZSMIMzha7DkLJqlYe7IR0ihKAlKdiHg68JJc5eVPt68rzAjzAAVXcUwjySHRCsgjQQ00gtRBUFNH","__pay_braintree_env":"production","__item":"{\"id\":78848229,\"user_id\":74045,\"html\":\"<p>\\n<label for=\\\"newTopic\\\">Enter New Topic: \\n\\t<input id=\\\"newTopic\\\"><\\/label> <button id=\\\"addTopic\\\">Add Topic<\\/button>\\n<\\/p>\\n\\n<div id=\\\"results\\\">\\n<\\/div>\\n\\n<div id=\\\"status\\\"><\\/div>\",\"css\":\"div#status {\\n\\tfont-style: italic;\\n}\\n\\ndiv.result {\\n\\tborder-style:solid;\\n\\tborder-width:thin;\\n\\tmargin-bottom: 10px;\\n\\tpadding: 10px;\\n}\",\"js\":\"import { pipeline } from 'https:\\/\\/cdn.jsdelivr.net\\/npm\\/@huggingface\\/transformers@3.0.2';\\n\\nlet $status, $results, $newTopic;\\nlet classifier, topics=[];\\n\\/\\/ interval for how often to check in miliseconds\\nconst INTERVAL = 30000;\\n\\ndocument.addEventListener('DOMContentLoaded', init, false);\\n\\nasync function init() {\\n\\t$status = document.querySelector('#status');\\n\\t$newTopic = document.querySelector('#newTopic');\\n\\t$results = document.querySelector('#results');\\n\\t\\n\\tdocument.querySelector('#addTopic').addEventListener('click', () => {\\n\\t\\tlet newTopic = $newTopic.value.trim().replaceAll('\\\"','');\\n\\t\\tif(newTopic !== '') topics.push(newTopic);\\n\\t\\t$newTopic.value = '';\\n\\t\\t\\n\\t\\tif(topics.length === 1) checkTopics();\\n\\t});\\n\\t\\n\\t\\/\\/ warn user and load up transformers\\n\\t$status.innerHTML = 'Loading sentiment analyzer...';\\n\\tclassifier = await pipeline('sentiment-analysis');\\n\\t$status.innerHTML = '';\\n\\t\\n}\\n\\nasync function checkTopics() {\\n\\tconsole.log('checkTopics');\\n\\tif(topics.length === 0) return;\\n\\t$status.innerHTML = 'Loading Bluesky data for topics.';\\n\\tlet responses = [];\\n\\ttopics.forEach(t => {\\n\\t\\tresponses.push(getSentiment(t));\\n\\t});\\n\\tconsole.log('fired off calls for each topic');\\n\\tlet results = await Promise.all(responses);\\n\\t\\n\\tconsole.log('all done', results);\\n\\t$status.innerHTML = '';\\n\\trenderResults(results);\\n\\tsetTimeout(checkTopics, INTERVAL);\\n}\\n\\nasync function getSentiment(topic) {\\n\\tconsole.log(`Get sentiment for ${topic}`);\\n\\tlet sentimentTotal = 0;\\n\\t\\n\\tlet req = await fetch(`https:\\/\\/public.api.bsky.app\\/xrpc\\/app.bsky.feed.searchPosts?q=${encodeURIComponent(topic)}&lang=en`);\\n\\tlet data = (await req.json()).posts;\\n\\tconsole.log(`Posts found: ${data.length}`);\\n\\tfor(let i=0; i<data.length; i++) {\\n\\t\\tlet sentiment = (await classifier(data[i].record.text))[0];\\n\\t\\t\\/\\/console.log(`Sentiment for ${data[i].record.text} is ${JSON.stringify(sentiment)}`); \\n\\t\\tif(sentiment.label === 'NEGATIVE') sentiment.score = -1 * sentiment.score;\\n\\t\\tsentimentTotal += sentiment.score;\\n\\t}\\n\\tlet avgSentiment = sentimentTotal \\/ data.length;\\n\\tconsole.log(`Total sentiment, ${sentimentTotal}, avg ${avgSentiment}`);\\n\\treturn { topic: topic, sentiment: avgSentiment, total:data.length, generated: new Date() };\\n}\\n\\nfunction renderResults(results) {\\n\\t\\n\\t\\/*\\n\\tIt's possible a user clicks remove while we were loading \\n\\tstuff, so we'll do a quick sanity check.\\n\\t*\\/\\n\\tresults = results.filter(r => topics.includes(r.topic));\\n\\t\\n\\tlet s = '';\\n\\tresults.forEach(r => {\\n\\t\\t\\n\\t\\t\\ts += `\\n\\t\\t\\t<div class=\\\"result\\\" data-topic=\\\"${r.topic}\\\">\\n<h2>Sentiment Analysis for: ${r.topic}<\\/h2>\\n<p>\\nAverage was <strong>${r.sentiment>0?'POSITIVE':'NEGATIVE'}<\\/strong> (Average Score: ${r.sentiment} over ${r.total} items)<br>\\nGenerated: ${dateFormat(r.generated)}\\n<\\/p>\\n<p>\\n<button class=\\\"removeBtn\\\" data-topic=\\\"${r.topic}\\\">Remove from Analysis<\\/button>\\n<\\/p>\\n\\t\\t\\t<\\/div>`;\\n\\t});\\n\\n\\t$results.innerHTML = s;\\n\\tdocument.querySelectorAll('button.removeBtn').forEach(d => {\\n\\t\\td.addEventListener('click', removeItem);\\n\\t});\\n}\\n\\nfunction dateFormat(d) {\\n\\treturn new Intl.DateTimeFormat('en-US', { dateStyle:'medium', timeStyle:'long' }).format(d);\\n}\\n\\nfunction removeItem(r) {\\n\\tlet topic = r.target.dataset.topic;\\n\\tconsole.log('remove', topic);\\n\\tdocument.querySelector(`[data-topic=\\\"${topic}\\\"]`).remove();\\n\\tconsole.log(topics);\\n\\ttopics = topics.filter(t => t !== topic);\\n\\tconsole.log(topics);\\n}\",\"html_pre_processor\":\"none\",\"css_pre_processor\":\"none\",\"js_pre_processor\":\"none\",\"html_classes\":\"\",\"css_starter\":\"neither\",\"js_library\":null,\"created_at\":\"2025-01-02T16:19:57.764Z\",\"updated_at\":\"2025-01-02T20:56:32.455Z\",\"title\":\"BS Search Panel\",\"description\":\"\",\"slug_hash\":\"jENaEMV\",\"head\":\"\",\"private\":false,\"slug_hash_private\":\"5c807cb3b7e99f78e8b0714112f4f2a8\",\"has_animation\":false,\"team_id\":0,\"css_prefix\":\"neither\",\"template\":false,\"parent_id\":78848061,\"comments_count\":0,\"custom_screenshot_filename\":null,\"loves_count\":1,\"pick\":false,\"popularity\":8,\"views_count\":30,\"pick_visible_at\":null,\"cpid\":\"019427d1-06c4-7395-bbcd-40c042845131\",\"is_new_editor_pen\":false,\"access\":\"Public\",\"pen_hash\":null,\"hashid\":\"jENaEMV\"}"}