akhaliq HF Staff commited on
Commit
ebdc25f
·
1 Parent(s): c6abd4e

Fix empty Language and AI Model dropdowns

Browse files

- Update CORS configuration to allow HuggingFace Space domain and use regex for *.hf.space
- Improve API URL logic in frontend to correctly detect production vs dev environment
- Fix EventSource and WebSocket URL construction to work in both environments
- Allow requests from localhost:7860 for Docker Space internal communication

Files changed (2) hide show
  1. backend_api.py +11 -2
  2. frontend/src/lib/api.ts +37 -15
backend_api.py CHANGED
@@ -34,13 +34,22 @@ LANGUAGE_CHOICES = ["html", "gradio", "transformers.js", "streamlit", "comfyui",
34
 
35
  app = FastAPI(title="AnyCoder API", version="1.0.0")
36
 
37
- # Configure CORS
 
 
 
 
 
 
 
 
38
  app.add_middleware(
39
  CORSMiddleware,
40
- allow_origins=["http://localhost:3000", "http://localhost:3001"], # Frontend URLs
41
  allow_credentials=True,
42
  allow_methods=["*"],
43
  allow_headers=["*"],
 
44
  )
45
 
46
  # OAuth configuration
 
34
 
35
  app = FastAPI(title="AnyCoder API", version="1.0.0")
36
 
37
+ # Configure CORS - allow all origins in production, specific in dev
38
+ # In Docker Space, requests come from the same domain via Next.js proxy
39
+ ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "*").split(",") if os.getenv("ALLOWED_ORIGINS") else [
40
+ "http://localhost:3000",
41
+ "http://localhost:3001",
42
+ "http://localhost:7860",
43
+ f"https://{SPACE_HOST}" if SPACE_HOST and not SPACE_HOST.startswith("localhost") else "http://localhost:7860"
44
+ ]
45
+
46
  app.add_middleware(
47
  CORSMiddleware,
48
+ allow_origins=ALLOWED_ORIGINS if ALLOWED_ORIGINS != ["*"] else ["*"],
49
  allow_credentials=True,
50
  allow_methods=["*"],
51
  allow_headers=["*"],
52
+ allow_origin_regex=r"https://.*\.hf\.space" if os.getenv("SPACE_HOST") else None,
53
  )
54
 
55
  # OAuth configuration
frontend/src/lib/api.ts CHANGED
@@ -11,11 +11,29 @@ import type {
11
  } from '@/types';
12
 
13
  // Use relative URLs in production (Next.js rewrites will proxy to backend)
14
- // In local dev without rewrites, use localhost:8000
15
- const API_URL = process.env.NEXT_PUBLIC_API_URL ||
16
- (typeof window !== 'undefined' && window.location.hostname !== 'localhost'
17
- ? '' // Use relative URLs in production (proxied by Next.js)
18
- : 'http://localhost:8000'); // Local development
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  class ApiClient {
21
  private client: AxiosInstance;
@@ -82,15 +100,17 @@ class ApiClient {
82
  onComplete: (code: string) => void,
83
  onError: (error: string) => void
84
  ): () => void {
85
- const url = new URL('/api/generate', API_URL);
86
- const eventSource = new EventSource(
87
- url.toString() + '?' + new URLSearchParams({
88
- query: request.query,
89
- language: request.language,
90
- model_id: request.model_id,
91
- provider: request.provider,
92
- })
93
- );
 
 
94
 
95
  eventSource.onmessage = (event) => {
96
  try {
@@ -129,7 +149,9 @@ class ApiClient {
129
  onComplete: (code: string) => void,
130
  onError: (error: string) => void
131
  ): WebSocket {
132
- const wsUrl = API_URL.replace('http', 'ws') + '/ws/generate';
 
 
133
  const ws = new WebSocket(wsUrl);
134
 
135
  ws.onopen = () => {
 
11
  } from '@/types';
12
 
13
  // Use relative URLs in production (Next.js rewrites will proxy to backend)
14
+ // In local dev, use localhost:8000 for direct backend access
15
+ const getApiUrl = () => {
16
+ // If explicitly set via env var, use it
17
+ if (process.env.NEXT_PUBLIC_API_URL) {
18
+ return process.env.NEXT_PUBLIC_API_URL;
19
+ }
20
+
21
+ // For server-side rendering, always use relative URLs
22
+ if (typeof window === 'undefined') {
23
+ return '';
24
+ }
25
+
26
+ // On localhost (dev mode), use direct backend URL
27
+ const hostname = window.location.hostname;
28
+ if (hostname === 'localhost' || hostname === '127.0.0.1') {
29
+ return 'http://localhost:8000';
30
+ }
31
+
32
+ // In production (HF Space), use relative URLs (Next.js proxies to backend)
33
+ return '';
34
+ };
35
+
36
+ const API_URL = getApiUrl();
37
 
38
  class ApiClient {
39
  private client: AxiosInstance;
 
100
  onComplete: (code: string) => void,
101
  onError: (error: string) => void
102
  ): () => void {
103
+ // Build the URL correctly whether we have a base URL or not
104
+ const baseUrl = API_URL || window.location.origin;
105
+ const url = new URL('/api/generate', baseUrl);
106
+ url.search = new URLSearchParams({
107
+ query: request.query,
108
+ language: request.language,
109
+ model_id: request.model_id,
110
+ provider: request.provider,
111
+ }).toString();
112
+
113
+ const eventSource = new EventSource(url.toString());
114
 
115
  eventSource.onmessage = (event) => {
116
  try {
 
149
  onComplete: (code: string) => void,
150
  onError: (error: string) => void
151
  ): WebSocket {
152
+ // Build WebSocket URL correctly for both dev and production
153
+ const baseUrl = API_URL || window.location.origin;
154
+ const wsUrl = baseUrl.replace('http', 'ws') + '/ws/generate';
155
  const ws = new WebSocket(wsUrl);
156
 
157
  ws.onopen = () => {