Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- Dockerfile +15 -0
- main.py +147 -0
- requirements.txt +0 -0
Dockerfile
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
WORKDIR /code
|
7 |
+
|
8 |
+
COPY ./requirements.txt /code/requirements.txt
|
9 |
+
|
10 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
11 |
+
|
12 |
+
COPY . .
|
13 |
+
|
14 |
+
CMD uvicorn main:app --port=8000 --host=0.0.0.0
|
15 |
+
|
main.py
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, HTTPException
|
2 |
+
import gspread
|
3 |
+
from google.oauth2.service_account import Credentials
|
4 |
+
from google.auth.exceptions import GoogleAuthError
|
5 |
+
import pandas as pd
|
6 |
+
from collections import defaultdict
|
7 |
+
from pydantic import BaseModel
|
8 |
+
from fastapi.middleware.cors import CORSMiddleware
|
9 |
+
import os
|
10 |
+
|
11 |
+
app = FastAPI()
|
12 |
+
app.add_middleware(
|
13 |
+
CORSMiddleware,
|
14 |
+
allow_origins=["*"], # You can specify domains instead of "*" to restrict access
|
15 |
+
allow_credentials=True,
|
16 |
+
allow_methods=["*"], # Allows all HTTP methods (POST, GET, OPTIONS, etc.)
|
17 |
+
allow_headers=["*"], # Allows all headers
|
18 |
+
)
|
19 |
+
# Define Google Sheets API credentials function
|
20 |
+
def get_credentials():
|
21 |
+
try:
|
22 |
+
service_account_info = {
|
23 |
+
"type": os.getenv("SERVICE_ACCOUNT_TYPE"),
|
24 |
+
"project_id": os.getenv("PROJECT_ID"),
|
25 |
+
"private_key_id": os.getenv("PRIVATE_KEY_ID"),
|
26 |
+
"private_key": os.getenv("PRIVATE_KEY").replace('\\n', '\n'),
|
27 |
+
"client_email": os.getenv("CLIENT_EMAIL"),
|
28 |
+
"client_id": os.getenv("CLIENT_ID"),
|
29 |
+
"auth_uri": os.getenv("AUTH_URI"),
|
30 |
+
"token_uri": os.getenv("TOKEN_URI"),
|
31 |
+
"auth_provider_x509_cert_url": os.getenv("AUTH_PROVIDER_X509_CERT_URL"),
|
32 |
+
"client_x509_cert_url": os.getenv("CLIENT_X509_CERT_URL"),
|
33 |
+
"universe_domain": os.getenv("UNIVERSE_DOMAIN")
|
34 |
+
}
|
35 |
+
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
|
36 |
+
creds = Credentials.from_service_account_info(service_account_info, scopes=scope)
|
37 |
+
return creds
|
38 |
+
except Exception as e:
|
39 |
+
print(f"Error getting credentials: {e}")
|
40 |
+
return None
|
41 |
+
|
42 |
+
# Initialize Google Sheets Client
|
43 |
+
creds = get_credentials()
|
44 |
+
if creds:
|
45 |
+
client = gspread.authorize(creds)
|
46 |
+
|
47 |
+
# Define input model
|
48 |
+
class CoachingCodeInput(BaseModel):
|
49 |
+
coachingCode: str
|
50 |
+
|
51 |
+
# Define the endpoint
|
52 |
+
@app.post("/process/")
|
53 |
+
def process_data(input_data: CoachingCodeInput):
|
54 |
+
coachingCode = input_data.coachingCode
|
55 |
+
|
56 |
+
# Define Google Sheet URLs based on coachingCode
|
57 |
+
journal_file_path = ''
|
58 |
+
panic_button_file_path = ''
|
59 |
+
test_file_path = ''
|
60 |
+
|
61 |
+
if coachingCode == '1919':
|
62 |
+
journal_file_path = 'https://docs.google.com/spreadsheets/d/1EFf2lr4A10nt4RhIqxCD_fxe-l3sXH09II0TEkMmvhA/edit?usp=drive_link'
|
63 |
+
panic_button_file_path = 'https://docs.google.com/spreadsheets/d/1nFZGkCvRV6qS-mhsORhX3dxI0JSge32_UwWgWKl3eyw/edit?usp=drive_link'
|
64 |
+
test_file_path = 'https://docs.google.com/spreadsheets/d/13PUHySUXWtKBusjugoe7Dbsm39PwBUfG4tGLipspIx4/edit?usp=drive_link'
|
65 |
+
else:
|
66 |
+
raise HTTPException(status_code=404, detail="Invalid coaching code")
|
67 |
+
|
68 |
+
try:
|
69 |
+
# Open the Google Sheets
|
70 |
+
journal_file = client.open_by_url(journal_file_path).worksheet('Sheet1')
|
71 |
+
panic_button_file = client.open_by_url(panic_button_file_path).worksheet('Sheet1')
|
72 |
+
test_file = client.open_by_url(test_file_path).worksheet('Sheet1')
|
73 |
+
|
74 |
+
# Step 1: Read the Google Sheets into DataFrames
|
75 |
+
journal_df = pd.DataFrame(journal_file.get_all_values())
|
76 |
+
panic_button_df = pd.DataFrame(panic_button_file.get_all_values())
|
77 |
+
test_df = pd.DataFrame(test_file.get_all_values())
|
78 |
+
|
79 |
+
# Label the columns manually
|
80 |
+
journal_df.columns = ['user_id', 'productivity_yes_no', 'productivity_rate']
|
81 |
+
panic_button_df.columns = ['user_id', 'panic_button']
|
82 |
+
|
83 |
+
# Step 2: Merge Journal and Panic Button data
|
84 |
+
panic_button_grouped = panic_button_df.groupby('user_id')['panic_button'].apply(lambda x: ','.join(x)).reset_index()
|
85 |
+
merged_journal_panic = pd.merge(journal_df, panic_button_grouped, on='user_id', how='outer')
|
86 |
+
|
87 |
+
# Step 3: Process Test data
|
88 |
+
test_data = []
|
89 |
+
for index, row in test_df.iterrows():
|
90 |
+
user_id = row[0]
|
91 |
+
i = 1
|
92 |
+
while i < len(row) and pd.notna(row[i]):
|
93 |
+
chapter = row[i].lower().strip()
|
94 |
+
score = row[i + 1]
|
95 |
+
if pd.notna(score):
|
96 |
+
test_data.append({'user_id': user_id, 'test_chapter': chapter, 'test_score': score})
|
97 |
+
i += 2
|
98 |
+
|
99 |
+
test_df_processed = pd.DataFrame(test_data)
|
100 |
+
|
101 |
+
# Step 4: Merge all data
|
102 |
+
merged_data = pd.merge(merged_journal_panic, test_df_processed, on='user_id', how='outer')
|
103 |
+
merged_data_cleaned = merged_data.dropna(subset=['productivity_yes_no', 'productivity_rate', 'panic_button', 'test_chapter'], how='all')
|
104 |
+
|
105 |
+
# Step 5: Process Data
|
106 |
+
df = pd.DataFrame(merged_data_cleaned)
|
107 |
+
academic_weights = {'BACKLOGS': -5, 'MISSED CLASSES': -4, 'NOT UNDERSTANDING': -3, 'BAD MARKS': -3, 'LACK OF MOTIVATION': -3}
|
108 |
+
non_academic_weights = {'EMOTIONAL FACTORS': -3, 'PROCRASTINATE': -2, 'LOST INTEREST': -4, 'LACK OF FOCUS': -2, 'GOALS NOT ACHIEVED': -2, 'LACK OF DISCIPLINE': -2}
|
109 |
+
max_weighted_panic_score = sum([max(academic_weights.values()) * 3, max(non_academic_weights.values()) * 3])
|
110 |
+
|
111 |
+
def calculate_potential_score(row):
|
112 |
+
test_score_normalized = 0
|
113 |
+
if row['test_scores']:
|
114 |
+
avg_test_score = sum(row['test_scores'].values()) / len(row['test_scores'])
|
115 |
+
test_score_normalized = (avg_test_score / 40) * 70
|
116 |
+
|
117 |
+
student_panic_score = 0
|
118 |
+
if row['panic_button']:
|
119 |
+
for factor, count in row['panic_button'].items():
|
120 |
+
if factor in academic_weights:
|
121 |
+
student_panic_score += academic_weights[factor] * count
|
122 |
+
elif factor in non_academic_weights:
|
123 |
+
student_panic_score += non_academic_weights[factor] * count
|
124 |
+
|
125 |
+
panic_score = 20 * (1 - (student_panic_score / max_weighted_panic_score)) if max_weighted_panic_score != 0 else 1
|
126 |
+
journal_score = (float(row['productivity_rate']) / 10) * 10 if pd.notna(row['productivity_rate']) else 0
|
127 |
+
|
128 |
+
total_potential_score = test_score_normalized + panic_score + journal_score
|
129 |
+
return total_potential_score
|
130 |
+
|
131 |
+
merged_df = df.groupby('user_id').apply(lambda group: pd.Series({
|
132 |
+
'potential_score': calculate_potential_score(group)
|
133 |
+
})).reset_index()
|
134 |
+
|
135 |
+
merged_df['potential_score'] = merged_df['potential_score'].round(2)
|
136 |
+
sorted_df = merged_df[['user_id', 'potential_score']].sort_values(by='potential_score', ascending=False)
|
137 |
+
|
138 |
+
# Return the result as JSON
|
139 |
+
return sorted_df.to_dict(orient='records')
|
140 |
+
|
141 |
+
except GoogleAuthError as e:
|
142 |
+
raise HTTPException(status_code=500, detail=f"Authentication failed: {str(e)}")
|
143 |
+
except Exception as e:
|
144 |
+
raise HTTPException(status_code=500, detail=f"Error processing data: {str(e)}")
|
145 |
+
|
146 |
+
# To run the app:
|
147 |
+
# uvicorn filename:app --reload
|
requirements.txt
ADDED
Binary file (98 Bytes). View file
|
|