feat: add LinkedIn jargon translator web app

Single-page interactive translator that converts plain language into
LinkedIn-style corporate posts and decodes them back to human speak.

- Two translation modes: to LinkedIn and to Human
- Cringe intensity slider (1-5)
- 3 variation cards per translation with copy buttons
- Dual engine support: direct API key or local proxy server
- i18n toggle for Portuguese and English (UI + AI prompts)
- Dark theme with LinkedIn blue accent, fully responsive
- Local proxy server (server.js) bridges to the LLM CLI
This commit is contained in:
authentik Default Admin 2026-03-19 22:56:50 +00:00
parent 904ee1f49a
commit 0e9f6952b4
4 changed files with 1197 additions and 1 deletions

BIN
Jargonify.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

View file

@ -1 +1,73 @@
# Jargonify
# Jargonify
**The LinkedIn post translator nobody asked for, but everyone needs.**
Ever read a LinkedIn post and thought "what does this even mean?" Or maybe you got fired and need to spin it into a *✨ career transition ✨*? Jargonify has you covered.
![Jargonify demo](Jargonify.gif)
## What it does
**→ LinkedIn Mode**: Type something honest like "I got fired" and watch it transform into a 3-paragraph motivational odyssey about resilience, growth mindset, and embracing new cycles. Hashtags included. Emojis mandatory.
**→ Human Mode**: Paste a LinkedIn post dripping with corporate jargon and get back what the person *actually* meant. Three translations ranging from polite to brutally honest.
**Cringe Intensity Slider**: Because sometimes you need a tasteful professional update (level 1), and sometimes you need to go full thought-leader-guru-who-cried-at-a-conference (level 5).
## Running it
You need [Node.js](https://nodejs.org) installed. That's it. No frameworks. No build step. No 400MB `node_modules`. Just vibes.
```bash
git clone <this-repo>
cd Jargonify
node server.js
```
Open `http://localhost:3000` in your browser. Done.
The server is ~80 lines of plain Node.js with zero dependencies. It talks to the AI through the CLI on your machine, which means **you need an active LLM CLI subscription** (Pro or Max plan) already set up and authenticated.
### Alternative: API Key mode
If you have an API key from a supported provider, you can skip the server entirely:
1. Open `index.html` directly in your browser
2. Click "API Key" in the engine selector
3. Paste your key
4. Translate away
## Why is this not hosted online?
Money. Specifically, the lack of it being allocated to this project.
Every translation costs real API tokens. Three variations per click, creative writing prompts, emojis — it adds up. Hosting this publicly would be like opening a free restaurant and hoping people tip. They won't. They'll translate "I hate my job" into LinkedIn poetry 47 times and leave.
So it runs locally, using your own subscription. Think of it as BYOK — Bring Your Own Key(board and subscription).
## Features
- Two translation modes with animated toggle
- Cringe intensity slider (1-5) for LinkedIn mode
- 3 variations per translation with individual copy buttons
- Dual engine: local proxy server or direct API key
- Full i18n: Portuguese and English (UI + AI prompts)
- Dark theme with that unmistakable LinkedIn blue
- Responsive layout
- Ctrl/Cmd+Enter keyboard shortcut
- Zero dependencies on the server side
## Tech stack
- **Frontend**: One HTML file. HTML, CSS, JS. Like it's 2009 and I'm proud of it.
- **Backend**: One JS file. Node.js `http` module. No Express. No framework. Just `req` and `res` doing honest work.
## Disclaimer
This project is satire. If your LinkedIn posts sound like Jargonify output at level 5, that's between you and your network.
No motivational gurus were harmed in the making of this application. Several were accurately parodied.
## License
MIT — feel free to fork it, deploy it, or translate your resignation letter with it.

1028
index.html Normal file

File diff suppressed because it is too large Load diff

96
server.js Normal file
View file

@ -0,0 +1,96 @@
const http = require("http");
const { spawn } = require("child_process");
const fs = require("fs");
const path = require("path");
const PORT = 3000;
const server = http.createServer((req, res) => {
// CORS
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
if (req.method === "OPTIONS") {
res.writeHead(204);
res.end();
return;
}
// Serve index.html
if ((req.method === "GET" || req.method === "HEAD") && (req.url === "/" || req.url === "/index.html")) {
const filePath = path.join(__dirname, "index.html");
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(500);
res.end("Erro ao carregar index.html");
return;
}
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(data);
});
return;
}
// Translation endpoint
if (req.method === "POST" && req.url === "/translate") {
let body = "";
req.on("data", (chunk) => { body += chunk; });
req.on("end", () => {
let parsed;
try {
parsed = JSON.parse(body);
} catch (e) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "JSON inválido" }));
return;
}
const { prompt } = parsed;
if (!prompt || typeof prompt !== "string") {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Campo 'prompt' é obrigatório" }));
return;
}
console.log(`[Jargonify] Traduzindo (${prompt.length} chars)...`);
const claudePath = "/opt/homebrew/bin/claude";
const childEnv = { ...process.env, PATH: process.env.PATH + ":/opt/homebrew/bin", LANG: "en_US.UTF-8", LC_ALL: "en_US.UTF-8" };
delete childEnv.CLAUDECODE;
delete childEnv.CLAUDE_CODE_ENTRYPOINT;
const child = spawn(claudePath, ["-p", "-"], { encoding: "utf-8", env: childEnv, timeout: 60000 });
let stdout = "";
let stderr = "";
child.stdout.on("data", (data) => { stdout += data; });
child.stderr.on("data", (data) => { stderr += data; });
child.on("close", (code) => {
if (code !== 0) {
console.error("[Jargonify] Erro (code " + code + "):", stderr);
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: `Erro ao executar Claude CLI: ${stderr || "exit code " + code}` }));
return;
}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ result: stdout.trim() }));
});
child.on("error", (err) => {
console.error("[Jargonify] Spawn erro:", err.message);
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: `Erro ao iniciar Claude CLI: ${err.message}` }));
});
child.stdin.write(prompt);
child.stdin.end();
});
return;
}
res.writeHead(404);
res.end("Not found");
});
server.listen(PORT, () => {
console.log(`\n ✨ Jargonify Server rodando em http://localhost:${PORT}\n`);
console.log(` Abra no browser para usar com traduções via Claude.\n`);
});