I Built a Free Article-to-Audio Converter!

від

у

Я створив безкоштовний конвертер статей у аудіо!

https://ift.tt/A4xb31k

Я створив безкоштовний конвертер статей у аудіо за вихідні

Мій список «прочитати пізніше» вийшов з-під контролю. Сотні статей, до яких я ніколи не дійду. Тож я створив Sornic — вставляєте будь-який URL статті, за секунди отримуєте аудіо.

Проблема

Я хотів наздогнати статті під час поїздок, готування або тренувань. Але:

Pocket/Instapaper просто заповнюються непрочитаним

Більшість TTS-додатків звучать роботоподібно

Розширення для браузера незручні

Я хотів щось надзвичайно просте: URL на вході — аудіо на виході.

Стек технологій

Next.js 14 (App Router)

OpenAI TTS API (натуральні голоси)

Vercel (хостинг та безсерверні функції)

Upstash Redis (обмеження швидкості запитів)

Tailwind CSS (стилізація)

Як це працює

1. Видобуток статті

Коли ви вставляєте URL, сервер завантажує сторінку та витягує вміст статті за допомогою бібліотеки Readability від Mozilla (та сама, яку Firefox використовує для Reader View).

const dom = new JSDOM(html, { url });
const reader = new Readability(dom.window.document);
const article = reader.parse();

Для сайтів із великим обсягом JavaScript, які не працюють з простим fetch, я використовую Firecrawl як резервний варіант.

2. Очищення контенту

Сирий витягнутий текст часто містить навігацію, оголошення, підказки «Підписатися зараз!» Я використовую Claude Haiku для очищення:

const response = await anthropic.messages.create({
model: ‘claude-haiku-4-20250514’,
messages: [{
role: ‘user’,
content: `Clean this article for text-to-speech.
Remove nav, ads, CTAs. Keep only the article body.
${rawText}`
}]
});

3. Перетворення тексту на мову

API OpenAI TTS має обмеження в 4096 символів, тому я розбиваю довгі статті на шматки:

function splitTextIntoChunks(text: string, maxLength: number): string[] {
// Розділяє на межах речень, коли це можливо
const sentenceMatch = remaining.slice(0, maxLength).match(/.*[.!?]\s/s);
// …
}

Потім генерую аудіо для кожного шматка та об’єдную його:

for (const chunk of chunks) {
const mp3Response = await openai.audio.speech.create({
model: ‘tts-1’,
voice: ‘nova’,
input: chunk,
speed: 1.0
});
audioBuffers.push(await mp3Response.arrayBuffer());
}

4. Обмеження швидкості

Безкоштовний тариф = 5 статей на день на IP. Використовую Upstash Redis:

const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.fixedWindow(5, ’24h’)
});

Проблеми

1. Тайм-аути Vercel

За замовчуванням — 10 секунд. Довгі статті можуть займати 30–60 секунд на обробку. Виправлено за допомогою:

// vercel.json
{
“functions”: {
“app/api/**/*.ts”: { “maxDuration”: 60 }
}
}

2. Конфлікти між ESM та CommonJS

jsdom v27 зламався на Vercel через проблеми з ESM. Перейшли на версію v24:

npm install jsdom@24.1.3

3. Сайти, що блокує скрапінг

Деякі сайти блокують запити з сервера. Firecrawl обробляє ці випадки як резервний варіант — він використовує безголовні браузери та обходить анти-бот-механізми.

Витрати

За статтю (~2000 слів):

OpenAI TTS: приблизно $0.03

Очищення Claude Haiku: приблизно $0.001

Vercel/Upstash: безкоштовний тариф

За 5 безкоштовних статей на користувача на день витрати залишаються помірними завдяки обмеженню швидкості.

Що далі

Завантаження як MP3

Розширення для браузера

Функція плейліста/черги

Преміум-ракурс із більшою кількістю статей

Спробуйте

sornic.com — реєстрація не потрібна.

Вставте URL, оберіть голос, натисніть відтворити. Було б чудово отримати відгуки щодо того, які функції зроблять це більш корисним.

Теги: webdev, nextjs, openai, javascript

HI-FI News

через DEV Community https://dev.to

23 січня 2026 о 06:51

January 23, 2026 at 06:51AM


Коментарі

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *