Developing a Toxicity Detection Communication App: Promoting Positive Dialogue with AI Ethics, React, and TensorFlow.js
Build a React web application that integrates TensorFlow.js for toxicity detection, visualizing potentially harmful language through graph structures to encourage more positive and ethical digital communication.
Daniel Kliewer
Author, Sovereign AI


Learning From the Past and Building a Better Future Through Technology
Our world stands at a critical juncture. We’ve witnessed how the unchecked pursuit of strategic advantage, from mid-20th century conflicts to the present day, can normalize moral compromises. The history of warfare, internment camps, and the nuclear arms race taught us a lesson: the ends do not justify the means. Yet here we are again, seeing advanced technologies—drones, AI, cryptographic frameworks—funneled into machines of war. We see hypocrisy in how international rules are applied selectively, and we see how the very frameworks meant to maintain peace can be bent or broken for short-term gain.
But technology doesn’t have to serve destruction. Just as the same drone technology can be repurposed to improve healthcare delivery in remote areas, or augmented reality can train doctors more efficiently, the tools we create can heal rather than harm. This choice—how we apply our technology—is ours to make. We can build a future where AI supports better communication, encourages empathy, and guides us toward more conscientious behavior.
This brings us to today’s project: a small web application that uses machine learning and a graph-based data structure to help people communicate more positively. Instead of guiding deadly precision strikes, this codebase is designed to guide more constructive dialogue. By highlighting and mapping out potentially hurtful language, the app nudges us toward healthier, more uplifting forms of expression.
We’re acknowledging our past failures and choosing a different path forward. This app, while small and symbolic, is a testament to the idea that we can use the most advanced tools at our disposal to cultivate empathy rather than enmity. We can support each other by learning from the past and building a kinder digital world, one line of code at a time.
Guide: Building the “PositiveWords Graph” Application
Goal:
Set up a React application that integrates a toxicity-detection ML model and visualizes user input as a weighted graph of words. This encourages more thoughtful communication and leverages technology to improve the world in a small but meaningful way.
Key Features:
- A React front-end that allows the user to enter a message.
- Integration with a pre-trained TensorFlow.js toxicity model to detect harmful language.
- A graph representation of the user’s text where nodes are words and edges represent adjacency and frequency, highlighting potentially problematic areas.
- Deployment capability via Git and Netlify so changes can be easily pushed live.
Prerequisites
- Node.js and npm installed (verify with
node -vandnpm -v) - Git installed (verify with
git --version) - A GitHub account for version control
- A Netlify account for free deployment
Step-by-Step Instructions
1. Create a New React App
Use create-react-app for quick setup.
bash1# Navigate to your projects directory2cd /path/to/projects34# Create a new React app5npx create-react-app positivewords-graph
2. Move Into the Project and Install Dependencies
bash1cd positivewords-graph2npm install @tensorflow/tfjs @tensorflow-models/toxicity
3. Replace the Default Code With Our Custom Code
- Open the project in your code editor.
- Replace
src/App.jsandsrc/App.csswith the provided code below. - Ensure
src/index.jsandpackage.jsonmatch the provided snippets.
package.json (already created by create-react-app, just ensure dependencies are present):
json1{2 "name": "positivewords-graph",3 "version": "1.0.0",4 "private": true,5 "dependencies": {6 "@tensorflow-models/toxicity": "^1.2.2",7 "@tensorflow/tfjs": "^4.0.0",8 "react": "^18.0.0",9 "react-dom": "^18.0.0",10 "react-scripts": "5.0.0"11 },12 "scripts": {13 "start": "react-scripts start",14 "build": "react-scripts build"15 }16}
src/index.js:
javascript1import React from 'react';2import ReactDOM from 'react-dom/client';3import App from './App';4import './App.css';56const root = ReactDOM.createRoot(document.getElementById('root'));7root.render(<App />);
src/App.js:
javascript1import React, { useState, useEffect } from 'react';2import * as tf from '@tensorflow/tfjs';3import { load } from '@tensorflow-models/toxicity';4import './App.css';56function buildGraphFromText(text, toxicWords) {7 const words = text8 .toLowerCase()9 .replace(/[^\w\s]/gi, '')10 .split(/\s+/)11 .filter(w => w.trim().length > 0);1213 const nodes = {};14 const edges = {};1516 words.forEach(w => {17 if (!nodes[w]) {18 nodes[w] = { word: w, toxicityWeight: toxicWords.includes(w) ? 1 : 0 };19 }20 });2122 for (let i = 0; i < words.length - 1; i++) {23 const a = words[i];24 const b = words[i + 1];25 const key = a < b ? `${a}-${b}` : `${b}-${a}`;26 if (!edges[key]) {27 edges[key] = { a, b, weight: 0 };28 }29 edges[key].weight += 1;30 }3132 return { nodes: Object.values(nodes), edges: Object.values(edges) };33}3435function App() {36 const [model, setModel] = useState(null);37 const [inputText, setInputText] = useState('');38 const [analysis, setAnalysis] = useState(null);39 const threshold = 0.9;4041 useEffect(() => {42 load(threshold).then(m => {43 setModel(m);44 });45 }, [threshold]);4647 const analyzeText = async () => {48 if (!model || !inputText) return;49 const predictions = await model.classify([inputText]);50 setAnalysis(predictions);51 };5253 const handleChange = (e) => {54 setInputText(e.target.value);55 };5657 const getToxicWords = () => {58 if (!analysis) return [];59 const toxicLabels = analysis.filter(pred => pred.results[0].match === true);60 if (toxicLabels.length === 0) return [];61 const words = inputText62 .toLowerCase()63 .replace(/[^\w\s]/gi, '')64 .split(/\s+/)65 .filter(w => w.trim().length > 0);66 return toxicLabels.length > 0 ? words : [];67 };6869 const toxicWords = getToxicWords();70 const graphData = buildGraphFromText(inputText, toxicWords);7172 return (73 <div className="App">74 <header className="App-header">75 <h1>PositiveWords Graph</h1>76 <p>Encouraging healthier communication with ML and graph insights.</p>77 </header>78 <main>79 <h2>Analyze Your Message</h2>80 <textarea81 placeholder="Type your message here..."82 value={inputText}83 onChange={handleChange}84 />85 <br />86 <button onClick={analyzeText} disabled={!model || !inputText}>87 Analyze88 </button>89 {analysis && (90 <div className="analysis-results">91 {analysis.some(a => a.results[0].match) ? (92 <div className="result negative">93 <h3>Consider Rewriting</h3>94 <p>Your message may contain harmful language. The graph below shows words detected and their relationships.</p>95 </div>96 ) : (97 <div className="result positive">98 <h3>Looks Good!</h3>99 <p>No harmful language detected. The graph below shows the words and their neutral relationships.</p>100 </div>101 )}102 </div>103 )}104 {graphData.nodes.length > 0 && (105 <div className="graph-display">106 <h3>Graph Overview</h3>107 <p><strong>Nodes:</strong> Each unique word, weighted if considered toxic.</p>108 <p><strong>Edges:</strong> Co-occurrence frequency between words.</p>109 <div className="graph-section">110 <h4>Nodes</h4>111 <ul>112 {graphData.nodes.map((node, i) => (113 <li key={i} style={{color: node.toxicityWeight > 0 ? 'red' : 'black'}}>114 {node.word} (toxicityWeight: {node.toxicityWeight})115 </li>116 ))}117 </ul>118 <h4>Edges</h4>119 <ul>120 {graphData.edges.map((edge, i) => (121 <li key={i}>122 {edge.a} - {edge.b} (weight: {edge.weight})123 </li>124 ))}125 </ul>126 </div>127 </div>128 )}129 </main>130 <footer>131 <p>© 2024 PositiveWords Graph. Building a kinder world through awareness and data.</p>132 </footer>133 </div>134 );135}136137export default App;
src/App.css:
css1.App {2 font-family: Arial, sans-serif;3 margin: 0;4 padding: 0;5 background: #f9f9f9;6 color: #333;7}89.App-header {10 background: #4CAF50;11 color: white;12 padding: 20px;13 text-align: center;14}1516main {17 padding: 20px;18 max-width: 600px;19 margin: 0 auto;20}2122main h2 {23 margin-bottom: 10px;24}2526textarea {27 width: 100%;28 height: 120px;29 font-size: 16px;30 padding: 10px;31 margin-bottom: 10px;32}3334button {35 padding: 10px 20px;36 background: #4CAF50;37 border: none;38 color: white;39 font-size: 16px;40 cursor: pointer;41}4243button:disabled {44 background: #ccc;45 cursor: not-allowed;46}4748.result {49 margin-top: 20px;50 padding: 20px;51 border-radius: 5px;52}5354.result.negative {55 background: #ffe0e0;56 border: 1px solid #ffcccc;57}5859.result.positive {60 background: #e0ffe0;61 border: 1px solid #ccffcc;62}6364.analysis-results {65 margin-top: 20px;66}6768.graph-display {69 margin-top: 20px;70 background: #fff;71 border: 1px solid #ddd;72 padding: 15px;73 border-radius: 5px;74}7576.graph-display ul {77 list-style: none;78 padding-left: 0;79}8081.graph-display li {82 margin-bottom: 5px;83}8485footer {86 text-align: center;87 padding: 10px;88 background: #eee;89 margin-top: 20px;90}
4. Run the App Locally
bash1npm start
Open http://localhost:3000 in your browser. Enter text, analyze it, and see the results and graph.
5. Initialize Git and Commit Changes
bash1git init2git add .3git commit -m "Initial commit of PositiveWords Graph"
6. Create a GitHub Repository and Push Code
- Go to GitHub, create a new repository
positivewords-graph. - Back in terminal:
bash1git remote add origin https://github.com/<your-username>/positivewords-graph.git2git branch -M main3git push -u origin main
7. Deploy to Netlify
- Log into Netlify and choose “Import from Git” → “GitHub”
- Select
positivewords-graph - Netlify will detect it’s a React app and set build command:
npm run buildand publish directory:build. - Deploy the site.
- After building, it will be accessible at a Netlify subdomain.
8. Continuous Updates
Make code changes locally, then:
bash1git add .2git commit -m "Update"3git push origin main
Netlify automatically rebuilds and redeploys the updated app.
Conclusion
This application merges cutting-edge AI with a graph-based data structure to encourage more thoughtful communication, standing in contrast to the technologies that have too often been harnessed for harm. By following these steps, you’ve created a tool that not only highlights negative language but also reveals patterns in how words connect, helping you reflect on your message. In doing so, you’re contributing—albeit in a small way—to shaping a future where technology guides us toward empathy and understanding, rather than conflict.

Sovereign AI: Building Local-First Intelligent Systems
by Daniel Kliewer · Paperback · 72 pages
The hands-on guide to building AI that runs on your hardware, keeps your data private, and eliminates cloud dependence. Working code included.