nexusbert's picture
push new routes
b3094b0
import "reflect-metadata";
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import swaggerJsdoc from "swagger-jsdoc";
import swaggerUi from "swagger-ui-express";
import { AppDataSource } from "./utils/dataSource";
import authRoute from "./routes/auth";
import uploadRoute from "./routes/upload";
import suggestRoute from "./routes/suggest";
import wardrobeRoute from "./routes/wardrobe";
import profileRoute from "./routes/profile";
import avatarRoute from "./routes/avatar";
import chatRoute from "./routes/chat";
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json({ limit: "10mb" }));
// Root endpoint with milestone information
app.get("/", (req, res) => {
res.json({
name: "StyleGPT Milestone 2",
version: "1.0.0",
description: "Visual Wardrobe Tagging & AI-Powered Outfit Suggestions",
milestone: 2,
features: [
"User Authentication (JWT-based)",
"Visual Wardrobe Management",
"AI-Powered Image Classification (Fashion-CLIP)",
"Smart Outfit Suggestions",
"User Profile Management"
],
endpoints: {
root: "/",
docs: "/docs",
health: "/health",
api: {
auth: "/api/auth",
profile: "/api/profile",
upload: "/api/upload",
suggest: "/api/suggest",
chat: "/api/chat",
wardrobe: "/api/wardrobe",
avatar: "/api/avatar"
}
},
technologies: [
"Node.js",
"TypeScript",
"Express.js",
"PostgreSQL",
"TypeORM",
"Hugging Face Fashion-CLIP",
"JWT Authentication"
]
});
});
// Swagger/OpenAPI configuration
const swaggerOptions: swaggerJsdoc.Options = {
definition: {
openapi: "3.0.0",
info: {
title: "StyleGPT Milestone 2 API",
version: "1.0.0",
description: "API documentation for StyleGPT Milestone 2 - Visual Wardrobe Tagging & AI-Powered Outfit Suggestions",
contact: {
name: "StyleGPT",
url: "https://huggingface.co/spaces/nexusbert/StyleGPT-milestone2"
}
},
servers: [
{
url: process.env.API_URL || `http://localhost:${process.env.PORT || 7860}`,
description: "API Server"
}
],
components: {
securitySchemes: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT"
}
},
schemas: {
User: {
type: "object",
properties: {
id: { type: "integer" },
name: { type: "string" },
email: { type: "string", format: "email" },
profilePicture: { type: "string", format: "uri", description: "Avatar render URL or base64 image" },
readyPlayerMeAvatarId: { type: "string", description: "Ready Player Me avatar ID" },
createdAt: { type: "string", format: "date-time" }
}
},
WardrobeItem: {
type: "object",
properties: {
id: { type: "integer" },
imageUrl: { type: "string", format: "uri" },
category: {
type: "string",
description: "Classification: shirt, pants, dress, jacket, shoes, sneakers, boots, watch, glasses, bag, hat, jewelry, accessories, etc."
},
style: {
type: "string",
enum: ["formal", "casual", "streetwear", "sportswear"],
description: "Style classification"
},
userId: { type: "integer" },
createdAt: { type: "string", format: "date-time" }
}
},
RegisterRequest: {
type: "object",
required: ["name", "email", "password"],
properties: {
name: { type: "string" },
email: { type: "string", format: "email" },
password: { type: "string", minLength: 6 }
}
},
LoginRequest: {
type: "object",
required: ["email", "password"],
properties: {
email: { type: "string", format: "email" },
password: { type: "string" }
}
},
AuthResponse: {
type: "object",
properties: {
success: { type: "boolean" },
user: { $ref: "#/components/schemas/User" },
token: { type: "string" },
error: { type: "string" }
}
},
UploadRequest: {
type: "object",
required: ["image"],
properties: {
image: {
type: "string",
format: "binary",
description: "Image file (JPEG, PNG, etc.)"
}
}
},
SuggestRequest: {
type: "object",
required: ["message"],
properties: {
message: { type: "string" },
session_id: { type: "string" }
}
}
}
},
tags: [
{ name: "Authentication", description: "User registration and login" },
{ name: "Profile", description: "User profile management" },
{ name: "Upload", description: "Wardrobe item upload and classification" },
{ name: "Suggest", description: "AI-powered outfit suggestions with wardrobe" },
{ name: "Chat", description: "Fashion chat without wardrobe" },
{ name: "Avatar", description: "Ready Player Me avatar management" },
{ name: "Health", description: "Health check endpoints" }
]
},
apis: ["./src/routes/*.ts", "./src/index.ts"]
};
const swaggerSpec = swaggerJsdoc(swaggerOptions);
// Swagger UI endpoint
app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
customCss: ".swagger-ui .topbar { display: none }",
customSiteTitle: "StyleGPT Milestone 2 API Docs"
}));
// Swagger JSON endpoint
app.get("/docs.json", (req, res) => {
res.setHeader("Content-Type", "application/json");
res.send(swaggerSpec);
});
// Health check endpoint
/**
* @openapi
* /health:
* get:
* summary: Health check endpoint
* tags: [Health]
* responses:
* 200:
* description: Service is healthy
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* example: healthy
* database:
* type: boolean
* example: true
*/
app.get("/health", (req, res) => {
res.json({ status: "healthy", database: AppDataSource.isInitialized });
});
app.use("/api/auth", authRoute);
app.use("/api/profile", profileRoute);
app.use("/api/upload", uploadRoute);
app.use("/api/suggest", suggestRoute);
app.use("/api/wardrobe", wardrobeRoute);
app.use("/api/avatar", avatarRoute);
app.use("/api/chat", chatRoute);
const PORT = process.env.PORT || 7860;
AppDataSource.initialize()
.then(() => {
console.log("✅ Database connected");
app.listen(PORT, () => console.log(`🧥 StyleGPT running on port ${PORT}`));
})
.catch((error) => console.error("❌ DB connection failed:", error));