ailixir-api / .github /workflows /integration-test-hf.yml
AILIXIR Bot
Auto-sync: d2402d260057f3dc7305a96f1743f9d64c1d5f30
2d89783
Raw
History Blame Contribute Delete
19.4 kB
name: HF Spaces Integration Test
on:
push:
branches: [main, develop, "feature/**"]
pull_request:
branches: [main, develop]
workflow_dispatch:
concurrency:
group: hf-integration-${{ github.ref }}
cancel-in-progress: true
jobs:
core-ai-proxy:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Warm up ailixir-api Space
run: |
echo "Waiting for ailixir-api HF Space..."
for i in $(seq 1 60); do
if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
echo "ailixir-api is up"
sleep 5
exit 0
fi
echo "Attempt $i/60..."
sleep 5
done
exit 1
- name: Warm up ailixir-drug-repurposing Space
run: |
echo "Waiting for ailixir-drug-repurposing HF Space..."
for i in $(seq 1 60); do
if curl -sf https://RottenShadow-ailixir-drug-repurposing.hf.space/health > /dev/null 2>&1; then
echo "ailixir-drug-repurposing is up"
sleep 3
exit 0
fi
echo "Attempt $i/60..."
sleep 5
done
exit 1
- name: Warm up ailixir-admet Space
run: |
echo "Waiting for ailixir-admet HF Space..."
for i in $(seq 1 60); do
if curl -sf https://shdwRow-ailixir-admet.hf.space/health > /dev/null 2>&1; then
echo "ailixir-admet is up"
sleep 3
exit 0
fi
echo "Attempt $i/60..."
sleep 5
done
exit 1
- name: Warm up ailixir-chemical-rag Space
run: |
echo "Waiting for ailixir-chemical-rag HF Space..."
for i in $(seq 1 60); do
if curl -sf https://RottenShadow-ailixir-chemical-rag.hf.space/health > /dev/null 2>&1; then
echo "ailixir-chemical-rag is up"
sleep 3
exit 0
fi
echo "Attempt $i/60..."
sleep 5
done
exit 1
- name: Login and get Bearer token
run: |
echo "POST /api/user/login"
HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
-H "Content-Type: application/json" \
-d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
echo "HTTP Status: $HTTP_CODE"
cat login.json
echo ""
if [ "$HTTP_CODE" != "200" ]; then
echo "Login failed with HTTP $HTTP_CODE"
exit 1
fi
python3 - <<'PY'
import json, sys
try:
data = json.load(open("login.json"))
except json.JSONDecodeError as e:
print("Invalid JSON response:", e)
with open("login.json") as f:
print("Raw response:", f.read())
sys.exit(1)
if not data.get("success"):
print("Login failed:", json.dumps(data, indent=2))
sys.exit(1)
token = data.get("data", {}).get("token")
if not token:
print("No token in response:", json.dumps(data, indent=2))
sys.exit(1)
with open("token.txt", "w") as f:
f.write(token)
print("Login OK - token saved")
PY
- name: Test aggregated AI health via Laravel
run: |
TOKEN=$(cat token.txt)
echo "GET /api/ai-services/health"
HTTP_CODE=$(curl -s -o health.json -w "%{http_code}" https://Ailixir-AI-Team-ailixir-api.hf.space/api/ai-services/health \
-H "Authorization: Bearer $TOKEN")
echo "HTTP Status: $HTTP_CODE"
cat health.json
echo ""
python3 - <<'PY'
import json, sys
data = json.load(open("health.json"))
if not data.get("success"):
print("AI services health check failed:", json.dumps(data, indent=2))
sys.exit(1)
print("All AI services healthy via Laravel proxy")
PY
- name: Test ADMET prediction via Laravel proxy
run: |
TOKEN=$(cat token.txt)
echo "POST /api/admet/predict"
HTTP_CODE=$(curl -s -o admet.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/admet/predict \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"smiles": "c1ccccc1, CCO, CCC"}')
echo "HTTP Status: $HTTP_CODE"
cat admet.json
echo ""
if [ "$HTTP_CODE" != "200" ]; then
echo "ADMET prediction failed with HTTP $HTTP_CODE"
exit 1
fi
python3 - <<'PY'
import json, sys
try:
data = json.load(open("admet.json"))
except json.JSONDecodeError as e:
print("Invalid JSON response:", e)
with open("admet.json") as f:
print("Raw response:", f.read())
sys.exit(1)
if not data.get("success"):
print("ADMET prediction test failed:", json.dumps(data, indent=2))
sys.exit(1)
results = data.get("data", {}).get("results", [])
if len(results) < 3:
print(f"Expected at least 3 results, got {len(results)}")
sys.exit(1)
print(f"ADMET prediction OK - {len(results)} compounds processed")
PY
- name: Test Chemical RAG proxy via Laravel
run: |
TOKEN=$(cat token.txt)
echo "POST /api/ai-services/test/chemical-search"
HTTP_CODE=$(curl -s -o chemical.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/ai-services/test/chemical-search \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "malaria drug"}')
echo "HTTP Status: $HTTP_CODE"
cat chemical.json
echo ""
python3 - <<'PY'
import json, sys
data = json.load(open("chemical.json"))
if not data.get("success"):
print("Chemical RAG proxy test failed:", json.dumps(data, indent=2))
sys.exit(1)
print("Chemical RAG proxy OK")
PY
- name: Test Drug Repurposing proxy via Laravel
run: |
TOKEN=$(cat token.txt)
echo "GET /api/ai-services/test/drug-repurposing"
HTTP_CODE=$(curl -s -o drug.json -w "%{http_code}" https://Ailixir-AI-Team-ailixir-api.hf.space/api/ai-services/test/drug-repurposing \
-H "Authorization: Bearer $TOKEN")
echo "HTTP Status: $HTTP_CODE"
cat drug.json
echo ""
python3 - <<'PY'
import json, sys
data = json.load(open("drug.json"))
if not data.get("success"):
print("Drug Repurposing proxy test failed:", json.dumps(data, indent=2))
sys.exit(1)
print("Drug Repurposing proxy OK")
PY
chemical-search:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Warm up ailixir-api Space
run: |
for i in $(seq 1 60); do
if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
echo "ailixir-api is up"
sleep 5
exit 0
fi
echo "Waiting ($i/60)..."
sleep 5
done
exit 1
- name: Login and get Bearer token
run: |
HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
-H "Content-Type: application/json" \
-d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
python3 - <<'PY'
import json
with open('login.json') as f: data = json.load(f)
token = data.get('data', {}).get('token')
if not token: exit(1)
with open('token.txt','w') as f: f.write(token)
print('Login OK')
PY
- name: Test retrieval-only chemical search
run: |
TOKEN=$(cat token.txt)
echo "POST /api/chemical-search (retrieval-only)"
HTTP_CODE=$(curl -s -o search.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/chemical-search \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"smiles":"CC(=O)O"}')
echo "HTTP Status: $HTTP_CODE"
cat search.json
echo ""
python3 - <<'PY'
import json, sys
data = json.load(open("search.json"))
if not data.get("success"):
print("Chemical search (retrieval-only) failed:", json.dumps(data, indent=2))
sys.exit(1)
if not isinstance(data.get("compounds"), list):
print("Missing 'compounds' array in response")
sys.exit(1)
if data.get("metadata", {}).get("source") != "retrieval":
print("Expected source='retrieval', got:", data.get("metadata", {}).get("source"))
sys.exit(1)
print("Chemical search (retrieval-only) OK - found", len(data["compounds"]), "compounds")
PY
- name: Test full RAG chemical search
run: |
TOKEN=$(cat token.txt)
echo "POST /api/chemical-search/full-rag"
HTTP_CODE=$(curl -s -o rag.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/chemical-search/full-rag \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"smiles":"CC(=O)O"}')
echo "HTTP Status: $HTTP_CODE"
cat rag.json
echo ""
python3 - <<'PY'
import json, sys
data = json.load(open("rag.json"))
if not data.get("success"):
print("Chemical search (full RAG) failed:", json.dumps(data, indent=2))
sys.exit(1)
if not isinstance(data.get("compounds"), list):
print("Missing 'compounds' array in response")
sys.exit(1)
if data.get("metadata", {}).get("source") != "full_rag":
print("Expected source='full_rag', got:", data.get("metadata", {}).get("source"))
sys.exit(1)
for compound in data["compounds"]:
if not compound.get("explanation"):
print("Missing explanation for compound:", compound.get("name"))
sys.exit(1)
print("Chemical search (full RAG) OK - found", len(data["compounds"]), "compounds with explanations")
PY
drug-repurposing-integration:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Warm up ailixir-api Space
run: |
for i in $(seq 1 60); do
if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
echo "ailixir-api is up"
sleep 5
exit 0
fi
echo "Waiting ($i/60)..."
sleep 5
done
exit 1
- name: Login and get Bearer token
run: |
HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
-H "Content-Type: application/json" \
-d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
python3 - <<'PY'
import json
with open('login.json') as f: data = json.load(f)
token = data.get('data', {}).get('token')
if not token: exit(1)
with open('token.txt','w') as f: f.write(token)
print('Login OK')
PY
- name: Test unauthenticated DR request is rejected
run: |
echo "POST /api/drug-repurposing/targets (no auth)"
HTTP_CODE=$(curl -s -o dr_unauth.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets \
-H "Content-Type: application/json" \
-d '{"disease_name":"Type 2 Diabetes"}')
if [ "$HTTP_CODE" != "401" ]; then
echo "Expected 401, got $HTTP_CODE"
exit 1
fi
python3 - <<'PY'
import json
with open('dr_unauth.json') as f: data = json.load(f)
assert not data.get('success', True), 'Expected success=false'
print('Unauthenticated DR request correctly rejected')
PY
- name: Test DR target lookup requires disease_name
run: |
TOKEN=$(cat token.txt)
echo "POST /api/drug-repurposing/targets (missing disease_name)"
HTTP_CODE=$(curl -s -o dr_validation.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"top_n": 2}')
if [ "$HTTP_CODE" != "422" ]; then
echo "Expected 422, got $HTTP_CODE"
exit 1
fi
echo "Missing disease_name correctly rejected"
- name: Test DR target lookup via Laravel proxy
run: |
TOKEN=$(cat token.txt)
echo "POST /api/drug-repurposing/targets"
HTTP_CODE=$(curl -s -o dr_targets.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"disease_name":"Type 2 Diabetes","top_n":2}')
echo "HTTP Status: $HTTP_CODE"
cat dr_targets.json
echo ""
if [ "$HTTP_CODE" != "200" ]; then
echo "DR target lookup failed with HTTP $HTTP_CODE"
exit 1
fi
python3 - <<'PY'
import json, sys, time, urllib.request
data = json.load(open("dr_targets.json"))
if not data.get("success"):
print("DR target lookup failed:", json.dumps(data, indent=2))
sys.exit(1)
job_id = data.get("data", {}).get("job_id")
status = data.get("data", {}).get("status")
print(f"DR target lookup OK - job_id={job_id}, status={status}")
# Poll for completion with exponential backoff
base = "https://Ailixir-AI-Team-ailixir-api.hf.space/api/drug-repurposing/targets"
with open("token.txt") as f: token = f.read().strip()
max_attempts = 30
backoff_base = 5 # Start with 5 second delay
retry_count = 0
max_retries = 3
for i in range(max_attempts):
try:
req = urllib.request.Request(f"{base}/{job_id}")
req.add_header("Authorization", f"Bearer {token}")
resp = urllib.request.urlopen(req)
status_data = json.loads(resp.read())
retry_count = 0 # Reset retry count on success
s = status_data.get("data", {}).get("status")
if s == "completed":
output = status_data.get("data", {}).get("output", {})
assert len(output.get("targets", [])) > 0, "No targets found"
print(f"DR targets completed - {len(output['targets'])} targets found")
sys.exit(0)
elif s == "failed":
print("DR target lookup failed:", json.dumps(status_data, indent=2))
sys.exit(1)
print(f" Polling... attempt {i+1}/{max_attempts}, status={s}")
time.sleep(backoff_base)
except urllib.error.HTTPError as e:
if e.code == 429 and retry_count < max_retries:
# Rate limited - exponential backoff
retry_count += 1
wait_time = backoff_base * (2 ** retry_count)
print(f" Rate limited (429). Retry {retry_count}/{max_retries}, waiting {wait_time}s...")
time.sleep(wait_time)
else:
print(f"HTTP Error {e.code}: {e.reason}")
sys.exit(1)
print("DR target lookup did not complete in time")
sys.exit(1)
PY
docking-integration:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Warm up ailixir-api Space
run: |
for i in $(seq 1 60); do
if curl -sf https://Ailixir-AI-Team-ailixir-api.hf.space/ > /dev/null 2>&1; then
echo "ailixir-api is up"
sleep 5
exit 0
fi
echo "Waiting ($i/60)..."
sleep 5
done
exit 1
- name: Login and get Bearer token
run: |
HTTP_CODE=$(curl -s -o login.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/user/login \
-H "Content-Type: application/json" \
-d '{"email":"salehyasmeen080@gmail.com","password":"123456789"}')
if [ "$HTTP_CODE" != "200" ]; then exit 1; fi
python3 - <<'PY'
import json
with open('login.json') as f: data = json.load(f)
token = data.get('data', {}).get('token')
if not token: exit(1)
with open('token.txt','w') as f: f.write(token)
print('Login OK')
PY
- name: Test docking submit
run: |
TOKEN=$(cat token.txt)
echo "POST /api/docking/submit"
HTTP_CODE=$(curl -s -o docking.json -w "%{http_code}" -X POST https://Ailixir-AI-Team-ailixir-api.hf.space/api/docking/submit \
-H "Authorization: Bearer $TOKEN" \
-F "protein_name=EGFR" \
-F "protein_file=@tests/Fixtures/docking/egfr_clean.pdbqt" \
-F "ligand_name=Erlotinib" \
-F "ligand_file=@tests/Fixtures/docking/ligand.pdbqt" \
-F "center_x=10.0" \
-F "center_y=15.0" \
-F "center_z=20.0" \
-F "box_size_x=25.0" \
-F "box_size_y=25.0" \
-F "box_size_z=25.0" \
-F "exhaustiveness=8")
echo "HTTP Status: $HTTP_CODE"
cat docking.json
echo ""
if [ "$HTTP_CODE" != "200" ]; then
echo "Docking submit failed with HTTP $HTTP_CODE"
exit 1
fi
python3 - <<'PY'
import json, sys
data = json.load(open("docking.json"))
if not data.get("success"):
print("Docking submit failed:", json.dumps(data, indent=2))
sys.exit(1)
print("Docking submit OK - job created")
PY