Skip to content

Commit abe8591

Browse files
authored
chore: remove unnecessary proxy layer (#234)
* Remove proxy layer in pages Signed-off-by: kerthcet <kerthcet@gmail.com> * Remove proxy layer Signed-off-by: kerthcet <kerthcet@gmail.com> --------- Signed-off-by: kerthcet <kerthcet@gmail.com>
1 parent b8806b2 commit abe8591

11 files changed

Lines changed: 105 additions & 127 deletions

File tree

alphatrion/server/cmd/main.py

Lines changed: 11 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
from importlib.metadata import PackageNotFoundError, version
1212
from pathlib import Path
1313

14-
import httpx
1514
import uvicorn
1615
from dotenv import load_dotenv
1716
from faker import Faker
18-
from fastapi import FastAPI, Request
19-
from fastapi.responses import FileResponse, Response
17+
from fastapi import FastAPI
18+
from fastapi.responses import FileResponse
2019
from fastapi.staticfiles import StaticFiles
2120
from rich.console import Console
2221
from rich.text import Text
@@ -49,19 +48,14 @@ def main():
4948
server.set_defaults(func=run_server)
5049

5150
dashboard = subparsers.add_parser(
52-
"dashboard", help="Launch the AlphaTrion web dashboard"
51+
"dashboard",
52+
help="Serve pre-built dashboard (for testing production builds locally)",
5353
)
5454
dashboard.add_argument(
5555
"--port",
5656
type=int,
5757
default=5173,
58-
help="Port to run the dashboard on (default: 5173)",
59-
)
60-
dashboard.add_argument(
61-
"--backend-url",
62-
type=str,
63-
default="http://localhost:8000",
64-
help="Backend server URL to proxy requests to (default: http://localhost:8000)",
58+
help="Port to serve the dashboard on (default: 5173)",
6559
)
6660
dashboard.set_defaults(func=start_dashboard)
6761

@@ -560,99 +554,29 @@ def start_dashboard(args):
560554
)
561555
console.print(msg)
562556
console.print(Text(f"📂 Serving static files from: {static_path}", style="dim"))
563-
564-
console.print(
565-
Text(f"🔗 Proxying backend requests to: {args.backend_url}", style="dim")
566-
)
567557
console.print()
568558
console.print(
569-
Text("💡 Note: Make sure the backend server is running:", style="bold yellow")
559+
Text(
560+
"💡 Note: Make sure the backend server is running at http://localhost:8000",
561+
style="bold yellow",
562+
)
570563
)
571-
console.print(Text(" alphatrion server", style="cyan"))
564+
console.print(Text(" Run: alphatrion server", style="cyan"))
572565
console.print()
573566

574567
app = FastAPI()
575568

576-
# Create HTTP client for proxying requests to backend
577-
http_client = httpx.AsyncClient(base_url=args.backend_url, timeout=30.0)
578-
579-
# Proxy /graphql requests to backend (MUST be before catch-all route)
580-
@app.api_route("/graphql", methods=["GET", "POST"])
581-
async def proxy_graphql(request: Request):
582-
headers = dict(request.headers)
583-
headers.pop("host", None) # Remove host header
584-
585-
try:
586-
response = await http_client.request(
587-
method=request.method,
588-
url="/graphql",
589-
content=await request.body(),
590-
headers=headers,
591-
)
592-
return Response(
593-
content=response.content,
594-
status_code=response.status_code,
595-
headers=dict(response.headers),
596-
)
597-
except Exception as e:
598-
console.print(Text(f"❌ Error connecting to backend: {e}", style="red"))
599-
return Response(
600-
content=f'{{"error": "Backend server not available. Make sure it\'s running at {args.backend_url}"}}',
601-
status_code=503,
602-
media_type="application/json",
603-
)
604-
605-
# Proxy /api requests to backend (MUST be before catch-all route)
606-
@app.api_route("/api/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
607-
async def proxy_api(path: str, request: Request):
608-
headers = dict(request.headers)
609-
headers.pop("host", None)
610-
611-
try:
612-
response = await http_client.request(
613-
method=request.method,
614-
url=f"/api/{path}",
615-
content=await request.body(),
616-
headers=headers,
617-
)
618-
return Response(
619-
content=response.content,
620-
status_code=response.status_code,
621-
headers=dict(response.headers),
622-
)
623-
except Exception as e:
624-
console.print(Text(f"❌ Error connecting to backend: {e}", style="red"))
625-
return Response(
626-
content='{"error": "Backend server not available"}',
627-
status_code=503,
628-
media_type="application/json",
629-
)
630-
631569
# Mount the entire static directory at /static
632570
app.mount("/static", StaticFiles(directory=static_path, html=True), name="static")
633571

634-
@app.get("/")
635-
def serve_root():
636-
# Serve index.html at root
637-
index_file = static_path / "index.html"
638-
if index_file.exists():
639-
return FileResponse(index_file)
640-
return {"error": "index.html not found"}
641-
572+
# SPA fallback: serve index.html for all routes (enables client-side routing)
642573
@app.get("/{full_path:path}")
643574
def spa_fallback(full_path: str):
644-
# Serve index.html for all routes (SPA fallback)
645-
# This enables client-side routing
646575
index_file = static_path / "index.html"
647576
if index_file.exists():
648577
return FileResponse(index_file)
649578
return {"error": "index.html not found"}
650579

651-
# Register cleanup handler for HTTP client
652-
@app.on_event("shutdown")
653-
async def shutdown_event():
654-
await http_client.aclose()
655-
656580
url = f"http://127.0.0.1:{args.port}"
657581

658582
console.print(Text(f"🌐 Dashboard URL: {url}", style="bold cyan"))

alphatrion/storage/runtime.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ def __init__(self):
7575
tracer_provider.add_span_processor(CostEnrichmentProcessor())
7676

7777
# 3. Add Prometheus exporter if enabled
78-
if os.getenv(envs.ENABLE_PROMETHEUS_EXPORTER, "false").lower() == "true":
78+
if (
79+
os.getenv(envs.ENABLE_PROMETHEUS_EXPORTER, "false").lower()
80+
== "true"
81+
):
7982
pushgateway_url = os.getenv(
8083
envs.PROMETHEUS_PUSHGATEWAY_URL, "localhost:9091"
8184
)

alphatrion/tracing/prometheus_exporter.py

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,14 @@ def _process_span(self, span: ReadableSpan):
206206
self.llm_errors_total.labels(error_type=error_type).inc()
207207

208208
self._process_llm_span(
209-
span, attributes, org_id, team_id, user_id, experiment_id, duration, status
209+
span,
210+
attributes,
211+
org_id,
212+
team_id,
213+
user_id,
214+
experiment_id,
215+
duration,
216+
status,
210217
)
211218

212219
except Exception as e:
@@ -272,7 +279,11 @@ def _process_llm_span(
272279

273280
if input_tokens > 0:
274281
self.llm_input_tokens_total.labels(
275-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
282+
org_id=org_id,
283+
team_id=team_id,
284+
user_id=user_id,
285+
experiment_id=experiment_id,
286+
model=model,
276287
).inc(input_tokens)
277288
self.llm_tokens_total.labels(
278289
org_id=org_id,
@@ -285,7 +296,11 @@ def _process_llm_span(
285296

286297
if output_tokens > 0:
287298
self.llm_output_tokens_total.labels(
288-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
299+
org_id=org_id,
300+
team_id=team_id,
301+
user_id=user_id,
302+
experiment_id=experiment_id,
303+
model=model,
289304
).inc(output_tokens)
290305
self.llm_tokens_total.labels(
291306
org_id=org_id,
@@ -298,7 +313,11 @@ def _process_llm_span(
298313

299314
if cache_read_input_tokens > 0:
300315
self.llm_cache_read_input_tokens_total.labels(
301-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
316+
org_id=org_id,
317+
team_id=team_id,
318+
user_id=user_id,
319+
experiment_id=experiment_id,
320+
model=model,
302321
).inc(cache_read_input_tokens)
303322
self.llm_tokens_total.labels(
304323
org_id=org_id,
@@ -311,7 +330,11 @@ def _process_llm_span(
311330

312331
if cache_creation_input_tokens > 0:
313332
self.llm_cache_creation_input_tokens_total.labels(
314-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
333+
org_id=org_id,
334+
team_id=team_id,
335+
user_id=user_id,
336+
experiment_id=experiment_id,
337+
model=model,
315338
).inc(cache_creation_input_tokens)
316339
self.llm_tokens_total.labels(
317340
org_id=org_id,
@@ -346,35 +369,60 @@ def _process_llm_span(
346369

347370
if input_cost > 0:
348371
self.llm_input_cost_total.labels(
349-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
372+
org_id=org_id,
373+
team_id=team_id,
374+
user_id=user_id,
375+
experiment_id=experiment_id,
376+
model=model,
350377
).inc(input_cost)
351378

352379
if output_cost > 0:
353380
self.llm_output_cost_total.labels(
354-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
381+
org_id=org_id,
382+
team_id=team_id,
383+
user_id=user_id,
384+
experiment_id=experiment_id,
385+
model=model,
355386
).inc(output_cost)
356387

357388
if cache_read_cost > 0:
358389
self.llm_cache_read_cost_total.labels(
359-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
390+
org_id=org_id,
391+
team_id=team_id,
392+
user_id=user_id,
393+
experiment_id=experiment_id,
394+
model=model,
360395
).inc(cache_read_cost)
361396

362397
if cache_creation_cost > 0:
363398
self.llm_cache_creation_cost_total.labels(
364-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
399+
org_id=org_id,
400+
team_id=team_id,
401+
user_id=user_id,
402+
experiment_id=experiment_id,
403+
model=model,
365404
).inc(cache_creation_cost)
366405

367406
except (ValueError, TypeError) as e:
368407
logger.debug(f"No cost data available for span: {e}")
369408

370409
# Request count
371410
self.llm_requests_total.labels(
372-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model, status=status
411+
org_id=org_id,
412+
team_id=team_id,
413+
user_id=user_id,
414+
experiment_id=experiment_id,
415+
model=model,
416+
status=status,
373417
).inc()
374418

375419
# Duration
376420
self.llm_request_duration_seconds.labels(
377-
org_id=org_id, team_id=team_id, user_id=user_id, experiment_id=experiment_id, model=model
421+
org_id=org_id,
422+
team_id=team_id,
423+
user_id=user_id,
424+
experiment_id=experiment_id,
425+
model=model,
378426
).observe(duration)
379427

380428
def _push_metrics(self):

charts/alphatrion/templates/ingress.yaml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,29 @@ spec:
2828
- host: {{ .host | quote }}
2929
http:
3030
paths:
31-
{{- range .paths }}
32-
- path: {{ .path }}
33-
pathType: {{ .pathType }}
31+
# API routes go to backend server
32+
- path: /api
33+
pathType: Prefix
34+
backend:
35+
service:
36+
name: {{ include "alphatrion.server.fullname" $ }}
37+
port:
38+
number: {{ $.Values.server.service.port }}
39+
# GraphQL routes go to backend server
40+
- path: /graphql
41+
pathType: Prefix
42+
backend:
43+
service:
44+
name: {{ include "alphatrion.server.fullname" $ }}
45+
port:
46+
number: {{ $.Values.server.service.port }}
47+
# Everything else (/, /static/*, SPA routes) goes to dashboard (static files)
48+
- path: /
49+
pathType: Prefix
3450
backend:
3551
service:
3652
name: {{ include "alphatrion.dashboard.fullname" $ }}
3753
port:
3854
number: {{ $.Values.dashboard.service.port }}
39-
{{- end }}
4055
{{- end }}
4156
{{- end }}

dashboard/src/components/layout/user-profile.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import { useTeamContext } from '../../context/team-context';
77
import { useOrganization } from '../../hooks/use-organization';
88
import { cn } from '../../lib/utils';
99

10-
// Use runtime config (Kubernetes) > build-time env (Docker) > relative URL (local dev with proxy)
10+
// Use runtime config (Kubernetes) > build-time env (Docker) > localhost dev
1111
const getApiBaseUrl = () => {
1212
// @ts-ignore - window.ENV is injected at runtime by entrypoint.sh
1313
if (typeof window !== 'undefined' && window.ENV?.VITE_API_URL) {
1414
// @ts-ignore
1515
return window.ENV.VITE_API_URL;
1616
}
17-
return import.meta.env.VITE_API_URL || '';
17+
return import.meta.env.VITE_API_URL || 'http://localhost:8000';
1818
};
1919

2020
export function UserProfile() {

dashboard/src/lib/graphql-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import axios from 'axios';
77
* with queries and mutations for teams, experiments, runs, and metrics.
88
*/
99

10-
// Use runtime config (Kubernetes) > build-time env (Docker) > relative URL (local dev with proxy)
10+
// Use runtime config (Kubernetes) > build-time env (Docker) > localhost dev
1111
const getApiBaseUrl = () => {
1212
// @ts-ignore - window.ENV is injected at runtime by entrypoint.sh
1313
if (typeof window !== 'undefined' && window.ENV?.VITE_API_URL) {
1414
// @ts-ignore
1515
return window.ENV.VITE_API_URL;
1616
}
17-
return import.meta.env.VITE_API_URL || '';
17+
return import.meta.env.VITE_API_URL || 'http://localhost:8000';
1818
};
1919

2020
const API_BASE_URL = getApiBaseUrl();

dashboard/src/pages/login.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { useState } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import logoImage from '../assets/logo.png';
44

5-
// Use runtime config (Kubernetes) > build-time env (Docker) > relative URL (local dev with proxy)
5+
// Use runtime config (Kubernetes) > build-time env (Docker) > localhost dev
66
const getApiBaseUrl = () => {
77
// @ts-ignore - window.ENV is injected at runtime by entrypoint.sh
88
if (typeof window !== 'undefined' && window.ENV?.VITE_API_URL) {
99
// @ts-ignore
1010
return window.ENV.VITE_API_URL;
1111
}
12-
return import.meta.env.VITE_API_URL || '';
12+
return import.meta.env.VITE_API_URL || 'http://localhost:8000';
1313
};
1414

1515
export function LoginPage() {

0 commit comments

Comments
 (0)