MukeshKapoor25 commited on
Commit
0e87fe4
·
1 Parent(s): c8cde52

feat: Implement Smart Tips feature with service, router, and schema

Browse files
app/app.py CHANGED
@@ -1,7 +1,7 @@
1
  from fastapi import FastAPI, Request
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.middleware.trustedhost import TrustedHostMiddleware
4
- from app.routers import auth_router, merchant_profile_router, merchant_router, merchant_settings_router, role_router,branch_router, location_router
5
  import logging
6
  from app.utils.logger import setup_logger
7
 
@@ -68,6 +68,18 @@ app.include_router(auth_router.router)
68
  app.include_router(role_router.router, prefix="/api", tags=["Roles"])
69
  app.include_router(branch_router.router,prefix="/api/branch",tags=["Branch"])
70
  app.include_router(location_router.router, prefix="/api", tags=["Locations"])
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  @app.get("/")
73
  def root():
 
1
  from fastapi import FastAPI, Request
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.middleware.trustedhost import TrustedHostMiddleware
4
+ from app.routers import auth_router, merchant_profile_router, merchant_router, merchant_settings_router, role_router, branch_router, location_router, smart_tips_router
5
  import logging
6
  from app.utils.logger import setup_logger
7
 
 
68
  app.include_router(role_router.router, prefix="/api", tags=["Roles"])
69
  app.include_router(branch_router.router,prefix="/api/branch",tags=["Branch"])
70
  app.include_router(location_router.router, prefix="/api", tags=["Locations"])
71
+ app.include_router(smart_tips_router.router, prefix="/api", tags=["SmartTips"])
72
+
73
+ @app.on_event("startup")
74
+ async def startup_event():
75
+ """
76
+ Initialize necessary data at application startup
77
+ """
78
+ from app.services.smart_tips_service import SmartTipsService
79
+ logger.info("Initializing smart tips collection")
80
+ service = SmartTipsService()
81
+ await service.ensure_collection_exists()
82
+ logger.info("Smart tips initialization complete")
83
 
84
  @app.get("/")
85
  def root():
app/routers/smart_tips_router.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from fastapi import APIRouter, HTTPException, Depends, Query
3
+ from typing import List, Optional
4
+ from app.schemas.smart_tips_schema import SmartTip
5
+ from app.services.smart_tips_service import SmartTipsService
6
+
7
+ logger = logging.getLogger("smart_tips_router")
8
+ router = APIRouter(tags=["SmartTips"])
9
+
10
+ # Define mandatory features
11
+ MANDATORY_FEATURES = ["asset", "associate"]
12
+
13
+ async def get_smart_tips_service():
14
+ """
15
+ Dependency to get a configured SmartTipsService instance
16
+ """
17
+ service = SmartTipsService()
18
+ await service.ensure_collection_exists()
19
+ return service
20
+
21
+ @router.get("/smart-tips", response_model=List[SmartTip])
22
+ async def get_smart_tips(
23
+ features: Optional[List[str]] = Query(None, description="Filter tips by feature(s)"),
24
+ include_mandatory: bool = Query(True, description="Include mandatory features (asset, associate)"),
25
+ smart_tips_service: SmartTipsService = Depends(get_smart_tips_service)
26
+ ):
27
+ """
28
+ Get a list of smart tips for different features.
29
+
30
+ - Optional query parameter to filter by features
31
+ - Always includes mandatory features if include_mandatory=True
32
+ """
33
+ try:
34
+ logger.info("Fetching smart tips from MongoDB")
35
+
36
+ # Handle mandatory features
37
+ if include_mandatory:
38
+ if features:
39
+ # Include mandatory features with user-requested features
40
+ request_features = list(set(features + MANDATORY_FEATURES))
41
+ return await smart_tips_service.get_smart_tips_by_features(request_features)
42
+ else:
43
+ # Include mandatory features with all other features
44
+ return await smart_tips_service.get_smart_tips_with_mandatory(MANDATORY_FEATURES)
45
+ else:
46
+ # Filter by features if provided, otherwise return all
47
+ if features:
48
+ return await smart_tips_service.get_smart_tips_by_features(features)
49
+ else:
50
+ return await smart_tips_service.get_all_smart_tips()
51
+ except Exception as e:
52
+ logger.error(f"Error fetching smart tips: {str(e)}")
53
+ raise HTTPException(status_code=500, detail=str(e))
app/schemas/smart_tips_schema.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel, Field, RootModel
3
+
4
+ class SmartTip(BaseModel):
5
+ id: str
6
+ title: str
7
+ description: str
8
+ icon: Optional[str] = Field(None, description="Must match a valid Lucide icon name: Target, BookOpen, AlertCircle, Clock, FileText, Save, Tag, BarChart3, Users, Settings, Lightbulb")
9
+ feature: str = Field(..., description="Feature category this tip belongs to (e.g., asset, associate, catalogue)")
10
+
11
+ class SmartTipsResponse(RootModel):
12
+ root: List[SmartTip]
app/services/smart_tips_service.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import List, Optional
3
+ from app.nosql import db
4
+ from app.schemas.smart_tips_schema import SmartTip
5
+
6
+ logger = logging.getLogger("smart_tips_service")
7
+
8
+ class SmartTipsService:
9
+ def __init__(self):
10
+ self.collection = db["smart_tips"]
11
+
12
+ async def ensure_collection_exists(self):
13
+ """
14
+ Check if the collection exists and has data. If not, seed with initial data.
15
+ """
16
+ count = await self.collection.count_documents({})
17
+ if count == 0:
18
+ await self.seed_initial_data()
19
+ logger.info("Smart tips collection seeded with initial data")
20
+
21
+ async def seed_initial_data(self):
22
+ """
23
+ Seed the collection with initial smart tips data
24
+ """
25
+ initial_tips = [
26
+ {
27
+ "id": "tip-1",
28
+ "title": "Complete in Order",
29
+ "description": "Fill out sections sequentially for the best experience.",
30
+ "icon": "Target",
31
+ "feature": "general"
32
+ },
33
+ {
34
+ "id": "tip-2",
35
+ "title": "Associate Management",
36
+ "description": "Add all your team members for better role management.",
37
+ "icon": "Users",
38
+ "feature": "associate"
39
+ },
40
+ {
41
+ "id": "tip-3",
42
+ "title": "Catalogue Best Practices",
43
+ "description": "Keep your product details consistent for better customer experience.",
44
+ "icon": "BookOpen",
45
+ "feature": "catalogue"
46
+ },
47
+ {
48
+ "id": "tip-4",
49
+ "title": "Asset Management",
50
+ "description": "Regularly update your asset inventory for accurate financial reporting.",
51
+ "icon": "FileText",
52
+ "feature": "asset"
53
+ },
54
+ {
55
+ "id": "tip-5",
56
+ "title": "Time Management",
57
+ "description": "Schedule regular inventory checks to maintain accuracy.",
58
+ "icon": "Clock",
59
+ "feature": "general"
60
+ }
61
+ ]
62
+ await self.collection.insert_many(initial_tips)
63
+
64
+ async def get_all_smart_tips(self) -> List[SmartTip]:
65
+ """
66
+ Get all smart tips from the database
67
+ """
68
+ cursor = self.collection.find({})
69
+ tips = await cursor.to_list(length=100)
70
+ return [SmartTip(**tip) for tip in tips]
71
+
72
+ async def get_smart_tips_by_features(self, features: List[str]) -> List[SmartTip]:
73
+ """
74
+ Get smart tips filtered by a list of features
75
+ """
76
+ cursor = self.collection.find({"feature": {"$in": features}})
77
+ tips = await cursor.to_list(length=100)
78
+ return [SmartTip(**tip) for tip in tips]
79
+
80
+ async def get_smart_tips_with_mandatory(self, mandatory_features: List[str]) -> List[SmartTip]:
81
+ """
82
+ Get all smart tips ensuring mandatory features are included
83
+ """
84
+ # First, get tips from mandatory features
85
+ mandatory_tips = await self.get_smart_tips_by_features(mandatory_features)
86
+
87
+ # Then get all other tips
88
+ cursor = self.collection.find({"feature": {"$nin": mandatory_features}})
89
+ other_tips = await cursor.to_list(length=100)
90
+ other_tips = [SmartTip(**tip) for tip in other_tips]
91
+
92
+ # Combine both sets
93
+ return mandatory_tips + other_tips
seed_smart_tips.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Script to seed the smart_tips collection in MongoDB
3
+ Run this script to initialize the collection if needed
4
+ """
5
+ import asyncio
6
+ import logging
7
+ import sys
8
+ import os
9
+
10
+ # Add the parent directory to sys.path to import app modules
11
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
+
13
+ from app.services.smart_tips_service import SmartTipsService
14
+
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ async def seed_smart_tips():
19
+ """
20
+ Seed the smart_tips collection with initial data
21
+ """
22
+ logger.info("Starting smart tips collection seeding process")
23
+ service = SmartTipsService()
24
+ await service.ensure_collection_exists()
25
+ logger.info("Smart tips collection seeding completed")
26
+
27
+ if __name__ == "__main__":
28
+ asyncio.run(seed_smart_tips())