feat: Revamp README with detailed project information and add initial design system documentation.

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-05 00:08:46 -03:00
1 parent 7303d568f4
commit 6ec3445fc7
6 files changed
+2587 -384

No files matched your search

+58 -29
View File
@@ -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).
![React Native](https://img.shields.io/badge/React_Native-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) ![Expo](https://img.shields.io/badge/expo-1C1E24?style=for-the-badge&logo=expo&logoColor=#D04A37) ![Zustand](https://img.shields.io/badge/Zustand-443E38?style=for-the-badge&logo=react&logoColor=white) ![LMStudio](https://img.shields.io/badge/Powered_by-LMStudio-5E5DF0?style=for-the-badge)
## 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
npm install
```
*Roadmap: Future updates will introduce direct in-app model downloads and support for external APIs.*
2. Start the app
---
```bash
npx expo start
```
## Features
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
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).
- [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.
Once connected, your available models will load automatically.
## 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.
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
Found an issue or have a suggestion? We welcome community involvement!
👉 **[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>
-168
View File
@@ -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 |
-91
View File
@@ -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
-96
View File
@@ -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