- PVSM.RU - https://www.pvsm.ru -
Наступил 2026 год, и у меня были новогодние праздники для создания международного стартапа - единорога 🦄.
Я поставил себе цель - заработать миллиард денег, поэтому проект должен быть международный (мультиязычный), чтобы увеличить трафик.
А чтобы успеть за две недели, я решил использовать vibe-кодинг, а то потом ещё к ЕГЭ по математике готовится.
Для написания кода я использую cursor.com [1] версию pro - стоимость 20 $(есть российские бесплатные аналоги - sourcecraft [2] и gigacode [3]). Сразу скажу что в cursor есть лимит токенов, и за пару неполных недель я сжёг 3 учётки на проект.
Советую настроить User Rules Oper Settings(Ctrl+Shift+J)->Rules and Commands и задать User Roles.
Каталог анимированных стикер-паков из мессенджеров https://ai-stickers.ru [4]
Телеграмм канал [5] с автопостингом
Анимированные ai-виджеты [6]на основе анимированных картинок с ролью и эмоциями
Телеграмм бот - с анимированным персонажем, например Дед мороз [7]
Картинки легко скачать из телеграмм, пример скрипта
#!/usr/bin/env python3
"""Скачивание стикеров из Telegram: python script.py pack_name bot_token"""
import sys, requests
from pathlib import Path
pack_name, bot_token = sys.argv[1], sys.argv[2]
Path(pack_name).mkdir(exist_ok=True)
api = f"https://api.telegram.org/bot{bot_token}/getStickerSet"
stickers = requests.get(api, params={"name": pack_name}).json()['result']['stickers']
for i, s in enumerate(stickers, 1):
file_path = requests.get(f"https://api.telegram.org/bot{bot_token}/getFile", params={"file_id": s['file_id']}).json()['result']['file_path']
file_url = f"https://api.telegram.org/file/bot{bot_token}/{file_path}"
Path(pack_name, f"{i:03d}{Path(file_path).suffix}").write_bytes(requests.get(file_url).content)
print(f"✅ {i}/{len(stickers)}")
Выбрал 50 языков для максимального охвата. Для удобства сделал API https://ai-stickers.ru/api/languages [8], который возвращает список видимых языков для фронтенда.
Перевод статики организован через JSON-файлы в папке locality: для каждого языка свой файл (например, ru.json [9], en.json [10], zh-CN.json [11]). Базовый файл — ru.json [9] с иерархической структурой (страницы, мета-теги, сообщения, кнопки). Скрипт на Python автоматически переводит ru.json на все языки через Google Translate API, сохраняя структуру и создавая файлы для всех языков.
#Пример кода перевода
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import os
import time
import requests
from googletrans import Translator
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
def translate_json(obj, dest_lang, src_lang='ru'):
if isinstance(obj, dict):
return {k: translate_json(v, dest_lang, src_lang) for k, v in obj.items()}
elif isinstance(obj, list):
return [translate_json(item, dest_lang, src_lang) for item in obj]
elif isinstance(obj, str) and obj.strip():
try:
result = Translator().translate(obj, dest=dest_lang, src=src_lang)
time.sleep(0.1)
return result.text
except:
return obj
return obj
# Загружаем ru.json
with open(os.path.join(SCRIPT_DIR, 'ru.json'), 'r', encoding='utf-8') as f:
ru_data = json.load(f)
# Получаем языки из API
languages = [lang['code'] for lang in requests.get('https://ai-stickers.ru/api/languages').json()['languages'] if lang['code'] != 'ru']
# Переводим и сохраняем
for lang_code in languages:
translated = translate_json(ru_data, lang_code)
with open(os.path.join(SCRIPT_DIR, f'{lang_code}.json'), 'w', encoding='utf-8') as f:
json.dump(translated, f, ensure_ascii=False, indent=2)
print(f"✓ {lang_code}.json")
Автоматическое определение языка реализовано в middleware i18n.py. При каждом запросе система проверяет наличие языка в URL (например, /ru/search или /en/pack/123). Если язык отсутствует, используется приоритет: язык из сессии → язык по домену → язык из заголовка Accept-Language → дефолтный язык из переменной окружения. После определения выполняется редирект на URL с языковым префиксом, язык сохраняется в сессии и доступен через g.current_language во всех обработчиках.
Для SEO используются hreflang-теги. На каждой странице генерируются альтернативные ссылки для всех языков, указывающие на соответствующие версии. В sitemap [12]каждая запись содержит полный набор hreflang-тегов для всех языков, что помогает поисковикам индексировать все языковые версии.
Без автотестов в VIBE-кодить нельзя, иначе это будет боль и слезы, всё будет ломаться постоянно. В этом проекте я выстроил систему автотестов, которая работает как страховка от регрессий и позволяет уверенно рефакторить код.
Все тесты наследуются от базового класса, который содержит общую логику настройки Flask-приложения и вспомогательные методы для проверки JSON-ответов API.
Автоматический запуск тестов при старте приложения в режиме разработки — ключевая фича. Тесты запускаются в фоновом потоке через 5 секунд после старта сервера, не блокируя основной процесс. Это позволяет сразу обнаруживать проблемы до деплоя.
Отдельный класс проверяет скорость работы критичных эндпоинтов, используемых в React-компонентах. Это критично для UX: если после рефакторинга API стал работать медленнее, тесты сразу это покажут. Множественные запросы (симуляция загрузки страницы) должны выполняться не более чем за 3 секунды.
Сперва я начал писать проект на ванильном js, но когда устал исправлять бесконечные ошибки JS верстки - перешёл на React+Typescript.
Для бэкенда я использую Flask+Flasgger
Для AI-агентов фреймворк CrewAI.
Без контроля версий нельзя vibe-кодить(даже самым маленьким), так как что-нибудь обязательно сломается и вам нужно будет вернуть предыдущую версию.
Быстро я понял, что на большом проекте llm теряется из-за обилия контекста.
Сперва я делил на модули и на папке, но в конечном счете перешёл на микро-сервисы по отдельным частям разработки. Здесь как раз и пригодился swagger(Flasgger).
Cursor прекрасно умеет создавать файлы openapi(swagger.yaml), при запуске приложения читает файл swagger.yaml с описанием всех API-эндпоинтов (что принимают, что возвращают, примеры) и автоматически создает интерактивную документацию по адресу /api-docs, где можно посмотреть все методы и протестировать их прямо в браузере.
Ссылку на документацию /api-docs достаточно скормить новому микро-сервису, чтобы он мог написать логику на её основе.


AI агенты - выполняют задачи, рассуждают и принимают решения. В проекте используется фреймворк CrewAI, который позволяет создавать команды из нескольких агентов с разными ролями: аналитик запросов, консультант-помощник, технический специалист и редактор ответов.
Агенты работают совместно по иерархической модели: аналитик распределяет задачи, специалисты обрабатывают запросы, редактор проверяет и улучшает финальный ответ. Система поддерживает streaming процесс рассуждения в реальном времени через Server-Sent Events. В качестве LLM используется DeepSeek API, что делает решение более доступным по сравнению с OpenAI. Каждый агент имеет свою роль, цель и backstory, что позволяет создавать специализированных виртуальных сотрудников для решения конкретных задач.
from crewai import Agent, Crew, Task, LLM
from crewai import Process
# Создаем LLM для агентов
llm = LLM(
model="deepseek-chat",
api_key="your-api-key",
base_url="https://api.deepseek.com/v1"
)
# Создаем агента-консультанта
consultant = Agent(
role='Консультант',
goal='Отвечать на вопросы пользователей',
backstory='Ты опытный консультант с широкими знаниями',
llm=llm,
verbose=True
)
# Создаем задачу для агента
task = Task(
description='Пользователь спрашивает: "Что такое машинное обучение?"',
expected_output='Краткий и понятный ответ на вопрос',
agent=consultant
)
# Создаем команду и выполняем задачу
crew = Crew(
agents=[consultant],
tasks=[task],
process=Process.sequential
)
result = crew.kickoff()
print(result)
Статическая sitemap [13] с автоматическим обновлением через скрипт, для высокой производительности (без нагрузки на БД) и кэширование на CDN.
Структура: разбит на файлы, по типам контента, с учетом лимитов(максимум 50,000 URL и 50 МБ на файл, учитывая размер hreflang тегов).
Интеграция: добавлен в Яндекс Вебмастер и Google Search Console.
Собрана база ключевых фраз через Яндекс Вордстат (несколько тысяч запросов с частотностью). Распределение по разметке:
Title и Meta Description — уникальные для каждой страницы с релевантными ключевыми словами.
Hreflang — в HTML и sitemap XML для правильной индексации мультиязычных версий.
Canonical URL — на каждой странице для предотвращения дублей.
Robots.txt — динамический, блокирует /api/, /debug/, /admin/, указывает sitemap, специфичные правила для разных ботов.
Для международного домена перевел DNS на Cloudflare и настроил кэширование.
Автор: garbuzenko
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/startap/441691
Ссылки в тексте:
[1] cursor.com: http://cursor.com
[2] sourcecraft: https://sourcecraft.dev/portal/docs/ru/code-assistant/
[3] gigacode: https://gitverse.ru/features/gigacode/
[4] https://ai-stickers.ru: https://ai-stickers.ru/ru/search
[5] Телеграмм канал: https://t.me/AI_STICKERS_RU
[6] Анимированные ai-виджеты : https://hero.ai-stickers.ru/
[7] Дед мороз: https://t.me/AI_STICKERS_RU_BOT?start=stickerPackId=461_language=ru
[8] https://ai-stickers.ru/api/languages: https://ai-stickers.ru/api/languages
[9] ru.json: https://ai-stickers.ru/locality/ru.json
[10] en.json: https://ai-stickers.ru/locality/en.json
[11] zh-CN.json: https://ai-stickers.ru/locality/zh-CN.json
[12] sitemap : https://ai-stickers.ru/sitemap-static.xml
[13] sitemap: https://ai-stickers.ru/sitemap.xml
[14] Источник: https://habr.com/ru/articles/984622/?utm_source=habrahabr&utm_medium=rss&utm_campaign=984622
Нажмите здесь для печати.