Ars/ai_functions.py CHANGED
@@ -3,16 +3,16 @@ from io import BytesIO
3
  from Ars.objects import ai,ResumeData,AutomationRiskResult,AutomationRiskInput,RealWorldQuestion,SkillDepthResult,SkillDepthInput,BreakDownByDomainUpdate,FlaggedRiskAreasUpdate,BoostSuggestionsUpdate,AICollabReadinessInput
4
  from Ars.embedDoc import search_pinecone_text
5
  from fastapi import UploadFile
 
6
  def extract_text_from_bytes(pdf_bytes: bytes) -> str:
7
  output_string = BytesIO()
8
  with BytesIO(pdf_bytes) as input_stream:
9
  extract_text_to_fp(input_stream, output_string)
10
  return output_string.getvalue().decode()
11
 
12
-
13
 
14
- async def resume_analysis(contents) -> ResumeData:
15
-
16
  resume = extract_text_from_bytes(pdf_bytes=contents)
17
  if resume:
18
  prompt = f"""
 
3
  from Ars.objects import ai,ResumeData,AutomationRiskResult,AutomationRiskInput,RealWorldQuestion,SkillDepthResult,SkillDepthInput,BreakDownByDomainUpdate,FlaggedRiskAreasUpdate,BoostSuggestionsUpdate,AICollabReadinessInput
4
  from Ars.embedDoc import search_pinecone_text
5
  from fastapi import UploadFile
6
+
7
  def extract_text_from_bytes(pdf_bytes: bytes) -> str:
8
  output_string = BytesIO()
9
  with BytesIO(pdf_bytes) as input_stream:
10
  extract_text_to_fp(input_stream, output_string)
11
  return output_string.getvalue().decode()
12
 
 
13
 
14
+ async def resume_analysis(upload_file:UploadFile) -> ResumeData:
15
+ contents = await upload_file.read()
16
  resume = extract_text_from_bytes(pdf_bytes=contents)
17
  if resume:
18
  prompt = f"""
Ars/controllers.py CHANGED
@@ -1,44 +1,19 @@
1
  from Ars.core import r
2
- from Ars.repositories import get_document_by_hashed_doc_complete,get_document_by_hashed_doc,create_new_hashed_doc_entry,create_boost_suggestions,create_breakdown_by_domain,create_flagged_risk_areas,create_user_resilience
3
  from fastapi import UploadFile
4
- from Ars.ai_functions import extract_text_from_bytes,resume_analysis,calculate_automation_risk,calculate_Ai_collab_readiness,calculate_skill_depth,generate_boost_suggestion,generate_domain_breakdown,generate_flagged_risk_areas
5
  from Ars.objects import AICollabReadiness,SkillDepthResult,AutomationRiskResult
6
- import hashlib
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- def get_document_hash(document_content: str) -> str:
9
- # Ensure consistent encoding (e.g., UTF-8) before hashing
10
- document_bytes = document_content.encode('utf-8')
11
- hasher = hashlib.sha256()
12
- hasher.update(document_bytes)
13
- return hasher.hexdigest()
14
-
15
- async def resilience_analysis(file:UploadFile,userId:str):
16
- contents = await file.read()
17
- resume_text = extract_text_from_bytes(pdf_bytes=contents)
18
- hashed_doc = get_document_hash(resume_text)
19
-
20
- check = await get_document_by_hashed_doc(hashed_doc=hashed_doc)
21
- if check==None:
22
- resume= await resume_analysis(contents)
23
- risk = calculate_automation_risk(resume)
24
- risk = AutomationRiskResult(**risk.model_dump())
25
- skill_depth = calculate_skill_depth(resume)
26
- skill_depth= SkillDepthResult(**skill_depth.model_dump())
27
- ai_readiness = calculate_Ai_collab_readiness(resume)
28
- ai_readiness = AICollabReadiness(**ai_readiness.model_dump())
29
- ResilienceScore = ((1-(risk.result/100))*0.5+(skill_depth.result/100)*0.3+(ai_readiness.result/100)*0.2)
30
- flagged_risk =generate_flagged_risk_areas(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
31
- boost_suggestion = generate_boost_suggestion(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
32
- domain_breakdown = generate_domain_breakdown(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
33
- final_analysis_response ={"overall score": ResilienceScore,"flagged Risk": flagged_risk.model_dump(),"boost suggestion":boost_suggestion.model_dump(),"domain breakdown":domain_breakdown.model_dump(),"resume":resume.model_dump(),"skil_depth":skill_depth.model_dump(),"risk":risk.model_dump(),"ai_readiness":ai_readiness.model_dump()}
34
- resultId =await create_new_hashed_doc_entry(data={"hashed_doc":hashed_doc,"resume":final_analysis_response,"userId":userId})
35
- return final_analysis_response
36
- else:
37
- result_hash =await get_document_by_hashed_doc_complete(hashed_doc)
38
- if result_hash['hashed_doc']==hashed_doc and result_hash['userId']== userId:
39
-
40
- await create_new_hashed_doc_entry(data={"hashed_doc":hashed_doc,"resume":check,"userId":userId})
41
- return check
42
-
43
- await create_new_hashed_doc_entry(data={"hashed_doc":hashed_doc,"resume":check,"userId":userId})
44
- return check
 
1
  from Ars.core import r
2
+ from Ars.repositories import create_boost_suggestions,create_breakdown_by_domain,create_flagged_risk_areas,create_user_resilience
3
  from fastapi import UploadFile
4
+ from Ars.ai_functions import resume_analysis,calculate_automation_risk,calculate_Ai_collab_readiness,calculate_skill_depth,generate_boost_suggestion,generate_domain_breakdown,generate_flagged_risk_areas
5
  from Ars.objects import AICollabReadiness,SkillDepthResult,AutomationRiskResult
6
+ async def resilience_analysis(file:UploadFile):
7
+ resume= await resume_analysis(file)
8
+ risk = calculate_automation_risk(resume)
9
+ risk = AutomationRiskResult(**risk.model_dump())
10
+ skill_depth = calculate_skill_depth(resume)
11
+ skill_depth= SkillDepthResult(**skill_depth.model_dump())
12
+ ai_readiness = calculate_Ai_collab_readiness(resume)
13
+ ai_readiness = AICollabReadiness(**ai_readiness.model_dump())
14
+ ResilienceScore = ((1-(risk.result/100))*0.5+(skill_depth.result/100)*0.3+(ai_readiness.result/100)*0.2)
15
+ flagged_risk =generate_flagged_risk_areas(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
16
+ boost_suggestion = generate_boost_suggestion(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
17
+ domain_breakdown = generate_domain_breakdown(resume=resume,skil_depth=skill_depth,risk=risk,ai_readiness=ai_readiness)
18
 
19
+ return {"overall score": ResilienceScore,"flagged Risk": flagged_risk,"boost suggestion":boost_suggestion,"domain breakdown":domain_breakdown,"resume":resume,"skil_depth":skill_depth,"risk":risk,"ai_readiness":ai_readiness}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Ars/repositories.py CHANGED
@@ -4,65 +4,8 @@ from fastapi import HTTPException
4
  from typing import Optional, List
5
  from motor.motor_asyncio import AsyncIOMotorDatabase
6
  from Ars.objects import UserResilienceScoreCreate, UserResilienceScoreOut,BreakDownByDomainCreate,BreakDownByDomainOut,FlaggedRiskAreasCreate,FlaggedRiskAreasOut,BoostSuggestionsCreate,BoostSuggestionsOut,BoostSuggestionsUpdate,UserResilienceScoreUpdate,FlaggedRiskAreasUpdate,BreakDownByDomainUpdate
7
- import pymongo
8
 
9
- async def create_new_hashed_doc_entry(data: dict):
10
-
11
- try:
12
- # Attempt to insert the document, ensuring hashed_doc is unique due to the index
13
- result = await db.resume_resilience_analysis.insert_one(document=data)
14
- return {"inserted_id": result.inserted_id,"error":None} # Return the inserted ID
15
- except pymongo.errors.DuplicateKeyError:
16
- # Handle the case where a document with the same 'hashed_doc' already exists
17
- return {"error": "Document with this 'hashed_doc' already exists"}
18
- except Exception as e:
19
- # Catch other exceptions (e.g., database connection issues)
20
- return {"error": str(e)}
21
-
22
- async def get_document_by_hashed_doc(hashed_doc: str):
23
- try:
24
- # Find the document using the hashed_doc field
25
- document = await db.resume_resilience_analysis.find_one({"hashed_doc": hashed_doc})
26
-
27
- if document:
28
- return document['resume']
29
- else:
30
- return None
31
-
32
- except Exception as e:
33
- # Handle any other errors, like database issues
34
- return {"error": str(e)}
35
-
36
- async def get_document_by_hashed_doc_complete(hashed_doc: str):
37
- try:
38
- # Find the document using the hashed_doc field
39
- document = await db.resume_resilience_analysis.find_one({"hashed_doc": hashed_doc})
40
-
41
- if document:
42
- return document
43
- else:
44
- return None
45
-
46
- except Exception as e:
47
- # Handle any other errors, like database issues
48
- return {"error": str(e)}
49
-
50
-
51
- async def get_document_by_userId(userId: str):
52
- try:
53
- # Find the document using the hashed_doc field
54
- document = await db.resume_resilience_analysis.find_one({"userId": userId})
55
-
56
- if document:
57
- return document['resume']
58
- else:
59
- return None
60
-
61
- except Exception as e:
62
- # Handle any other errors, like database issues
63
- return {"error": str(e)}
64
-
65
-
66
  async def create_user_resilience( data: UserResilienceScoreCreate) -> UserResilienceScoreOut:
67
  """
68
  Create a new UserResilienceScore in the database.
 
4
  from typing import Optional, List
5
  from motor.motor_asyncio import AsyncIOMotorDatabase
6
  from Ars.objects import UserResilienceScoreCreate, UserResilienceScoreOut,BreakDownByDomainCreate,BreakDownByDomainOut,FlaggedRiskAreasCreate,FlaggedRiskAreasOut,BoostSuggestionsCreate,BoostSuggestionsOut,BoostSuggestionsUpdate,UserResilienceScoreUpdate,FlaggedRiskAreasUpdate,BreakDownByDomainUpdate
 
7
 
8
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  async def create_user_resilience( data: UserResilienceScoreCreate) -> UserResilienceScoreOut:
10
  """
11
  Create a new UserResilienceScore in the database.
Ars/routes.py CHANGED
@@ -1,31 +1,15 @@
1
  import base64
2
- from fastapi import FastAPI, File, UploadFile,HTTPException,Depends
3
  from Ars.controllers import resilience_analysis
4
- from Ars.repositories import get_document_by_userId
5
- from security.authDependency import verifyAccessToken
6
  from Ars.embedDoc import upsert_text_with_chunks,search_pinecone_text
7
- import hashlib
8
-
9
-
10
  ARS = FastAPI()
11
 
12
-
13
-
14
-
15
-
16
  @ARS.post("/risk-analysis")
17
- async def perform_risk_analysis(user =Depends(verifyAccessToken) ,file: UploadFile = File(...), ):
18
  if file.content_type != "application/pdf":
19
  return HTTPException(status_code=400, detail={"error": "File must be a PDF."})
20
-
21
- ResilienceScore = await resilience_analysis(file=file,userId=user['userId'])
22
  return ResilienceScore
23
 
24
 
25
 
26
- @ARS.get("/risk-analysis")
27
- async def perform_risk_analysis(user=Depends(verifyAccessToken) ):
28
- ResilienceScore = await get_document_by_userId(userId=user['userId'])
29
-
30
- return ResilienceScore
31
-
 
1
  import base64
2
+ from fastapi import FastAPI, File, UploadFile,HTTPException
3
  from Ars.controllers import resilience_analysis
 
 
4
  from Ars.embedDoc import upsert_text_with_chunks,search_pinecone_text
 
 
 
5
  ARS = FastAPI()
6
 
 
 
 
 
7
  @ARS.post("/risk-analysis")
8
+ async def perform_risk_analysis(file: UploadFile = File(...)):
9
  if file.content_type != "application/pdf":
10
  return HTTPException(status_code=400, detail={"error": "File must be a PDF."})
11
+ ResilienceScore = await resilience_analysis(file=file)
 
12
  return ResilienceScore
13
 
14
 
15
 
 
 
 
 
 
 
Dockerfile CHANGED
@@ -1,7 +1,7 @@
1
  # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
  # you will also find guides on how best to write your Dockerfile
3
 
4
- FROM python:3.11
5
 
6
  RUN useradd -m -u 1000 user
7
  USER user
 
1
  # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
  # you will also find guides on how best to write your Dockerfile
3
 
4
+ FROM python:3.9
5
 
6
  RUN useradd -m -u 1000 user
7
  USER user
README.md CHANGED
@@ -8,4 +8,7 @@ pinned: false
8
  license: apache-2.0
9
  ---
10
 
 
 
11
  if you are changing the connection string in the env to a new one ensure you populate the levels table with levels up to level9 for a default career path and default level name else points won't be calculated properly
 
 
8
  license: apache-2.0
9
  ---
10
 
11
+ <<<<<<< HEAD
12
+ =======
13
  if you are changing the connection string in the env to a new one ensure you populate the levels table with levels up to level9 for a default career path and default level name else points won't be calculated properly
14
+ >>>>>>> master
app.py CHANGED
@@ -256,17 +256,8 @@ def get_user_details(authorization: str = Header(...)):
256
  user_info = user_details_func(db_uri=MONGO_URI,document=doc)
257
  return { "userInfo": user_info}
258
 
259
- @app.post("/mailing/list",tags=["guest"])
260
- def add_new_member_to_mailing_list(document: MailingList):
261
- from pymongo import ASCENDING
262
- collection = db['MailingList']
263
 
264
- # Ensure the email field has a unique index
265
- collection.create_index([('email', ASCENDING)], unique=True)
266
 
267
- # Insert the document
268
- collection.insert_one(document.model_dump())
269
-
270
 
271
  @app.get("/protected-route")
272
  def protected_route(authorization: str = Header(...)):
 
256
  user_info = user_details_func(db_uri=MONGO_URI,document=doc)
257
  return { "userInfo": user_info}
258
 
 
 
 
 
259
 
 
 
260
 
 
 
 
261
 
262
  @app.get("/protected-route")
263
  def protected_route(authorization: str = Header(...)):
controller/imports.py CHANGED
@@ -12,7 +12,7 @@ import fitz
12
  from gamification.routes import gamification
13
  from controller.scraper import scrapeCourse
14
  import asyncio
15
- from google import genai
16
  from typing import Optional,List
17
  from pydantic import BaseModel
18
  import re
@@ -20,7 +20,7 @@ from bson.json_util import dumps
20
  import threading
21
  import concurrent.futures
22
  from gamification.pointLogic import get_all_simple_points_func,get_dream_job
23
- from pydantic import BaseModel, EmailStr
24
  from datetime import datetime
25
  from bson import ObjectId
26
  import os
@@ -73,9 +73,6 @@ class UserCourse(BaseModel):
73
  timeframeToAchieveDreamRole:str
74
  recommendedCourses: Optional[List[RecommendedCourse]]=None
75
 
76
-
77
- class MailingList(BaseModel):
78
- email:EmailStr
79
  class LeaderBoardRanking(BaseModel):
80
  userId:str
81
  firstName:str
 
12
  from gamification.routes import gamification
13
  from controller.scraper import scrapeCourse
14
  import asyncio
15
+ from google import genai
16
  from typing import Optional,List
17
  from pydantic import BaseModel
18
  import re
 
20
  import threading
21
  import concurrent.futures
22
  from gamification.pointLogic import get_all_simple_points_func,get_dream_job
23
+ from pydantic import BaseModel
24
  from datetime import datetime
25
  from bson import ObjectId
26
  import os
 
73
  timeframeToAchieveDreamRole:str
74
  recommendedCourses: Optional[List[RecommendedCourse]]=None
75
 
 
 
 
76
  class LeaderBoardRanking(BaseModel):
77
  userId:str
78
  firstName:str
requirements.txt CHANGED
@@ -1,75 +1,20 @@
1
- # Core web stack
2
  fastapi[all]
3
- uvicorn
4
- gunicorn
5
  requests
6
  python-dotenv
7
-
8
- # PDF, Docx handling
9
  pymupdf
10
- python-docx
11
- docx2txt
12
- pdfminer.six # Use only this (newest), remove old 'pdfminer'
13
-
14
- # MongoDB
15
  motor
16
- pymongo
17
-
18
- # AI and embedding
19
  openai
20
- sentence-transformers
21
  pinecone
22
- langchain-text-splitters
23
- langchain-core
24
- transformers
25
- torch
26
  einops
27
-
28
- # Google GenAI
29
- google-generativeai
30
- google-auth
31
- google-api-python-client
32
  google-genai
33
-
34
- # Authentication
 
35
  bcrypt
36
- passlib[bcrypt]
37
  python-jose[cryptography]
38
-
39
- # Redis
 
40
  redis
41
-
42
- # Frontend templating and security
43
- jinja2
44
- itsdangerous
45
-
46
- # Other utilities
47
- python-multipart
48
- pydantic-settings
49
- pydantic-extra-types
50
-
51
- # Windows only (skip on Linux/mac)
52
- # Remove pywin32==308, use the latest
53
-
54
- # Optional tools
55
- tqdm
56
- beautifulsoup4
57
- httpx
58
- httpcore
59
-
60
- # ML / Data
61
- scikit-learn
62
- pandas
63
- numpy
64
- matplotlib-inline
65
- joblib
66
- scipy
67
-
68
- # Optional for resume parsing
69
- pyresparser
70
- email-validator
71
-
72
- # Logging, async, extras
73
- rich
74
- watchfiles
75
- nest-asyncio
 
 
1
  fastapi[all]
 
 
2
  requests
3
  python-dotenv
 
 
4
  pymupdf
 
 
 
 
 
5
  motor
 
 
 
6
  openai
 
7
  pinecone
8
+ sentence-transformers
 
 
 
9
  einops
 
 
 
 
 
10
  google-genai
11
+ python-docx
12
+ beautifulsoup4
13
+ pymongo
14
  bcrypt
 
15
  python-jose[cryptography]
16
+ passlib[bcrypt]
17
+ uvicorn
18
+ gunicorn # Add this for production
19
  redis
20
+ cryptography
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
security/__init__.py DELETED
File without changes
security/authDependency.py DELETED
@@ -1,14 +0,0 @@
1
- from fastapi.security import HTTPBearer
2
- from fastapi import Depends
3
- from controller.imports import *
4
-
5
- token_auth_scheme = HTTPBearer()
6
-
7
- def verifyAccessToken(token:str =Depends(token_auth_scheme)):
8
- credentials = token.credentials
9
- decoded_user_id,decoded_access_token = decode_jwt(credentials)
10
- is_valid = verify_access_token(db_uri=MONGO_URI, user_id=decoded_user_id, access_token=decoded_access_token)
11
- if is_valid != True: # Example check
12
- raise HTTPException(status_code=401, detail="Invalid token")
13
- else:
14
- return {"userId":decoded_user_id}