Spaces:
Sleeping
Sleeping
SuZeAI commited on
Commit ·
437ffc0
1
Parent(s): ff5991d
feat: update subscription response to track AI credits instead of tokens
Browse files- app/api/v1/subscription.py +13 -9
- app/schemas/subscription.py +2 -2
app/api/v1/subscription.py
CHANGED
|
@@ -7,6 +7,7 @@ from app.api.deps import get_current_user
|
|
| 7 |
from app.models.user import User
|
| 8 |
from app.models.wardrobe import WardrobeItem
|
| 9 |
from app.models.chat import ChatMessage
|
|
|
|
| 10 |
from app.schemas.subscription import SubscriptionResponse
|
| 11 |
|
| 12 |
router = APIRouter()
|
|
@@ -14,9 +15,10 @@ router = APIRouter()
|
|
| 14 |
# Free-tier caps advertised on the landing page's pricing table.
|
| 15 |
FREE_WARDROBE_ITEM_LIMIT = 30
|
| 16 |
FREE_AI_RECOMMENDATIONS_PER_WEEK = 5
|
| 17 |
-
# AI Stylist usage is metered like an LLM API quota
|
| 18 |
-
#
|
| 19 |
-
|
|
|
|
| 20 |
|
| 21 |
|
| 22 |
def _build_response(db: Session, user: User) -> SubscriptionResponse:
|
|
@@ -26,13 +28,13 @@ def _build_response(db: Session, user: User) -> SubscriptionResponse:
|
|
| 26 |
db.query(WardrobeItem).filter(WardrobeItem.user_id == user.id).count()
|
| 27 |
)
|
| 28 |
|
|
|
|
| 29 |
week_ago = datetime.now(timezone.utc) - timedelta(days=7)
|
| 30 |
ai_used = (
|
| 31 |
-
db.query(
|
| 32 |
.filter(
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
ChatMessage.created_at >= week_ago,
|
| 36 |
)
|
| 37 |
.count()
|
| 38 |
)
|
|
@@ -47,6 +49,8 @@ def _build_response(db: Session, user: User) -> SubscriptionResponse:
|
|
| 47 |
)
|
| 48 |
.scalar()
|
| 49 |
)
|
|
|
|
|
|
|
| 50 |
|
| 51 |
return SubscriptionResponse(
|
| 52 |
plan=user.plan,
|
|
@@ -55,8 +59,8 @@ def _build_response(db: Session, user: User) -> SubscriptionResponse:
|
|
| 55 |
wardrobe_items_limit=None if is_premium else FREE_WARDROBE_ITEM_LIMIT,
|
| 56 |
ai_recommendations_used=ai_used,
|
| 57 |
ai_recommendations_limit=None if is_premium else FREE_AI_RECOMMENDATIONS_PER_WEEK,
|
| 58 |
-
|
| 59 |
-
|
| 60 |
)
|
| 61 |
|
| 62 |
|
|
|
|
| 7 |
from app.models.user import User
|
| 8 |
from app.models.wardrobe import WardrobeItem
|
| 9 |
from app.models.chat import ChatMessage
|
| 10 |
+
from app.models.tryon import TryOnTask
|
| 11 |
from app.schemas.subscription import SubscriptionResponse
|
| 12 |
|
| 13 |
router = APIRouter()
|
|
|
|
| 15 |
# Free-tier caps advertised on the landing page's pricing table.
|
| 16 |
FREE_WARDROBE_ITEM_LIMIT = 30
|
| 17 |
FREE_AI_RECOMMENDATIONS_PER_WEEK = 5
|
| 18 |
+
# AI Stylist usage is metered like an LLM API quota, expressed in "credits"
|
| 19 |
+
# (1 credit = 1,000 tokens) over a rolling 30-day window.
|
| 20 |
+
TOKENS_PER_CREDIT = 1_000
|
| 21 |
+
FREE_AI_CREDIT_LIMIT_PER_30D = 500
|
| 22 |
|
| 23 |
|
| 24 |
def _build_response(db: Session, user: User) -> SubscriptionResponse:
|
|
|
|
| 28 |
db.query(WardrobeItem).filter(WardrobeItem.user_id == user.id).count()
|
| 29 |
)
|
| 30 |
|
| 31 |
+
# "AI outfits" = virtual try-on generations (each one produces one AI-styled outfit).
|
| 32 |
week_ago = datetime.now(timezone.utc) - timedelta(days=7)
|
| 33 |
ai_used = (
|
| 34 |
+
db.query(TryOnTask)
|
| 35 |
.filter(
|
| 36 |
+
TryOnTask.user_id == user.id,
|
| 37 |
+
TryOnTask.created_at >= week_ago,
|
|
|
|
| 38 |
)
|
| 39 |
.count()
|
| 40 |
)
|
|
|
|
| 49 |
)
|
| 50 |
.scalar()
|
| 51 |
)
|
| 52 |
+
# Round up: any partial usage still consumes a whole credit, like real LLM billing.
|
| 53 |
+
credits_used = -(-int(tokens_used or 0) // TOKENS_PER_CREDIT)
|
| 54 |
|
| 55 |
return SubscriptionResponse(
|
| 56 |
plan=user.plan,
|
|
|
|
| 59 |
wardrobe_items_limit=None if is_premium else FREE_WARDROBE_ITEM_LIMIT,
|
| 60 |
ai_recommendations_used=ai_used,
|
| 61 |
ai_recommendations_limit=None if is_premium else FREE_AI_RECOMMENDATIONS_PER_WEEK,
|
| 62 |
+
ai_credits_used=credits_used,
|
| 63 |
+
ai_credits_limit=None if is_premium else FREE_AI_CREDIT_LIMIT_PER_30D,
|
| 64 |
)
|
| 65 |
|
| 66 |
|
app/schemas/subscription.py
CHANGED
|
@@ -9,8 +9,8 @@ class SubscriptionResponse(BaseModel):
|
|
| 9 |
wardrobe_items_limit: Optional[int] # None = unlimited
|
| 10 |
ai_recommendations_used: int
|
| 11 |
ai_recommendations_limit: Optional[int] # None = unlimited
|
| 12 |
-
|
| 13 |
-
|
| 14 |
|
| 15 |
class Config:
|
| 16 |
from_attributes = True
|
|
|
|
| 9 |
wardrobe_items_limit: Optional[int] # None = unlimited
|
| 10 |
ai_recommendations_used: int
|
| 11 |
ai_recommendations_limit: Optional[int] # None = unlimited
|
| 12 |
+
ai_credits_used: int # 1 credit = 1,000 LLM tokens
|
| 13 |
+
ai_credits_limit: Optional[int] # None = unlimited
|
| 14 |
|
| 15 |
class Config:
|
| 16 |
from_attributes = True
|