OVDR (Online Virtual Dressing Room) is a full-stack web application that enables users to virtually try on clothing. It combines user-uploaded full-body images with a selected clothing item to generate a photorealistic try-on result using the StableVITON model. The platform also features intelligent clothing search (powered by CLIP), closet management, and browsing history.
This system aims to improve online fashion shopping experiences through: - AI-powered virtual try-on - Text-based outfit search - Smart closet & history tracking - Personalized recommendations
This system integrates computer vision, recommendation systems, and text-image matching to support a complete virtual fitting experience. It is suitable for online retail platforms looking to enhance user experience and reduce return rates.
| Task | Achivements |
|---|---|
| Web-based application with intuitive UI | React frontend + Flask backend |
| Clothing dataset with corresponding text descriptions | Organized dataset (tops, bottoms, dresses) with auto-generated captions |
| Functional clothing retrieval and recommendation systems | CLIP-based similarity search and planned collaborative filtering module |
| Efficient browsing and try-on with integrated text search | Connects search โ try-on โ save/share experience |
The OVDR project is organized into the following main folders:
backend/: Flask-based server-side applicationdata/: All images and user uploadsfrontend/: React-based user interfacedocs/: Project documentationwebsite/: Static HTML website of project๐ OVDR/ (Root Project)
OVDR/
โโโ app.py # Project root entrypoint (if needed)
โโโ README.md # Project overview
โโโ .gitignore # Git ignored files
๐ backend/ โ Flask backend
โโโ backend/ # Flask backend
โ โโโ __init__.py # create_app() and app initialization
โ โโโ config.py # Config class for DB, mail, etc.
โ โโโ exts.py # db/mail/cors plugin initialization
โ โโโ .env # Environment variables for secrets
โ
โ โโโ database/ # DB schema, data and documentation
โ โ โโโ OVDR.sql
โ โ โโโ ovdr_structure.sql
โ โ โโโ ovdr_data_only.sql
โ โ โโโ backup.sql
โ โ โโโ ERD.png # Database Entity-Relationship Diagram
โ โ โโโ database.md # DB documentation
โ
โ โโโ migrations/ # Flask-Migrate migration files
โ
โ โโโ models/ # Model directories
โ โ โโโ clip-vit-large-patch14 # CLIP model
โ โ โโโ StableVITON/ # StableVITON try-on model
โ
โ โโโ routes/ # Flask route blueprints
โ โ โโโ __init__.py
โ โ โโโ auth.py # Login/Register routes
โ โ โโโ closet.py # Clothing listing & closet management
โ โ โโโ combination.py # Outfit combination logic
โ โ โโโ email.py # Email sending routes
โ โ โโโ forms.py # WTForms for validation
โ โ โโโ history.py # Browsing history
โ โ โโโ process.py # Try-on image generation
โ โ โโโ recommend.py # Recommendation system
โ โ โโโ search.py # CLIP-based text search
โ โ โโโ user_image.py # User image upload & fetch
โ
โ โโโ scripts/ # One-time utility scripts
โ โ โโโ image_embedding.py
โ โ โโโ insert_clothes_data.py
โ โ โโโ precompute_similarity.py
โ โ โโโ qwen_generate_caption.py
โ โ โโโ recommend_clicktime.py
โ โ โโโ recommend_sim_algorithm.py
โ โ โโโ rename_clothes.py
โ โ โโโ save_CLIP_model.py
โ โ โโโ search_algorithm.py
โ โ โโโ search_api.py
โ โ โโโ similarity_matrix.npy
โ
โ โโโ utils/ # Utility modules
โ โ โโโ caption_utils.py # Caption formatting and generation
โ โ โโโ download_utils.py # Download cloth image from URL
โ โ โโโ helpers.py # URL/path formatting utilities
โ โ โโโ image_utils.py # Save/rename/delete user images
โ โ โโโ stableviton_runner.py # Run StableVITON subprocess
โ โ โโโ static_serve.py # Static image serving utilities
โ โ โโโ config.py # Duplicate? (backend/config.py used)
โ โ โโโ exts.py # Duplicate? (used for plugin setup)
โ โ โโโ models.py # SQLAlchemy models (User, Clothing...)
โ
โ โโโ similarity_matrix.npy # Precomputed similarity matrix
๐ data/ โ Static & dynamic image data
โโโ data/ # Image assets & user uploads
โ โโโ clothes/ # Main clothing image dataset
โ โ โโโ tops/
โ โ โ โโโ cloth/
โ โ โ โโโ cloth-mask/
โ โ โ โโโ model-tryon/
โ โ โโโ bottoms/
โ โ โโโ dresses/
โ โ โโโ captions/ # Generated captions JSONs
โ
โ โโโ users/
โ โ โโโ image/ # Uploaded user full-body images
โ โ โโโ 1.jpg # Named by user_id
โ
โ โโโ combinations/ # Output try-on images
โ โโโ user_1/
โ โโโ 000001.jpg
๐ frontend/ โ React-based frontend
โโโ frontend/ # React frontend
โ โโโ node_modules/ # Frontend dependencies
โ โโโ public/
โ โโโ src/ # Main frontend code
โ โ โโโ App.js / App.css
โ โ โโโ ClothesDetail.js / .css
โ โ โโโ FullCloset.js / .css
โ โ โโโ History.js / .css
โ โ โโโ Home.js / .css
โ โ โโโ Login.js / .css
โ โ โโโ Register.js
โ โ โโโ SendImage.js / .css
โ โ โโโ TryOn.js / .css
โ โ โโโ UploadImage.js / .css
โ โ โโโ index.js / index.css
โ โ โโโ setupTests.js / reportWebVitals.js
โ โโโ package.json # React project config
โ โโโ package-lock.json
โ โโโ README.md # Frontend description
๐ docs/ โ Project documentation
โโโ docs/ # Project documentation
โ โโโ code_report.md # Final report with structure & logic
โ โโโ api_documentation.md # Full REST API documentation
โ โโโ Summary_of_quality_assurance.pdf # Quality testing doc
๐ website/ โ Static information site
โโโ website/ # Static info website
โ โโโ css/
โ โโโ minutes/
โ โโโ src/
โ โโโ projectindex.html # Presentation site
Please refer to JSdoc at https://csprojects.nottingham.edu.cn/grp-team07-gitlab/grp-team07-gitlab-work/-/tree/main/docs/JSdocs
Each route module encapsulates one set of responsibilities:
user_image.py: Handle upload/retrieve user photoscloset.py: Clothing catalog and user closetprocess.py: Virtual try-on (StableVITON)search.py: Search with CLIP and text querieshistory.py: User browsing records recommend.py: Related outfit recommendation (optional)All static image routing handled by static_serve.py
Database managed via SQLAlchemy + Flask-Migrate
The OVDR backend system is powered by a MySQL-compatible relational database to store users, clothing metadata, try-on results, and behavioral logs. SQLAlchemy ORM is used for seamless object-relational mapping.
Database credentials and server details are managed through environment variables in a .env file located under ./backend/, loaded via python-dotenv. This prevents hardcoding sensitive credentials in source code.
In backend/config.py, SQLAlchemy URI is constructed as:
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USER_NAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
The database schema and sample data are provided under:
backend/database/ovdr_structure.sql โ full schema (tables, constraints, types)
backend/database/ovdr_data_only.sql โ data-only insert statements
To initialize a local MySQL database:
mysql -u root -p
CREATE DATABASE ovdr;
USE ovdr;
SOURCE path/to/ovdr_structure.sql;
SOURCE path/to/ovdr_data_only.sql;
Once completed, update .env with:
HOSTNAME=localhost
The following are commonly used IP addresses during internal development:
- 10.176.45.0: used under eduroam
- 172.19.108.9: used under UNNC-Living
If your system fails to connect to these, migrate to local MySQL using the above steps.
If you encounter access issues, please reach out to the maintainer via email: ssyzd4@nottingham.edu.cn.
This section documents all RESTful APIs for the OVDR system. Each subsection corresponds to one module.
routes/auth.py)Manage user login and registration logic
POST /loginDescription: Authenticate user using username and password.
Form Data:
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | Yes | The user's username |
| password | string | Yes | Plaintext password input |
Response:
{
"success": "Login successful!",
"username": "testuser",
"user_id": 1
}
Error Responses:
- 400 Bad Request - Username does not exist
- 400 Bad Request - Password entered incorrectly
- 400 Bad Request - Invalid input (form validation failed)
POST /registerDescription: Register a new user with a unique username and encrypted password.
Form Data:
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | Yes | Unique username |
| password | string | Yes | Password to encrypt |
Response:
{
"message": "User registration succeeded!"
}
Error Response:
{
"error": [["Username already exists."]]
}
GET /captcha/emailDescription: Sends a 4-digit verification code to the provided email address. (To be integrated into registration in future)
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email to receive code |
Response:
success
GET /testDescription: Test email sending (hardcoded email). For development/debugging purposes.
Response:
Send successfully
routes/user_image.py)Upload or retrieve user full-body photos
POST /upload_image
Description: Upload a user full-body image and update the database with the saved path.
Form Data:
| Field | Type | Required | Description |
|---|---|---|---|
| user_id | int | Yes | ID of the user |
| file | file | Yes | Image file to be uploaded |
Response:
{
"message": "Image uploaded and path updated successfully",
"image_path": "data/users/image/1.jpg"
}
Errors: - 400: Missing fields or empty file - 404: User not found
GET /get_user_infoDescription: Retrieve user profile information including the uploaded image path.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | int | Yes | ID of the user |
Response:
{
"user_id": 1,
"username": "alice",
"image_path": "data/users/image/1.jpg"
}
Errors: - 400: Missing user_id - 404: User not found
routes/closet.py)Endpoints for browsing and managing virtual clothing closet.
GET /api/clothesDescription: Retrieve all clothing items filtered by category.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| category | string | No | Clothing category: tops, bottoms, dresses (default: tops) |
Response:
{
"message": "Success",
"items": [
{
"id": 1,
"title": "Red Floral Cotton Blouse with v-neckline and short sleeves",
"image_path": "http://localhost:5000/data/clothes/tops/model-tryon/00001.jpg",
"closet_users": 3
}
]
}
GET /detail/<clothing_id>Description: Retrieve detailed info about a specific clothing item.
Path Parameters:
| Name | Type | Description |
|---|---|---|
| clothing_id | int | Clothing item ID |
Response:
{
"message": "Success",
"item": {
"id": 1,
"labels": ["red", "floral", "cotton", "blouse"],
"title": "Red Floral Cotton Blouse with v-neckline and short sleeves",
"cloth_path": "http://localhost:5000/data/clothes/tops/cloth/00001.jpg"
}
}
POST /add-to-closetDescription: Add a clothing item to a user's closet.
Request Body:
{
"user_id": 1,
"clothing_id": 5
}
Constraints: - A user can have up to 5 items per category. - Duplicate additions are not allowed.
Success Response:
{
"message": "Item added to closet successfully!"
}
Error Responses:
{
"error": "Item already in closet!"
}
{
"error": "Max 5 tops items allowed. Remove one to add new."
}
GET /get-closetDescription: Get all clothing items in a user's closet, optionally filtered by category.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | int | Yes | ID of the user |
| category | string | No | Category to filter (default: tops) |
Response:
{
"message": "Success",
"closet": [
{
"id": 5,
"category": "tops",
"url": "http://localhost:5000/data/clothes/tops/cloth/00005.jpg"
}
]
}
POST /remove-from-closetDescription: Remove a clothing item from a user's closet.
Request Body:
{
"user_id": 1,
"clothing_id": 5
}
Response:
{
"message": "Item removed from closet successfully."
}
GET /data/clothes/<path:filename>Description: Serve static clothing images from the /data/clothes/ directory.
Example Request:
GET /data/clothes/tops/model-tryon/00001.jpg
Response: - Returns the image directly if found.
routes/history.py)Track and retrieve browsing history
POST /add-historyDescription:
Adds a clothing item to the user's browsing history.
- Prevents duplicate entries.
- Keeps only the latest 20 records per user.
Request Body (JSON):
{
"user_id": 1,
"clothing_id": 5
}
Response:
{
"message": "History recorded successfully."
}
Errors:
- 400: Missing user_id or clothing_id.
- 500: Database error or insertion failure.
GET /get-historyDescription:
Retrieves the latest 20 items viewed by a specific user from their browsing history.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | int | Yes | ID of the user |
Example Request:
GET /get-history?user_id=1
Response:
{
"message": "Success",
"history": [
{
"id": 5,
"image": "http://localhost:5000/data/clothes/tops/cloth/00005_top.jpg",
"title": "Red Floral Cotton Blouse with round neckline and long sleeves",
"created_at": "2024-03-30 14:23:12",
"closet_users": 7,
"category": "tops"
}
]
}
Errors:
- 400: Missing user_id.
- 500: Database error or malformed caption field.
routes/process.py)POST /process_imageDescription:
Generate a virtual try-on image by combining a user-uploaded full-body image and a selected clothing item.
You can either:
- Provide item_id (recommended): automatically fetch clothing from database.
- OR provide cloth_url directly (e.g., from frontend image selection).
Request Body (JSON):
| Field | Type | Required | Description |
|---|---|---|---|
| user_id | int | โ Yes | ID of the user |
| item_id | int | โ No | Closet item ID to fetch clothing from DB |
| cloth_url | string | โ No | Optional: URL or path to clothing image |
| item_category | string | โ Yes | Type of clothing: "tops", "bottoms", or "dresses" |
โ ๏ธ Either
item_idorcloth_urlmust be provided.
Example:
{
"user_id": 1,
"item_id": 15,
"item_category": "tops"
}
Success Response:
{
"message": "success",
"image_path": "0000012.jpg"
}
Error Responses:
400 Bad Request: Missing required fields or image404 Not Found: User or image not found500 Internal Server Error: StableVITON failure or file I/O issuesGET /data/clothes/<filename>Description:
Serve static clothing images from the /data/clothes/ directory.
Example:
Request: GET /data/clothes/tops/cloth/000001_top.jpg
Returns: Clothing image file.
routes/search.py)GET /searchDescription:
Search for clothing items using a natural language text query. The backend uses a pretrained CLIP model to match text to clothing image embeddings.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | โ Yes | Natural language query (e.g. "red hoodie") |
| top_n | int | โ No | Number of results to return (default: 20) |
Response: Returns an array of matched clothing items ranked by similarity.
{
"items": [
{
"id": 12,
"title": "Red Cotton Hoodie",
"category": "tops",
"image_path": "http://localhost:5000/data/clothes/tops/cloth/00012_top.jpg",
"closet_users": 3
},
...
]
}
Errors:
| Code | Description |
|---|---|
| 400 | Missing query parameter |
| 500 | Internal error (model failure, DB error) |
routes/recommend.py)GET /clothing/{id}{
"id": 1,
"name": "White Blouse",
"category": "tops"
}
GET /recommend/{clothing_id}{
"recommendations": [
{
"id": 12,
"url": "http://localhost:5000/data/clothes/tops/000045_top.jpg"
}
]
}
GET /recommend/popular{
"recommended_popular": [
{
"id": 88,
"category": "bottoms",
"url": "http://localhost:5000/data/clothes/bottoms/000088_bottom.jpg"
}
]
}
GET /recommend/user/{user_id}{
"personalized_recommendations": [
{
"id": 73,
"category": "dresses",
"url": "http://localhost:5000/data/clothes/dresses/000073_dress.jpg"
}
]
}
routes/combination.py)Save try-on results and show outfit combinations
POST /save-combinationDescription: Save a virtual try-on combination to the database.
Request Body (JSON):
| Field | Type | Required | Description |
|---|---|---|---|
| user_id | int | โ Yes | ID of the user |
| top_id | int | โ No | ID of the top clothing item |
| bottom_id | int | โ No | ID of the bottom clothing item |
| dress_id | int | โ No | ID of the dress item |
| resultImage | string | โ Yes | Relative path to the generated try-on image |
Response Example:
{
"message": "Combination saved!"
}
GET /get-combinationsDescription: Retrieve all saved try-on combinations for a given user.
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | int | โ Yes | ID of the user |
Response Example:
{
"message": "Success",
"combinations": [
{
"id": 12,
"top_id": 3,
"bottom_id": 5,
"dress_id": null,
"url": "data/combinations/user_1/000023.jpg"
}
]
}
DELETE /delete-combinationDescription:
Delete a previously saved outfit combination by its ID.
Request Body:
{
"id": 12
}
| Field | Type | Required | Description |
|---|---|---|---|
| id | int | โ Yes | The ID of the combination to delete |
Response (Success):
{
"message": "Combination deleted successfully."
}
Error Responses:
- 400 Bad Request:
{ "error": "Missing combination ID" }
404 Not Found:
{ "error": "Combination not found" }
500 Internal Server Error:
{ "error": "Database error or deletion failed" }
GET /show_image/<userid>/<filename>Description: Serve generated outfit image from the /data/combinations/user_<userid>/ folder.
Path Parameters:
| Name | Type | Description |
|---|---|---|
| userid | int | User ID, used to locate the user directory |
| filename | string | File name of the image (URL-encoded if needed) |
Example:
GET /show_image/1/000003.jpg
Returns: The image file if found.
routes/email.py)POST /send-emailDescription:
Send a try-on result image to a specified email address. This endpoint expects a base64-encoded image (JPEG) and recipient email.
Request Body:
{
"email": "user@example.com",
"imageBase64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
}
Response: - On success:
{
"success": true,
"message": "Email sent successfully!"
}
{
"success": false,
"message": "Missing email or image"
}
Notes: - Make sure your Flask app is configured with SMTP credentials:
MAILSERVER = "smtp.qq.com"
MAILPORT = 465
MAILUSERNAME = "youremail@qq.com"
MAILPASSWORD = "yourapppassword"
MAILUSE_SSL = True
email_bp in create_app().The OVDR (Online Virtual Dressing Room) database is designed to store user information, virtual try-on data, and clothing items. It supports features like: - User information (user name, hash password and full body image) - Clothing item storage with corresponding text descriptions (captions) - Virtual try-on outfit combinations - User wardrobe (Closet) management - History tracking
The following tables are included in the OVDR database (obsolete or temporarily unused tables are not included):
users (User Table)Stores user credentials and profile data.
| Column | Type | Constraints | Description |
|---|---|---|---|
user_id |
INT (PK, AUTO_INCREMENT) | Primary key | Unique ID for each user |
username |
VARCHAR(255) | UNIQUE, NOT NULL | Unique username for login |
password_hash |
VARCHAR(255) | NOT NULL | Hashed password |
image_path |
VARCHAR(255) | DEFAULT NULL | Path to user's full-body image |
clothing (Clothing Items)Stores clothing data and AI-generated descriptions.
| Column | Type | Constraints | Description |
|---|---|---|---|
cid |
INT (PK, AUTO_INCREMENT) | Primary key | Unique clothing item ID |
category |
ENUM('tops', 'bottoms', 'dresses') | NOT NULL | Clothing category |
caption |
JSON | NULL | AI-generated clothing description |
closet_users |
INT | DEFAULT 0 | Number of users who added this to wardrobe |
cloth_path |
VARCHAR(255) | NOT NULL | Path to clothing image |
closet (User Wardrobe)Tracks clothing items added to users' wardrobes.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INT (PK, AUTO_INCREMENT) | Primary key | Record ID |
user_id |
INT | NOT NULL, FK โ users(user_id) |
User who owns this wardrobe |
clothing_id |
INT | NOT NULL, FK โ clothing(cid) ON DELETE CASCADE |
Clothing item |
DELIMITER //
CREATE TRIGGER limit_closet_items
AFTER INSERT ON Closet
FOR EACH ROW
BEGIN
DELETE FROM Closet
WHERE user_id = NEW.user_id
AND id NOT IN (
SELECT id FROM (
SELECT id FROM Closet
WHERE user_id = NEW.user_id
ORDER BY added_at DESC
LIMIT 5
) AS temp_table
);
END;
//
DELIMITER ;
history (User View History)Tracks which clothing items users have viewed.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INT (PK, AUTO_INCREMENT) | Primary key | Record ID |
user_id |
INT | NOT NULL, FK โ users(user_id) |
User who viewed clothing |
clothing_id |
INT | NOT NULL, FK โ clothing(cid) ON DELETE CASCADE |
Clothing item |
created_at |
TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Timestamp of viewing |
DELIMITER //
CREATE TRIGGER limit_history_records
AFTER INSERT ON `history`
FOR EACH ROW
BEGIN
DELETE FROM `history`
WHERE user_id = NEW.user_id
AND id NOT IN (
SELECT id FROM (
SELECT id FROM history
WHERE user_id = NEW.user_id
ORDER BY created_at DESC
LIMIT 20
) AS temp_table
);
END;
//
DELIMITER ;

./backend/models.py
User Table| Field | Type | Constraints | Description |
|---|---|---|---|
| user_id | Integer | Primary Key | Unique user ID |
| username | String | Not Null, Unique | Username for login |
| password | String | Not Null | Hashed password |
| image_path | String | Nullable | Path to uploaded full-body image |
Clothing Table| Field | Type | Constraints | Description |
|---|---|---|---|
| cid | Integer | Primary Key | Clothing item ID |
| category | Enum | Not Null | 'tops', 'bottoms', or 'dresses' |
| caption | JSON | Nullable | Structured description of the item |
| closet_users | Integer | Default 0 | Number of users who added this to closet |
| cloth_path | String | Nullable | Flat cloth image path |
| clothmaskpath | String | Nullable | Binary mask path |
| modeltryonpath | String | Nullable | Model try-on image path |
Closet Table| Field | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | Primary Key | Closet entry ID |
| user_id | Integer | Foreign Key (User) | Owner of this closet item |
| clothing_id | Integer | Foreign Key (Clothing) | Clothing item stored |
| added_at | TIMESTAMP | Auto Timestamp | Time added to closet |
Combination Table| Field | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | Primary Key | Combination record ID |
| user_id | Integer | Foreign Key (User) | User who created this outfit |
| top_id | Integer | FK (Clothing, Nullable) | Top clothing item |
| bottom_id | Integer | FK (Clothing, Nullable) | Bottom clothing item |
| dress_id | Integer | FK (Clothing, Nullable) | Dress clothing item |
| outfit_path | String | Not Null | Path to generated try-on image |
| created_at | TIMESTAMP | Auto Timestamp | Creation time |
History Table| Field | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | Primary Key | History record ID |
| user_id | Integer | Foreign Key (User) | User who viewed the item |
| clothing_id | Integer | Foreign Key (Clothing) | Clothing item that was viewed |
| created_at | TIMESTAMP | Auto Timestamp | Time of browsing |
StableVITON: Generates try-on results using user photo + garment mask + layout
Input: Absolute paths
Output: Saved to data/combinations/user_
CLIP (OpenAI): Used for text-to-image similarity in search.py
Text queries โ CLIP text embedding
Compared against precomputed image_embeddings.npy
50003000cd frontend
npm install -g concurrently
npm run dev # Starts both backend and frontend
./backend/models/ directoryimage_embeddings.npy for fast searchThis section outlines both the overall system components and the specific responsibilities undertaken by each team member during development.
create_app)config.py)| Team Member | Responsibilities | ||
|---|---|---|---|
| Zixin Ding | Backend architecture, dataset and database, caption generation, user auth, upload, closet and history logic, frontend improvement, bug fixing, Code Report, README, Installation Manual, Final Report | ||
| Zhihao Cao | StableVITON try-on module, image I/O handling, bug fixing, Final Report | ||
| Peini She | React frontend development, combination and email routing, bug fixing, User Manual writing | ||
| Jinghao Liu & Zihan Zhou | Search and Reccomendation module with CLIP, embedding logic, semantic search, Quality Assurance |
Sample SQL schema: ./backend/database/OVDR.sql
Sample try-on output: data/combinations/user_1/*.jpg