Ars/ai_functions.py CHANGED
@@ -1,18 +1,18 @@
1
  from pdfminer.high_level import extract_text_to_fp
2
  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"""
 
1
  from pdfminer.high_level import extract_text_to_fp
2
  from io import BytesIO
3
+ from objects import ai,ResumeData,AutomationRiskResult,AutomationRiskInput,RealWorldQuestion,SkillDepthResult,SkillDepthInput,BreakDownByDomainUpdate,FlaggedRiskAreasUpdate,BoostSuggestionsUpdate,AICollabReadinessInput
4
+ from 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 core import r
2
+ from repositories import create_boost_suggestions,create_breakdown_by_domain,create_flagged_risk_areas,create_user_resilience
3
  from fastapi import UploadFile
4
+ from 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 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
@@ -1,68 +1,11 @@
1
- from Ars.core import db
2
  from bson import ObjectId
3
  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.
 
1
+ from core import db
2
  from bson import ObjectId
3
  from fastapi import HTTPException
4
  from typing import Optional, List
5
  from motor.motor_asyncio import AsyncIOMotorDatabase
6
+ from 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 controllers import resilience_analysis
4
+ from 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
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
 
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
gamification/pointLogic.py CHANGED
@@ -93,6 +93,16 @@ def get_all_simple_points_func(userId) -> SimpleIndividualUserLevel:
93
  db = client[db_name]
94
  collection = db[collection_name]
95
  dreamJob = get_dream_job(userId=userId)
 
 
 
 
 
 
 
 
 
 
96
  print(dreamJob)
97
  point_cursor = collection.find({"userId": userId})
98
  try:
@@ -102,6 +112,7 @@ def get_all_simple_points_func(userId) -> SimpleIndividualUserLevel:
102
 
103
  particularLevelInfo = get_particular_level(dreamJob=dreamJob,totalPoints=totalPoints)
104
  print(particularLevelInfo)
 
105
  points = SimpleIndividualUserLevel(totalpoints=totalPoints,levelName=particularLevelInfo[0].levelName,maxPoints=particularLevelInfo[0].maxPoints,minPoints=particularLevelInfo[0].minPoints,levelNumber=particularLevelInfo[0].levelNumber)
106
  except:
107
  totalPoints = 0
 
93
  db = client[db_name]
94
  collection = db[collection_name]
95
  dreamJob = get_dream_job(userId=userId)
96
+ <<<<<<< HEAD
97
+
98
+ point_cursor = collection.find({"userId": userId})
99
+ try:
100
+ points_list = list(point_cursor)
101
+
102
+ totalPoints = sum([point['numOfPoints'] for point in points_list])
103
+ particularLevelInfo = get_particular_level(dreamJob=dreamJob,totalPoints=totalPoints)
104
+
105
+ =======
106
  print(dreamJob)
107
  point_cursor = collection.find({"userId": userId})
108
  try:
 
112
 
113
  particularLevelInfo = get_particular_level(dreamJob=dreamJob,totalPoints=totalPoints)
114
  print(particularLevelInfo)
115
+ >>>>>>> master
116
  points = SimpleIndividualUserLevel(totalpoints=totalPoints,levelName=particularLevelInfo[0].levelName,maxPoints=particularLevelInfo[0].maxPoints,minPoints=particularLevelInfo[0].minPoints,levelNumber=particularLevelInfo[0].levelNumber)
117
  except:
118
  totalPoints = 0
requirements.txt CHANGED
@@ -1,75 +1,22 @@
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
+ <<<<<<< HEAD
6
+ =======
 
 
 
7
  motor
8
+ >>>>>>> master
 
 
 
 
9
  pinecone
10
+ sentence-transformers
 
 
 
11
  einops
 
 
 
 
 
12
  google-genai
13
+ python-docx
14
+ beautifulsoup4
15
+ pymongo
16
  bcrypt
 
17
  python-jose[cryptography]
18
+ passlib[bcrypt]
19
+ uvicorn
20
+ gunicorn # Add this for production
21
  redis
22
+ 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}