AILIXIR Bot commited on
Commit
e563279
·
1 Parent(s): c308fad

Auto-sync: b39e10c7605f8154aad9e7cc661051f7af2f4a81

Browse files
.github/workflows/integration-test-hf.yml CHANGED
@@ -12,110 +12,108 @@ concurrency:
12
  cancel-in-progress: true
13
 
14
  jobs:
15
- warmup-spaces:
16
  runs-on: ubuntu-latest
17
- timeout-minutes: 15
 
18
  steps:
 
 
 
19
  - name: Warm up ailixir-api Space
20
  run: |
21
  echo "Waiting for ailixir-api HF Space..."
22
  for i in $(seq 1 60); do
23
- if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/health > /dev/null 2>&1; then
24
- echo "✓ ailixir-api is up"
25
- break
 
26
  fi
27
  echo "Attempt $i/60..."
28
  sleep 5
29
  done
 
30
 
31
  - name: Warm up ailixir-drug-repurposing Space
32
  run: |
33
  echo "Waiting for ailixir-drug-repurposing HF Space..."
34
  for i in $(seq 1 60); do
35
  if curl -sf https://RottenShadow-ailixir-drug-repurposing.hf.space/health > /dev/null 2>&1; then
36
- echo "✓ ailixir-drug-repurposing is up"
37
- break
 
38
  fi
39
  echo "Attempt $i/60..."
40
  sleep 5
41
  done
 
42
 
43
  - name: Warm up ailixir-admet Space
44
  run: |
45
  echo "Waiting for ailixir-admet HF Space..."
46
  for i in $(seq 1 60); do
47
  if curl -sf https://shdwRow-ailixir-admet.hf.space/health > /dev/null 2>&1; then
48
- echo "✓ ailixir-admet is up"
49
- break
 
50
  fi
51
  echo "Attempt $i/60..."
52
  sleep 5
53
  done
 
54
 
55
  - name: Warm up ailixir-chemical-rag Space
56
  run: |
57
  echo "Waiting for ailixir-chemical-rag HF Space..."
58
  for i in $(seq 1 60); do
59
  if curl -sf https://RottenShadow-ailixir-chemical-rag.hf.space/health > /dev/null 2>&1; then
60
- echo "✓ ailixir-chemical-rag is up"
61
- break
 
62
  fi
63
  echo "Attempt $i/60..."
64
  sleep 5
65
  done
66
-
67
- core-ai-proxy:
68
- needs: warmup-spaces
69
- runs-on: ubuntu-latest
70
- timeout-minutes: 30
71
-
72
- steps:
73
- - name: Checkout
74
- uses: actions/checkout@v4
75
 
76
  - name: Login and get Bearer token
77
  run: |
78
  echo "POST /api/user/login"
79
- for attempt in {1..3}; do
80
- HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
81
- -H "Content-Type: application/json" \
82
- -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
83
- echo "HTTP Status: $HTTP_CODE (attempt $attempt/3)"
84
-
85
- if [ "$HTTP_CODE" = "200" ]; then
86
- python3 - <<'PY'
87
- import json, sys
88
- try:
89
- data = json.load(open("login.json"))
90
- except json.JSONDecodeError as e:
91
- print("Invalid JSON response:", e)
92
- with open("login.json") as f:
93
- print("Raw response:", f.read())
94
- sys.exit(1)
95
-
96
- if not data.get("success"):
97
- print("Login failed:", json.dumps(data, indent=2))
98
- sys.exit(1)
99
-
100
- token = data.get("data", {}).get("token")
101
- if not token:
102
- print("No token in response:", json.dumps(data, indent=2))
103
- sys.exit(1)
104
-
105
- with open("token.txt", "w") as f:
106
- f.write(token)
107
- print("✓ Login OK - token saved")
108
- PY
109
- if [ $? -eq 0 ]; then exit 0; fi
110
- fi
111
-
112
- if [ $attempt -lt 3 ]; then
113
- echo "Login attempt $attempt failed, retrying in 10s..."
114
- sleep 10
115
- fi
116
- done
117
- echo "Login failed after 3 attempts"
118
- exit 1
119
 
120
  - name: Test aggregated AI health via Laravel
121
  run: |
@@ -127,13 +125,13 @@ PY
127
  cat health.json
128
  echo ""
129
  python3 - <<'PY'
130
- import json, sys
131
- data = json.load(open("health.json"))
132
- if not data.get("success"):
133
- print("AI services health check failed:", json.dumps(data, indent=2))
134
- sys.exit(1)
135
- print("✓ All AI services healthy via Laravel proxy")
136
- PY
137
 
138
  - name: Test ADMET prediction via Laravel proxy
139
  run: |
@@ -153,26 +151,26 @@ PY
153
  fi
154
 
155
  python3 - <<'PY'
156
- import json, sys
157
- try:
158
- data = json.load(open("admet.json"))
159
- except json.JSONDecodeError as e:
160
- print("Invalid JSON response:", e)
161
- with open("admet.json") as f:
162
- print("Raw response:", f.read())
163
- sys.exit(1)
164
-
165
- if not data.get("success"):
166
- print("ADMET prediction test failed:", json.dumps(data, indent=2))
167
- sys.exit(1)
168
-
169
- results = data.get("data", {}).get("results", [])
170
- if len(results) < 3:
171
- print(f"Expected at least 3 results, got {len(results)}")
172
- sys.exit(1)
173
-
174
- print(f"✓ ADMET prediction OK - {len(results)} compounds processed")
175
- PY
176
 
177
  - name: Test Chemical RAG proxy via Laravel
178
  run: |
@@ -186,13 +184,13 @@ PY
186
  cat chemical.json
187
  echo ""
188
  python3 - <<'PY'
189
- import json, sys
190
- data = json.load(open("chemical.json"))
191
- if not data.get("success"):
192
- print("Chemical RAG proxy test failed:", json.dumps(data, indent=2))
193
- sys.exit(1)
194
- print("✓ Chemical RAG proxy OK")
195
- PY
196
 
197
  - name: Test Drug Repurposing proxy via Laravel
198
  run: |
@@ -204,16 +202,15 @@ PY
204
  cat drug.json
205
  echo ""
206
  python3 - <<'PY'
207
- import json, sys
208
- data = json.load(open("drug.json"))
209
- if not data.get("success"):
210
- print("Drug Repurposing proxy test failed:", json.dumps(data, indent=2))
211
- sys.exit(1)
212
- print("✓ Drug Repurposing proxy OK")
213
- PY
214
 
215
  chemical-search:
216
- needs: warmup-spaces
217
  runs-on: ubuntu-latest
218
  timeout-minutes: 15
219
 
@@ -221,42 +218,34 @@ PY
221
  - name: Checkout
222
  uses: actions/checkout@v4
223
 
224
- - name: Login and get Bearer token
225
  run: |
226
- for attempt in {1..3}; do
227
- HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
228
- -H "Content-Type: application/json" \
229
- -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
230
- if [ "$HTTP_CODE" = "200" ]; then
231
- python3 - <<'PY'
232
- import json, sys
233
- try:
234
- data = json.load(open("login.json"))
235
- except json.JSONDecodeError as e:
236
- print("Invalid JSON response:", e)
237
- with open("login.json") as f:
238
- print("Raw response:", f.read())
239
- sys.exit(1)
240
-
241
- if not data.get("success"):
242
- print("Login failed:", json.dumps(data, indent=2))
243
- sys.exit(1)
244
-
245
- token = data.get("data", {}).get("token")
246
- if not token:
247
- print("No token in response:", json.dumps(data, indent=2))
248
- sys.exit(1)
249
-
250
- with open("token.txt", "w") as f:
251
- f.write(token)
252
- print("✓ Login OK - token saved")
253
- PY
254
- if [ $? -eq 0 ]; then exit 0; fi
255
  fi
256
- [ $attempt -lt 3 ] && sleep 10
 
257
  done
258
  exit 1
259
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  - name: Test retrieval-only chemical search
261
  run: |
262
  TOKEN=$(cat token.txt)
@@ -269,19 +258,19 @@ PY
269
  cat search.json
270
  echo ""
271
  python3 - <<'PY'
272
- import json, sys
273
- data = json.load(open("search.json"))
274
- if not data.get("success"):
275
- print("Chemical search (retrieval-only) failed:", json.dumps(data, indent=2))
276
- sys.exit(1)
277
- if not isinstance(data.get("compounds"), list):
278
- print("Missing 'compounds' array in response")
279
- sys.exit(1)
280
- if data.get("metadata", {}).get("source") != "retrieval":
281
- print("Expected source='retrieval', got:", data.get("metadata", {}).get("source"))
282
- sys.exit(1)
283
- print("✓ Chemical search (retrieval-only) OK - found", len(data["compounds"]), "compounds")
284
- PY
285
 
286
  - name: Test full RAG chemical search
287
  run: |
@@ -295,26 +284,25 @@ PY
295
  cat rag.json
296
  echo ""
297
  python3 - <<'PY'
298
- import json, sys
299
- data = json.load(open("rag.json"))
300
- if not data.get("success"):
301
- print("Chemical search (full RAG) failed:", json.dumps(data, indent=2))
302
- sys.exit(1)
303
- if not isinstance(data.get("compounds"), list):
304
- print("Missing 'compounds' array in response")
305
- sys.exit(1)
306
- if data.get("metadata", {}).get("source") != "full_rag":
307
- print("Expected source='full_rag', got:", data.get("metadata", {}).get("source"))
308
- sys.exit(1)
309
- for compound in data["compounds"]:
310
- if not compound.get("explanation"):
311
- print("Missing explanation for compound:", compound.get("name"))
312
- sys.exit(1)
313
- print("✓ Chemical search (full RAG) OK - found", len(data["compounds"]), "compounds with explanations")
314
- PY
315
 
316
  drug-repurposing-integration:
317
- needs: warmup-spaces
318
  runs-on: ubuntu-latest
319
  timeout-minutes: 30
320
 
@@ -322,42 +310,34 @@ PY
322
  - name: Checkout
323
  uses: actions/checkout@v4
324
 
325
- - name: Login and get Bearer token
326
  run: |
327
- for attempt in {1..3}; do
328
- HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
329
- -H "Content-Type: application/json" \
330
- -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
331
- if [ "$HTTP_CODE" = "200" ]; then
332
- python3 - <<'PY'
333
- import json, sys
334
- try:
335
- data = json.load(open("login.json"))
336
- except json.JSONDecodeError as e:
337
- print("Invalid JSON response:", e)
338
- with open("login.json") as f:
339
- print("Raw response:", f.read())
340
- sys.exit(1)
341
-
342
- if not data.get("success"):
343
- print("Login failed:", json.dumps(data, indent=2))
344
- sys.exit(1)
345
-
346
- token = data.get("data", {}).get("token")
347
- if not token:
348
- print("No token in response:", json.dumps(data, indent=2))
349
- sys.exit(1)
350
-
351
- with open("token.txt", "w") as f:
352
- f.write(token)
353
- print("✓ Login OK - token saved")
354
- PY
355
- if [ $? -eq 0 ]; then exit 0; fi
356
  fi
357
- [ $attempt -lt 3 ] && sleep 10
 
358
  done
359
  exit 1
360
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  - name: Test unauthenticated DR request is rejected
362
  run: |
363
  echo "POST /api/drug-repurposing/targets (no auth)"
@@ -369,11 +349,11 @@ PY
369
  exit 1
370
  fi
371
  python3 - <<'PY'
372
- import json
373
- with open('dr_unauth.json') as f: data = json.load(f)
374
- assert not data.get('success', True), 'Expected success=false'
375
- print('✓ Unauthenticated DR request correctly rejected')
376
- PY
377
 
378
  - name: Test DR target lookup requires disease_name
379
  run: |
@@ -387,7 +367,7 @@ PY
387
  echo "Expected 422, got $HTTP_CODE"
388
  exit 1
389
  fi
390
- echo "✓ Missing disease_name correctly rejected"
391
 
392
  - name: Test DR target lookup via Laravel proxy
393
  run: |
@@ -407,41 +387,40 @@ PY
407
  fi
408
 
409
  python3 - <<'PY'
410
- import json, sys
411
- data = json.load(open("dr_targets.json"))
412
- if not data.get("success"):
413
- print("DR target lookup failed:", json.dumps(data, indent=2))
414
- sys.exit(1)
415
- job_id = data.get("data", {}).get("job_id")
416
- status = data.get("data", {}).get("status")
417
- print(f"✓ DR target lookup OK - job_id={job_id}, status={status}")
418
-
419
- # Poll for completion
420
- import time, urllib.request
421
- base = "https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets"
422
- with open("token.txt") as f: token = f.read().strip()
423
- for i in range(30):
424
- req = urllib.request.Request(f"{base}/{job_id}")
425
- req.add_header("Authorization", f"Bearer {token}")
426
- resp = urllib.request.urlopen(req)
427
- status_data = json.loads(resp.read())
428
- s = status_data.get("data", {}).get("status")
429
- if s == "completed":
430
- output = status_data.get("data", {}).get("output", {})
431
- assert len(output.get("targets", [])) > 0, "No targets found"
432
- print(f"✓ DR targets completed - {len(output['targets'])} targets found")
433
- sys.exit(0)
434
- elif s == "failed":
435
- print("DR target lookup failed:", json.dumps(status_data, indent=2))
436
- sys.exit(1)
437
- print(f" Polling... attempt {i+1}/30, status={s}")
438
- time.sleep(5)
439
- print("DR target lookup did not complete in time")
440
- sys.exit(1)
441
- PY
442
 
443
  docking-integration:
444
- needs: warmup-spaces
445
  runs-on: ubuntu-latest
446
  timeout-minutes: 15
447
 
@@ -449,42 +428,34 @@ PY
449
  - name: Checkout
450
  uses: actions/checkout@v4
451
 
452
- - name: Login and get Bearer token
453
  run: |
454
- for attempt in {1..3}; do
455
- HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
456
- -H "Content-Type: application/json" \
457
- -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
458
- if [ "$HTTP_CODE" = "200" ]; then
459
- python3 - <<'PY'
460
- import json, sys
461
- try:
462
- data = json.load(open("login.json"))
463
- except json.JSONDecodeError as e:
464
- print("Invalid JSON response:", e)
465
- with open("login.json") as f:
466
- print("Raw response:", f.read())
467
- sys.exit(1)
468
-
469
- if not data.get("success"):
470
- print("Login failed:", json.dumps(data, indent=2))
471
- sys.exit(1)
472
-
473
- token = data.get("data", {}).get("token")
474
- if not token:
475
- print("No token in response:", json.dumps(data, indent=2))
476
- sys.exit(1)
477
-
478
- with open("token.txt", "w") as f:
479
- f.write(token)
480
- print("✓ Login OK - token saved")
481
- PY
482
- if [ $? -eq 0 ]; then exit 0; fi
483
  fi
484
- [ $attempt -lt 3 ] && sleep 10
 
485
  done
486
  exit 1
487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  - name: Test docking submit
489
  run: |
490
  TOKEN=$(cat token.txt)
@@ -512,10 +483,10 @@ PY
512
  fi
513
 
514
  python3 - <<'PY'
515
- import json, sys
516
- data = json.load(open("docking.json"))
517
- if not data.get("success"):
518
- print("Docking submit failed:", json.dumps(data, indent=2))
519
- sys.exit(1)
520
- print("✓ Docking submit OK - job created")
521
- PY
 
12
  cancel-in-progress: true
13
 
14
  jobs:
15
+ core-ai-proxy:
16
  runs-on: ubuntu-latest
17
+ timeout-minutes: 30
18
+
19
  steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@v4
22
+
23
  - name: Warm up ailixir-api Space
24
  run: |
25
  echo "Waiting for ailixir-api HF Space..."
26
  for i in $(seq 1 60); do
27
+ if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
28
+ echo "ailixir-api is up"
29
+ sleep 5
30
+ exit 0
31
  fi
32
  echo "Attempt $i/60..."
33
  sleep 5
34
  done
35
+ exit 1
36
 
37
  - name: Warm up ailixir-drug-repurposing Space
38
  run: |
39
  echo "Waiting for ailixir-drug-repurposing HF Space..."
40
  for i in $(seq 1 60); do
41
  if curl -sf https://RottenShadow-ailixir-drug-repurposing.hf.space/health > /dev/null 2>&1; then
42
+ echo "ailixir-drug-repurposing is up"
43
+ sleep 3
44
+ exit 0
45
  fi
46
  echo "Attempt $i/60..."
47
  sleep 5
48
  done
49
+ exit 1
50
 
51
  - name: Warm up ailixir-admet Space
52
  run: |
53
  echo "Waiting for ailixir-admet HF Space..."
54
  for i in $(seq 1 60); do
55
  if curl -sf https://shdwRow-ailixir-admet.hf.space/health > /dev/null 2>&1; then
56
+ echo "ailixir-admet is up"
57
+ sleep 3
58
+ exit 0
59
  fi
60
  echo "Attempt $i/60..."
61
  sleep 5
62
  done
63
+ exit 1
64
 
65
  - name: Warm up ailixir-chemical-rag Space
66
  run: |
67
  echo "Waiting for ailixir-chemical-rag HF Space..."
68
  for i in $(seq 1 60); do
69
  if curl -sf https://RottenShadow-ailixir-chemical-rag.hf.space/health > /dev/null 2>&1; then
70
+ echo "ailixir-chemical-rag is up"
71
+ sleep 3
72
+ exit 0
73
  fi
74
  echo "Attempt $i/60..."
75
  sleep 5
76
  done
77
+ exit 1
 
 
 
 
 
 
 
 
78
 
79
  - name: Login and get Bearer token
80
  run: |
81
  echo "POST /api/user/login"
82
+ HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
83
+ -H "Content-Type: application/json" \
84
+ -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
85
+ echo "HTTP Status: $HTTP_CODE"
86
+ cat login.json
87
+ echo ""
88
+
89
+ if [ "$HTTP_CODE" != "200" ]; then
90
+ echo "Login failed with HTTP $HTTP_CODE"
91
+ exit 1
92
+ fi
93
+
94
+ python3 - <<'PY'
95
+ import json, sys
96
+ try:
97
+ data = json.load(open("login.json"))
98
+ except json.JSONDecodeError as e:
99
+ print("Invalid JSON response:", e)
100
+ with open("login.json") as f:
101
+ print("Raw response:", f.read())
102
+ sys.exit(1)
103
+
104
+ if not data.get("success"):
105
+ print("Login failed:", json.dumps(data, indent=2))
106
+ sys.exit(1)
107
+
108
+ token = data.get("data", {}).get("token")
109
+ if not token:
110
+ print("No token in response:", json.dumps(data, indent=2))
111
+ sys.exit(1)
112
+
113
+ with open("token.txt", "w") as f:
114
+ f.write(token)
115
+ print("Login OK - token saved")
116
+ PY
 
 
 
 
 
117
 
118
  - name: Test aggregated AI health via Laravel
119
  run: |
 
125
  cat health.json
126
  echo ""
127
  python3 - <<'PY'
128
+ import json, sys
129
+ data = json.load(open("health.json"))
130
+ if not data.get("success"):
131
+ print("AI services health check failed:", json.dumps(data, indent=2))
132
+ sys.exit(1)
133
+ print("All AI services healthy via Laravel proxy")
134
+ PY
135
 
136
  - name: Test ADMET prediction via Laravel proxy
137
  run: |
 
151
  fi
152
 
153
  python3 - <<'PY'
154
+ import json, sys
155
+ try:
156
+ data = json.load(open("admet.json"))
157
+ except json.JSONDecodeError as e:
158
+ print("Invalid JSON response:", e)
159
+ with open("admet.json") as f:
160
+ print("Raw response:", f.read())
161
+ sys.exit(1)
162
+
163
+ if not data.get("success"):
164
+ print("ADMET prediction test failed:", json.dumps(data, indent=2))
165
+ sys.exit(1)
166
+
167
+ results = data.get("data", {}).get("results", [])
168
+ if len(results) < 3:
169
+ print(f"Expected at least 3 results, got {len(results)}")
170
+ sys.exit(1)
171
+
172
+ print(f"ADMET prediction OK - {len(results)} compounds processed")
173
+ PY
174
 
175
  - name: Test Chemical RAG proxy via Laravel
176
  run: |
 
184
  cat chemical.json
185
  echo ""
186
  python3 - <<'PY'
187
+ import json, sys
188
+ data = json.load(open("chemical.json"))
189
+ if not data.get("success"):
190
+ print("Chemical RAG proxy test failed:", json.dumps(data, indent=2))
191
+ sys.exit(1)
192
+ print("Chemical RAG proxy OK")
193
+ PY
194
 
195
  - name: Test Drug Repurposing proxy via Laravel
196
  run: |
 
202
  cat drug.json
203
  echo ""
204
  python3 - <<'PY'
205
+ import json, sys
206
+ data = json.load(open("drug.json"))
207
+ if not data.get("success"):
208
+ print("Drug Repurposing proxy test failed:", json.dumps(data, indent=2))
209
+ sys.exit(1)
210
+ print("Drug Repurposing proxy OK")
211
+ PY
212
 
213
  chemical-search:
 
214
  runs-on: ubuntu-latest
215
  timeout-minutes: 15
216
 
 
218
  - name: Checkout
219
  uses: actions/checkout@v4
220
 
221
+ - name: Warm up ailixir-api Space
222
  run: |
223
+ for i in $(seq 1 60); do
224
+ if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
225
+ echo "ailixir-api is up"
226
+ sleep 5
227
+ exit 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  fi
229
+ echo "Waiting ($i/60)..."
230
+ sleep 5
231
  done
232
  exit 1
233
 
234
+ - name: Login and get Bearer token
235
+ run: |
236
+ HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
237
+ -H "Content-Type: application/json" \
238
+ -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
239
+ if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
240
+ python3 - <<'PY'
241
+ import json
242
+ with open('login.json') as f: data = json.load(f)
243
+ token = data.get('data', {}).get('token')
244
+ if not token: exit(1)
245
+ with open('token.txt','w') as f: f.write(token)
246
+ print('Login OK')
247
+ PY
248
+
249
  - name: Test retrieval-only chemical search
250
  run: |
251
  TOKEN=$(cat token.txt)
 
258
  cat search.json
259
  echo ""
260
  python3 - <<'PY'
261
+ import json, sys
262
+ data = json.load(open("search.json"))
263
+ if not data.get("success"):
264
+ print("Chemical search (retrieval-only) failed:", json.dumps(data, indent=2))
265
+ sys.exit(1)
266
+ if not isinstance(data.get("compounds"), list):
267
+ print("Missing 'compounds' array in response")
268
+ sys.exit(1)
269
+ if data.get("metadata", {}).get("source") != "retrieval":
270
+ print("Expected source='retrieval', got:", data.get("metadata", {}).get("source"))
271
+ sys.exit(1)
272
+ print("Chemical search (retrieval-only) OK - found", len(data["compounds"]), "compounds")
273
+ PY
274
 
275
  - name: Test full RAG chemical search
276
  run: |
 
284
  cat rag.json
285
  echo ""
286
  python3 - <<'PY'
287
+ import json, sys
288
+ data = json.load(open("rag.json"))
289
+ if not data.get("success"):
290
+ print("Chemical search (full RAG) failed:", json.dumps(data, indent=2))
291
+ sys.exit(1)
292
+ if not isinstance(data.get("compounds"), list):
293
+ print("Missing 'compounds' array in response")
294
+ sys.exit(1)
295
+ if data.get("metadata", {}).get("source") != "full_rag":
296
+ print("Expected source='full_rag', got:", data.get("metadata", {}).get("source"))
297
+ sys.exit(1)
298
+ for compound in data["compounds"]:
299
+ if not compound.get("explanation"):
300
+ print("Missing explanation for compound:", compound.get("name"))
301
+ sys.exit(1)
302
+ print("Chemical search (full RAG) OK - found", len(data["compounds"]), "compounds with explanations")
303
+ PY
304
 
305
  drug-repurposing-integration:
 
306
  runs-on: ubuntu-latest
307
  timeout-minutes: 30
308
 
 
310
  - name: Checkout
311
  uses: actions/checkout@v4
312
 
313
+ - name: Warm up ailixir-api Space
314
  run: |
315
+ for i in $(seq 1 60); do
316
+ if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
317
+ echo "ailixir-api is up"
318
+ sleep 5
319
+ exit 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  fi
321
+ echo "Waiting ($i/60)..."
322
+ sleep 5
323
  done
324
  exit 1
325
 
326
+ - name: Login and get Bearer token
327
+ run: |
328
+ HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
329
+ -H "Content-Type: application/json" \
330
+ -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
331
+ if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
332
+ python3 - <<'PY'
333
+ import json
334
+ with open('login.json') as f: data = json.load(f)
335
+ token = data.get('data', {}).get('token')
336
+ if not token: exit(1)
337
+ with open('token.txt','w') as f: f.write(token)
338
+ print('Login OK')
339
+ PY
340
+
341
  - name: Test unauthenticated DR request is rejected
342
  run: |
343
  echo "POST /api/drug-repurposing/targets (no auth)"
 
349
  exit 1
350
  fi
351
  python3 - <<'PY'
352
+ import json
353
+ with open('dr_unauth.json') as f: data = json.load(f)
354
+ assert not data.get('success', True), 'Expected success=false'
355
+ print('Unauthenticated DR request correctly rejected')
356
+ PY
357
 
358
  - name: Test DR target lookup requires disease_name
359
  run: |
 
367
  echo "Expected 422, got $HTTP_CODE"
368
  exit 1
369
  fi
370
+ echo "Missing disease_name correctly rejected"
371
 
372
  - name: Test DR target lookup via Laravel proxy
373
  run: |
 
387
  fi
388
 
389
  python3 - <<'PY'
390
+ import json, sys
391
+ data = json.load(open("dr_targets.json"))
392
+ if not data.get("success"):
393
+ print("DR target lookup failed:", json.dumps(data, indent=2))
394
+ sys.exit(1)
395
+ job_id = data.get("data", {}).get("job_id")
396
+ status = data.get("data", {}).get("status")
397
+ print(f"DR target lookup OK - job_id={job_id}, status={status}")
398
+
399
+ # Poll for completion
400
+ import time, urllib.request
401
+ base = "https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets"
402
+ with open("token.txt") as f: token = f.read().strip()
403
+ for i in range(30):
404
+ req = urllib.request.Request(f"{base}/{job_id}")
405
+ req.add_header("Authorization", f"Bearer {token}")
406
+ resp = urllib.request.urlopen(req)
407
+ status_data = json.loads(resp.read())
408
+ s = status_data.get("data", {}).get("status")
409
+ if s == "completed":
410
+ output = status_data.get("data", {}).get("output", {})
411
+ assert len(output.get("targets", [])) > 0, "No targets found"
412
+ print(f"DR targets completed - {len(output['targets'])} targets found")
413
+ sys.exit(0)
414
+ elif s == "failed":
415
+ print("DR target lookup failed:", json.dumps(status_data, indent=2))
416
+ sys.exit(1)
417
+ print(f" Polling... attempt {i+1}/30, status={s}")
418
+ time.sleep(5)
419
+ print("DR target lookup did not complete in time")
420
+ sys.exit(1)
421
+ PY
422
 
423
  docking-integration:
 
424
  runs-on: ubuntu-latest
425
  timeout-minutes: 15
426
 
 
428
  - name: Checkout
429
  uses: actions/checkout@v4
430
 
431
+ - name: Warm up ailixir-api Space
432
  run: |
433
+ for i in $(seq 1 60); do
434
+ if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
435
+ echo "ailixir-api is up"
436
+ sleep 5
437
+ exit 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  fi
439
+ echo "Waiting ($i/60)..."
440
+ sleep 5
441
  done
442
  exit 1
443
 
444
+ - name: Login and get Bearer token
445
+ run: |
446
+ HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
447
+ -H "Content-Type: application/json" \
448
+ -d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
449
+ if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
450
+ python3 - <<'PY'
451
+ import json
452
+ with open('login.json') as f: data = json.load(f)
453
+ token = data.get('data', {}).get('token')
454
+ if not token: exit(1)
455
+ with open('token.txt','w') as f: f.write(token)
456
+ print('Login OK')
457
+ PY
458
+
459
  - name: Test docking submit
460
  run: |
461
  TOKEN=$(cat token.txt)
 
483
  fi
484
 
485
  python3 - <<'PY'
486
+ import json, sys
487
+ data = json.load(open("docking.json"))
488
+ if not data.get("success"):
489
+ print("Docking submit failed:", json.dumps(data, indent=2))
490
+ sys.exit(1)
491
+ print("Docking submit OK - job created")
492
+ PY
docker/laravel.env CHANGED
@@ -24,9 +24,15 @@ AI_SERVICE_URL=http://drug-repurposing:8000
24
 
25
  AI_INTEGRATION_ROUTES_ENABLED=true
26
 
27
- # ✅ CI ENVIRONMENT: Use LOG driver for email (no actual SMTP)
28
- # This keeps tests fast and doesn't require real email credentials
29
- MAIL_MAILER=log
 
 
 
 
 
 
30
 
31
  CLOUDINARY_URL=cloudinary://dummy_key:dummy_secret@dummy_cloud
32
  CLOUDINARY_CLOUD_NAME=dummy_cloud
 
24
 
25
  AI_INTEGRATION_ROUTES_ENABLED=true
26
 
27
+ # ✅ SMTP Mail Settings
28
+ MAIL_MAILER=smtp
29
+ MAIL_HOST=smtp.gmail.com
30
+ MAIL_PORT=587
31
+ MAIL_USERNAME=yasmeensaleh747@gmail.com
32
+ MAIL_PASSWORD="fghu ijct vhfu xnud"
33
+ MAIL_ENCRYPTION=tls
34
+ MAIL_FROM_ADDRESS=yasmeensaleh747@gmail.com
35
+ MAIL_FROM_NAME="AILIXIR - Omar Fadlallah"
36
 
37
  CLOUDINARY_URL=cloudinary://dummy_key:dummy_secret@dummy_cloud
38
  CLOUDINARY_CLOUD_NAME=dummy_cloud