Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Test script for /v1/predict endpoint. | |
| This script demonstrates the correct request format: | |
| - inputId: required string | |
| - payload: object containing the feature data | |
| """ | |
| import hmac | |
| import hashlib | |
| import time | |
| import uuid | |
| import requests | |
| # ============================================ | |
| # CONFIGURATION (from tenant creation) | |
| # ============================================ | |
| CLIENT_ID = "acme-bank-463edc0a" | |
| CLIENT_SECRET = "yPqsrtBizHgDvnK-NpkgVXMXw3WbV_s_JGK-c2pWr3U" | |
| HMAC_SECRET = "OSSBJgx2QToeQhGtQgzwS_8Kf1QvTraq6M67uNrBKEo" | |
| BASE_URL = "https://frankscore-backend.onrender.com" | |
| # ============================================ | |
| # STEP 1: Login as Tenant | |
| # ============================================ | |
| print("Step 1: Logging in...") | |
| login_response = requests.post( | |
| f"{BASE_URL}/auth/login", | |
| json={ | |
| "clientId": CLIENT_ID, | |
| "clientSecret": CLIENT_SECRET | |
| } | |
| ) | |
| if login_response.status_code != 200: | |
| print(f"β Login failed: {login_response.status_code}") | |
| print(login_response.text) | |
| exit(1) | |
| login_data = login_response.json() | |
| jwt_token = login_data["access_token"] # Note: camelCase, not snake_case | |
| print(f"β Logged in. JWT: {jwt_token[:20]}...") | |
| # ============================================ | |
| # STEP 2: Prepare End-User Identity | |
| # ============================================ | |
| end_user_id = "user-alice-123" # Your customer | |
| timestamp = str(int(time.time())) | |
| request_id = str(uuid.uuid4()) | |
| # ============================================ | |
| # STEP 3: Compute HMAC Signature | |
| # ============================================ | |
| signing_string = f"{end_user_id}|{timestamp}|{request_id}" | |
| signature = hmac.new( | |
| HMAC_SECRET.encode('utf-8'), # SECRET KEY (never sent!) | |
| signing_string.encode('utf-8'), | |
| hashlib.sha256 | |
| ).hexdigest() | |
| print(f"π Signing string: {signing_string}") | |
| print(f"π Signature: {signature[:20]}...") | |
| # ============================================ | |
| # STEP 4: Make Prediction Request | |
| # ============================================ | |
| print("\nStep 4: Making prediction request...") | |
| # IMPORTANT: The request format is: | |
| # { | |
| # "inputId": "string", # REQUIRED | |
| # "payload": { ... } # The features go here | |
| # } | |
| request_body = { | |
| "inputId": "loan-app-78945", # REQUIRED - unique identifier for this request | |
| "payload": { | |
| "num_previous_loans": 9, | |
| "num_previous_defaults": 4, | |
| "past_default_rate": 0.44, | |
| "days_since_last_loan": 2, | |
| "avg_time_bw_loans": 20, | |
| "avg_past_amount": 26000, | |
| "avg_past_daily_burden": 950, | |
| "std_past_amount": 4000, | |
| "std_past_daily_burden": 180, | |
| "trend_in_amount": 1.3, | |
| "trend_in_burden": 1.35, | |
| "Total_Amount": 30000, | |
| "Total_Amount_to_Repay": 36000, | |
| "duration": 20, | |
| "daily_burden": 1500, | |
| "amount_ratio": 2.0, | |
| "burden_ratio": 1.8, | |
| "duration_bucket": "20", | |
| "amount_bucket": "high", | |
| "burden_percentile": 0.95, | |
| "borrower_history_strength": "weak", | |
| "month": 1, | |
| "quarter": 1, | |
| "week_of_year": 3, | |
| "days_to_salary_day": 28, | |
| "days_to_local_festival": 2, | |
| "lender_id": "L_high3", | |
| "lender_exposure_ratio": 0.4, | |
| "account_age_days": 150, | |
| "loan_frequency_per_year": 12, | |
| "repayment_consistency": 0.4, | |
| "latest_amount_ma3": 28000 | |
| } | |
| } | |
| response = requests.post( | |
| f"{BASE_URL}/v1/predict_explain", | |
| headers={ | |
| "Authorization": f"Bearer {jwt_token}", | |
| "Content-Type": "application/json", | |
| "X-End-User-Id": end_user_id, | |
| "X-End-User-Timestamp": timestamp, | |
| "X-Request-Id": request_id, | |
| "X-End-User-Signature": signature | |
| }, | |
| json=request_body | |
| ) | |
| print(f"\nResponse Status: {response.status_code}") | |
| if response.status_code == 200: | |
| result = response.json() | |
| print("β Prediction successful!") | |
| print(f" Input ID: {result.get('inputId')}") | |
| print(f" Score: {result.get('score')}") | |
| if result.get('topFeatures'): | |
| print(f" Top Features: {len(result.get('topFeatures'))} features") | |
| print(f"\nFull response: {result}") | |
| else: | |
| print(f"β Prediction failed: {response.status_code}") | |
| print(response.text) | |