Maksymilian Jankowski commited on
Commit
56d209d
Β·
1 Parent(s): ea12465
Files changed (7) hide show
  1. .env +0 -10
  2. README.md +45 -181
  3. check_deployment.py +0 -145
  4. main.py +1 -1
  5. simple_test.py +126 -0
  6. test_deployment.py +325 -0
  7. test_endpoints.sh +104 -0
.env DELETED
@@ -1,10 +0,0 @@
1
- # OpenAI API Key
2
- #OPENAI_API_KEY="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"
3
- OPENAI_API_KEY="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"
4
- # Google API Key (for Gemini)
5
- GOOGLE_API_KEY="AIzaSyCH4rdbuK1cfRpwkhpnpxbdWnrO8RsxAD8"
6
- MESHY_API_KEY="msy_UnUQpybrhKHfDdgIbpkYw4BEBWZ2WV2wEImI"
7
- SUPABASE_URL="https://blhjlpokxsdalllewjbx.supabase.co"
8
- SUPABASE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJsaGpscG9reHNkYWxsbGV3amJ4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDgyNjY0MjksImV4cCI6MjA2Mzg0MjQyOX0.TsoeN7Lid7gmlTJ18Ayp31LEt6Xpyg5VbKt4J5EJGNE"
9
- STRIPE_SECRET_KEY=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
10
- #STRIPE_WEBHOOK_SECRET=
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,220 +1,84 @@
1
  ---
2
- title: 3D E-Commerce Backend API
3
  emoji: 🎯
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: docker
7
- sdk_version: "4.36.0"
8
- app_file: main.py
9
  app_port: 7860
10
  pinned: false
 
11
  ---
12
 
13
- # 3D E-Commerce Backend API
14
 
15
- This repository contains a FastAPI backend for a robust 3D model e-commerce platform. It integrates:
16
 
17
- - **Supabase** for authentication, user, and credit management
18
- - **Meshy** for 3D model generation (Image-to-3D, Text-to-3D)
19
- - **OpenAI** for prompt reframing
20
- - Endpoints for user onboarding, credit-guarded model generation, credit purchase, order placement, and user dashboard
21
 
22
- ---
23
-
24
- ## Table of Contents
25
-
26
- - [Prerequisites](#prerequisites)
27
- - [Installation](#installation)
28
- - [Configuration](#configuration)
29
- - [Running Locally](#running-locally)
30
- - [API Endpoints](#api-endpoints)
31
- - [Authentication](#authentication)
32
- - [User Onboarding & Profile](#user-onboarding--profile)
33
- - [Credits](#credits)
34
- - [3D Model Generation](#3d-model-generation)
35
- - [Orders](#orders)
36
- - [User Dashboard](#user-dashboard)
37
- - [Health Check](#health-check)
38
- - [References](#references)
39
-
40
- ---
41
 
42
- ## Prerequisites
43
-
44
- - Python 3.10+
45
- - `pip`
46
- - Supabase project (with tables: User, User_Credit_Account, Generated_Models, Model_Order_History, Credit_Order_History)
47
- - Meshy and OpenAI API keys
48
-
49
- ---
50
 
51
- ## Installation
52
 
53
- ```bash
54
- git clone <your-repo-url>
55
- cd api-backend
56
- python -m venv venv
57
- source venv/bin/activate
58
- pip install -r requirements.txt
59
  ```
60
-
61
- ---
62
-
63
- ## Configuration
64
-
65
- Create a `.env` file in the project root:
66
-
67
- ```ini
68
  SUPABASE_URL=https://<your-supabase>.supabase.co
69
  SUPABASE_KEY=<your-supabase-service-role-key>
70
- MESHY_API_KEY=msy_<your_meshy_key>
71
- OPENAI_API_KEY=sk-<your_openai_key>
 
72
  ```
73
 
74
- ---
75
-
76
- ## Running Locally
77
 
 
78
  ```bash
79
- export SUPABASE_URL=...
80
- export SUPABASE_KEY=...
81
- export MESHY_API_KEY=...
82
- export OPENAI_API_KEY=...
83
- python main.py
84
  ```
85
 
86
- - Swagger UI: http://127.0.0.1:8000/docs
87
-
88
- ---
89
-
90
- ## API Endpoints
91
-
92
- ### Authentication
93
-
94
- - **POST `/auth/signup`**
95
- Sign up a new user.
96
- **Body:** `{ "email": "...", "password": "..." }`
97
-
98
- - **POST `/auth/signin`**
99
- Sign in and receive JWT.
100
- **Body:** `{ "email": "...", "password": "..." }`
101
- **Response:** `{ "access_token": "...", "user": {...} }`
102
-
103
- - **POST `/auth/complete-profile`**
104
- Complete user profile and initialize credits.
105
- **Auth:** Bearer token
106
- **Body:** `{ "address": "...", "fullname": "...", "phone_number": "..." }`
107
-
108
- ---
109
-
110
- ### User Onboarding & Profile
111
-
112
- - **GET `/user/profile`**
113
- Get current user's profile.
114
- **Auth:** Bearer token
115
-
116
- ---
117
-
118
- ### Credits
119
-
120
- - **GET `/user/credits`**
121
- Get available generation credits.
122
- **Auth:** Bearer token
123
-
124
- - **POST `/credits/purchase`**
125
- Purchase credits, updates credit account and order history.
126
- **Auth:** Bearer token
127
- **Body:**
128
- ```json
129
- {
130
- "number_of_generations": 10,
131
- "price": 19.99,
132
- "transaction_id": "txn_123"
133
- }
134
- ```
135
-
136
- ---
137
-
138
- ### 3D Model Generation
139
-
140
- - **POST `/req-img-to-3d`**
141
- Generate 3D model from image (costs 1 credit).
142
- **Auth:** Bearer token
143
- **Body:** `multipart/form-data` with `image` file
144
-
145
- - **GET `/req-result-img-to-3d/{task_id}`**
146
- Get status/result of image-to-3D task.
147
- **Auth:** Bearer token
148
-
149
- - **GET `/list-img-to-3d-req`**
150
- List all image-to-3D tasks for user.
151
- **Auth:** Bearer token
152
-
153
- - **POST `/req-text-to-3d`**
154
- Generate 3D model from text (costs 1 credit, prompt reframed by OpenAI).
155
- **Auth:** Bearer token
156
- **Body:** `{ "text": "..." }`
157
 
158
- - **GET `/req-result-text-to-3d/{task_id}`**
159
- Get status/result of text-to-3D task.
160
- **Auth:** Bearer token
161
 
162
- - **GET `/list-text-to-3d-req`**
163
- List all text-to-3D tasks for user.
164
- **Auth:** Bearer token
165
 
166
- ---
167
 
168
- ### Orders
169
-
170
- - **POST `/orders/place`**
171
- Place an order for a 3D model print.
172
- **Auth:** Bearer token
173
- **Body:**
174
- ```json
175
- {
176
- "generated_model_id": "...",
177
- "price": 29.99,
178
- "packaging_price": 5.00,
179
- "material_price": 10.00,
180
- "delivery_address": "...",
181
- "order_status": "pending",
182
- "estimated_delivery_date": "2024-07-01",
183
- "shipping_tracking_id": "track_123",
184
- "payment_status": "paid",
185
- "transaction_id": "txn_456"
186
- }
187
- ```
188
-
189
- - **GET `/user/orders`**
190
- Get all orders for the current user.
191
- **Auth:** Bearer token
192
 
193
- ---
 
 
194
 
195
- ### User Dashboard
196
 
197
- - **GET `/user/models`**
198
- Get all generated models for the current user.
199
- **Auth:** Bearer token
200
 
201
- ---
 
 
 
 
202
 
203
- ### Health Check
204
 
205
- - **GET `/`**
206
- Returns `{ "status": "ok" }`
207
 
208
- ---
209
 
210
- ## References
211
 
212
- - [Supabase Docs](https://supabase.com/docs)
213
- - [Meshy Image-to-3D API](https://docs.meshy.ai/en/api/image-to-3d)
214
- - [Meshy Text-to-3D API](https://docs.meshy.ai/en/api/text-to-3d)
215
- - [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat/create)
216
 
217
- ---
218
 
219
- **Note:** All endpoints requiring authentication expect a Bearer token in the `Authorization` header.
220
- **Credit-guarded endpoints** will decrement user credits atomically and return an error if insufficient.
 
1
  ---
2
+ title: 3DAI API Backend
3
  emoji: 🎯
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: docker
 
 
7
  app_port: 7860
8
  pinned: false
9
+ license: apache-2.0
10
  ---
11
 
12
+ # 3DAI API Backend
13
 
14
+ A FastAPI backend for 3D AI model generation services.
15
 
16
+ ## Features
 
 
 
17
 
18
+ - User authentication with Supabase
19
+ - Image-to-3D conversion using Meshy AI
20
+ - Text-to-3D conversion
21
+ - Credit system for usage tracking
22
+ - Stripe integration for payments
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ ## Environment Variables
 
 
 
 
 
 
 
25
 
26
+ Create a `.env` file with the following variables:
27
 
 
 
 
 
 
 
28
  ```
 
 
 
 
 
 
 
 
29
  SUPABASE_URL=https://<your-supabase>.supabase.co
30
  SUPABASE_KEY=<your-supabase-service-role-key>
31
+ JWT_SECRET_KEY=<your-jwt-secret-key>
32
+ OPENAI_API_KEY=<your-openai-api-key>
33
+ STRIPE_SECRET_KEY=<your-stripe-secret-key>
34
  ```
35
 
36
+ ## Local Development
 
 
37
 
38
+ 1. Install dependencies:
39
  ```bash
40
+ pip install -r requirements.txt
 
 
 
 
41
  ```
42
 
43
+ 2. Run the development server:
44
+ ```bash
45
+ uvicorn main:app --host 0.0.0.0 --port 7860 --reload
46
+ ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ 3. Visit http://localhost:7860/docs for API documentation
 
 
49
 
50
+ ## Deployment
 
 
51
 
52
+ ### Hugging Face Spaces
53
 
54
+ This app is configured to run on Hugging Face Spaces using Docker. Make sure to:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ 1. Set all required environment variables in your Space settings
57
+ 2. Use the Docker SDK configuration
58
+ 3. Set app_port to 7860
59
 
60
+ ### Environment Setup for Deployment
61
 
62
+ Set these environment variables in your deployment platform:
 
 
63
 
64
+ - `SUPABASE_URL`: Your Supabase project URL
65
+ - `SUPABASE_KEY`: Your Supabase service role key
66
+ - `JWT_SECRET_KEY`: A secure random string for JWT signing
67
+ - `OPENAI_API_KEY`: Your OpenAI API key
68
+ - `STRIPE_SECRET_KEY`: Your Stripe secret key
69
 
70
+ ## API Documentation
71
 
72
+ Once running, visit `/docs` for interactive API documentation.
 
73
 
74
+ ## Testing
75
 
76
+ Run the comprehensive test suite:
77
 
78
+ ```bash
79
+ python test_deployment.py
80
+ ```
 
81
 
82
+ ## License
83
 
84
+ Apache 2.0
 
check_deployment.py DELETED
@@ -1,145 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Deployment troubleshooting script for 3DAI API Backend
4
- Run this script to check your deployment configuration
5
- """
6
-
7
- import os
8
- import sys
9
- from dotenv import load_dotenv
10
-
11
- def check_environment_variables():
12
- """Check if all required environment variables are set"""
13
- print("πŸ” Checking Environment Variables...")
14
-
15
- required_vars = [
16
- "SUPABASE_URL",
17
- "SUPABASE_KEY",
18
- "OPENAI_API_KEY",
19
- "STRIPE_SECRET_KEY"
20
- ]
21
-
22
- optional_vars = [
23
- "JWT_SECRET_KEY"
24
- ]
25
-
26
- missing_vars = []
27
-
28
- for var in required_vars:
29
- value = os.getenv(var)
30
- if not value:
31
- missing_vars.append(var)
32
- print(f"❌ {var}: Not set")
33
- else:
34
- # Show partial value for security
35
- masked_value = value[:8] + "..." if len(value) > 8 else "***"
36
- print(f"βœ… {var}: {masked_value}")
37
-
38
- for var in optional_vars:
39
- value = os.getenv(var)
40
- if not value:
41
- print(f"⚠️ {var}: Not set (using default)")
42
- else:
43
- masked_value = value[:8] + "..." if len(value) > 8 else "***"
44
- print(f"βœ… {var}: {masked_value}")
45
-
46
- return missing_vars
47
-
48
- def check_dependencies():
49
- """Check if all required Python packages are installed"""
50
- print("\nπŸ“¦ Checking Dependencies...")
51
-
52
- required_packages = [
53
- "fastapi",
54
- "uvicorn",
55
- "supabase",
56
- "httpx",
57
- "stripe",
58
- "pydantic",
59
- "python-jose",
60
- "passlib"
61
- ]
62
-
63
- missing_packages = []
64
-
65
- for package in required_packages:
66
- try:
67
- __import__(package.replace("-", "_"))
68
- print(f"βœ… {package}: Installed")
69
- except ImportError:
70
- missing_packages.append(package)
71
- print(f"❌ {package}: Not installed")
72
-
73
- return missing_packages
74
-
75
- def check_supabase_connection():
76
- """Test Supabase connection"""
77
- print("\nπŸ—„οΈ Testing Supabase Connection...")
78
-
79
- try:
80
- from supabase import create_client
81
-
82
- url = os.getenv("SUPABASE_URL")
83
- key = os.getenv("SUPABASE_KEY")
84
-
85
- if not url or not key:
86
- print("❌ Supabase credentials not set")
87
- return False
88
-
89
- client = create_client(url, key)
90
-
91
- # Test a simple query
92
- result = client.from_("User").select("user_id").limit(1).execute()
93
- print("βœ… Supabase connection successful")
94
- return True
95
-
96
- except Exception as e:
97
- print(f"❌ Supabase connection failed: {str(e)}")
98
- return False
99
-
100
- def main():
101
- """Main troubleshooting function"""
102
- print("πŸš€ 3DAI API Backend Deployment Check")
103
- print("=" * 50)
104
-
105
- # Load environment variables
106
- load_dotenv()
107
-
108
- # Check environment variables
109
- missing_env_vars = check_environment_variables()
110
-
111
- # Check dependencies
112
- missing_packages = check_dependencies()
113
-
114
- # Check Supabase connection
115
- supabase_ok = check_supabase_connection()
116
-
117
- # Summary
118
- print("\nπŸ“‹ Summary:")
119
- print("=" * 30)
120
-
121
- if missing_env_vars:
122
- print(f"❌ Missing environment variables: {', '.join(missing_env_vars)}")
123
- print(" Fix: Set these in your deployment environment or .env file")
124
-
125
- if missing_packages:
126
- print(f"❌ Missing packages: {', '.join(missing_packages)}")
127
- print(" Fix: Run 'pip install -r requirements.txt'")
128
-
129
- if not supabase_ok:
130
- print("❌ Supabase connection failed")
131
- print(" Fix: Check your SUPABASE_URL and SUPABASE_KEY")
132
-
133
- if not missing_env_vars and not missing_packages and supabase_ok:
134
- print("βœ… All checks passed! Your deployment should work.")
135
- print("\nπŸ”§ If sync-supabase-user still doesn't work, check:")
136
- print(" 1. Network connectivity to your deployed service")
137
- print(" 2. API endpoint URL is correct")
138
- print(" 3. Check application logs for specific errors")
139
- print(" 4. Verify your Supabase database schema matches the code")
140
- else:
141
- print("\n❌ Issues found. Fix the above problems and try again.")
142
- sys.exit(1)
143
-
144
- if __name__ == "__main__":
145
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
main.py CHANGED
@@ -21,7 +21,7 @@ dev_mode = False
21
 
22
  class Settings:
23
  def __init__(self):
24
- self.mesh_api_key = "msy_slVFWXjDQvc2BR8ltSacK79YshK9KCXkaV3F"
25
  if not self.mesh_api_key:
26
  raise RuntimeError("MESHY_API_KEY environment variable not set")
27
  self.openai_api_key = os.getenv("OPENAI_API_KEY")
 
21
 
22
  class Settings:
23
  def __init__(self):
24
+ self.mesh_api_key = os.getenv("MESHY_API_KEY")
25
  if not self.mesh_api_key:
26
  raise RuntimeError("MESHY_API_KEY environment variable not set")
27
  self.openai_api_key = os.getenv("OPENAI_API_KEY")
simple_test.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple backend test to diagnose connection issues
4
+ """
5
+
6
+ import requests
7
+ import json
8
+ from urllib3.exceptions import InsecureRequestWarning
9
+ import urllib3
10
+
11
+ # Disable SSL warnings for testing
12
+ urllib3.disable_warnings(InsecureRequestWarning)
13
+
14
+ def test_backend(url):
15
+ """Test backend with browser-like headers"""
16
+ print(f"πŸ” Testing backend at: {url}")
17
+
18
+ # Create session with browser-like headers
19
+ session = requests.Session()
20
+ session.headers.update({
21
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
22
+ 'Accept': 'application/json, text/plain, */*',
23
+ 'Accept-Language': 'en-US,en;q=0.9',
24
+ 'Accept-Encoding': 'gzip, deflate, br',
25
+ 'Connection': 'keep-alive',
26
+ 'Upgrade-Insecure-Requests': '1',
27
+ })
28
+
29
+ try:
30
+ print("πŸ“‘ Making request...")
31
+ response = session.get(url, timeout=30, verify=False)
32
+
33
+ print(f"βœ… Status Code: {response.status_code}")
34
+ print(f"πŸ“„ Response Headers:")
35
+ for key, value in response.headers.items():
36
+ print(f" {key}: {value}")
37
+
38
+ print(f"πŸ“ Response Content:")
39
+ print(f" {response.text}")
40
+
41
+ if response.status_code == 200:
42
+ try:
43
+ json_data = response.json()
44
+ print(f"βœ… Valid JSON response: {json_data}")
45
+ return True
46
+ except:
47
+ print("⚠️ Response is not valid JSON")
48
+ return True
49
+ else:
50
+ print(f"❌ Non-200 status code: {response.status_code}")
51
+ return False
52
+
53
+ except requests.exceptions.Timeout:
54
+ print("❌ Request timed out (30 seconds)")
55
+ return False
56
+ except requests.exceptions.ConnectionError as e:
57
+ print(f"❌ Connection error: {str(e)}")
58
+ return False
59
+ except requests.exceptions.SSLError as e:
60
+ print(f"❌ SSL error: {str(e)}")
61
+ return False
62
+ except Exception as e:
63
+ print(f"❌ Unexpected error: {str(e)}")
64
+ return False
65
+
66
+ def test_multiple_endpoints(base_url):
67
+ """Test multiple endpoints"""
68
+ endpoints = [
69
+ "/",
70
+ "/docs",
71
+ "/openapi.json",
72
+ "/auth/signup",
73
+ ]
74
+
75
+ results = {}
76
+
77
+ for endpoint in endpoints:
78
+ url = f"{base_url.rstrip('/')}{endpoint}"
79
+ print(f"\n🎯 Testing endpoint: {endpoint}")
80
+ print("-" * 40)
81
+
82
+ if endpoint == "/auth/signup":
83
+ # Test with POST method
84
+ try:
85
+ session = requests.Session()
86
+ session.headers.update({
87
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
88
+ 'Content-Type': 'application/json',
89
+ })
90
+
91
+ response = session.post(url,
92
+ json={"email": "test@example.com", "password": "test123"},
93
+ timeout=30,
94
+ verify=False
95
+ )
96
+ print(f"Status: {response.status_code}")
97
+ print(f"Response: {response.text[:200]}...")
98
+ results[endpoint] = response.status_code < 500
99
+ except Exception as e:
100
+ print(f"Error: {str(e)}")
101
+ results[endpoint] = False
102
+ else:
103
+ # Test with GET method
104
+ results[endpoint] = test_backend(url)
105
+
106
+ return results
107
+
108
+ if __name__ == "__main__":
109
+ base_url = "https://maxjski-3dai.hf.space"
110
+
111
+ print("πŸš€ Simple Backend Diagnostic Tool")
112
+ print("=" * 50)
113
+
114
+ # Test main endpoint first
115
+ main_works = test_backend(base_url)
116
+
117
+ if main_works:
118
+ print(f"\nβœ… Main endpoint works! Testing other endpoints...")
119
+ results = test_multiple_endpoints(base_url)
120
+
121
+ print(f"\nπŸ“Š Summary:")
122
+ for endpoint, status in results.items():
123
+ status_text = "βœ… Working" if status else "❌ Issues"
124
+ print(f" {endpoint}: {status_text}")
125
+ else:
126
+ print(f"\n❌ Main endpoint has issues. Check your deployment.")
test_deployment.py ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Comprehensive test script for 3DAI API Backend deployment
4
+ Tests all endpoints to verify they're working properly
5
+ """
6
+
7
+ import requests
8
+ import json
9
+ import time
10
+ import os
11
+ from typing import Optional, Dict, Any
12
+
13
+ class BackendTester:
14
+ def __init__(self, base_url: str):
15
+ self.base_url = base_url.rstrip('/')
16
+ self.session = requests.Session()
17
+ self.session.headers.update({
18
+ 'Content-Type': 'application/json',
19
+ 'User-Agent': '3DAI-Backend-Tester/1.0'
20
+ })
21
+
22
+ def test_health_check(self) -> bool:
23
+ """Test the basic health check endpoint"""
24
+ print("πŸ₯ Testing Health Check...")
25
+ try:
26
+ response = self.session.get(f"{self.base_url}/", timeout=10)
27
+ if response.status_code == 200:
28
+ print("βœ… Health check passed")
29
+ print(f" Response: {response.json()}")
30
+ return True
31
+ else:
32
+ print(f"❌ Health check failed with status {response.status_code}")
33
+ print(f" Response: {response.text}")
34
+ return False
35
+ except Exception as e:
36
+ print(f"❌ Health check failed: {str(e)}")
37
+ return False
38
+
39
+ def test_docs_endpoint(self) -> bool:
40
+ """Test if the API documentation is accessible"""
41
+ print("\nπŸ“š Testing API Documentation...")
42
+ try:
43
+ response = self.session.get(f"{self.base_url}/docs", timeout=10)
44
+ if response.status_code == 200:
45
+ print("βœ… API docs accessible")
46
+ return True
47
+ else:
48
+ print(f"❌ API docs failed with status {response.status_code}")
49
+ return False
50
+ except Exception as e:
51
+ print(f"❌ API docs failed: {str(e)}")
52
+ return False
53
+
54
+ def test_openapi_spec(self) -> bool:
55
+ """Test if the OpenAPI specification is accessible"""
56
+ print("\nπŸ”§ Testing OpenAPI Specification...")
57
+ try:
58
+ response = self.session.get(f"{self.base_url}/openapi.json", timeout=10)
59
+ if response.status_code == 200:
60
+ print("βœ… OpenAPI spec accessible")
61
+ spec = response.json()
62
+ print(f" API Title: {spec.get('info', {}).get('title', 'N/A')}")
63
+ print(f" API Version: {spec.get('info', {}).get('version', 'N/A')}")
64
+ print(f" Available endpoints: {len(spec.get('paths', {}))}")
65
+ return True
66
+ else:
67
+ print(f"❌ OpenAPI spec failed with status {response.status_code}")
68
+ return False
69
+ except Exception as e:
70
+ print(f"❌ OpenAPI spec failed: {str(e)}")
71
+ return False
72
+
73
+ def test_signup_endpoint(self) -> Optional[Dict[str, Any]]:
74
+ """Test the signup endpoint"""
75
+ print("\nπŸ‘€ Testing Signup Endpoint...")
76
+ try:
77
+ test_email = f"test_{int(time.time())}@example.com"
78
+ test_password = "TestPassword123!"
79
+
80
+ payload = {
81
+ "email": test_email,
82
+ "password": test_password
83
+ }
84
+
85
+ response = self.session.post(
86
+ f"{self.base_url}/auth/signup",
87
+ json=payload,
88
+ timeout=15
89
+ )
90
+
91
+ if response.status_code in [200, 201]:
92
+ print("βœ… Signup endpoint working")
93
+ result = response.json()
94
+ print(f" Created user: {result.get('user', {}).get('email', 'unknown')}")
95
+ return result
96
+ else:
97
+ print(f"❌ Signup failed with status {response.status_code}")
98
+ print(f" Response: {response.text}")
99
+ return None
100
+ except Exception as e:
101
+ print(f"❌ Signup test failed: {str(e)}")
102
+ return None
103
+
104
+ def test_signin_endpoint(self, email: str, password: str) -> Optional[str]:
105
+ """Test the signin endpoint"""
106
+ print("\nπŸ” Testing Signin Endpoint...")
107
+ try:
108
+ payload = {
109
+ "email": email,
110
+ "password": password
111
+ }
112
+
113
+ response = self.session.post(
114
+ f"{self.base_url}/auth/signin",
115
+ json=payload,
116
+ timeout=15
117
+ )
118
+
119
+ if response.status_code == 200:
120
+ print("βœ… Signin endpoint working")
121
+ result = response.json()
122
+ token = result.get('access_token')
123
+ if token:
124
+ print(f" Token received: {token[:20]}...")
125
+ return token
126
+ else:
127
+ print(" ⚠️ No token in response")
128
+ return None
129
+ else:
130
+ print(f"❌ Signin failed with status {response.status_code}")
131
+ print(f" Response: {response.text}")
132
+ return None
133
+ except Exception as e:
134
+ print(f"❌ Signin test failed: {str(e)}")
135
+ return None
136
+
137
+ def test_sync_supabase_user_endpoint(self, token: str) -> bool:
138
+ """Test the sync-supabase-user endpoint"""
139
+ print("\nπŸ”„ Testing Sync Supabase User Endpoint...")
140
+ try:
141
+ headers = {"Authorization": f"Bearer {token}"}
142
+ payload = {
143
+ "supabase_user_id": "test_user_id",
144
+ "email": "test@example.com",
145
+ "full_name": "Test User"
146
+ }
147
+
148
+ response = self.session.post(
149
+ f"{self.base_url}/auth/sync-supabase-user",
150
+ json=payload,
151
+ headers=headers,
152
+ timeout=15
153
+ )
154
+
155
+ if response.status_code in [200, 201]:
156
+ print("βœ… Sync Supabase User endpoint working")
157
+ result = response.json()
158
+ print(f" Message: {result.get('message', 'No message')}")
159
+ return True
160
+ else:
161
+ print(f"❌ Sync Supabase User failed with status {response.status_code}")
162
+ print(f" Response: {response.text}")
163
+ return False
164
+ except Exception as e:
165
+ print(f"❌ Sync Supabase User test failed: {str(e)}")
166
+ return False
167
+
168
+ def test_protected_endpoint(self, token: str) -> bool:
169
+ """Test a protected endpoint (user profile)"""
170
+ print("\nπŸ›‘οΈ Testing Protected Endpoint (User Profile)...")
171
+ try:
172
+ headers = {"Authorization": f"Bearer {token}"}
173
+
174
+ response = self.session.get(
175
+ f"{self.base_url}/user/profile",
176
+ headers=headers,
177
+ timeout=15
178
+ )
179
+
180
+ if response.status_code == 200:
181
+ print("βœ… Protected endpoint working")
182
+ result = response.json()
183
+ print(f" Profile data received: {len(str(result))} characters")
184
+ return True
185
+ else:
186
+ print(f"❌ Protected endpoint failed with status {response.status_code}")
187
+ print(f" Response: {response.text}")
188
+ return False
189
+ except Exception as e:
190
+ print(f"❌ Protected endpoint test failed: {str(e)}")
191
+ return False
192
+
193
+ def test_cors_headers(self) -> bool:
194
+ """Test CORS headers"""
195
+ print("\n🌐 Testing CORS Headers...")
196
+ try:
197
+ response = self.session.options(f"{self.base_url}/", timeout=10)
198
+ cors_headers = {
199
+ 'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
200
+ 'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
201
+ 'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers'),
202
+ }
203
+
204
+ if any(cors_headers.values()):
205
+ print("βœ… CORS headers present")
206
+ for header, value in cors_headers.items():
207
+ if value:
208
+ print(f" {header}: {value}")
209
+ return True
210
+ else:
211
+ print("⚠️ No CORS headers found")
212
+ return False
213
+ except Exception as e:
214
+ print(f"❌ CORS test failed: {str(e)}")
215
+ return False
216
+
217
+ def main():
218
+ """Main testing function"""
219
+ print("πŸš€ 3DAI API Backend Deployment Test Suite")
220
+ print("=" * 60)
221
+
222
+ # Get base URL from user input or environment
223
+ base_url = input("Enter your deployed backend URL (e.g., https://your-app.hf.space): ").strip()
224
+
225
+ if not base_url:
226
+ print("❌ No URL provided. Exiting.")
227
+ return
228
+
229
+ # Initialize tester
230
+ tester = BackendTester(base_url)
231
+
232
+ # Run tests
233
+ print(f"\n🎯 Testing backend at: {base_url}")
234
+ print("-" * 60)
235
+
236
+ # Basic connectivity tests
237
+ health_ok = tester.test_health_check()
238
+ docs_ok = tester.test_docs_endpoint()
239
+ openapi_ok = tester.test_openapi_spec()
240
+ cors_ok = tester.test_cors_headers()
241
+
242
+ # Authentication tests
243
+ signup_result = tester.test_signup_endpoint()
244
+ token = None
245
+ signin_ok = False
246
+ sync_ok = False
247
+ protected_ok = False
248
+
249
+ if signup_result and signup_result.get('user'):
250
+ # Try to sign in with the created user
251
+ user_email = signup_result['user']['email']
252
+ token = tester.test_signin_endpoint(user_email, "TestPassword123!")
253
+ signin_ok = token is not None
254
+
255
+ if token:
256
+ # Test sync endpoint
257
+ sync_ok = tester.test_sync_supabase_user_endpoint(token)
258
+
259
+ # Test protected endpoint
260
+ protected_ok = tester.test_protected_endpoint(token)
261
+
262
+ # Summary
263
+ print("\n" + "=" * 60)
264
+ print("πŸ“Š TEST RESULTS SUMMARY")
265
+ print("=" * 60)
266
+
267
+ basic_tests = [
268
+ ("Health Check", health_ok),
269
+ ("API Documentation", docs_ok),
270
+ ("OpenAPI Specification", openapi_ok),
271
+ ("CORS Headers", cors_ok),
272
+ ]
273
+
274
+ auth_tests = [
275
+ ("User Signup", signup_result is not None),
276
+ ("User Signin", signin_ok),
277
+ ("Sync Supabase User", sync_ok),
278
+ ("Protected Endpoint", protected_ok),
279
+ ]
280
+
281
+ print("\nπŸ”§ Basic Functionality:")
282
+ for test_name, result in basic_tests:
283
+ status = "βœ… PASS" if result else "❌ FAIL"
284
+ print(f" {test_name}: {status}")
285
+
286
+ print("\nπŸ” Authentication & Authorization:")
287
+ for test_name, result in auth_tests:
288
+ status = "βœ… PASS" if result else "❌ FAIL"
289
+ print(f" {test_name}: {status}")
290
+
291
+ # Overall status
292
+ all_basic_pass = all(result for _, result in basic_tests)
293
+ some_auth_pass = any(result for _, result in auth_tests)
294
+
295
+ print("\n🎯 OVERALL STATUS:")
296
+ if all_basic_pass and some_auth_pass:
297
+ print("βœ… Backend is working! Most functionality is operational.")
298
+ elif all_basic_pass:
299
+ print("⚠️ Backend is partially working. Basic endpoints work but authentication has issues.")
300
+ elif health_ok:
301
+ print("⚠️ Backend is running but has significant issues.")
302
+ else:
303
+ print("❌ Backend appears to be down or not accessible.")
304
+
305
+ # Recommendations
306
+ print("\nπŸ’‘ RECOMMENDATIONS:")
307
+ if not health_ok:
308
+ print(" 1. Check if your backend is actually deployed and running")
309
+ print(" 2. Verify the URL is correct")
310
+ print(" 3. Check deployment logs for errors")
311
+ elif not some_auth_pass:
312
+ print(" 1. Check environment variables (SUPABASE_URL, SUPABASE_KEY, etc.)")
313
+ print(" 2. Verify database connectivity")
314
+ print(" 3. Check authentication service configuration")
315
+ elif not sync_ok:
316
+ print(" 1. The sync-supabase-user endpoint specifically has issues")
317
+ print(" 2. Check database schema (User and User_Credit_Account tables)")
318
+ print(" 3. Review application logs for specific errors")
319
+ else:
320
+ print(" 1. Your backend appears to be working well!")
321
+ print(" 2. Test with real data and scenarios")
322
+ print(" 3. Monitor performance and error rates")
323
+
324
+ if __name__ == "__main__":
325
+ main()
test_endpoints.sh ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Quick endpoint testing script using curl
3
+ # Usage: ./test_endpoints.sh <your-backend-url>
4
+
5
+ BASE_URL=${1:-"http://localhost:7860"}
6
+ BASE_URL=${BASE_URL%/} # Remove trailing slash
7
+
8
+ echo "πŸš€ Testing 3DAI API Backend at: $BASE_URL"
9
+ echo "=" * 60
10
+
11
+ # Test 1: Health Check
12
+ echo "πŸ₯ Testing Health Check..."
13
+ curl -s -w "Status: %{http_code}\n" "$BASE_URL/" | head -10
14
+ echo ""
15
+
16
+ # Test 2: API Documentation
17
+ echo "πŸ“š Testing API Documentation..."
18
+ curl -s -I "$BASE_URL/docs" | grep "HTTP"
19
+ echo ""
20
+
21
+ # Test 3: OpenAPI Specification
22
+ echo "πŸ”§ Testing OpenAPI Specification..."
23
+ curl -s -w "Status: %{http_code}\n" "$BASE_URL/openapi.json" | head -5
24
+ echo ""
25
+
26
+ # Test 4: Signup (this will create a test user)
27
+ echo "πŸ‘€ Testing Signup..."
28
+ TEST_EMAIL="test_$(date +%s)@example.com"
29
+ SIGNUP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/auth/signup" \
30
+ -H "Content-Type: application/json" \
31
+ -d "{\"email\":\"$TEST_EMAIL\",\"password\":\"TestPassword123!\"}")
32
+
33
+ HTTP_STATUS=$(echo $SIGNUP_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
34
+ SIGNUP_BODY=$(echo $SIGNUP_RESPONSE | sed -E 's/HTTPSTATUS:[0-9]{3}$//')
35
+
36
+ echo "Status: $HTTP_STATUS"
37
+ echo "Response: $SIGNUP_BODY" | head -3
38
+ echo ""
39
+
40
+ # Test 5: Signin (if signup worked)
41
+ if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "201" ]; then
42
+ echo "πŸ” Testing Signin..."
43
+ SIGNIN_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/auth/signin" \
44
+ -H "Content-Type: application/json" \
45
+ -d "{\"email\":\"$TEST_EMAIL\",\"password\":\"TestPassword123!\"}")
46
+
47
+ SIGNIN_HTTP_STATUS=$(echo $SIGNIN_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
48
+ SIGNIN_BODY=$(echo $SIGNIN_RESPONSE | sed -E 's/HTTPSTATUS:[0-9]{3}$//')
49
+
50
+ echo "Status: $SIGNIN_HTTP_STATUS"
51
+
52
+ if [ "$SIGNIN_HTTP_STATUS" = "200" ]; then
53
+ # Extract token
54
+ TOKEN=$(echo $SIGNIN_BODY | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
55
+ echo "Token received: ${TOKEN:0:20}..."
56
+ echo ""
57
+
58
+ # Test 6: Sync Supabase User
59
+ echo "πŸ”„ Testing Sync Supabase User..."
60
+ SYNC_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/auth/sync-supabase-user" \
61
+ -H "Content-Type: application/json" \
62
+ -H "Authorization: Bearer $TOKEN" \
63
+ -d "{\"supabase_user_id\":\"test_user_id\",\"email\":\"$TEST_EMAIL\",\"full_name\":\"Test User\"}")
64
+
65
+ SYNC_HTTP_STATUS=$(echo $SYNC_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
66
+ SYNC_BODY=$(echo $SYNC_RESPONSE | sed -E 's/HTTPSTATUS:[0-9]{3}$//')
67
+
68
+ echo "Status: $SYNC_HTTP_STATUS"
69
+ echo "Response: $SYNC_BODY" | head -3
70
+ echo ""
71
+
72
+ # Test 7: Protected endpoint
73
+ echo "πŸ›‘οΈ Testing Protected Endpoint (User Profile)..."
74
+ PROFILE_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X GET "$BASE_URL/user/profile" \
75
+ -H "Authorization: Bearer $TOKEN")
76
+
77
+ PROFILE_HTTP_STATUS=$(echo $PROFILE_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
78
+ PROFILE_BODY=$(echo $PROFILE_RESPONSE | sed -E 's/HTTPSTATUS:[0-9]{3}$//')
79
+
80
+ echo "Status: $PROFILE_HTTP_STATUS"
81
+ echo "Response: $PROFILE_BODY" | head -3
82
+ echo ""
83
+ else
84
+ echo "Signin failed, skipping protected endpoint tests"
85
+ echo ""
86
+ fi
87
+ else
88
+ echo "Signup failed, skipping signin and protected endpoint tests"
89
+ echo ""
90
+ fi
91
+
92
+ echo "βœ… Testing complete!"
93
+ echo ""
94
+ echo "πŸ’‘ Quick Status Check:"
95
+ echo "- Health endpoint working: Check if you see 'message': 'API is running' above"
96
+ echo "- Signup working: Check if signup status was 200/201"
97
+ echo "- Signin working: Check if signin status was 200"
98
+ echo "- Sync endpoint working: Check if sync status was 200/201"
99
+ echo ""
100
+ echo "πŸ”§ If endpoints are failing:"
101
+ echo "1. Verify your backend URL is correct"
102
+ echo "2. Check if environment variables are set properly"
103
+ echo "3. Look at deployment logs for errors"
104
+ echo "4. Use the Python test script for more detailed testing: python test_deployment.py"