# Brooks Computing Systems - Jacksonville AI GPU
A web-based chat interface for interacting with local LLMs via `llama.cpp` server, with Whisper speech-to-text integration and a MariaDB-backed prompt history.
## Features
- **Chat Interface** — Streaming chat with local `llama.cpp` server (port 8085)
- **Model Switching** — Dropdown to load/switch between `.gguf` models on the fly
- **Speech-to-Text** — Browser microphone → Whisper (port 8090) → prompt field
- **Prompt History** — Searchable, paginated CRUD modal for saved conversations (MySQL)
- **PDF Export** — Print conversation or individual prompt records as PDF
- **Dark/Light Theme** — Persisted in `localStorage`
- **Keyboard Shortcuts** — `Enter` to send, `Escape` to clear, double-click saved prompt to load
## Requirements
- PHP 8.0+ with PDO MySQL
- MySQL/MariaDB database
- `llama.cpp` server running on `http://127.0.0.1:8085`
- Whisper server (optional) on `http://localhost:8090/inference`
- `.gguf` models in `MODELS_DIR` (`/home/archman/models` by default)
## Installation
1. **Clone / copy** this directory to your web root (e.g., `/var/www/localhost/htdocs/ab_ai`)
2. **Configure database** in `config/database.php`:
```php
return [
'host' => '127.0.0.1',
'port' => 3306,
'dbname' => 'your_db',
'username' => 'your_user',
'password' => 'your_pass',
'charset' => 'utf8mb4',
];
```
3. **Create the prompts table**:
```sql
CREATE TABLE prompts (
id INT AUTO_INCREMENT PRIMARY KEY,
model VARCHAR(255),
prompt TEXT,
resp TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
4. **Configure paths** in `includes/config.php`:
```php
define('MODELS_DIR', '/path/to/your/gguf/models');
define('LLAMA_SERVER_URL', 'http://127.0.0.1:8085');
define('WHISPER_URL', 'http://localhost:8090/inference');
```
5. **Start llama.cpp server**:
```bash
llama-server -m /path/to/model.gguf -c 4096 --host 127.0.0.1 --port 8085
```
6. **(Optional) Start Whisper server** for speech-to-text:
```bash
# Example using whisper.cpp server
./server -m models/ggml-base.bin -f /dev/stdin --port 8090
```
7. **Serve via PHP** (or Apache/Nginx with PHP-FPM):
```bash
cd /var/www/localhost/htdocs/ab_ai
php -S 0.0.0.0:8000
```
8. Open `http://localhost:8000` in your browser.
## Usage
### Chat Modal
- **Model selector** — Choose a loaded `.gguf` model; switches on-the-fly
- **Microphone** — Click to record, click again to transcribe via Whisper
- **Prompt input** — Type or paste; press `Enter` to send
- **Send** — Streams response from `llama-server`
- **PDF** — Opens printable conversation report
- **Save** — Stores full conversation to database
- **Search** — Opens saved prompts modal
- **Clear** — Clears conversation history
- **Clear prompt (×)** — Clears the input field only
- **Theme toggle** — Switch light/dark mode (persisted)
### Saved Prompts Modal
- **Search** — Filter by prompt/response text
- **Pagination** — 5/10/25/50/100 per page
- **New** — Create a manual entry
- **Table actions**:
- **Edit** (pencil) — Modify prompt/response
- **PDF** (file) — Print single record
- **Delete** (trash) — Remove record
- **Double-click row** — Loads prompt into main chat input and closes modal
## API Endpoints
| Endpoint | Method | Action |
|----------|--------|--------|
| `api/models.php` | GET | List `.gguf` models + current |
| `api/load-model.php` | POST | Switch model (`{path}`) |
| `api/save-prompt.php` | POST | Save conversation (`{prompt,resp,model}`) |
| `api/prompts-crud.php?action=list&q=` | GET | Search/list prompts |
| `api/prompts-crud.php?action=get&id=` | GET | Fetch single prompt |
| `api/prompts-crud.php?action=create` | POST | Create prompt |
| `api/prompts-crud.php?action=update` | POST | Update prompt |
| `api/prompts-crud.php?action=delete&id=` | GET | Delete prompt |
| `api/proxy-whisper.php` | POST | Proxy audio → Whisper |
## Project Structure
```
ab_ai/
├── index.php # Entry point (serves app.html)
├── app.html # Main UI (modals, chat, scripts)
├── includes/
│ └── config.php # App constants
├── config/
│ └── database.php # DB credentials (gitignored in prod)
├── api/
│ ├── models.php
│ ├── load-model.php
│ ├── save-prompt.php
│ ├── prompts-crud.php
│ └── proxy-whisper.php
└── vendor/ # Bootstrap 5 + Icons (bundled)
```
## Configuration Constants (`includes/config.php`)
| Constant | Default | Description |
|----------|---------|-------------|
| `APP_NAME` | `BCS AI` | App title |
| `APP_VERSION` | `1.0.0` | Version |
| `WHISPER_URL` | `http://localhost:8090/inference` | Whisper endpoint |
| `WHISPER_ENABLED` | `true` | Enable mic button |
| `WHISPER_MODEL` | `base` | Whisper model name |
| `LLAMA_SERVER_URL` | `http://127.0.0.1:8085` | llama.cpp server |
| `MODELS_DIR` | `/home/archman/models` | `.gguf` model directory |
| `DB_CONFIG_PATH` | `../config/database.php` | DB config path |
## Security Notes
- **No authentication built-in** — Protect via web server auth (`.htaccess`, Nginx `auth_basic`, etc.)
- **Database credentials** — Store `config/database.php` outside web root in production
- **CORS** — APIs allow `*` origin; restrict in production
- **Whisper/llama.cpp** — Bind to localhost only unless behind VPN/firewall
## Troubleshooting
| Issue | Fix |
|-------|-----|
| "Failed to load models" | Check `MODELS_DIR` exists and contains `.gguf` files |
| "Unable to connect to llama-server" | Ensure `llama-server` running on port 8085 |
| "Pop-up blocked" (PDF) | Allow pop-ups for the site |
| Microphone not working | Serve over HTTPS or `localhost`; check Whisper server |
| DB errors | Verify `config/database.php` credentials and table exists |
## License
Internal use — Brooks Computing Systems, Jacksonville FL.