PHhTTPS commited on
Commit
7dbf588
·
1 Parent(s): d72bfb3

Final Stack: Go Proxy on 7860

Browse files
Files changed (2) hide show
  1. Dockerfile +25 -23
  2. static/status.html +7 -20
Dockerfile CHANGED
@@ -1,49 +1,51 @@
1
- # 1. Schritt: Wir bauen den Go-Proxy (CLIProxyAPIPlus)
2
  FROM golang:1.24-alpine AS builder
3
  WORKDIR /app
4
  COPY . .
5
  RUN go mod download
6
  RUN CGO_ENABLED=0 GOOS=linux go build -o /app/cliproxy ./cmd/server/
7
 
8
- # 2. Schritt: Clean Runtime
9
- FROM debian:bookworm-slim
10
-
11
- # Cache Buster
12
- ENV BUILD_ID=123456789
13
 
14
  USER root
15
 
16
- # Install dependencies
17
- RUN apt-get update && apt-get install -y python3-pip curl && rm -rf /var/lib/apt/lists/*
 
 
18
 
19
- # Proxy und Config kopieren
20
  COPY --from=builder /app/cliproxy /usr/local/bin/cliproxy
21
  COPY config.yaml /etc/cliproxy/config.yaml
22
  COPY static /etc/cliproxy/static
23
 
24
- # Free APIs Proxy kopieren
25
- # COPY freeapis-proxy /app/freeapis-proxy
26
- # WORKDIR /app/freeapis-proxy
27
- # RUN pip3 install --break-system-packages -r requirements.txt || pip3 install -r requirements.txt
28
 
29
- # Force static path via environment variable
30
  ENV MANAGEMENT_STATIC_PATH=/etc/cliproxy/static
31
 
32
  WORKDIR /app
33
  RUN mkdir -p /app/auth && chmod 777 /app/auth
34
 
35
- # Start-Skript
 
 
 
 
36
  RUN echo "#!/bin/bash" > /start.sh && \
37
- echo "# Fix config for local usage in HF Space" >> /start.sh && \
38
  echo "sed -i 's/freeapis-proxy:5001/localhost:5001/g' /etc/cliproxy/config.yaml" >> /start.sh && \
39
- echo "echo 'Locating status.html:'" >> /start.sh && \
40
- echo "find /etc/cliproxy -name status.html" >> /start.sh && \
41
- # echo "Starting Free APIs Proxy..." >> /start.sh && \
42
- # echo "cd /app/freeapis-proxy && PORT=5001 python3 server.py > /tmp/freeapis.log 2>&1 &" >> /start.sh && \
43
- echo "Starting CLI Proxy on Port 8080..." >> /start.sh && \
44
- echo "exec /usr/local/bin/cliproxy -config /etc/cliproxy/config.yaml -port 8080" >> /start.sh && \
45
  chmod +x /start.sh
46
 
47
- EXPOSE 8080
48
 
49
  ENTRYPOINT ["/start.sh"]
 
1
+ # 1. Build Go Proxy
2
  FROM golang:1.24-alpine AS builder
3
  WORKDIR /app
4
  COPY . .
5
  RUN go mod download
6
  RUN CGO_ENABLED=0 GOOS=linux go build -o /app/cliproxy ./cmd/server/
7
 
8
+ # 2. Runtime (Puter Base)
9
+ FROM heyputer/puter:latest
 
 
 
10
 
11
  USER root
12
 
13
+ # Install dependencies for Python proxy
14
+ RUN if command -v apt-get >/dev/null; then \
15
+ apt-get update && apt-get install -y python3-pip curl procps && rm -rf /var/lib/apt/lists/*; \
16
+ fi
17
 
18
+ # Copy Go Proxy & Assets
19
  COPY --from=builder /app/cliproxy /usr/local/bin/cliproxy
20
  COPY config.yaml /etc/cliproxy/config.yaml
21
  COPY static /etc/cliproxy/static
22
 
23
+ # Setup Free APIs Proxy
24
+ COPY freeapis-proxy /app/freeapis-proxy
25
+ WORKDIR /app/freeapis-proxy
26
+ RUN pip3 install --break-system-packages -r requirements.txt || pip3 install -r requirements.txt
27
 
28
+ # Environment Variables
29
  ENV MANAGEMENT_STATIC_PATH=/etc/cliproxy/static
30
 
31
  WORKDIR /app
32
  RUN mkdir -p /app/auth && chmod 777 /app/auth
33
 
34
+ # Startup Script
35
+ # 1. Fix config to use localhost
36
+ # 2. Start FreeAPIs Proxy (Background, Port 5001)
37
+ # 3. Start Puter (Background, Port 8081 - Internal)
38
+ # 4. Start Go Proxy (Foreground, Port 7860 - Public)
39
  RUN echo "#!/bin/bash" > /start.sh && \
 
40
  echo "sed -i 's/freeapis-proxy:5001/localhost:5001/g' /etc/cliproxy/config.yaml" >> /start.sh && \
41
+ echo "echo 'Starting Free APIs Proxy (5001)...'" >> /start.sh && \
42
+ echo "cd /app/freeapis-proxy && PORT=5001 python3 server.py > /tmp/freeapis.log 2>&1 &" >> /start.sh && \
43
+ echo "echo 'Starting Puter (8081)...'" >> /start.sh && \
44
+ echo "PORT=8081 python3 /opt/puter/puter/server.py --port 8081 > /tmp/puter.log 2>&1 &" >> /start.sh && \
45
+ echo "echo 'Starting Go Proxy (7860)...'" >> /start.sh && \
46
+ echo "exec /usr/local/bin/cliproxy -config /etc/cliproxy/config.yaml -port 7860" >> /start.sh && \
47
  chmod +x /start.sh
48
 
49
+ EXPOSE 7860
50
 
51
  ENTRYPOINT ["/start.sh"]
static/status.html CHANGED
@@ -1,3 +1,4 @@
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
@@ -88,7 +89,7 @@
88
  .modal-overlay {
89
  position: fixed;
90
  top: 0; left: 0; right: 0; bottom: 0;
91
- background: rgba(0,0,0,0.9); /* Darker background to hide content */
92
  display: flex;
93
  align-items: center;
94
  justify-content: center;
@@ -184,22 +185,18 @@
184
  </div>
185
 
186
  <script>
 
187
  const API_BASE = "/v0/management";
188
 
189
  function getKey() {
190
  return localStorage.getItem("managementKey");
191
  }
192
 
193
- // Initialize: Check auth immediately
194
  function init() {
195
  const key = getKey();
196
  if (key) {
197
- // If we have a key, hide the login screen and fetch data
198
  document.getElementById('login-modal').classList.add('hidden');
199
  fetchData();
200
- } else {
201
- // No key? The login modal is visible by default.
202
- console.log("No auth key found, waiting for login...");
203
  }
204
  }
205
 
@@ -214,7 +211,6 @@
214
  btn.innerText = "Checking...";
215
  btn.disabled = true;
216
 
217
- // Test the key
218
  try {
219
  const res = await fetch(API_BASE + "/config", {
220
  headers: { "Authorization": "Bearer " + key }
@@ -230,7 +226,7 @@
230
  }
231
  } catch (err) {
232
  console.error(err);
233
- showLoginError("Connection failed: " + err.message);
234
  } finally {
235
  btn.innerText = originalText;
236
  btn.disabled = false;
@@ -251,26 +247,21 @@
251
 
252
  async function fetchData() {
253
  const key = getKey();
254
- if (!key) return; // Should be handled by init, but double check
255
 
256
  const headers = { "Authorization": "Bearer " + key };
257
 
258
  try {
259
- // Parallel fetch
260
  const [configRes, usageRes] = await Promise.all([
261
  fetch(API_BASE + "/config", { headers }),
262
  fetch(API_BASE + "/usage", { headers })
263
  ]);
264
 
265
  if (configRes.status === 401 || usageRes.status === 401) {
266
- handleLogout(); // Auto logout on invalid token
267
  return;
268
  }
269
 
270
- if (!configRes.ok || !usageRes.ok) {
271
- throw new Error("API Error");
272
- }
273
-
274
  const config = await configRes.json();
275
  const usage = await usageRes.json();
276
 
@@ -308,7 +299,6 @@
308
  function renderProviders(config, usage) {
309
  let html = "<table><thead><tr><th>Provider / Model</th><th>Type</th><th>Key Configured</th></tr></thead><tbody>";
310
 
311
- // OpenAI Compatibility
312
  if (config.openaiCompatibility) {
313
  config.openaiCompatibility.forEach(p => {
314
  html += `<tr>
@@ -319,7 +309,6 @@
319
  });
320
  }
321
 
322
- // Gemini
323
  if (config.geminiApiKeys) {
324
  html += `<tr>
325
  <td>Gemini (Google)</td>
@@ -328,7 +317,6 @@
328
  </tr>`;
329
  }
330
 
331
- // Free APIs
332
  if (config.freeapis && config.freeapis.enabled) {
333
  html += `<tr>
334
  <td>Free APIs (g4f/Cohere)</td>
@@ -345,8 +333,7 @@
345
  document.getElementById("activity-log").innerHTML = "<p>Check logs for detailed activity.</p>";
346
  }
347
 
348
- // Start everything
349
  document.addEventListener('DOMContentLoaded', init);
350
  </script>
351
  </body>
352
- </html>
 
1
+ <!-- Build Trigger: 1 -->
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
 
89
  .modal-overlay {
90
  position: fixed;
91
  top: 0; left: 0; right: 0; bottom: 0;
92
+ background: rgba(0,0,0,0.9);
93
  display: flex;
94
  align-items: center;
95
  justify-content: center;
 
185
  </div>
186
 
187
  <script>
188
+ // Serving from /v0/management/status.html
189
  const API_BASE = "/v0/management";
190
 
191
  function getKey() {
192
  return localStorage.getItem("managementKey");
193
  }
194
 
 
195
  function init() {
196
  const key = getKey();
197
  if (key) {
 
198
  document.getElementById('login-modal').classList.add('hidden');
199
  fetchData();
 
 
 
200
  }
201
  }
202
 
 
211
  btn.innerText = "Checking...";
212
  btn.disabled = true;
213
 
 
214
  try {
215
  const res = await fetch(API_BASE + "/config", {
216
  headers: { "Authorization": "Bearer " + key }
 
226
  }
227
  } catch (err) {
228
  console.error(err);
229
+ showLoginError("Connection failed");
230
  } finally {
231
  btn.innerText = originalText;
232
  btn.disabled = false;
 
247
 
248
  async function fetchData() {
249
  const key = getKey();
250
+ if (!key) return;
251
 
252
  const headers = { "Authorization": "Bearer " + key };
253
 
254
  try {
 
255
  const [configRes, usageRes] = await Promise.all([
256
  fetch(API_BASE + "/config", { headers }),
257
  fetch(API_BASE + "/usage", { headers })
258
  ]);
259
 
260
  if (configRes.status === 401 || usageRes.status === 401) {
261
+ handleLogout();
262
  return;
263
  }
264
 
 
 
 
 
265
  const config = await configRes.json();
266
  const usage = await usageRes.json();
267
 
 
299
  function renderProviders(config, usage) {
300
  let html = "<table><thead><tr><th>Provider / Model</th><th>Type</th><th>Key Configured</th></tr></thead><tbody>";
301
 
 
302
  if (config.openaiCompatibility) {
303
  config.openaiCompatibility.forEach(p => {
304
  html += `<tr>
 
309
  });
310
  }
311
 
 
312
  if (config.geminiApiKeys) {
313
  html += `<tr>
314
  <td>Gemini (Google)</td>
 
317
  </tr>`;
318
  }
319
 
 
320
  if (config.freeapis && config.freeapis.enabled) {
321
  html += `<tr>
322
  <td>Free APIs (g4f/Cohere)</td>
 
333
  document.getElementById("activity-log").innerHTML = "<p>Check logs for detailed activity.</p>";
334
  }
335
 
 
336
  document.addEventListener('DOMContentLoaded', init);
337
  </script>
338
  </body>
339
+ </html>