Omkar008 commited on
Commit
2542be6
·
verified ·
1 Parent(s): 0c2e1b7

Upload 9 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12.2-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY . /app
6
+
7
+ RUN pip install -r requirements.txt
8
+
9
+ RUN useradd -m -u 1000 user
10
+
11
+ USER user
12
+
13
+ # Copy the rest of the application code into the container at /app
14
+ COPY --chown=user . /app/
15
+
16
+
17
+ # Command to run your application
18
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860" , "--workers" , "5"]
api/endpoints/location.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException , Body
2
+ from models.location_models import BodyData,ErrorResponse
3
+ from services.location_service import LocationService
4
+ import core.init_supabase as sp
5
+ router = APIRouter()
6
+
7
+ @router.post("/get_coordinates")
8
+ async def get_coordinates(data: BodyData = Body(...)):
9
+ token = data.jwt_token
10
+ user_id = sp.authenticate_user(token)
11
+ if user_id == "Exceptional error":
12
+ return {"User not Authenticated!"}
13
+ else:
14
+ print(user_id)
15
+ supabase_user_data = sp.fetch_data(user_id)
16
+ print("supabase data")
17
+ print(supabase_user_data)
18
+ coords=[]*len(supabase_user_data)
19
+ for cord in supabase_user_data:
20
+ result = LocationService.get_coordinates(cord)
21
+ coords.append(result)
22
+ if isinstance(result, ErrorResponse):
23
+ print(HTTPException(status_code=400, detail=result.error))
24
+ return {"message":"An unexpected error occured please try again !!"}
25
+ print(coords)
26
+ return {"data":coords}
27
+
28
+
29
+
30
+ @router.post("/get_card_reccomendation")
31
+ async def get_coordinates(data: BodyData = Body(...)):
32
+ token = data.jwt_token
33
+ user_id = sp.authenticate_user(token)
34
+ if user_id == "Exceptional error":
35
+ return {"User not Authenticated!"}
36
+ else:
37
+ print(user_id)
38
+ try:
39
+ supabase_card_data = sp.fetch_cards_data(user_id)
40
+ print("supabase data")
41
+ print(supabase_card_data)
42
+ except Exception as e:
43
+ print(HTTPException(status_code=400, detail=e))
44
+ return {"message":"An unexpected error occured please try again !!"}
45
+ print("Returning the data")
46
+ return {"data":supabase_card_data}
47
+
core/config.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from pydantic_settings import BaseSettings
2
+
3
+ class Settings(BaseSettings):
4
+ APP_NAME: str = "Location Analytics API"
5
+ DEBUG_MODE: bool = False
6
+ SPACY_MODEL: str = "en_core_web_sm" # or any other model you prefer
7
+
8
+ settings = Settings()
core/init_nlp.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import nltk
2
+ import nltk.downloader
3
+ import spacy
4
+ from core.config import settings
5
+
6
+ def initialize_nlp():
7
+ print("Initializing NLP resources...")
8
+
9
+ # Download NLTK resources
10
+ nltk_resources = [
11
+ 'maxent_ne_chunker',
12
+ 'words',
13
+ 'treebank',
14
+ 'maxent_treebank_pos_tagger',
15
+ 'punkt',
16
+ 'averaged_perceptron_tagger'
17
+ ]
18
+
19
+ for resource in nltk_resources:
20
+ nltk.downloader.download(resource, quiet=True)
21
+
22
+ # Load spaCy model
23
+ spacy.load(settings.SPACY_MODEL)
24
+
25
+ print("NLP resources initialized successfully.")
26
+
27
+ # Global variables to store initialized resources
28
+ nlp = None
29
+ nltk_initialized = False
30
+
31
+ def get_nlp():
32
+ global nlp
33
+ if nlp is None:
34
+ nlp = spacy.load(settings.SPACY_MODEL)
35
+ return nlp
36
+
37
+ def get_nltk():
38
+ global nltk_initialized
39
+ if not nltk_initialized:
40
+ nltk.downloader.download('punkt', quiet=True)
41
+ nltk.download('averaged_perceptron_tagger', quiet=True)
42
+ nltk_initialized = True
43
+ return nltk
core/init_supabase.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from dotenv import load_dotenv
3
+ from supabase import create_client
4
+ from functools import lru_cache
5
+ import os
6
+ load_dotenv()
7
+ @lru_cache(maxsize=1)
8
+ class Supabase_Settings(BaseModel):
9
+
10
+ SUPABASE_URL: str = os.getenv("SUPABASE_URL")
11
+ SUPABASE_ANON_KEY: str = os.getenv("SUPABASE_ANON_KEY")
12
+ SUPABASE_SERVICE_KEY: str = os.getenv("SUPABASE_SERVICE_KEY")
13
+
14
+
15
+
16
+ @lru_cache(maxsize=1)
17
+ class Supabase_Clients:
18
+ values = Supabase_Settings()
19
+ anon_supabase = create_client(values.SUPABASE_URL, values.SUPABASE_ANON_KEY)
20
+ service_supabase = create_client(values.SUPABASE_URL, values.SUPABASE_SERVICE_KEY)
21
+
22
+ def fetch_data(user_id:str):
23
+ supabase_clients=Supabase_Clients()
24
+ supabase = supabase_clients.anon_supabase
25
+ response_0 = (
26
+ supabase.table("receipt_radar_structured_data")
27
+ .select("location")
28
+ .eq("user_id",f"{user_id}")
29
+ .eq("brand_category","Travel and Leisure")
30
+ .execute()
31
+ )
32
+ print("Printing fetched data")
33
+ print(response_0)
34
+ return response_0.data
35
+
36
+ def authenticate_user(apitoken: str):
37
+ supabase_clients = Supabase_Clients()
38
+ supabase = supabase_clients.anon_supabase
39
+ try:
40
+ user = supabase.auth.get_user(apitoken)
41
+ return str(user.user.id)
42
+ except Exception as e:
43
+ print("Exceptional error")
44
+ return "Exceptional error"
45
+
46
+ def fetch_cards_data(user_id:str):
47
+ supabase_clients=Supabase_Clients()
48
+ supabase = supabase_clients.anon_supabase
49
+ response_0 = (
50
+ supabase.table("receipt_radar_structured_data")
51
+ .select("brand")
52
+ .eq("user_id",f"{user_id}")
53
+ .execute()
54
+ ).data
55
+ response_1 = (
56
+ supabase.table("card_market")
57
+ .select("brand_name")
58
+ .execute()
59
+ ).data
60
+ brands_response_1_set = set(item['brand_name'].lower() for item in response_1)
61
+ common_brands = [item['brand'] for item in response_0 if item['brand'].lower() in brands_response_1_set]
62
+ print("common_brands")
63
+ print(common_brands)
64
+ return common_brands
main.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from core.init_nlp import initialize_nlp
3
+ from contextlib import asynccontextmanager
4
+ import logging
5
+ from api.endpoints import location
6
+
7
+
8
+ @asynccontextmanager
9
+ async def lifespan(app: FastAPI):
10
+ print("Initialising nlp spacy libs")
11
+ logging.info("Initialising nlp spacy libs")
12
+ initialize_nlp()
13
+ yield
14
+
15
+ app = FastAPI(lifespan=lifespan)
16
+ app.include_router(location.router, prefix="/location/api/v1")
17
+
models/location_models.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from typing import Optional,List
3
+
4
+ class LocationData(BaseModel):
5
+ location: Optional[str] = None
6
+
7
+ class BodyData(BaseModel):
8
+ jwt_token:Optional[str]=None
9
+
10
+
11
+
12
+ class Coordinates(BaseModel):
13
+ latitude: Optional[float] = None
14
+ longitude: Optional[float] = None
15
+
16
+
17
+ class ErrorResponse(BaseModel):
18
+ error: str
requirements.txt ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated-types==0.7.0
2
+ anyio==4.4.0
3
+ beautifulsoup4==4.12.3
4
+ blis==0.7.11
5
+ catalogue==2.0.10
6
+ certifi==2024.7.4
7
+ charset-normalizer==3.3.2
8
+ click==8.1.7
9
+ cloudpathlib==0.18.1
10
+ confection==0.1.5
11
+ cssselect==1.2.0
12
+ cymem==2.0.8
13
+ deprecation==2.1.0
14
+ dnspython==2.6.1
15
+ email_validator==2.2.0
16
+ en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.7.1/en_core_web_sm-3.7.1-py3-none-any.whl#sha256=86cc141f63942d4b2c5fcee06630fd6f904788d2f0ab005cce45aadb8fb73889
17
+ fastapi==0.111.1
18
+ fastapi-cli==0.0.4
19
+ feedfinder2==0.0.4
20
+ feedparser==6.0.11
21
+ filelock==3.15.4
22
+ geographiclib==2.0
23
+ geopy==2.4.1
24
+ gotrue==2.5.5
25
+ h11==0.14.0
26
+ h2==4.1.0
27
+ hpack==4.0.0
28
+ httpcore==1.0.5
29
+ httptools==0.6.1
30
+ httpx==0.27.0
31
+ hyperframe==6.0.1
32
+ idna==3.7
33
+ jieba3k==0.35.1
34
+ Jinja2==3.1.4
35
+ joblib==1.4.2
36
+ langcodes==3.4.0
37
+ language_data==1.2.0
38
+ locationtagger==0.0.1
39
+ lxml==5.2.2
40
+ lxml_html_clean==0.1.1
41
+ marisa-trie==1.2.0
42
+ markdown-it-py==3.0.0
43
+ MarkupSafe==2.1.5
44
+ mdurl==0.1.2
45
+ murmurhash==1.0.10
46
+ newspaper3k==0.2.8
47
+ nltk==3.8.1
48
+ numpy==1.26.4
49
+ packaging==24.1
50
+ pillow==10.4.0
51
+ postgrest==0.16.9
52
+ preshed==3.0.9
53
+ pycountry==24.6.1
54
+ pydantic==2.8.2
55
+ pydantic-settings==2.3.4
56
+ pydantic_core==2.20.1
57
+ Pygments==2.18.0
58
+ python-dateutil==2.9.0.post0
59
+ python-dotenv==1.0.1
60
+ python-multipart==0.0.9
61
+ PyYAML==6.0.1
62
+ realtime==1.0.6
63
+ regex==2024.5.15
64
+ requests==2.32.3
65
+ requests-file==2.1.0
66
+ rich==13.7.1
67
+ setuptools==70.3.0
68
+ sgmllib3k==1.0.0
69
+ shellingham==1.5.4
70
+ six==1.16.0
71
+ smart-open==7.0.4
72
+ sniffio==1.3.1
73
+ soupsieve==2.5
74
+ spacy==3.7.5
75
+ spacy-legacy==3.0.12
76
+ spacy-loggers==1.0.5
77
+ srsly==2.4.8
78
+ starlette==0.37.2
79
+ storage3==0.7.7
80
+ StrEnum==0.4.15
81
+ supabase==2.5.3
82
+ supafunc==0.4.7
83
+ thinc==8.2.5
84
+ tinysegmenter==0.3
85
+ tldextract==5.1.2
86
+ tqdm==4.66.4
87
+ typer==0.12.3
88
+ typing_extensions==4.12.2
89
+ urllib3==2.2.2
90
+ uvicorn==0.30.1
91
+ uvloop==0.19.0
92
+ wasabi==1.1.3
93
+ watchfiles==0.22.0
94
+ weasel==0.4.1
95
+ websockets==12.0
96
+ wrapt==1.16.0
services/location_service.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import locationtagger
2
+ from geopy.geocoders import Nominatim
3
+ from geopy.exc import GeocoderTimedOut, GeocoderUnavailable
4
+ from models.location_models import LocationData, Coordinates, ErrorResponse
5
+
6
+ class LocationService:
7
+ @staticmethod
8
+ def get_coordinates(data:dict) -> Coordinates | ErrorResponse:
9
+ print("Inside get coordinates")
10
+ print(data)
11
+ try:
12
+ location = data.get('location')
13
+ except:
14
+ return Coordinates(latitude=None , longitude=None)
15
+ location_string=None
16
+ city=None
17
+ state=None
18
+ country=None
19
+ if location:
20
+ place_entity = locationtagger.find_locations(text=location)
21
+
22
+ extracted_cities = list(place_entity.cities)
23
+ extracted_regions = list(place_entity.regions)
24
+ extracted_countries = list(place_entity.countries)
25
+
26
+ if extracted_cities:
27
+ city = extracted_cities[0]
28
+ if extracted_regions:
29
+ state = extracted_regions[0]
30
+ if extracted_countries:
31
+ country = extracted_countries[0]
32
+
33
+ # location_string = ' '.join(filter(None, [city, state, country]))
34
+
35
+ if not location_string:
36
+ location_string = location
37
+ else:
38
+ return ErrorResponse(error="No location information provided")
39
+
40
+ geolocator = Nominatim(user_agent="Geolocation")
41
+ print("Printing location string")
42
+ print(location_string)
43
+ if city or state or country :
44
+ location_string = city
45
+ elif country is None:
46
+ location_string = city
47
+ elif city is None:
48
+ location_string = state
49
+ elif state is None:
50
+ location_string = city
51
+
52
+ try:
53
+ getLoc = geolocator.geocode(location_string)
54
+ print(getLoc.latitude)
55
+ print(getLoc.longitude)
56
+ return Coordinates(
57
+ latitude=getLoc.latitude,
58
+ longitude=getLoc.longitude
59
+ )
60
+ except Exception as e:
61
+ print(f"Error {e}")
62
+ return Coordinates(latitude=None , longitude=None)