Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Enhanced Google Calendar Credential Diagnostics & Refresh Tool | |
| This script diagnoses calendar authentication issues and refreshes credentials. | |
| Usage locally: | |
| python3 refresh_credentials.py | |
| Usage via SSH on HuggingFace: | |
| ssh -i ~/.ssh/id_ed25519 pgits-voicecal-ai@ssh.hf.space | |
| cd /app && python refresh_credentials.py | |
| """ | |
| import sys | |
| import os | |
| sys.path.insert(0, '/app') | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from datetime import datetime | |
| import requests | |
| def check_environment_variables(): | |
| """Check all required environment variables.""" | |
| print("\n" + "=" * 70) | |
| print("STEP 1: Environment Variables Check") | |
| print("=" * 70) | |
| required_vars = { | |
| 'GOOGLE_CLIENT_ID': os.environ.get('GOOGLE_CLIENT_ID'), | |
| 'GOOGLE_CLIENT_SECRET': os.environ.get('GOOGLE_CLIENT_SECRET'), | |
| 'GOOGLE_REFRESH_TOKEN': os.environ.get('GOOGLE_REFRESH_TOKEN'), | |
| 'GOOGLE_ACCESS_TOKEN': os.environ.get('GOOGLE_ACCESS_TOKEN'), | |
| 'GOOGLE_TOKEN_EXPIRY': os.environ.get('GOOGLE_TOKEN_EXPIRY'), | |
| } | |
| all_present = True | |
| for var_name, var_value in required_vars.items(): | |
| if var_value: | |
| # Show first 20 chars for security | |
| display_value = f"{var_value[:20]}..." if len(var_value) > 20 else var_value | |
| print(f"β {var_name}: {display_value}") | |
| else: | |
| print(f"β {var_name}: MISSING") | |
| all_present = False | |
| if not all_present: | |
| print("\nβ οΈ Missing required environment variables!") | |
| print(" These must be configured in HuggingFace Secrets") | |
| return False | |
| return True | |
| def test_token_refresh(): | |
| """Test token refresh with Google OAuth API.""" | |
| print("\n" + "=" * 70) | |
| print("STEP 2: Token Refresh Test") | |
| print("=" * 70) | |
| refresh_token = os.environ.get('GOOGLE_REFRESH_TOKEN') | |
| client_id = os.environ.get('GOOGLE_CLIENT_ID') | |
| client_secret = os.environ.get('GOOGLE_CLIENT_SECRET') | |
| print("π Attempting to refresh access token via Google OAuth API...") | |
| data = { | |
| 'client_id': client_id, | |
| 'client_secret': client_secret, | |
| 'refresh_token': refresh_token, | |
| 'grant_type': 'refresh_token' | |
| } | |
| try: | |
| response = requests.post('https://oauth2.googleapis.com/token', data=data) | |
| print(f"Response Status: {response.status_code}") | |
| if response.status_code == 200: | |
| tokens = response.json() | |
| new_access_token = tokens['access_token'] | |
| expires_in = tokens.get('expires_in', 3600) | |
| from datetime import timedelta | |
| new_expiry = datetime.utcnow() + timedelta(seconds=expires_in) | |
| print("β Token refresh SUCCESSFUL!") | |
| print(f" New Access Token: {new_access_token[:30]}...") | |
| print(f" Expires in: {expires_in} seconds ({expires_in//3600} hours)") | |
| print(f" Expiry Time: {new_expiry.isoformat()}") | |
| print("\nπ Update these in HuggingFace Secrets:") | |
| print(f" GOOGLE_ACCESS_TOKEN={new_access_token}") | |
| print(f" GOOGLE_TOKEN_EXPIRY={new_expiry.isoformat()}") | |
| return True, new_access_token, new_expiry.isoformat() | |
| else: | |
| print(f"β Token refresh FAILED!") | |
| print(f" Status: {response.status_code}") | |
| print(f" Error: {response.text}") | |
| if response.status_code == 400: | |
| error_data = response.json() | |
| if error_data.get('error') == 'invalid_grant': | |
| print("\nπ DIAGNOSIS: invalid_grant error") | |
| print(" Possible causes:") | |
| print(" 1. Refresh token has been revoked") | |
| print(" 2. OAuth consent screen needs re-approval") | |
| print(" 3. Redirect URI mismatch in Google Cloud Console") | |
| print("\nπ οΈ SOLUTION:") | |
| print(" Re-authenticate: https://pgits-voicecal-ai-v3.hf.space/auth/login") | |
| elif response.status_code == 401: | |
| print("\nπ DIAGNOSIS: Authentication error") | |
| print(" Possible causes:") | |
| print(" 1. Wrong GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET") | |
| print(" 2. OAuth app not enabled in Google Cloud Console") | |
| print("\nπ οΈ SOLUTION:") | |
| print(" Verify credentials in Google Cloud Console") | |
| return False, None, None | |
| except Exception as e: | |
| print(f"β Exception: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return False, None, None | |
| def test_calendar_auth(): | |
| """Test calendar authentication using app's CalendarAuth.""" | |
| print("\n" + "=" * 70) | |
| print("STEP 3: Calendar Service Authentication Test") | |
| print("=" * 70) | |
| try: | |
| from app.calendar.auth import CalendarAuth | |
| from app.config import settings | |
| print("π Initializing CalendarAuth...") | |
| auth = CalendarAuth() | |
| print("π Loading credentials...") | |
| credentials = auth.load_credentials() | |
| if not credentials: | |
| print("β No credentials found!") | |
| print(" DIAGNOSIS: Environment variables may be missing") | |
| print(" SOLUTION: Ensure all GOOGLE_* vars are in HuggingFace Secrets") | |
| return False | |
| print(f"β Credentials loaded!") | |
| print(f" Token Expiry: {credentials.expiry}") | |
| print(f" Token Expired: {credentials.expired}") | |
| print(f" Has Refresh Token: {credentials.refresh_token is not None}") | |
| # Try to get calendar service | |
| print("\nπ§ Attempting to get calendar service...") | |
| service = auth.get_calendar_service() | |
| if not service: | |
| print("β Calendar service is None!") | |
| return False | |
| print("β Calendar service obtained!") | |
| # Test API call | |
| print("\nπ§ͺ Testing Calendar API call (list calendars)...") | |
| calendars = service.calendarList().list().execute() | |
| print(f"β API call successful! Found {len(calendars.get('items', []))} calendars") | |
| return True | |
| except ValueError as e: | |
| if "No valid credentials" in str(e): | |
| print(f"β FATAL: {e}") | |
| print("\nπ DIAGNOSIS: No valid credentials available") | |
| print(" This is the error you're seeing in production") | |
| print("\nπ οΈ SOLUTION:") | |
| print(" 1. Check all GOOGLE_* environment variables are set") | |
| print(" 2. Run token refresh (STEP 2)") | |
| print(" 3. Update GOOGLE_ACCESS_TOKEN and GOOGLE_TOKEN_EXPIRY") | |
| print(" 4. Or re-authenticate via /auth/login") | |
| else: | |
| print(f"β ValueError: {e}") | |
| return False | |
| except Exception as e: | |
| print(f"β Exception: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return False | |
| def main(): | |
| print("=" * 70) | |
| print("π§ VOICECAL.AI - GOOGLE CALENDAR AUTH DIAGNOSTICS") | |
| print("=" * 70) | |
| print(f"Timestamp: {datetime.now().isoformat()}") | |
| print(f"Environment: {os.environ.get('APP_ENV', 'unknown')}") | |
| print() | |
| # Step 1: Check environment variables | |
| env_ok = check_environment_variables() | |
| if not env_ok: | |
| print("\nβ CRITICAL: Environment variables missing. Cannot proceed.") | |
| print(" Add them to HuggingFace Secrets first.") | |
| return | |
| # Step 2: Test token refresh | |
| refresh_ok, new_token, new_expiry = test_token_refresh() | |
| # Step 3: Test calendar authentication | |
| auth_ok = test_calendar_auth() | |
| # Summary | |
| print("\n" + "=" * 70) | |
| print("DIAGNOSTIC SUMMARY") | |
| print("=" * 70) | |
| print(f"Environment Variables: {'β OK' if env_ok else 'β FAILED'}") | |
| print(f"Token Refresh: {'β OK' if refresh_ok else 'β FAILED'}") | |
| print(f"Calendar Auth: {'β OK' if auth_ok else 'β FAILED'}") | |
| print("=" * 70) | |
| if env_ok and refresh_ok and not auth_ok: | |
| print("\nπ‘ RECOMMENDATION:") | |
| print(" The token refresh worked, but calendar auth failed.") | |
| print(" Update these secrets in HuggingFace:") | |
| print(f" GOOGLE_ACCESS_TOKEN={new_token}") | |
| print(f" GOOGLE_TOKEN_EXPIRY={new_expiry}") | |
| print(" Then restart the space.") | |
| elif not refresh_ok: | |
| print("\nπ‘ RECOMMENDATION:") | |
| print(" Token refresh failed. You need to re-authenticate.") | |
| print(" Visit: https://pgits-voicecal-ai-v3.hf.space/auth/login") | |
| elif auth_ok: | |
| print("\nπ SUCCESS! Calendar authentication is working properly!") | |
| print("\n" + "=" * 70) | |
| if __name__ == "__main__": | |
| main() |