Fix file uploads: include content in messages, update README, remove secrets

- File uploads now read content and include in AI context
- Truncate files over 50KB to avoid token limits
- Updated README with JSON config documentation
- Removed secrets.json from git tracking
This commit is contained in:
2026-02-25 03:54:51 +00:00
parent e6ba19fe8e
commit 05b3ae0071
2 changed files with 132 additions and 103 deletions

203
README.md
View File

@@ -2,12 +2,10 @@
A modern, OpenWebUI-compatible chat interface for OpenClaw with LDAP SSO support. A modern, OpenWebUI-compatible chat interface for OpenClaw with LDAP SSO support.
![OpenClaw WebUI](https://via.placeholder.com/800x400?text=OpenClaw+WebUI)
## Features ## Features
- **Modern Chat Interface** - Clean, responsive UI inspired by OpenWebUI - **Modern Chat Interface** - Clean, responsive UI inspired by OpenWebUI
- **Multi-file Upload** - Attach files to messages - **Multi-file Upload** - Attach files with content included in context
- **Code Canvas** - Side panel for code editing and viewing - **Code Canvas** - Side panel for code editing and viewing
- **Chat History** - Persistent conversation storage - **Chat History** - Persistent conversation storage
- **Streaming Responses** - Real-time token streaming - **Streaming Responses** - Real-time token streaming
@@ -18,43 +16,95 @@ A modern, OpenWebUI-compatible chat interface for OpenClaw with LDAP SSO support
## Quick Start ## Quick Start
```bash ```bash
# Install dependencies # Clone
git clone https://git.theta42.com/nova/openclaw-webui.git
cd openclaw-webui
# Install
npm install npm install
# Development mode (with hot reload) # Development (hot reload)
npm run dev npm run dev
# Production build # Production build
npm run build npm run build
# Start production server # Production server
npm start NODE_ENV=production npm start
``` ```
The server runs on port 3000 by default.
## Configuration ## Configuration
Configure via environment variables: Uses JSON config files in `conf/` directory:
```bash ```
# Server conf/
PORT=3000 ├── base.json # Base config (all environments)
NODE_ENV=production ├── development.json # Dev overrides (auth disabled)
├── production.json # Production overrides
├── secrets.json # Secrets (gitignored!)
└── secrets.example.json # Template
```
# OpenClaw Gateway ### Load Order
OPENCLAW_GATEWAY=http://127.0.0.1:18789
# LDAP Authentication Files merge in order: `base.json``[environment].json``secrets.json`
LDAP_ENABLED=true
LDAP_URL=ldap://localhost:389
LDAP_BASE_DN=ou=users,dc=example,dc=com
# Session ### Example Configs
SESSION_SECRET=your-secret-key
# Development (disable auth) **conf/base.json:**
DISABLE_AUTH=true ```json
{
"server": { "port": 8089 },
"gateway": { "url": "http://127.0.0.1:18789" },
"auth": {
"disabled": false,
"ldap": {
"enabled": true,
"url": "ldap://10.1.0.55:389",
"baseDN": "dc=example,dc=com",
"searchFilter": "(uid={{username}})"
}
}
}
```
**conf/secrets.json:**
```json
{
"gateway": { "token": "your-openclaw-token" },
"session": { "secret": "random-session-secret" },
"auth": {
"ldap": {
"bindDN": "cn=service,ou=people,dc=example,dc=com",
"bindPassword": "ldap-password"
}
}
}
```
### Environment Variables
Can override config at runtime:
- `PORT` - Server port
- `OPENCLAW_GATEWAY` - Gateway URL
- `OPENCLAW_TOKEN` - Gateway auth token
- `SESSION_SECRET` - Session signing secret
- `LDAP_ENABLED` - Enable LDAP auth
## LDAP Authentication
Supports standard LDAP servers (OpenLDAP, Active Directory):
1. Service binds with `bindDN` + `bindPassword`
2. Searches for user with `searchFilter`
3. Binds as user to verify password
**Search Filter:**
Use `{{username}}` as placeholder:
```
(&(memberof=cn=app_access,ou=groups,dc=example,dc=com)(uid={{username}}))
``` ```
## Architecture ## Architecture
@@ -65,7 +115,7 @@ DISABLE_AUTH=true
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ Frontend (Vanilla JS + Vite) │ │ Frontend (Vanilla JS + Vite) │
│ ├── Chat Interface │ │ ├── Chat Interface │
│ ├── File Upload │ ├── File Upload (content included)
│ ├── Code Canvas │ │ ├── Code Canvas │
│ └── History Sidebar │ │ └── History Sidebar │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
@@ -73,108 +123,67 @@ DISABLE_AUTH=true
│ ├── LDAP SSO Authentication │ │ ├── LDAP SSO Authentication │
│ ├── Session Management │ │ ├── Session Management │
│ ├── Chat History Persistence │ │ ├── Chat History Persistence │
│ ├── File Upload Handling │
│ └── /v1/chat/completions Proxy │ │ └── /v1/chat/completions Proxy │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────┤
│ OpenClaw Gateway (port 18789) │ │ OpenClaw Gateway (port 18789) │
│ ├── WebSocket Protocol │
│ ├── OpenAI-Compatible API │
│ └── Agent Execution │
└─────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────┘
``` ```
## API Endpoints ## API Endpoints
### Authentication ### Authentication
- `GET /api/auth/status` - Check authentication status - `GET /api/auth/status` - Check auth status
- `POST /api/auth/login` - Login with username/password - `POST /api/auth/login` - Login
- `POST /api/auth/logout` - Logout - `POST /api/auth/logout` - Logout
### Conversations ### Conversations
- `GET /api/conversations` - List all conversations - `GET /api/conversations` - List conversations
- `POST /api/conversations` - Create new conversation - `POST /api/conversations` - Create conversation
- `PUT /api/conversations/:id` - Update conversation - `PUT /api/conversations/:id` - Update conversation
- `DELETE /api/conversations/:id` - Delete conversation - `DELETE /api/conversations/:id` - Delete conversation
- `GET /api/conversations/:id/messages` - Get messages - `GET /api/conversations/:id/messages` - Get messages
- `POST /api/conversations/:id/messages` - Save message
### Files
- `POST /api/upload` - Upload file
- `GET /api/upload/:id` - Download file
- `GET /api/upload/:id/meta` - Get file metadata
### OpenAI-Compatible ### OpenAI-Compatible
- `POST /v1/chat/completions` - Chat completions (proxied to OpenClaw) - `POST /v1/chat/completions` - Chat (proxied to OpenClaw)
- `GET /v1/models` - List available models - `GET /v1/models` - List models
## LDAP Configuration ## Production Deployment
The LDAP integration supports standard Active Directory and OpenLDAP setups:
**Systemd Service:**
```bash ```bash
# LDAP Server URL # Create service file
LDAP_URL=ldap://ldap.example.com:389 mkdir -p ~/.config/systemd/user
cp openclaw-webui.service ~/.config/systemd/user/
# Base DN for user search # Enable and start
LDAP_BASE_DN=ou=users,dc=example,dc=com systemctl --user enable openclaw-webui
systemctl --user start openclaw-webui
# Bind DN for searching (if needed) # View logs
LDAP_BIND_DN=cn=admin,dc=example,dc=com journalctl --user -u openclaw-webui -f
LDAP_BIND_PASSWORD=admin_password
# Custom search filter (optional)
LDAP_SEARCH_FILTER=(uid={{username}})
``` ```
Users authenticate with their LDAP username and password. **Requirements:**
- OpenClaw Gateway running on port 18789
- Enable HTTP chat completions in gateway config:
```json
{
"gateway": {
"http": {
"endpoints": { "chatCompletions": { "enabled": true } }
}
}
}
```
## Development ## Development
```bash ```bash
# Run in development mode
npm run dev npm run dev
# Frontend: http://localhost:5173 (Vite HMR)
# This starts: # Backend: http://localhost:3000 (auto-restart)
# - Backend server on port 3000 (with hot reload)
# - Vite dev server on port 5173 (with HMR)
# - Proxy from Vite to backend for /api and /v1
```
## Production Deployment
```bash
# Build frontend
npm run build
# Start production server
NODE_ENV=production npm start
```
The production server serves static files from `dist/` and handles all API routes.
## File Structure
```
openclaw-webui/
├── client/
│ ├── index.html
│ ├── main.js # Main application
│ └── public/
│ ├── styles.css
│ └── favicon.svg
├── server/
│ └── index.js # Express server
├── data/ # Chat history (gitignored)
├── dist/ # Production build (gitignored)
├── package.json
├── vite.config.js
└── README.md
``` ```
## License ## License
MIT License - See LICENSE file for details. MIT
## Credits
Built for [OpenClaw](https://github.com/openclaw/openclaw) - AI assistant framework.

View File

@@ -550,15 +550,18 @@ async function handleFileSelect(e) {
for (const file of files) { for (const file of files) {
try { try {
const uploaded = await api.uploadFile(file); // Read file content
const content = await readFileContent(file);
state.files.push({ state.files.push({
id: uploaded.id, id: file.name + '-' + Date.now(),
name: file.name, name: file.name,
type: file.type, type: file.type,
size: file.size size: file.size,
content: content
}); });
} catch (err) { } catch (err) {
console.error('Failed to upload file:', file.name, err); console.error('Failed to read file:', file.name, err);
} }
} }
@@ -566,6 +569,15 @@ async function handleFileSelect(e) {
e.target.value = ''; e.target.value = '';
} }
function readFileContent(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsText(file);
});
}
function renderFilesPreview() { function renderFilesPreview() {
const container = document.getElementById('files-preview'); const container = document.getElementById('files-preview');
if (!container) return; if (!container) return;
@@ -663,8 +675,16 @@ async function handleSendMessage() {
function buildMessageContent(text, files) { function buildMessageContent(text, files) {
if (!files.length) return text; if (!files.length) return text;
const fileDescriptions = files.map(f => `[Attached: ${f.name}]`).join('\n'); const fileContents = files.map(f => {
return `${text}\n\n${fileDescriptions}`; const maxLen = 50000; // Limit file content length
const content = f.content || '[File content not available]';
const truncated = content.length > maxLen
? content.substring(0, maxLen) + '\n... [truncated]'
: content;
return `--- ${f.name} ---\n${truncated}\n--- end of ${f.name} ---`;
}).join('\n\n');
return `${text}\n\n${fileContents}`;
} }
function updateLastMessage(content) { function updateLastMessage(content) {