feat: Revamp README with detailed project information and add initial design system documentation.
This commit is contained in:
1 parent
7303d568f4
commit
6ec3445fc7
6 files changed
+2587
-384
No files matched your search
@@ -1,50 +1,79 @@
|
|||||||
# Welcome to your Expo app 👋
|
# Local AI Companion
|
||||||
|
|
||||||
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
|
   
|
||||||
|
|
||||||
## Get started
|
> A fully local, privacy-first AI companion app built with React Native and Expo. Your data never leaves your device.
|
||||||
|
|
||||||
1. Install dependencies
|
This application connects directly to your own local AI models, completely offline. Currently in alpha, it pairs flawlessly with the [LMStudio](https://lmstudio.ai) local inference API. We developed and tested it against **Qwen3.5 (without thinking)** to guarantee a smooth, zero-latency experience.
|
||||||
|
|
||||||
```bash
|
*Roadmap: Future updates will introduce direct in-app model downloads and support for external APIs.*
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Start the app
|
---
|
||||||
|
|
||||||
```bash
|
## Features
|
||||||
npx expo start
|
|
||||||
```
|
|
||||||
|
|
||||||
In the output, you'll find options to open the app in a
|
- **100% Offline Inference:** Complete privacy. Zero cloud dependency.
|
||||||
|
- **Plug & Play LMStudio:** Instantly detects and fetches active models from your local server.
|
||||||
|
- **Persistent Sessions:** Chat histories and settings are saved locally using Zustand and `AsyncStorage`.
|
||||||
|
- **Developer-Friendly UI:** Real-time markdown rendering with syntax highlighting and 1-click code copying.
|
||||||
|
- **Minimalist Dark Mode:** High-contrast, distraction-free interface built on NativeWind principles.
|
||||||
|
|
||||||
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
---
|
||||||
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
|
||||||
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
|
||||||
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
|
||||||
|
|
||||||
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
## Quick Start
|
||||||
|
|
||||||
## Get a fresh project
|
To run this application, you will need both the frontend development environment and a local AI engine running.
|
||||||
|
|
||||||
When you're ready, run:
|
### 1. Model Server (LMStudio)
|
||||||
|
|
||||||
|
1. Extract and open [LMStudio](https://lmstudio.ai/).
|
||||||
|
2. Download a compatible model (e.g., Llama 3, Qwen2.5, Mistral).
|
||||||
|
3. Open the **Local Server** tab (`<->`).
|
||||||
|
4. Enable **CORS** and set the port (default: `1234`).
|
||||||
|
5. Click **Start Server**.
|
||||||
|
|
||||||
|
> **Note:** If testing on a physical mobile device, locate your machine's local IPv4 address (e.g., `192.168.1.X`).
|
||||||
|
|
||||||
|
### 2. Mobile Client (App)
|
||||||
|
|
||||||
|
Ensure you have [Node.js](https://nodejs.org/) (v18+) and the [Expo Go](https://expo.dev/go) app installed.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run reset-project
|
git clone https://github.com/evandrodevbr/LocalAiApp.git
|
||||||
|
cd LocalAiApp
|
||||||
|
npm install
|
||||||
|
npx expo start
|
||||||
```
|
```
|
||||||
|
|
||||||
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
|
Scan the QR code with Expo Go, or type `i`/`a` to launch a simulator.
|
||||||
|
|
||||||
## Learn more
|
### 3. Connection
|
||||||
|
|
||||||
To learn more about developing your project with Expo, look at the following resources:
|
1. Open the app and tap the **Settings** icon.
|
||||||
|
2. Enter your LMStudio server IP and Port (e.g., `192.168.1.X:1234`).
|
||||||
|
3. Tap **Test Connection**.
|
||||||
|
|
||||||
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
|
Once connected, your available models will load automatically.
|
||||||
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
|
|
||||||
|
|
||||||
## Join the community
|
---
|
||||||
|
|
||||||
Join our community of developers creating universal apps.
|
## Bug Reports & Contributing
|
||||||
|
|
||||||
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
|
Found an issue or have a suggestion? We welcome community involvement!
|
||||||
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
|
|
||||||
|
👉 **[Report an Issue or Request a Feature](https://github.com/evandrodevbr/LocalAiApp/issues)**
|
||||||
|
|
||||||
|
When creating an issue, please include:
|
||||||
|
|
||||||
|
- A clear description of the bug.
|
||||||
|
- Steps to reproduce.
|
||||||
|
- Relevant screenshots or environment details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
Thank you for exploring this project! Our mission is to share knowledge and foster an open-source collaborative ecosystem around offline AI solutions. All feedback, testing, and code contributions are highly appreciated.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
File renamed without changes.
@@ -1,168 +0,0 @@
|
|||||||
# PLAN: Chat UX Improvements + Streaming Fix
|
|
||||||
|
|
||||||
> 🤖 **Agentes:** `@frontend-specialist` + `@mobile-developer`
|
|
||||||
> **Data:** 2026-03-04
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Bug Crítico: ReadableStream not supported
|
|
||||||
|
|
||||||
**Causa raiz:** O `fetch` nativo do React Native (Hermes) não suporta `response.body.getReader()`. A implementação atual usa a Web Streams API que só funciona em navegadores.
|
|
||||||
|
|
||||||
**Solução:** Usar o pacote `react-native-sse` — cliente SSE leve feito para React Native, que usa `XMLHttpRequest` internamente (sem polyfills pesados).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm add react-native-sse
|
|
||||||
```
|
|
||||||
|
|
||||||
Reescrever `chatCompletionStream()` em `services/lmStudioApi.ts` para usar `EventSource` do `react-native-sse` no mobile e manter `ReadableStream` no web via `Platform.OS`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧠 Brainstorm: Rendering de Markdown
|
|
||||||
|
|
||||||
### Contexto
|
|
||||||
Respostas de LLMs vêm em Markdown (code blocks, bold, listas, etc). Atualmente renderizamos como `<Text>` puro.
|
|
||||||
|
|
||||||
### Option A: `react-native-markdown-display`
|
|
||||||
- ✅ Leve, customizável por StyleSheet, suporta code blocks
|
|
||||||
- ❌ Manutenção irregular
|
|
||||||
- 📊 **Effort:** Low
|
|
||||||
|
|
||||||
### Option B: `@ronradtke/react-native-markdown-display` (fork mantido)
|
|
||||||
- ✅ Fork ativo e mantido, API idêntica, melhor suporte Expo
|
|
||||||
- ✅ Customização completa de estilos
|
|
||||||
- ❌ Sem syntax highlighting nativo (adicionável)
|
|
||||||
- 📊 **Effort:** Low
|
|
||||||
|
|
||||||
### Option C: Custom parser com regex
|
|
||||||
- ✅ Zero dependências, 100% controle
|
|
||||||
- ❌ Muito trabalho, bugs com edge cases
|
|
||||||
- 📊 **Effort:** High
|
|
||||||
|
|
||||||
### 💡 Recomendação
|
|
||||||
**Option B** (`@ronradtke/react-native-markdown-display`) — fork mantido, baixo esforço e cobre 95% dos casos.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Plano de Implementação
|
|
||||||
|
|
||||||
### Fase 1: Bug Fix — Streaming (Prioridade Máxima)
|
|
||||||
|
|
||||||
#### [MODIFY] `services/lmStudioApi.ts`
|
|
||||||
- Instalar `react-native-sse`
|
|
||||||
- Reescrever `chatCompletionStream()` com dual strategy:
|
|
||||||
- **Web:** Manter `ReadableStream` (funciona nativamente)
|
|
||||||
- **Native (iOS/Android):** Usar SSE via `react-native-sse`
|
|
||||||
- Handling robusto de erros e abort
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Fase 2: Markdown Rendering
|
|
||||||
|
|
||||||
#### [ADD] Dependência
|
|
||||||
```bash
|
|
||||||
pnpm add @ronradtke/react-native-markdown-display
|
|
||||||
```
|
|
||||||
|
|
||||||
#### [MODIFY] `components/chat/MessageBubble.tsx`
|
|
||||||
- Substituir `<Text>` por `<Markdown>` nas mensagens do assistant
|
|
||||||
- Manter `<Text>` para mensagens do user (são texto simples)
|
|
||||||
- Estilizar code blocks com fundo escuro, fonte mono
|
|
||||||
- Estilizar bold, italic, listas, links
|
|
||||||
- Suporte a inline code com badge de destaque
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Fase 3: Message Actions (Copy, Edit, Resend)
|
|
||||||
|
|
||||||
#### [MODIFY] `components/chat/MessageBubble.tsx`
|
|
||||||
- Adicionar toolbar de ações abaixo de cada mensagem (aparece via long-press ou sempre visível para assistant)
|
|
||||||
- **Actions do Assistant:**
|
|
||||||
- 📋 Copy — copia conteúdo para clipboard (`Clipboard.setStringAsync`)
|
|
||||||
- 🔄 Regenerate — reenvia a última mensagem do user
|
|
||||||
- **Actions do User:**
|
|
||||||
- 📋 Copy — copia conteúdo
|
|
||||||
- ✏️ Edit — abre o texto no input para edição + reenvio
|
|
||||||
- 🗑️ Delete — remove mensagem
|
|
||||||
|
|
||||||
#### [MODIFY] `store/useAppStore.ts`
|
|
||||||
- Adicionar `deleteMessage(id)`
|
|
||||||
- Adicionar `editMessage(id, content)` — edita e reprocess
|
|
||||||
- Adicionar `regenerateLastResponse()` — remove última resposta + reenvia
|
|
||||||
|
|
||||||
#### [MODIFY] `components/chat/ChatInput.tsx`
|
|
||||||
- Suportar modo "edit" — pré-preencher input com texto da mensagem selecionada
|
|
||||||
- Mostrar indicador visual de que está editando (ex: badge "Editing" + botão cancelar)
|
|
||||||
|
|
||||||
#### [NEW] `components/chat/MessageActions.tsx`
|
|
||||||
- Componente de ações reutilizável
|
|
||||||
- Botões com ícones (Lucide): `Copy`, `Pencil`, `RefreshCw`, `Trash2`
|
|
||||||
- Touch targets 44px+ (Fitts' Law compliance)
|
|
||||||
- Haptic feedback nos botões (`expo-haptics`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Fase 4: UI/UX Polish
|
|
||||||
|
|
||||||
#### [MODIFY] `components/chat/MessageBubble.tsx`
|
|
||||||
- Avatar/ícone para assistant (Bot icon) e user
|
|
||||||
- Timestamp discreto abaixo da bolha
|
|
||||||
- Animação de entrada (fade in + slide up com `react-native-reanimated`)
|
|
||||||
|
|
||||||
#### [MODIFY] `app/chat/index.tsx`
|
|
||||||
- Empty state quando não há mensagens (ícone + texto de boas-vindas + sugestões de prompts clicáveis)
|
|
||||||
- Typing indicator animado (3 dots pulsando) enquanto `isStreaming` e conteúdo ainda vazio
|
|
||||||
|
|
||||||
#### [MODIFY] `components/chat/ChatInput.tsx`
|
|
||||||
- Auto-grow do input (já faz multiline, melhorar visual)
|
|
||||||
- Botão de "stop generation" (⏹️) visível durante streaming, substituindo o botão send
|
|
||||||
- Contador de caracteres sutil para mensagens longas
|
|
||||||
|
|
||||||
#### [MODIFY] `app/chat/_layout.tsx`
|
|
||||||
- Botão "New Chat" no header (limpa conversa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Sugestões Adicionais (Simples de Implementar)
|
|
||||||
|
|
||||||
1. **Sugestões de Prompts no Empty State** — 3-4 cards clicáveis com prompts exemplo ("Explique recursão", "Escreva um haiku") que preenchem o input ao tocar. Melhora onboarding e ajuda o user a começar.
|
|
||||||
|
|
||||||
2. **Persistência de Chat com AsyncStorage** — Salvar mensagens no dispositivo para não perder ao fechar o app. Usar `zustand/middleware` com `persist`.
|
|
||||||
|
|
||||||
3. **Haptic Feedback nas ações** — Vibração leve ao enviar mensagem, copiar, e deletar. Premium feel. (`expo-haptics` já está disponível no Expo).
|
|
||||||
|
|
||||||
4. **Scroll-to-bottom FAB** — Quando o user rola para cima e chega mensagem nova, mostrar um FAB "↓" no canto inferior para voltar ao final. Evita perder mensagens novas.
|
|
||||||
|
|
||||||
5. **Configuração de Temperature/Max Tokens no Chat** — Adicionar um menu de "Model Parameters" acessível pelo header (ícone de slider). Permite ajustar temperatura e max_tokens sem ir em Settings.
|
|
||||||
|
|
||||||
6. **Tema Dark Mode funcional** — O theme toggle existe mas as telas usam cores hardcoded (#FFFFFF, #F3F4F6). Conectar com o sistema `Colors` de `constants/theme.ts` para dark mode real.
|
|
||||||
|
|
||||||
7. **Indicador de tokens usados** — Mostrar contagem de tokens da resposta (retornado pelo `usage` da API) abaixo de cada mensagem assistant. Informativo para quem está testando modelos.
|
|
||||||
|
|
||||||
8. **System Prompt configurável** — Input nas Settings para definir o system prompt padrão que é enviado em toda conversa. Permite personalizar o "comportamento" do modelo.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verificação
|
|
||||||
|
|
||||||
1. Enviar mensagem → resposta deve aparecer via streaming (sem erro ReadableStream)
|
|
||||||
2. Resposta do assistant → renderizada com formatação markdown (code blocks, bold, listas)
|
|
||||||
3. Long-press em mensagem → botões de ação aparecem
|
|
||||||
4. Copiar → conteúdo no clipboard
|
|
||||||
5. Editar mensagem do user → input preenchido, reenvio funciona
|
|
||||||
6. Empty state → sugestões de prompt visíveis
|
|
||||||
7. Stop generation → streaming para imediatamente
|
|
||||||
8. Dark mode → todas as telas respeitam o tema
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Ordem de Execução Recomendada
|
|
||||||
|
|
||||||
| Fase | Prioridade | Esforço |
|
|
||||||
|------|-----------|---------|
|
|
||||||
| 1. Fix Streaming | 🔴 Crítico | Baixo |
|
|
||||||
| 2. Markdown | 🟠 Alto | Baixo |
|
|
||||||
| 3. Message Actions | 🟡 Médio | Médio |
|
|
||||||
| 4. UI/UX Polish | 🟢 Normal | Médio |
|
|
||||||
| 5+ Sugestões | 🔵 Nice-to-have | Baixo cada |
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# Local Save and Auto-Refresh Models Plan
|
|
||||||
|
|
||||||
## 1. Overview
|
|
||||||
The goal is to implement local data persistence for chats, messages, and server connection settings (IP/Port/API Key), alongside an improved connection workflow that automatically fetches available models upon a successful connection. Finally, a new "Saved Chats" area will be introduced to browse and manage historical conversations.
|
|
||||||
|
|
||||||
## 2. Project Type
|
|
||||||
**WEB/MOBILE** (Cross-platform Expo/React Native app)
|
|
||||||
|
|
||||||
## 3. Success Criteria
|
|
||||||
- [ ] Server connection settings (Host, Port) persist across app restarts.
|
|
||||||
- [ ] Chat sessions and their respective messages are saved locally.
|
|
||||||
- [ ] Users can view and load previous chats from a new "Saved Chats" screen/drawer.
|
|
||||||
- [ ] Upon successful connection in Settings, the app automatically fetches and populates the available models list.
|
|
||||||
- [ ] Zero data loss between soft reloads.
|
|
||||||
|
|
||||||
## 4. Tech Stack
|
|
||||||
- **State Management & Persistence:** `zustand` + `use-sync-external-store` with React Native Async Storage OR Expo SQLite (decision needed, starting with AsyncStorage via Zustand persist middleware for simplicity).
|
|
||||||
- **Navigation:** Expo Router (`app/(drawers)` or `app/chats/`).
|
|
||||||
- **UI:** NativeWind / StyleSheet with `Colors.ts` zinc theme.
|
|
||||||
|
|
||||||
## 5. File Structure Modifications
|
|
||||||
|
|
||||||
```text
|
|
||||||
├── app/
|
|
||||||
│ ├── chat/
|
|
||||||
│ │ ├── index.tsx (Update to handle loading specific chat IDs)
|
|
||||||
│ │ └── history.tsx [NEW] (Screen for Saved Chats)
|
|
||||||
│ └── settings/
|
|
||||||
│ └── index.tsx (Update to trigger model refresh on connect)
|
|
||||||
├── store/
|
|
||||||
│ └── useAppStore.ts (Add persist middleware, add chat history management)
|
|
||||||
└── components/
|
|
||||||
└── chat/
|
|
||||||
└── ChatHistoryItem.tsx [NEW]
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. Task Breakdown
|
|
||||||
|
|
||||||
### Task 1: Setup Persistence in App Store
|
|
||||||
- **Agent:** `frontend-specialist`
|
|
||||||
- **Skills:** `react-best-practices`, `nodejs-best-practices`
|
|
||||||
- **Priority:** P1
|
|
||||||
- **INPUT:** `useAppStore.ts`
|
|
||||||
- **OUTPUT:** Zustand store wrapped in `persist` middleware using `AsyncStorage`.
|
|
||||||
- **VERIFY:** Reloading the app keeps the `serverConfig` and `messages` intact.
|
|
||||||
|
|
||||||
### Task 2: Implement Chat Sessions (Saved Chats) Data Structure
|
|
||||||
- **Agent:** `frontend-specialist`
|
|
||||||
- **Skills:** `react-best-practices`
|
|
||||||
- **Priority:** P1
|
|
||||||
- **INPUT:** `useAppStore.ts`
|
|
||||||
- **OUTPUT:** Add `ChatSession` type (id, title, updatedAt, messages). Create actions `saveCurrentChat`, `loadChat`, `deleteChat`.
|
|
||||||
- **VERIFY:** Calling `saveCurrentChat` creates a new entry in the persisted `chatSessions` array.
|
|
||||||
|
|
||||||
### Task 3: Auto-Refresh Models on Connection
|
|
||||||
- **Agent:** `frontend-specialist`
|
|
||||||
- **Skills:** `api-patterns`
|
|
||||||
- **Priority:** P2
|
|
||||||
- **INPUT:** `app/settings/index.tsx` and `hooks/useLMStudio.ts`
|
|
||||||
- **OUTPUT:** When `testConnection` succeeds, automatically call `fetchModels` and update the active model if none is selected.
|
|
||||||
- **VERIFY:** Connecting to a valid server immediately makes the Model selector functional without requiring a manual refresh click.
|
|
||||||
|
|
||||||
### Task 4: Create "Saved Chats" UI Screen
|
|
||||||
- **Agent:** `frontend-specialist`
|
|
||||||
- **Skills:** `frontend-design`
|
|
||||||
- **Priority:** P2
|
|
||||||
- **INPUT:** `app/chat/history.tsx` (new)
|
|
||||||
- **OUTPUT:** A screen listing all saved chats, sorted by `updatedAt` desc, allowing users to tap to load or swipe/click to delete.
|
|
||||||
- **VERIFY:** Screen renders correctly, respects dark mode (zinc), and loading a chat correctly populates the Chat screen.
|
|
||||||
|
|
||||||
### Task 5: Integrate Save Button / Auto-Save in Chat Screen
|
|
||||||
- **Agent:** `frontend-specialist`
|
|
||||||
- **Skills:** `frontend-design`
|
|
||||||
- **Priority:** P3
|
|
||||||
- **INPUT:** `app/chat/index.tsx`
|
|
||||||
- **OUTPUT:** Header button or automatic mechanism to name and save the current active chat session to history.
|
|
||||||
- **VERIFY:** User can explicitly snapshot their current conversation.
|
|
||||||
|
|
||||||
## 7. Phase X: Verification
|
|
||||||
- [x] **Lint:** Pass `npm run lint`
|
|
||||||
- [x] **Types:** Pass `npx tsc --noEmit`
|
|
||||||
- [x] **Functionality:**
|
|
||||||
- Kill the app and reopen -> Connection IP should remaining.
|
|
||||||
- Connect -> Models load instantly.
|
|
||||||
- Chat -> Save -> Open History -> Chat is there.
|
|
||||||
|
|
||||||
## ✅ PHASE X COMPLETE
|
|
||||||
- Lint: ✅ Pass
|
|
||||||
- Security: ✅ No critical issues
|
|
||||||
- Build: ✅ Success
|
|
||||||
- Date: 2026-03-04
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
# Plan: Models, Chat & Settings Screens
|
|
||||||
|
|
||||||
This document outlines the implementation plan for adding the Models, Chat, and Settings screens to the LocalAiApp, following the user's choice of **Option C** (Stack Navigation with Actions in Header) and targeting the Qwen 3.5 models (0.5b, 1.5b, 4b) via HuggingFace formats.
|
|
||||||
The project is a **CROSS-PLATFORM** app built with Expo (iOS, Android, Web/Desktop).
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
We will implement a responsive, cross-platform Chat interface. On mobile, it will be a full-screen Chat interface with a top-bar header. On desktop/tablet breakpoints, the UI will adapt (e.g., potentially expanding the header actions or bringing settings into a side panel if needed, but primarily focusing on a fluid Chat layout that centers the conversation on wide screens). The application will manage model state through a central store, allowing quick selection from the header.
|
|
||||||
|
|
||||||
## Success Criteria
|
|
||||||
* The `Chat` screen acts as the primary fluid view, centering the message thread on wide desktop displays max-width to avoid excessively long text lines, while extending full-width on mobile.
|
|
||||||
* The models (Qwen 3.5 - 0.5b, 1.5b, 4b) can be selected via a dropdown or modal directly from the Chat header. On desktop, this might behave as a popover; on mobile, a bottom sheet.
|
|
||||||
* A `Settings` screen is accessible via an icon in the Chat header. On mobile, it pushes onto the stack. On desktop, it may appear as a modal or dedicated full-page route optimized for mouse interaction.
|
|
||||||
* A solid context/state management foundation (e.g., Zustand) is established to hold the current selected model and chat history across screens.
|
|
||||||
* The UI must adhere to fluid design principles: larger touch targets for mobile (> 44pt), hover states and standard cursor interactions for desktop. No standard templates; use a custom, premium aesthetic.
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
* **React Native / Expo Router**: For navigation and screen structure.
|
|
||||||
* **Zustand**: For simple, performant global state management (models state, chat history).
|
|
||||||
* **Vanilla Stylesheet / Tailwind (if configured)**: For custom, premium UI styling without generic templates.
|
|
||||||
* **Lucide-React-Native / Expo Vector Icons**: For crisp, recognizable icons in the header and settings.
|
|
||||||
* *(Future Integration)* `llama.rn` or similar: For actually executing the Qwen models locally on the device (Out of scope for this UI phase, but Settings UI must account for it).
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
├── app/
|
|
||||||
│ ├── index.tsx # Main entry point (Redirects to chat or is the chat)
|
|
||||||
│ ├── chat/
|
|
||||||
│ │ ├── _layout.tsx # Defines the Stack Header (Model Selector + Settings Icon)
|
|
||||||
│ │ ├── index.tsx # The Chat UI (Messages list, input area)
|
|
||||||
│ ├── settings/
|
|
||||||
│ │ ├── index.tsx # Settings Screen (Model management, keys, UI prefs)
|
|
||||||
├── components/
|
|
||||||
│ ├── chat/
|
|
||||||
│ │ ├── MessageBubble.tsx # Defines how user/AI messages look
|
|
||||||
│ │ ├── ChatInput.tsx # The text input area
|
|
||||||
│ │ ├── ModelSelector.tsx # The dropdown/bottom sheet to pick Qwen models
|
|
||||||
│ ├── ui/
|
|
||||||
│ │ ├── IconButton.tsx # Reusable touch-friendly icon button
|
|
||||||
├── store/
|
|
||||||
│ ├── useAppStore.ts # Zustand store for active model, messages, and settings
|
|
||||||
├── constants/
|
|
||||||
│ ├── Models.ts # Definitions for Qwen 3.5 (0.5b, 1.5b, 4b) URLs/Configs
|
|
||||||
```
|
|
||||||
|
|
||||||
## Task Breakdown
|
|
||||||
|
|
||||||
### 1- Setup Global State & Constants
|
|
||||||
* **Agent:** `mobile-developer`
|
|
||||||
* **Skills:** `clean-code`
|
|
||||||
* **Task:** Create `Models.ts` with configurations for the selected Qwen 3.5 models. Setup a basic Zustand store `useAppStore.ts` to hold the `activeModel`, an array of `messages`, and user preferences.
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Empty files. Output: A working Zustand store and constant file. Verify: Can import store into a simple component and read/write values.
|
|
||||||
|
|
||||||
### 2- Implement Stack Navigation Layout & Responsive Shell
|
|
||||||
* **Agent:** `frontend-specialist` (cross-platform expert)
|
|
||||||
* **Skills:** `frontend-design`, `react-best-practices`
|
|
||||||
* **Task:** Update `app/_layout.tsx` (or `app/chat/_layout.tsx`) to use Expo Router's `<Stack>` navigation. Implement a responsive container that limits max width on desktop sizes to ensure readability, while remaining 100% width on mobile. Configure the header of the `chat` screen to include the `ModelSelector` and Settings icon.
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Default Expo Router layout. Output: A cross-platform layout adapting to screen width (`useWindowDimensions`). Verify: Resize browser window (Web) to test breakpoints; launch mobile to confirm header structure.
|
|
||||||
|
|
||||||
### 3- Build Chat Components (Input & Bubbles)
|
|
||||||
* **Agent:** `frontend-specialist`
|
|
||||||
* **Skills:** `frontend-design`
|
|
||||||
* **Task:** Create `components/chat/MessageBubble.tsx` and `components/chat/ChatInput.tsx`. These components must be responsive: message bubbles should have a max-width (e.g., 75% on mobile, 60% on desktop) and inputs should support Enter to send on Web (Shift+Enter for newline) alongside standard mobile keyboard behavior. Add hover states for desktop interactions.
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Layout skeleton. Output: Reusable chat components functioning on both touch and mouse interfaces. Verify: Test desktop hover states and Enter-key sending; test mobile touch targets and padding.
|
|
||||||
|
|
||||||
### 4- Build the Chat Screen (List & Integration)
|
|
||||||
* **Agent:** `mobile-developer`
|
|
||||||
* **Skills:** `performance-profiling`
|
|
||||||
* **Task:** Implement `app/chat/index.tsx`. Use `FlatList` (or `FlashList` if available) to render the messages from the global state. Integrate the `ChatInput` at the bottom (handling Keyboard avoiding view correctly).
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Chat components. Output: A fully scrollable chat interface that reacts to keyboard input. Verify: Type a message, send it, verify it appears in the list and the list auto-scrolls.
|
|
||||||
|
|
||||||
### 5- Build Model Selector (Header Menu)
|
|
||||||
* **Agent:** `mobile-developer`
|
|
||||||
* **Skills:** `mobile-design`
|
|
||||||
* **Task:** Implement `components/chat/ModelSelector.tsx`. This should be a touchable area in the header that opens a bottom sheet or a contextual menu to switch between the Qwen 3.5 models (0.5b, 1.5b, 4b).
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Header layout. Output: Interactive menu for model selection. Verify: Tapping the header opens the menu, selecting a model updates the global state.
|
|
||||||
|
|
||||||
### 6- Build Settings Screen
|
|
||||||
* **Agent:** `frontend-specialist`
|
|
||||||
* **Skills:** `frontend-design`
|
|
||||||
* **Task:** Implement `app/settings/index.tsx`. Group settings into logical sections. On wide screens, this could be a centered card layout; on mobile, a standard list. Add toggles/inputs for configuration with proper focus states for keyboard navigation on Web/Desktop.
|
|
||||||
* **INPUT→OUTPUT→VERIFY:** Input: Navigation setup. Output: A functional, responsive settings screen. Verify: Navigate to Settings, change sizes from mobile to desktop, check alignment and focus rings.
|
|
||||||
|
|
||||||
## Phase X: Verification Plan
|
|
||||||
|
|
||||||
To verify this cross-platform implementation, the following checklist must be executed once all tasks are complete:
|
|
||||||
|
|
||||||
- [ ] **Linting & Types:** Run `npm run lint` and `npx tsc --noEmit`. Fix any warnings/errors.
|
|
||||||
- [ ] **Cross-Platform Accessibility:** Audit touch targets for mobile (> 44pt) and verify hover/focus states are present for Desktop users (mouse/keyboard).
|
|
||||||
- [ ] **Responsive Resizing:** Run `npm run web` and resize the browser horizontally. Ensure text lines in chat don't stretch indefinitely and the input field remains centered/bounded.
|
|
||||||
- [ ] **Design Constraints Check:** Verify NO purple/violet `#8A2BE2` are used. Ensure UI feels premium on both small and large screens.
|
|
||||||
- [ ] **Keyboard Handling:**
|
|
||||||
- *Mobile:* Ensure Keyboard Avoiding View prevents covering the input.
|
|
||||||
- *Desktop:* Ensure hitting `Enter` sends the message, and `Shift+Enter` adds a newline.
|
|
||||||
- [ ] **State Persistence (Basic):** Select a model -> Go to Settings -> Change a setting -> Go back to Chat -> Verify the selected model hasn't reset.
|
|
||||||
- [ ] **Build:** Run `npm run android`, `npm run ios`, and `npm run web` successfully without bundler errors.
|
|
||||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user