Skip to content

Commit

Permalink
sort and delete files (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
jjschulz authored Nov 21, 2024
2 parents 9898827 + d8f5254 commit 4d9e8cb
Show file tree
Hide file tree
Showing 18 changed files with 573 additions and 29 deletions.
Binary file added .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ TBD

### Dependencies

TBD
- [Consert Install Guide](flaskApp/consert/CONSERT_INSTALLATION.md)

### Installing

Expand Down
Binary file added flaskApp/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions flaskApp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ firebase/serviceAccountKey.json
__pycache__/
*.pyc
*.log
email_credentials.py
207 changes: 196 additions & 11 deletions flaskApp/app.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify, flash, json
import firebase_admin
from firebase_admin import credentials, firestore
import bcrypt
import bcrypt, secrets
from firebase.config import Config
from db_utils import upload_file_to_db, connect_to_database
from flask_mail import Mail, Message
import email_credentials
from datetime import datetime, timedelta, timezone

app = Flask(__name__)
app.config.from_object(Config)
Expand All @@ -22,6 +25,15 @@ def initialize_firebase():
initialize_firebase()
db = firestore.client()

# Configure Flask-Mail email settings
app.config['MAIL_SERVER'] = 'smtp.gmail.com' # SMTP email server
app.config['MAIL_PORT'] = 587
app.config['MAIL_USERNAME'] = email_credentials.hua_email
app.config['MAIL_PASSWORD'] = email_credentials.hua_password
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
mail = Mail(app)


@app.route("/")
def home():
Expand Down Expand Up @@ -50,7 +62,7 @@ def register():
'email': email,
'password': hashed_password.decode('utf-8')
})
return redirect(url_for('homepage'))
return redirect(url_for('homepage', email=email))

except Exception as e:
flash(f"An error occurred: {str(e)}", "danger")
Expand All @@ -61,13 +73,169 @@ def register():
def forgot_password():
return render_template('forgot_password.html')

@app.route('/pi_access_request', methods=['GET', 'POST'])
def pi_access_request():
name = request.form.get('name')
email = request.form.get('email')
institution = request.form.get('institution')
if request.method == 'POST':
try:
# Add request to HUA firebase
requests_ref = db.collection('request')
requests_doc = requests_ref.add({"username":email})

# Send email
recipients = email_credentials.recipients

emailMessage = Message("Request for PI Access", sender=email,recipients=recipients)
emailMessage.body = f"Hello Bob and Donna,\n\n {name} is requesting admin access. {name} is from {institution} and reachable at {email}.\n\n You will find their request on the View Requests for Access page in the Heard and Understood App."
mail.send(emailMessage)
print('email sent successfully!')
except Exception as e:
print('problem sending email')
print(e)

return redirect(url_for('homepage'))
return render_template('pi_access_request.html')

@app.route('/pre_approved_access_code', methods=['GET', 'POST'])
def pre_approved_access_code():
access_code = request.form.get('PIAccessCode')
if request.method == 'POST':
try:
print(f"pre-approved code {access_code} entered")
except:
print("issue with pre-approved code")
return redirect(url_for('homepage'))
return render_template('pre_approved_access_code.html')

@app.route('/reset_password', methods=['GET', 'POST'])
def reset_password():
if request.method == 'POST':
email = request.form.get('email').strip().lower()
user_ref = db.collection('users').document(email)
user_doc = user_ref.get()

if user_doc.exists:
verification_secret = secrets.token_hex(3)
expiration_time = datetime.now(timezone.utc) + timedelta(minutes=15)


user_ref.update({
'verification_code': verification_secret,
'verification_expiry': expiration_time
})

subject = "HUA Password Reset"
body = f"""Hi,
You recently requested a password reset for HUA. Your verification code is below.
{verification_secret}
This code will expire in 15 minutes.
If you didn't request a password reset, you can safely disregard this email.
This account is not monitored, please do not reply to this email.
"""
try:
msg = Message(subject, sender="Huaverso@gmail.com", recipients=[email], body=body)
mail.send(msg)

flash("A verification code has been sent to your email.", "success")
return redirect(url_for('enter_code', email=email))
except Exception:
flash("Failed to send verification email. Please try again later.", "danger")
return redirect(url_for('reset_password'))
else:
flash("No account with this email exists.", "danger")
return redirect(url_for('reset_password'))

return render_template('reset_password.html')

@app.route('/enter_code', methods=['GET', 'POST'])
def enter_code():
email = request.args.get('email')
if not email:
flash("Invalid request.", "danger")
return redirect(url_for('reset_password'))

if request.method == 'POST':
entered_code = request.form.get('verification_code').strip()
user_ref = db.collection('users').document(email)
user_doc = user_ref.get()

if not user_doc.exists:
flash("Invalid request.", "danger")
return redirect(url_for('reset_password'))

stored_code = user_doc.to_dict().get('verification_code')
expiry_time = user_doc.to_dict().get('verification_expiry')

if not stored_code or not expiry_time:
flash("No verification code found. Please initiate the password reset again.", "danger")
return redirect(url_for('reset_password'))

if entered_code != stored_code:
flash("Invalid verification code.", "danger")
return redirect(url_for('enter_code', email=email))

if datetime.now(timezone.utc) > expiry_time:
flash("The verification code has expired. Please request a new one.", "danger")
user_ref.update({
'verification_code': firestore.DELETE_FIELD,
'verification_expiry': firestore.DELETE_FIELD
})
return redirect(url_for('reset_password'))

return redirect(url_for('new_password', email=email))

return render_template('enter_code.html', email=email)

@app.route('/new_password', methods=['GET', 'POST'])
def new_password():
email = request.args.get('email')
if not email:
flash("Invalid request.", "danger")
return redirect(url_for('reset_password'))

if request.method == 'POST':
new_password = request.form.get('new_password')
confirm_password = request.form.get('confirm_password')

if new_password != confirm_password:
flash("Passwords do not match.", "danger")
return redirect(url_for('new_password', email=email))

if len(new_password) < 6:
flash("Password must be at least 6 characters long.", "danger")
return redirect(url_for('new_password', email=email))

# Hash the new password and decode to store as string
hashed_password = bcrypt.hashpw(new_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
user_ref = db.collection('users').document(email)
user_ref.update({'password': hashed_password})

user_ref.update({
'verification_code': firestore.DELETE_FIELD,
'verification_expiry': firestore.DELETE_FIELD
})

flash("Your password has been successfully reset. You can now log in.", "success")
return redirect(url_for('home'))

return render_template('new_password.html', email=email)




@app.route('/login', methods=['GET', 'POST'])
def login():
email = request.form.get('email')
password = request.form.get('password')

if request.method == 'POST':
print("Form Data:", request.form)
email = request.form.get('email')
password = request.form.get('password')
try:
# Retrieve user data from Firestore
user_ref = db.collection('users').document(email)
Expand All @@ -76,11 +244,21 @@ def login():
if user_doc.exists:
stored_hashed_password = user_doc.to_dict().get('password')

# Check if the password matches
if bcrypt.checkpw(password.encode('utf-8'), stored_hashed_password.encode('utf-8')):
return redirect(url_for('homepage'))
# Ensure the stored hashed password exists
if stored_hashed_password:
# Encode the stored hashed password to bytes
stored_hashed_password_bytes = stored_hashed_password.encode('utf-8')

# Check if the password matches
if bcrypt.checkpw(password.encode('utf-8'), stored_hashed_password_bytes):
flash("Logged in successfully.", "success")
return redirect(url_for('homepage', email=email))
else:
flash("Invalid password", "danger")
return redirect(url_for('login'))

else:
flash("Invalid password", "danger")
flash("Password not set for this account.", "danger")
return redirect(url_for('login'))
else:
flash("User not found", "danger")
Expand All @@ -89,13 +267,19 @@ def login():
except Exception as e:
flash(f"An error occurred: {str(e)}", "danger")
return redirect(url_for('login'))
if request.method == "GET":
return render_template('login.html')

# Handle GET requests
return render_template('login.html')


@app.route("/dashboard")
def dashboard():
return render_template("dashboard.html")

@app.route("/ground_truthing")
def ground_truthing():
return render_template("ground_truthing.html")

@app.route("/homepage")
def homepage():
return render_template('home.html')
Expand Down Expand Up @@ -139,3 +323,4 @@ def view_files():

if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5001, threaded=False)

32 changes: 19 additions & 13 deletions CONSERT_INSTALLION.MD → flaskApp/consert/CONSERT_INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,32 @@ Read more here: https://github.com/Heard-and-Understood/CONSert

## Installing the CONSert Package

This section of the guide is meant for HUA contributors who have access to the CONSert repository. The installation guide there has inaccuracies and can be streamlined for HUA contributors.
This section of the guide is meant for HUA contributors who have access to the CONSert repository.

As of 10/24/2024 testing and implementation of CONSert has been done with CONDA environments running python 3.10.11. The linux/macos version of this package must be run on python 3.10 or earlier.

### Cloning the Repository
### Pip Install Via Local Repository

Start by cloning the repository from github into your desired directory and activating any desired virtual environment.

### Install Via pip

If you are a owner/maintainer/developer you can install the packagage via pip install (path to cloned repo).

```
pip install path/to/cloned/CONSert
```

### Pip Install Via Github Repository

Alternatively the package can be installed without the original source code.

```
pip install git+https://github.com/Heard-and-Understood/CONSert.git
```

### The Models

CONSert's pause detection requires several models to run: CNN, RF, and BERT. The paths to the models are specified in package.json which can be found here:
CONSert's pause detection and classification requires several models to run: CNN, RF, and BERT. The paths to the models are specified in package.json which can be found in the root directory of the package:
```
CONSERT/consert/package.json
/consert/package.json
```
and looks like this:

Expand All @@ -45,7 +50,7 @@ and looks like this:

Update your model paths by replacaing: aboslute/path/to/ with the absolute path to the original code directory. When you're done, save the packages.json file.

As of now the BERT models are too large to store in GitHub. The can be transferred as .tar compressed file using fileshare. Create a directory title BERT inside "absolute/path/to/original_code/models/ " and extract the tar file here.
As of now we are not sure the best practice for storing these models in git. The can be transferred as .tar compressed file using fileshare. Create a directory title BERT inside "absolute/path/to/original_code/models/ " and extract the tar file here.

### Whisper AI Transcription

Expand All @@ -59,10 +64,11 @@ This will downgrade the version of Whisper to the most recent compatable version

### Testing

The CONSert repository now has a test_script.py file. Update the media_file fiel to have the correct path to your mp3 or wav. Similarly update the audio format field to the correct file type.

You can verify the package's installation via:
````
pip show consert
````
media_file = 'path/to/test/file.wav'

audio_file_format = 'wav'
````
Once consert has been installed update the path to media file in [Consert Test Script](consert_test_script.py) and give it a run. If consert is able to fully process it will create a summary png in the test_output directory.


25 changes: 25 additions & 0 deletions flaskApp/consert/consert_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import consert

class ConsertProcess:
def __init__(self):
"""Initializes the ConsertProcess with test data and runs consert."""
print("starting init")
self.media_file = '/Users/tucker/Documents/ORCA/CONSert/test_video.mp3' #TODO will need to adjust for input data
self.run_consert(self.media_file)

def run_consert(self, media_file):
# Test 1: Run pause identification and classification
consert.classify_pauses(
input_filepath=media_file,
output_directory='test_output', # TODO: Adjust output path as needed
save_output_file=True,
save_intermediate_files=True,
audio_file_format='mp3', # Ensure correct format for 'mp3'
whisper_model_name='medium'
)

# Test 2: Plot results
consert.plot_classification(media_file, 'test_output')

# Initialize the class to run the process
process = ConsertProcess()
Loading

0 comments on commit 4d9e8cb

Please sign in to comment.