Spaces:
Running
Running
Update Dockerfile
Browse files- Dockerfile +59 -76
Dockerfile
CHANGED
@@ -156,111 +156,94 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
156 |
});
|
157 |
EOF
|
158 |
|
159 |
-
#
|
160 |
-
COPY <<"EOF" /app/
|
161 |
-
from flask import Flask, request, jsonify, render_template
|
162 |
-
from
|
163 |
-
from werkzeug.security import generate_password_hash
|
164 |
-
import os
|
165 |
import sqlite3
|
166 |
-
from pathlib import Path
|
167 |
import subprocess
|
168 |
-
import requests
|
169 |
-
from waitress import serve
|
170 |
import threading
|
171 |
-
import
|
|
|
172 |
|
173 |
-
app = Flask(__name__,
|
174 |
-
|
175 |
-
static_folder='/app/admin/static',
|
176 |
-
template_folder='/app/admin/templates')
|
177 |
-
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
178 |
-
app.secret_key = os.getenv("FLASK_SECRET")
|
179 |
|
180 |
# Database setup
|
181 |
-
DB_PATH = '/app/data/admin.db'
|
182 |
-
|
183 |
def get_db():
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
189 |
|
190 |
-
#
|
191 |
-
@app.route('/admin')
|
192 |
@app.route('/sudo')
|
193 |
-
def
|
194 |
return render_template('login.html')
|
195 |
|
196 |
-
@app.route('/admin/login', methods=['POST'])
|
197 |
@app.route('/sudo/login', methods=['POST'])
|
198 |
def login():
|
199 |
if request.json.get('sudo_secret') == os.getenv("SUDO_SECRET"):
|
200 |
return jsonify({
|
201 |
-
"status": "success",
|
202 |
-
"token": os.getenv("SUDO_SECRET")
|
203 |
-
"redirect": "/admin/dashboard"
|
204 |
})
|
205 |
-
return jsonify({"error": "Invalid
|
206 |
|
207 |
-
@app.route('/admin/dashboard')
|
208 |
@app.route('/sudo/dashboard')
|
209 |
def dashboard():
|
210 |
return render_template('dashboard.html')
|
211 |
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
# ===== LibreChat Proxy =====
|
220 |
-
def is_librechat_ready():
|
221 |
try:
|
222 |
-
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
-
@app.route('/',
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
if path.startswith(('admin/', 'sudo/', 'admin', 'sudo')):
|
231 |
-
return "Route not found", 404
|
232 |
-
|
233 |
-
# Wait for backend
|
234 |
-
if not is_librechat_ready():
|
235 |
-
return "LibreChat backend starting...", 503
|
236 |
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
)
|
246 |
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
response.headers[k] = v
|
252 |
-
return response
|
253 |
|
|
|
254 |
def start_librechat():
|
255 |
-
subprocess.
|
|
|
|
|
256 |
|
|
|
257 |
if __name__ == "__main__":
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
# Start server
|
262 |
-
print("Starting combined server on port 7860")
|
263 |
-
serve(app, host='0.0.0.0', port=7860, threads=4)
|
264 |
EOF
|
265 |
|
266 |
# Startup script
|
|
|
156 |
});
|
157 |
EOF
|
158 |
|
159 |
+
# 3. Create the Python server
|
160 |
+
COPY <<"EOF" /app/server.py
|
161 |
+
from flask import Flask, request, jsonify, render_template
|
162 |
+
from waitress import serve
|
|
|
|
|
163 |
import sqlite3
|
|
|
164 |
import subprocess
|
|
|
|
|
165 |
import threading
|
166 |
+
import os
|
167 |
+
from werkzeug.security import generate_password_hash
|
168 |
|
169 |
+
app = Flask(__name__, template_folder='/app/admin/templates')
|
170 |
+
app.secret_key = os.getenv("FLASK_SECRET", "secret-key-123")
|
|
|
|
|
|
|
|
|
171 |
|
172 |
# Database setup
|
|
|
|
|
173 |
def get_db():
|
174 |
+
conn = sqlite3.connect('/app/data/users.db')
|
175 |
+
conn.execute('''
|
176 |
+
CREATE TABLE IF NOT EXISTS users (
|
177 |
+
username TEXT PRIMARY KEY,
|
178 |
+
password TEXT,
|
179 |
+
role TEXT DEFAULT 'user'
|
180 |
+
)
|
181 |
+
''')
|
182 |
+
return conn
|
183 |
|
184 |
+
# Admin routes
|
|
|
185 |
@app.route('/sudo')
|
186 |
+
def admin_login():
|
187 |
return render_template('login.html')
|
188 |
|
|
|
189 |
@app.route('/sudo/login', methods=['POST'])
|
190 |
def login():
|
191 |
if request.json.get('sudo_secret') == os.getenv("SUDO_SECRET"):
|
192 |
return jsonify({
|
193 |
+
"status": "success",
|
194 |
+
"token": os.getenv("SUDO_SECRET")
|
|
|
195 |
})
|
196 |
+
return jsonify({"error": "Invalid password"}), 403
|
197 |
|
|
|
198 |
@app.route('/sudo/dashboard')
|
199 |
def dashboard():
|
200 |
return render_template('dashboard.html')
|
201 |
|
202 |
+
@app.route('/sudo/add_user', methods=['POST'])
|
203 |
+
def add_user():
|
204 |
+
if request.headers.get('X-Sudo-Secret') != os.getenv("SUDO_SECRET"):
|
205 |
+
return jsonify({"error": "Unauthorized"}), 403
|
206 |
+
|
207 |
+
db = get_db()
|
|
|
|
|
|
|
208 |
try:
|
209 |
+
db.execute(
|
210 |
+
"INSERT INTO users (username, password) VALUES (?, ?)",
|
211 |
+
[request.json["username"], generate_password_hash(request.json["password"])]
|
212 |
+
)
|
213 |
+
db.commit()
|
214 |
+
return jsonify({"status": "User added"})
|
215 |
+
except sqlite3.IntegrityError:
|
216 |
+
return jsonify({"error": "User exists"}), 400
|
217 |
|
218 |
+
@app.route('/sudo/list_users', methods=['GET'])
|
219 |
+
def list_users():
|
220 |
+
if request.headers.get('X-Sudo-Secret') != os.getenv("SUDO_SECRET"):
|
221 |
+
return jsonify({"error": "Unauthorized"}), 403
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
|
223 |
+
db = get_db()
|
224 |
+
users = db.execute("SELECT username FROM users").fetchall()
|
225 |
+
return jsonify([{"username": u[0]} for u in users])
|
226 |
+
|
227 |
+
@app.route('/sudo/remove_user', methods=['POST'])
|
228 |
+
def remove_user():
|
229 |
+
if request.headers.get('X-Sudo-Secret') != os.getenv("SUDO_SECRET"):
|
230 |
+
return jsonify({"error": "Unauthorized"}), 403
|
|
|
231 |
|
232 |
+
db = get_db()
|
233 |
+
db.execute("DELETE FROM users WHERE username = ?", [request.json["username"]])
|
234 |
+
db.commit()
|
235 |
+
return jsonify({"status": "User deleted"})
|
|
|
|
|
236 |
|
237 |
+
# Start LibreChat in background
|
238 |
def start_librechat():
|
239 |
+
subprocess.run(["npm", "run", "backend"], cwd="/app")
|
240 |
+
|
241 |
+
threading.Thread(target=start_librechat, daemon=True).start()
|
242 |
|
243 |
+
# Start server
|
244 |
if __name__ == "__main__":
|
245 |
+
print("Admin panel: http://localhost:7860/sudo")
|
246 |
+
serve(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
|
|
|
247 |
EOF
|
248 |
|
249 |
# Startup script
|