feat: add Ollama (local AI) integration for AIUI
- Create Ollama provider plugin in AIUI (ollama-provider.ts) - Register Ollama alongside Claude in plugin system - Auto-detect installed models via /api/tags endpoint - Add Ollama proxy in mock backend (forwards to localhost:11434) - Add nginx proxy rules for /aiui/api/ollama/ (both HTTP and HTTPS) - Rebuild AIUI dist with Ollama provider included - Qwen 2.5 Coder 3B installed on dev server via Ollama Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
00ad7a42f5
commit
825d082003
@@ -86,6 +86,18 @@ http {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Proxy Ollama (local AI) requests to backend
|
||||
location /aiui/api/ollama/ {
|
||||
proxy_pass http://neode-backend:5959;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
|
||||
# Proxy Claude API requests to backend (which handles API key + streaming)
|
||||
location /aiui/api/claude/ {
|
||||
proxy_pass http://neode-backend:5959;
|
||||
|
||||
@@ -1087,6 +1087,74 @@ app.post('/aiui/api/claude/*', (req, res) => {
|
||||
proxyReq.end()
|
||||
})
|
||||
|
||||
// Ollama (local AI) proxy — forwards to localhost:11434
|
||||
app.all('/aiui/api/ollama/*', (req, res) => {
|
||||
const ollamaPath = '/' + req.params[0]
|
||||
const bodyStr = JSON.stringify(req.body)
|
||||
|
||||
const options = {
|
||||
hostname: '127.0.0.1',
|
||||
port: 11434,
|
||||
path: ollamaPath,
|
||||
method: req.method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(bodyStr),
|
||||
},
|
||||
}
|
||||
|
||||
const proxyReq = http.request(options, (proxyRes) => {
|
||||
res.writeHead(proxyRes.statusCode, proxyRes.headers)
|
||||
proxyRes.pipe(res)
|
||||
})
|
||||
|
||||
proxyReq.on('error', (err) => {
|
||||
const msg = err.message || err.code || 'Ollama not available'
|
||||
console.error('[Ollama Proxy] Error:', msg)
|
||||
if (!res.headersSent) {
|
||||
res.status(502).json({ error: msg })
|
||||
}
|
||||
})
|
||||
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||
proxyReq.write(bodyStr)
|
||||
}
|
||||
proxyReq.end()
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Ollama Local AI Proxy (forwards to Ollama on localhost:11434)
|
||||
// =============================================================================
|
||||
app.all('/api/ollama/*', (req, res) => {
|
||||
const ollamaPath = '/' + req.params[0]
|
||||
const isPost = req.method === 'POST'
|
||||
const bodyStr = isPost ? JSON.stringify(req.body) : null
|
||||
|
||||
const options = {
|
||||
hostname: '127.0.0.1',
|
||||
port: 11434,
|
||||
path: ollamaPath,
|
||||
method: req.method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}
|
||||
|
||||
const proxyReq = http.request(options, (proxyRes) => {
|
||||
res.writeHead(proxyRes.statusCode, proxyRes.headers)
|
||||
proxyRes.pipe(res)
|
||||
})
|
||||
|
||||
proxyReq.on('error', (err) => {
|
||||
const msg = err.message || err.code || 'Ollama not available'
|
||||
console.error('[Ollama Proxy] Error:', msg)
|
||||
if (!res.headersSent) {
|
||||
res.status(502).json({ error: msg })
|
||||
}
|
||||
})
|
||||
|
||||
if (bodyStr) proxyReq.write(bodyStr)
|
||||
proxyReq.end()
|
||||
})
|
||||
|
||||
// Web search stub (no search engine configured in demo)
|
||||
app.get('/api/web-search', (req, res) => {
|
||||
res.json({ results: [] })
|
||||
|
||||
Reference in New Issue
Block a user