chore: add openai-bridge deployment script for Erik
This commit is contained in:
parent
7599f33866
commit
e128d39818
174
scripts/deploy-bridges.sh
Normal file
174
scripts/deploy-bridges.sh
Normal file
@ -0,0 +1,174 @@
|
||||
#!/bin/bash
|
||||
# Deploy OpenAI Bridge and other subscription services to Erik
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Deploying OpenAI Bridge to Erik ==="
|
||||
|
||||
# Create openai-bridge directory
|
||||
mkdir -p /opt/openai-bridge
|
||||
|
||||
# Create server.js for openai-bridge
|
||||
cat > /opt/openai-bridge/server.js << 'BRIDGE_EOF'
|
||||
import { execFile } from 'child_process'
|
||||
import { createServer } from 'http'
|
||||
import { promisify } from 'util'
|
||||
|
||||
const exec = promisify(execFile)
|
||||
const PORT = process.env.OPENAI_BRIDGE_PORT || 3251
|
||||
const API_KEY = process.env.OPENAI_API_KEY
|
||||
const DEFAULT_MODEL = process.env.OPENAI_MODEL || 'gpt-4-turbo'
|
||||
|
||||
const SYSTEM_CODEX = `You are an expert code generation AI.
|
||||
Generate clean, well-documented, production-ready code.
|
||||
Output only the code — no explanations, no markdown blocks, no preamble.`
|
||||
|
||||
const SYSTEM_CHATGPT = `You are a helpful AI assistant.
|
||||
Provide clear, concise, accurate responses.
|
||||
Output only the response — no preamble.`
|
||||
|
||||
async function callOpenAI(messages, model, temperature = 0.3, maxTokens = 2048) {
|
||||
if (!API_KEY) {
|
||||
throw new Error('OPENAI_API_KEY not configured')
|
||||
}
|
||||
|
||||
const args = [
|
||||
'api', 'chat.completions.create',
|
||||
'-m', model,
|
||||
'-t', String(temperature),
|
||||
'-M', String(maxTokens),
|
||||
]
|
||||
|
||||
for (const msg of messages) {
|
||||
args.push('-g', msg.role, msg.content)
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const env = {
|
||||
...process.env,
|
||||
OPENAI_API_KEY: API_KEY
|
||||
}
|
||||
|
||||
exec('openai', args, { env, timeout: 300_000, maxBuffer: 1024 * 1024 * 10 }, (err, stdout) => {
|
||||
if (err) {
|
||||
resolve({
|
||||
success: false,
|
||||
content: null,
|
||||
error: err.message.slice(0, 500),
|
||||
stderr: err.stderr?.slice(0, 500)
|
||||
})
|
||||
} else {
|
||||
try {
|
||||
const result = JSON.parse(stdout)
|
||||
const content = result.choices?.[0]?.message?.content || result.message?.content || stdout
|
||||
resolve({ success: true, content, error: null })
|
||||
} catch (e) {
|
||||
resolve({ success: true, content: stdout.trim(), error: null })
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
|
||||
|
||||
if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return }
|
||||
|
||||
if (req.method === 'GET' && req.url === '/health') {
|
||||
res.writeHead(200)
|
||||
res.end(JSON.stringify({
|
||||
status: 'ok',
|
||||
version: '1.0.0',
|
||||
provider: 'openai',
|
||||
model: DEFAULT_MODEL,
|
||||
configured: !!API_KEY
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
if (req.method === 'POST' && req.url === '/v1/chat/completions') {
|
||||
let body = ''
|
||||
req.on('data', chunk => body += chunk)
|
||||
req.on('end', async () => {
|
||||
try {
|
||||
const { model, messages, temperature, max_tokens, type } = JSON.parse(body)
|
||||
|
||||
if (!messages || !Array.isArray(messages)) {
|
||||
res.writeHead(400)
|
||||
res.end(JSON.stringify({ error: 'messages array required' }))
|
||||
return
|
||||
}
|
||||
|
||||
const selectedModel = model || DEFAULT_MODEL
|
||||
const temp = temperature ?? 0.3
|
||||
const maxTok = max_tokens ?? 2048
|
||||
|
||||
console.log(`[${new Date().toISOString()}] OpenAI ${selectedModel} (${type || 'chat'})`)
|
||||
|
||||
const result = await callOpenAI(messages, selectedModel, temp, maxTok)
|
||||
|
||||
if (result.success) {
|
||||
res.writeHead(200)
|
||||
res.end(JSON.stringify({
|
||||
success: true,
|
||||
content: result.content,
|
||||
provider: 'openai',
|
||||
model: selectedModel
|
||||
}))
|
||||
} else {
|
||||
res.writeHead(500)
|
||||
res.end(JSON.stringify({
|
||||
success: false,
|
||||
error: result.error,
|
||||
stderr: result.stderr
|
||||
}))
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error:', e.message)
|
||||
res.writeHead(500)
|
||||
res.end(JSON.stringify({ error: e.message }))
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify({ error: 'not found' }))
|
||||
})
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`openai-bridge running on port ${PORT}`)
|
||||
console.log(` POST http://localhost:${PORT}/v1/chat/completions`)
|
||||
console.log(` GET http://localhost:${PORT}/health`)
|
||||
console.log(` Model: ${DEFAULT_MODEL}`)
|
||||
console.log(` API Key configured: ${!!API_KEY}`)
|
||||
})
|
||||
BRIDGE_EOF
|
||||
|
||||
# Create package.json
|
||||
cat > /opt/openai-bridge/package.json << 'PACKAGE_EOF'
|
||||
{
|
||||
"name": "openai-bridge",
|
||||
"version": "1.0.0",
|
||||
"description": "OpenAI API bridge for ChatGPT and Codex integration",
|
||||
"type": "module",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"pm2": "pm2 start server.js --name openai-bridge"
|
||||
}
|
||||
}
|
||||
PACKAGE_EOF
|
||||
|
||||
echo "✓ openai-bridge deployed to /opt/openai-bridge"
|
||||
echo "✓ Ready for PM2 deployment"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Set OPENAI_API_KEY in ecosystem.config.cjs"
|
||||
echo "2. Run: pm2 start deploy/ecosystem.config.cjs --update-env"
|
||||
echo "3. Verify: pm2 status | grep openai-bridge"
|
||||
echo "4. Test: curl http://localhost:3251/health"
|
||||
Loading…
x
Reference in New Issue
Block a user