# Vocalize

> Build Vocalize — a multi-platform content tone converter that rewrites content for 小红书, 公众号, LinkedIn, Medium, and X/Twitter using AI. Use when the user asks to build or extend a content repurposing tool, tone converter, or multi-platform writing assistant.

- Skill: `yanliudesign/vocalize` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yanliudesign/vocalize`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yanliudesign/vocalize/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: yanliudesign (https://skillmd.com/u/yanliudesign)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yanliudesign/vocalize

---


# Vocalize — Multi-Platform Content Tone Converter

## What it does

Takes one piece of content and rewrites it in the authentic voice of each platform:

| Platform | Style |
|---|---|
| 小红书 (Xiaohongshu) | Lively, emoji-rich, Gen-Z Chinese |
| 公众号 (WeChat Official Account) | Thoughtful, narrative essay-style Chinese |
| LinkedIn | Professional, credibility-building English |
| Medium | Conversational English storytelling |
| X/Twitter | Punchy, under 280 chars, bold takes |

## Stack

- **Frontend**: React + Vite (`artifacts/tone-converter`)
- **Backend**: Express 5 (`artifacts/api-server`)
- **AI**: Replit OpenAI integration (`@workspace/integrations-openai-ai-server`) — no API key needed
- **DB**: PostgreSQL + Drizzle ORM (`lib/db`) — saves conversions server-side
- **History**: localStorage on the frontend — each user's history is private and local
- **API contract**: OpenAPI → Orval-generated hooks in `lib/api-client-react`

## Key Features

### 1. Tone Sliders
Two sliders (0–100): **Formality** and **Boldness**. Injected at the end of every platform prompt:

```ts
function buildToneInstruction(formality: number, boldness: number): string {
  // maps 0-100 to descriptive labels, appends to system prompt
}
```

### 2. Per-Platform Refinement Chat
Each platform card has an inline chat (MessageSquarePlus icon). Sends `POST /api/refine` with:
```json
{ "platform": "xiaohongshu", "currentContent": "...", "userMessage": "...", "conversationHistory": [...] }
```
Multi-turn: `conversationHistory` is an array of `{ role, content }` pairs maintained in component state.

### 3. Local History (localStorage)
Hook: `artifacts/tone-converter/src/hooks/use-local-history.ts`
- Key: `vocalize_history`, max 20 records
- Each record includes full `results` for restoration (click history item → restores all tabs)
- No server read on load — each user sees only their own history
- Delete removes from localStorage, no API call needed

### 4. Tab-based Results
Output shown in `<Tabs>` — one tab per platform. Clicking a history item restores results AND active tab.

## Critical Prompt Rules

Apply these to ALL platform prompts without exception:

1. **No markdown** — never use `**`, `*`, `#`, or any markdown syntax
2. **English-only** for LinkedIn / Medium / X (Twitter) — never mix in Chinese
3. **Chinese-only** for 小红书 / 公众号 — never mix in English
4. **X/Twitter**: hard cap at 280 characters — enforce in prompt, check in frontend

## API Endpoints

| Method | Path | Purpose |
|---|---|---|
| POST | `/api/convert` | Convert content. Body: `{ content, platforms[], formality, boldness }` |
| GET | `/api/history` | Server-side history (not used by frontend — frontend uses localStorage) |
| DELETE | `/api/history/:id` | Delete a server-side record |
| POST | `/api/refine` | Refine one platform's output via chat |
| GET | `/api/healthz` | Health check |

## Important Gotchas

- `SiLinkedin` from `react-icons` is unavailable — use `Linkedin` from `lucide-react` instead
- API client is hand-maintained in `lib/api-client-react/src/generated/` (not auto-generated by orval for this project)
- Use `gpt-4o` (or the latest available model via Replit AI Integrations) with `max_completion_tokens: 8192`
- Never call service ports directly; always go through the shared proxy at `localhost:80`
- Use `@workspace/api-client-react` package root — never deep import paths

## File Map

```
artifacts/
  tone-converter/src/
    pages/Home.tsx                  — main page, orchestrates state
    components/PlatformCard.tsx     — output card + refinement chat
    components/HistorySidebar.tsx   — collapsible sidebar, local history
    hooks/use-local-history.ts      — localStorage history hook
    lib/platforms.ts                — platform definitions (id, name, icon, color)
  api-server/src/
    routes/convert/index.ts         — POST /api/convert + POST /api/refine
lib/
  db/src/schema/conversions.ts      — Drizzle schema
  api-client-react/src/generated/  — hand-maintained API client + types
  api-spec/openapi.yaml             — OpenAPI contract
```

## Sharing / Multi-user

Because history lives in localStorage, each user who opens the app sees only their own conversions — no login required, no history mixing. Trade-off: clearing browser data or switching devices loses history. Add Replit Auth + per-user DB rows if persistence across devices is needed.

