NeerajCodz Copilot commited on
Commit
715b529
·
1 Parent(s): 7d51cb2

fix: satisfy openenv multi-mode validation

Browse files

Add root pyproject.toml and uv.lock with server script + openenv-core dependency, and expose server.app:main entrypoint for validator checks.

Also harden frontend health status handling to avoid false offline state when health responses vary by status text/content-type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

frontend/src/api/client.ts CHANGED
@@ -273,11 +273,21 @@ export const apiClient = {
273
 
274
  // Health Check
275
  async healthCheck(): Promise<{ status: string; version: string }> {
276
- const response = await fetch(`${API_BASE}/health`);
277
  if (!response.ok) {
278
  throw new APIError('Health check failed', response.status);
279
  }
280
- return response.json();
 
 
 
 
 
 
 
 
 
 
281
  },
282
 
283
  // Scraping with streaming
 
273
 
274
  // Health Check
275
  async healthCheck(): Promise<{ status: string; version: string }> {
276
+ const response = await fetch(`${API_BASE}/health`, { cache: 'no-store' });
277
  if (!response.ok) {
278
  throw new APIError('Health check failed', response.status);
279
  }
280
+ const contentType = response.headers.get('content-type') || '';
281
+ if (contentType.includes('application/json')) {
282
+ return response.json();
283
+ }
284
+
285
+ const text = await response.text();
286
+ try {
287
+ return JSON.parse(text) as { status: string; version: string };
288
+ } catch {
289
+ return { status: 'healthy', version: 'unknown' };
290
+ }
291
  },
292
 
293
  // Scraping with streaming
frontend/src/components/Dashboard.tsx CHANGED
@@ -490,7 +490,7 @@ export const Dashboard: React.FC = () => {
490
  const [stats, setStats] = useState({ episodes: 0, steps: 0, totalReward: 0, avgReward: 0 });
491
 
492
  // API Queries
493
- const { data: health } = useQuery({
494
  queryKey: ['health'],
495
  queryFn: () => apiClient.healthCheck(),
496
  refetchInterval: 5000,
@@ -863,7 +863,15 @@ export const Dashboard: React.FC = () => {
863
  };
864
 
865
  // Check system status
866
- const isSystemOnline = health?.status === 'healthy';
 
 
 
 
 
 
 
 
867
 
868
  // Show info popup
869
  const showInfo = (title: string, description: string, details?: Record<string, string>) => {
 
490
  const [stats, setStats] = useState({ episodes: 0, steps: 0, totalReward: 0, avgReward: 0 });
491
 
492
  // API Queries
493
+ const { data: health, isError: healthError } = useQuery({
494
  queryKey: ['health'],
495
  queryFn: () => apiClient.healthCheck(),
496
  refetchInterval: 5000,
 
863
  };
864
 
865
  // Check system status
866
+ const normalizedHealthStatus = typeof health?.status === 'string'
867
+ ? health.status.toLowerCase()
868
+ : null;
869
+ const isSystemOnline = !healthError && (
870
+ normalizedHealthStatus === null
871
+ || normalizedHealthStatus === 'healthy'
872
+ || normalizedHealthStatus === 'ok'
873
+ || normalizedHealthStatus === 'ready'
874
+ );
875
 
876
  // Show info popup
877
  const showInfo = (title: string, description: string, details?: Record<string, string>) => {
frontend/src/components/Settings.tsx CHANGED
@@ -101,6 +101,14 @@ export const Settings: React.FC<SettingsProps> = ({ className }) => {
101
  refetchInterval: 10000,
102
  });
103
 
 
 
 
 
 
 
 
 
104
  // Mutation to update API key
105
  const updateApiKeyMutation = useMutation({
106
  mutationFn: async ({ provider, api_key }: { provider: string; api_key: string }) => {
@@ -223,7 +231,7 @@ export const Settings: React.FC<SettingsProps> = ({ className }) => {
223
  <span className="text-xs text-gray-400">Backend</span>
224
  </div>
225
  <p className="text-sm font-medium text-white mt-1">
226
- {health?.status === 'ok' ? 'Connected' : 'Disconnected'}
227
  </p>
228
  </div>
229
  <div className="p-3 bg-gray-900/50 rounded-lg">
@@ -588,8 +596,8 @@ export const Settings: React.FC<SettingsProps> = ({ className }) => {
588
  {/* Status Footer */}
589
  <div className="p-4 border-t border-gray-700/50">
590
  <div className="flex items-center gap-2">
591
- <div className={classNames('w-2 h-2 rounded-full', health?.status === 'ok' ? 'bg-emerald-400' : 'bg-red-400')} />
592
- <span className="text-xs text-gray-400">{health?.status === 'ok' ? 'System Online' : 'System Offline'}</span>
593
  </div>
594
  </div>
595
  </div>
 
101
  refetchInterval: 10000,
102
  });
103
 
104
+ const normalizedHealthStatus = typeof health?.status === 'string'
105
+ ? health.status.toLowerCase()
106
+ : '';
107
+ const isBackendOnline =
108
+ normalizedHealthStatus === 'healthy'
109
+ || normalizedHealthStatus === 'ok'
110
+ || normalizedHealthStatus === 'ready';
111
+
112
  // Mutation to update API key
113
  const updateApiKeyMutation = useMutation({
114
  mutationFn: async ({ provider, api_key }: { provider: string; api_key: string }) => {
 
231
  <span className="text-xs text-gray-400">Backend</span>
232
  </div>
233
  <p className="text-sm font-medium text-white mt-1">
234
+ {isBackendOnline ? 'Connected' : 'Disconnected'}
235
  </p>
236
  </div>
237
  <div className="p-3 bg-gray-900/50 rounded-lg">
 
596
  {/* Status Footer */}
597
  <div className="p-4 border-t border-gray-700/50">
598
  <div className="flex items-center gap-2">
599
+ <div className={classNames('w-2 h-2 rounded-full', isBackendOnline ? 'bg-emerald-400' : 'bg-red-400')} />
600
+ <span className="text-xs text-gray-400">{isBackendOnline ? 'System Online' : 'System Offline'}</span>
601
  </div>
602
  </div>
603
  </div>
pyproject.toml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "scraperl-openenv"
7
+ version = "0.1.0"
8
+ description = "ScrapeRL OpenEnv-compatible environment package"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "openenv-core>=0.2.0",
13
+ "fastapi>=0.109.0",
14
+ "uvicorn[standard]>=0.27.0",
15
+ ]
16
+
17
+ [project.scripts]
18
+ server = "server.app:main"
19
+
server/app.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
 
5
  import sys
6
  from pathlib import Path
7
 
@@ -11,3 +12,16 @@ if str(BACKEND_DIR) not in sys.path:
11
 
12
  from app.main import app # noqa: E402,F401
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  from __future__ import annotations
4
 
5
+ import os
6
  import sys
7
  from pathlib import Path
8
 
 
12
 
13
  from app.main import app # noqa: E402,F401
14
 
15
+
16
+ def main() -> None:
17
+ """Run the FastAPI app for OpenEnv multi-mode validation."""
18
+ import uvicorn
19
+
20
+ host = os.getenv("HOST", "0.0.0.0")
21
+ port = int(os.getenv("PORT", "7860"))
22
+ uvicorn.run("server.app:app", host=host, port=port)
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
27
+
uv.lock ADDED
The diff for this file is too large to render. See raw diff