File size: 5,539 Bytes
02cb283
 
 
 
 
 
 
 
 
 
 
 
 
 
9d094d2
02cb283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea3463e
 
 
 
02cb283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from fastapi import FastAPI, File, UploadFile, HTTPException, Header
from pydantic import BaseModel,EmailStr, field_validator
from fastapi.middleware.cors import CORSMiddleware
import datetime
import jwt
import pandas as pd
from io import StringIO
import re
import os
import psycopg2
from bcrypt import hashpw,checkpw, gensalt
from sentiment import predict_sentiment
from dotenv import load_dotenv,find_dotenv

load_dotenv(find_dotenv(raise_error_if_not_found=False))

DATABASE_CONFIG = {
    'dbname': os.getenv("pg_db_name"),
    'user': os.getenv("pg_user"),
    'password': os.getenv("pg_password"),
    'host': os.getenv("pg_host"), 
    'port': os.getenv("pg_port")        
}

app = FastAPI()

# Add CORS Middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Allow requests from any origin (can be restricted)
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Secret key for JWT
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"  # Hashing algorithm for JWT



class LoginRequest(BaseModel):
    email: EmailStr
    password: str

    @field_validator("password")
    def validate_password(cls, value):
        if len(value) < 8:
            raise ValueError("Password must be at least 8 characters long.")
        if not re.search(r"[A-Za-z]", value):
            raise ValueError("Password must contain at least one letter.")
        if not re.search(r"[0-9]", value):
            raise ValueError("Password must contain at least one number.")
        return value


def create_jwt_token(email: str):
    """
    Create a JWT token with an expiration time.
    """
    payload = {
        "sub": email,  # Subject (user's email)
        "exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=1),  # Token expiry
        "iat": datetime.datetime.now(datetime.timezone.utc),  # Issued at time
    }
    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)


def verify_jwt_token(token: str):
    """
    Verify and decode the JWT token.
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload["sub"]  # Return the email (or user identifier)
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token has expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

def create_user(email:str,password:str)->bool:
    try:
        hashed_password = hashpw(password.encode('utf-8'), gensalt())
        conn = psycopg2.connect(**DATABASE_CONFIG)
        print("Connection successful!")
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO hanabi_user (email,password)
            VALUES (%s, %s)
        """, (
            email,
            hashed_password.decode("utf-8")
        ))
        conn.commit()
        cursor.close()
        conn.close()
        return True
    except psycopg2.Error as _:
        print(_)
        return False

def validate_user(email: str, password: str) -> bool:
    try:
        # Fetch the stored hashed password from the database
        conn = psycopg2.connect(**DATABASE_CONFIG)
        cursor = conn.cursor()
        query = "SELECT password FROM hanabi_user WHERE email=%s;"
        cursor.execute(query, (email,))
        row = cursor.fetchone()  # Fetch one row
        cursor.close()
        conn.close()
        # print(row)
        if row:
            stored_hashed_password = row[0]  # The hashed password from the DB
            # Compare the entered password with the stored hashed password
            if checkpw(password.encode('utf-8'), stored_hashed_password.encode('utf-8')):
                return True  # Password is correct
            else:
                return False  # Password is incorrect
        else:
            return False  # User not found
    except Exception as _:
        print(_)
        return False

@app.post("/login/")
def login(data: LoginRequest):
    if validate_user(data.email,data.password):
        # Generate a JWT token
        token = create_jwt_token(data.email)
        return {"token": token}
    else:
        raise HTTPException(status_code=401, detail="Invalid email or password")

@app.post("/signup/")
def signup(data: LoginRequest):
    if create_user(data.email,data.password):
        return {"response":"successful"}
    else:
        raise HTTPException(status_code=401, detail="error")


@app.get("/")
async def home():
        return {"message": "hello world"}

@app.post("/upload-csv/")
async def upload_csv(
    file: UploadFile = File(...),
    authorization: str = Header(None),  # Get the Authorization header
):
    # Verify the token
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Authorization token missing or invalid")
    token = authorization.split(" ")[1]  # Extract the token
    email = verify_jwt_token(token)  # Verify token and get the email

    # Process the file
    content = await file.read()
    df = pd.read_csv(StringIO(content.decode("utf-8")))
    texts = df["text"].tolist()
    sentiments = predict_sentiment(texts)
    df["sentiment"] = sentiments
    sentiment_counts = df["sentiment"].value_counts().to_dict()
    sentiment_records = df.to_dict(orient="index")

    # Return results
    return {
        "user": email,  # Include user info (from token)
        "sentiment_counts": sentiment_counts,
        "sentiments": list(sentiment_records.values()),
    }