Files
admin 46af290db3
Build and Push Docker Images / build-and-push (push) Failing after 3m33s
initial commit
2026-11-07 16:39:43 +03:00

259 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
### 📄 Файл: `TASKS.md` (Этап 1: Полный разбор)
```markdown
# Задачи проекта Writer IDE
## 🟢 Этап 1: Фундамент, Layout и Базовый Редактор
### Задача 1.1: Инициализация Frontend и установка зависимостей
**Описание**: Создание базового Next.js приложения и установка всех необходимых библиотек для Этапа 1.
**Критерии успеха**:
- Команда `npm run dev` в папке `frontend` запускает приложение на `localhost:3000`.
- Tailwind CSS работает (проверка через класс `bg-red-500`).
**Инструкция для AI-агента**:
> "Инициализируй Next.js проект в текущей папке с TypeScript, Tailwind, App Router и src-директорией. Затем установи следующие зависимости: `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-text-style`, `@tiptap/extension-color`, `@tiptap/extension-blockquote`, `@tiptap/extension-underline`, `zustand`, `lucide-react`, `axios`. Убедись, что `tailwind.config.ts` настроен корректно."
---
### Задача 1.2: Настройка Zustand Store (Состояние приложения)
**Описание**: Создание глобального хранилища для управления активным документом, его содержимым и состоянием боковых панелей.
**Критерии успеха**:
- Создан файл `frontend/src/stores/appStore.ts`.
- Store содержит: `activeDocumentId`, `documents` (массив объектов с id, title, content), функции `setActiveDocument`, `updateDocumentContent`.
**Инструкция для AI-агента**:
> "Создай Zustand store в `src/stores/appStore.ts`. Определи интерфейс `Document` (id: string, title: string, content: string, type: 'scene' | 'chapter'). Добавь состояния для списка документов и активного документа, а также экшены для их обновления. Инициализируй store одним тестовым документом."
---
### Задача 1.3: Архитектура Layout (Трехколоночный интерфейс)
**Описание**: Создание основного макета приложения `src/app/layout.tsx` и `src/app/page.tsx` с тремя колонками.
**Критерии успеха**:
- Левая колонка (w-64): Заглушка компонента `FileExplorer`.
- Средняя колонка (w-72): Заглушка компонента `StoryExplorer`.
- Правая колонка (flex-1): Область для редактора.
- Используется CSS Grid или Flexbox. Адаптивность: на экранах < 1024px боковые панели скрываются (или сжимаются).
**Инструкция для AI-агента**:
> "Создай компоненты-заглушки `FileExplorer.tsx` и `StoryExplorer.tsx` в `src/components/sidebar/`. Реализуй основной Layout в `src/app/page.tsx`, используя Flexbox или Grid для создания трех колонок с фиксированной шириной для сайдбаров и `flex-1` для центральной области. Примени темную/светлую тему через Tailwind."
---
### Задача 1.4: Ядро Tiptap Редактора
**Описание**: Создание переиспользуемого компонента редактора с поддержкой базового форматирования.
**Критерии успеха**:
- Компонент `src/components/editor/Editor.tsx` инициализирует `useEditor` с расширениями: `StarterKit`, `TextStyle`, `Color`, `Underline`, `Blockquote`.
- Редактор привязан к Zustand store (загружает `content` активного документа и сохраняет изменения через `onUpdate`).
**Инструкция для AI-агента**:
> "Создай компонент `Editor.tsx`. Используй `@tiptap/react`. Подключи расширения: StarterKit, TextStyle, Color, Underline, Blockquote. Настрой `onUpdate`, чтобы при изменении текста вызывался экшен `updateDocumentContent` из `appStore`. Оберни редактор в div с классами для красивого отображения (max-w-3xl, mx-auto, prose)."
---
### Задача 1.5: Панель инструментов (Toolbar) для форматирования
**Описание**: Создание плавающей или верхней панели инструментов для управления стилями текста.
**Критерии успеха**:
- Компонент `src/components/editor/Toolbar.tsx`.
- Кнопки для: Bold, Italic, Underline, Blockquote, выбор цвета текста (используй стандартный `<input type="color">` для простоты).
- Кнопки используют `editor.chain().focus().toggleBold().run()` и аналоги.
**Инструкция для AI-агента**:
> "Создай компонент `Toolbar.tsx`, который принимает экземпляр `editor` из Tiptap как пропс. Реализуй кнопки форматирования с использованием Lucide React иконок. Добавь простую логику подсветки активной кнопки (через `editor.isActive('bold')`). Размести этот Toolbar над компонентом Editor."
---
### Задача 1.6: Инициализация Backend (FastAPI)
**Описание**: Базовая настройка Python-сервера для обслуживания frontend и подготовки к работе с файлами.
**Критерии успеха**:
- Файл `backend/main.py` запускается через `uvicorn main:app --reload`.
- Настроен CORS middleware, разрешающий запросы с `http://localhost:3000`.
- Эндпоинт `GET /api/health` возвращает `{"status": "ok"}`.
**Инструкция для AI-агента**:
> "Создай базовое приложение FastAPI в `backend/main.py`. Добавь `CORSMiddleware` с разрешенными источниками `http://localhost:3000`. Создай простой роутер `/api/health`. Напиши инструкцию по запуску (создание venv, `pip install fastapi uvicorn pydantic`, запуск)."
---
### Задача 1.7: Интеграция Frontend и Backend (Сохранение/Загрузка)
**Описание**: Связывание Zustand store с Backend для имитации сохранения данных (пока в памяти или простом JSON).
**Критерии успеха**:
- При изменении текста в редакторе, через debounced-запрос (или по кнопке "Сохранить") данные отправляются на backend.
- При загрузке страницы frontend запрашивает список документов и контент активного документа с backend.
**Инструкция для AI-агента**:
> "Создай в `backend` простой in-memory список документов (или запись в `data.json`). Добавь эндпоинты `GET /api/documents` и `POST /api/documents/{id}/content`. В `frontend/src/lib/api.ts` создай типизированные функции для этих запросов. Обнови `appStore`, чтобы он загружал данные при инициализации."
---
## 🟡 Этап 2: AI Интеграция и Inline-действия
### Задача 2.1: Backend AI сервис (базовый роутер для LLM)
**Описание**: Создание сервиса на backend для работы с AI-моделями (Ollama локально и OpenRouter API).
**Критерии успеха**:
- Создан файл `backend/services/llm_router.py`
- Сервис поддерживает два провайдера: `ollama` и `openrouter`
- Эндпоинт `POST /api/ai/generate` принимает промпт и возвращает сгенерированный текст
- Поддержка выбора модели через параметр запроса
**Инструкция для AI-агента**:
> "Создай сервис `backend/services/llm_router.py` с классом `LLMRouter`. Реализуй методы:
> - `generate_ollama(prompt, model)` — вызов локальной Ollama через `http://localhost:11434/api/generate`
> - `generate_openrouter(prompt, model, api_key)` — вызов OpenRouter API
> - `generate(prompt, provider, model, **kwargs)` — универсальный метод, который маршрутизирует запрос
> Создай эндпоинт `POST /api/ai/generate` в `backend/routers/ai.py`, который принимает JSON: `{prompt, provider, model, options}` и возвращает `{generated_text}`. Используй `httpx` для async HTTP запросов. Добавь `httpx` в requirements.txt."
---
### Задача 2.2: Система пресетов для генерации
**Описание**: Реализация пресетов параметров генерации (Creative Draft, Editor, Brainstorm) на backend.
**Критерии успеха**:
- Создан файл `backend/services/presets.py`
- Определены три пресета с разными параметрами (temperature, top_p, frequency_penalty, presence_penalty)
- Эндпоинт `/api/ai/generate` принимает параметр `preset` и применяет соответствующие настройки
**Инструкция для AI-агента**:
> "Создай `backend/services/presets.py` с тремя пресетами:
> - `CREATIVE_DRAFT`: temperature=0.85, top_p=0.92, frequency_penalty=0.3, presence_penalty=0.4
> - `EDITOR`: temperature=0.3, top_p=0.85, frequency_penalty=0.0, presence_penalty=0.0
> - `BRAINSTORM`: temperature=1.0, top_p=0.95, frequency_penalty=0.5, presence_penalty=0.6
> Обнови `llm_router.py`, чтобы метод `generate` принимал параметр `preset` и применял соответствующие параметры к запросу. Обнови эндпоинт `/api/ai/generate` для поддержки пресетов."
---
### Задача 2.3: Frontend API клиент для AI
**Описание**: Создание типизированного API клиента на frontend для работы с AI эндпоинтами.
**Критерии успеха**:
- Создан файл `frontend/src/lib/ai-api.ts`
- Функция `generateText(prompt, provider, model, preset)` возвращает сгенерированный текст
- Все типы типизированы (никаких `any`)
**Инструкция для AI-агента**:
> "Создай `frontend/src/lib/ai-api.ts` с типами:
> ```typescript
> interface GenerateRequest {
> prompt: string;
> provider: 'ollama' | 'openrouter';
> model: string;
> preset: 'creative_draft' | 'editor' | 'brainstorm';
> options?: Record<string, any>;
> }
> interface GenerateResponse {
> generated_text: string;
> }
> ```
> Реализуй функцию `generateText(request: GenerateRequest): Promise<string>`, которая вызывает `POST /api/ai/generate` и возвращает `generated_text`. Используй axios из `lib/api.ts`."
---
### Задача 2.4: Inline AI меню в редакторе (UI)
**Описание**: Создание всплывающего меню при выделении текста в редакторе для выбора AI действий.
**Критерии успеха**:
- Создан компонент `frontend/src/components/editor/AIMenu.tsx`
- При выделении текста появляется кнопка "✨ AI"
- При клике на кнопку открывается меню с действиями: "Переписать", "Расширить", "Упростить", "Свой промпт"
**Инструкция для AI-агента**:
> "Создай компонент `AIMenu.tsx`, который использует Tiptap BubbleMenu или FloatingMenu. При выделении текста показывай кнопку с иконкой `Sparkles` из lucide-react. При клике на кнопку открывай dropdown с пунктами: 'Переписать', 'Расширить', 'Упростить', 'Свой промпт...'. Каждый пункт при клике вызывает callback `onAction(action: string, selectedText: string)`. Стилизуй меню в темной теме (bg-gray-800, border-gray-700)."
---
### Задача 2.5: Diff view для предпросмотра AI изменений
**Описание**: Создание компонента для визуального сравнения оригинального текста и AI-предложения.
**Критерии успеха**:
- Создан компонент `frontend/src/components/editor/AIDiffView.tsx`
- Компонент показывает оригинальный текст слева и AI-текст справа
- Есть кнопки "Принять" и "Отклонить"
- Использует библиотеку для сравнения текста (например, `diff` или простую визуализацию)
**Инструкция для AI-агента**:
> "Создай компонент `AIDiffView.tsx`, который принимает пропсы: `originalText: string`, `aiText: string`, `onAccept: () => void`, `onReject: () => void`. Отображай два блока текста (можно просто два div рядом или друг под другом). Добавь кнопки '✅ Принять' и '❌ Отклонить' вверху. Стилизуй: оригинальный текст с красноватым фоном (bg-red-900/20), AI текст с зеленоватым (bg-green-900/20). Кнопки: Accept — bg-green-600, Reject — bg-red-600."
---
### Задача 2.6: Интеграция AI действий с редактором
**Описание**: Связывание AIMenu, AIDiffView и API клиента для полноценной работы AI-редактирования.
**Критерии успеха**:
- При выборе действия в AIMenu вызывается API с соответствующим промптом
- Пока идет генерация, показывается спиннер
- После получения ответа открывается AIDiffView
- При нажатии "Принять" выделенный текст заменяется на AI-текст
- При нажатии "Отклонить" возвращается оригинальный текст
**Инструкция для AI-агента**:
> "Интегрируй AIMenu и AIDiffView в Editor.tsx:
> 1. Добавь состояние: `selectedText`, `aiGeneratedText`, `showDiffView`, `isLoading`
> 2. При выборе действия в AIMenu:
> - Сохрани `selectedText` из `editor.state.doc.textBetween(selection.from, selection.to)`
> - Сформируй промпт в зависимости от действия (например, для 'Переписать': 'Перепиши этот текст, сделай его более живым и кинематографичным: [selectedText]')
> - Вызови `generateText` из `ai-api.ts` с пресетом `creative_draft`
> - Установи `aiGeneratedText` и `showDiffView = true`
> 3. В AIDiffView:
> - `onAccept`: замени выделенный текст через `editor.chain().focus().deleteRange(selection).insertContent(aiGeneratedText).run()`
> - `onReject`: закрой diff view, ничего не меняй
> 4. Покажи спиннер (из lucide-react: `Loader2` с анимацией `animate-spin`), пока `isLoading = true`"
---
## 🟠 Этап 3: Контекст и Story Bible
### Задача 3.1: Backend модель и API для Story Bible
**Описание**: Создание структуры данных для Story Bible (персонажи, локации, события) и API для работы с ней.
**Критерии успеха**:
- Созданы Pydantic модели для сущностей (Character, Location, Event, StoryThread)
- Создан эндпоинт `GET /api/projects/{id}/bible` для получения Story Bible
- Создан эндпоинт `PUT /api/projects/{id}/bible` для обновления Story Bible
- Данные хранятся в JSON файле на диске (локально)
**Рекомендуемая модель**: `qwen/qwen-2.5-coder-7b-instruct` (простая CRUD задача)
**Инструкция для AI-агента**:
> "Создай Pydantic модели в `backend/models/bible.py` для сущностей: Character (id, name, description, traits, appearance), Location (id, name, description, atmosphere), Event (id, title, description, chapter), StoryThread (id, title, description, status). Создай модель StoryBible, которая содержит списки этих сущностей. Создай роутер `backend/routers/bible.py` с эндпоинтами для получения и обновления Story Bible. Данные храни в файле `data/story_bible.json`. Добавь функцию инициализации с примером данных."
---
### Задача 3.2: Frontend UI для Story Bible (панель)
**Описание**: Создание панели для просмотра и редактирования Story Bible.
**Критерии успеха**:
- Создан компонент `StoryBiblePanel.tsx` с вкладками: Персонажи, Локации, События, Сюжетные нити
- Каждая вкладка показывает список сущностей с возможностью редактирования
- Есть кнопки "Добавить" и "Удалить" для каждой сущности
- Панель интегрирована в layout (заменяет или дополняет StoryExplorer)
**Рекомендуемая модель**: `qwen/qwen-2.5-coder-7b-instruct` (UI компонент)
**Инструкция для AI-агента**:
> "Создай компонент `src/components/sidebar/StoryBiblePanel.tsx` с вкладками для персонажей, локаций, событий и сюжетных нитей. Каждая вкладка показывает список карточек сущностей. Карточка содержит название, краткое описание и кнопки редактирования/удаления. Добавь модальное окно для создания/редактирования сущности с полями, соответствующими модели. Интегрируй панель в layout, заменив заглушку StoryExplorer. Используй Zustand store для управления состоянием."
---
### Задача 3.3: Настройки выбора моделей для разных задач
**Описание**: Создание UI и backend логики для выбора моделей под разные задачи (генерация, фоновая обработка, анализ).
**Критерии успеха**:
- Создан компонент `ModelSettings.tsx` с выбором моделей для:
- Генерации текста (основная модель)
- Фоновой обработки (извлечение сущностей)
- Анализа текста (проверка логики)
- Настройки сохраняются в localStorage или backend
- При генерации используются выбранные модели
**Рекомендуемая модель**: `qwen/qwen-2.5-coder-7b-instruct` (UI + интеграция)
**Инструкция для AI-агента**:
> "Создай компонент `src/components/settings/ModelSettings.tsx` с dropdown для выбора моделей для разных задач: 'Основная модель для генерации', 'Модель для фоновой обработки', 'Модель для анализа'. Загружай список доступных моделей через `getAvailableModels()` из `ai-api.ts`. Сохраняй настройки в Zustand store. Обнови `ai-api.ts`, чтобы функция `generateText` принимала параметр `task_type` и использовала соответствующую модель из настроек."
---
### Задача 3.4: Фоновый агент для извлечения сущностей
**Описание**: Создание сервиса для автоматического извлечения персонажей, локаций и событий из текста главы.
**Критерии успеха**:
- Создан сервис `backend/services/entity_extractor.py`
- Сервис принимает текст главы и возвращает JSON с извлеченными сущностями
- Использует промпт для структурированного вывода (JSON mode)
- Интегрирован с Story Bible (обновляет или добавляет новые сущности)
**Рекомендуемая модель**: `qwen/qwen-2.5-coder-32b-instruct` (сложный промпт-инжиниринг)
**Инструкция для AI-агента**:
> "Создай сервис `backend/services/entity_extractor.py` с функцией `extract_entities(text, existing_bible)`. Функция формирует промпт для LLM, который извлекает из текста новых персонажей, локации и события в формате JSON. Промпт должен включать примеры формата вывода и инструкцию не дублировать существующие сущности из `existing_bible`. Используй модель для фоновой обработки из настроек. Пресет: `editor` (низкая температура для точности)."
---
### Задача 3.5: Автоматическое обновление Story Bible при сохранении
**Описание**: Интеграция извлечения сущностей с процессом сохранения главы.
**Критерии успеха**:
- При сохранении главы (автосохранение) вызывается фоновый агент
- Агент анализирует текст и обновляет Story Bible
- Пользователь видит уведомление "Story Bible обновлена"
- Есть возможность отключить автоматическое обновление в настройках
**Рекомендуемая модель**: `qwen/qwen-2.5-coder-32b-instruct` (интеграция)
**Инструкция для AI-агента**:
> "Обнови `Editor.tsx`, чтобы при автосохранении (после debounce) отправлял запрос на backend для извлечения сущностей. Создай эндпоинт `POST /api/ai/extract-entities` в `backend/routers/ai.py`, который принимает текст главы и текущую Story Bible, вызывает `entity_extractor`, и возвращает обновленную Bible. На frontend добавь переключатель 'Автоматически обновлять Story Bible' в настройках. Показывай уведомление (toast) при успешном обновлении."
---
## 🔴 Этап 4: Экспорт и полировка
*(Будет активирован после успешного завершения Этапа 3)*