Skip to content

Commit

Permalink
Merge pull request #254 from fcampise/main
Browse files Browse the repository at this point in the history
added Track 2, Sprint 6
  • Loading branch information
fcampise authored Apr 22, 2024
2 parents c77c712 + 4c54b84 commit d0faa0f
Show file tree
Hide file tree
Showing 22 changed files with 1,002 additions and 0 deletions.

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions Track_2_ToDo_App/Sprint-06 - Advanced To-Do Details/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Sprint 6: Advanced Task Details
⏲️ _Est. time to complete: 60 min._ ⏲️

This sprint is designed to help students add additional details to the To-Do application. The sprint will walk students through adding details about the task such as Due Date, Priority, Additional Notes, and whether or not the Task has been completed.

**📕Feature: Add additional about to-do item**
1. [**📖 Add Due Date, Priority, Notes and Completion Status to To-Do item**](/Track_2_ToDo_App/Sprint-06%20-%20Advanced%20To-Do%20Details/Feature%201%20-%20Add%20Additional%20To-Do%20Details/User%20Story%201%20-%20Add%20additional%20details%20to%20to-do%20item.md)


<br/>

[🔼 Hackathon Home Page ](/Track_2_ToDo_App/README.md) | [◀ Previous Sprint](/Track_2_ToDo_App/Sprint-05%20-%20Advanced%20AI%20recommendations/README.md) | [Next sprint ▶](/Track_2_ToDo_App/Sprint-07%20-%20Advanced%20Styling%20Your%20Web%20App/README.md)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DEBUG_APP="True"
USE_AZURE_OPENAI="True"
OPENAI_API_KEY="<get the key from https://platform.openai.com/api-keys>"
OPENAI_ORG_ID="<get the ord-id from https://platform.openai.com/account/organization>"
OPEN_AI_DEPLOYMENT_NAME="gpt-3.5-turbo"
AZURE_OPENAI_DEPLOYMENT_NAME="gpt-35-turbo"
AZURE_OPENAI_ENDPOINT=""
AZURE_OPENAI_API_KEY=""
AZURE_OPENAI_VERSION="2023-05-15"
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
###############################################################################
## Sprint 6: Advanced To-DO Details
## Feature 1: Add Additional Details to To-Do Items
## User Story 1: Add Due Date, Priority, Notes and Completion Status to To-Do item
############################################################################
import os
import json
from flask import Flask, render_template, request, redirect, url_for, g
from database import db, Todo
from recommendation_engine import RecommendationEngine
from tab import Tab

app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__)) # Get the directory of the this file
todo_file = os.path.join(basedir, 'todo_list.txt') # Create the path to the to-do list file using the directory
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + os.path.join(basedir, 'todos.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db.init_app(app)

with app.app_context():
db.create_all()

@app.before_request
def load_data_to_g():
todos = Todo.query.all()
g.todos = todos
g.todo = None
g.TabEnum = Tab
g.selectedTab = Tab.NONE


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

@app.route("/add", methods=["POST"])
def add_todo():

# Get the data from the form
todo = Todo(
name=request.form["todo"]
)

# Add the new ToDo to the list
db.session.add(todo)
db.session.commit()

# Add the new ToDo to the list
return redirect(url_for('index'))

# Details of ToDo Item
@app.route('/details/<int:id>', methods=['GET'])
def details(id):
g.selectedTab = Tab.DETAILS
g.todos = Todo.query.all()
g.todo = Todo.query.filter_by(id=id).first()

return render_template('index.html')

# Edit a new ToDo
@app.route('/edit/<int:id>', methods=['GET'])
def edit(id):
g.selectedTab = Tab.EDIT
g.todos = Todo.query.all()
g.todo = Todo.query.filter_by(id=id).first()

return render_template('index.html')

# Save existing To Do Item
@app.route('/update/<int:id>', methods=['POST'])
def update_todo(id):
g.selectedTab = Tab.DETAILS

if request.form.get('cancel') != None:
return redirect(url_for('index'))

# Get the data from the form
name = request.form['name']
due_date = request.form.get('duedate')
notes=request.form.get('notes')
priority=request.form.get('priority')
completed=request.form.get('completed')

todo = db.session.query(Todo).filter_by(id=id).first()
if todo != None:
todo.name = name

if due_date != "None":
todo.due_date = due_date

if notes != None:
todo.notes = notes

if priority != None:
todo.priority = int(priority)

if completed == None:
todo.completed = False
elif completed == "on":
todo.completed = True
#
db.session.add(todo)
db.session.commit()
#
return redirect(url_for('index'))


# Delete a ToDo
@app.route('/remove/<int:id>', methods=["POST"])
def remove_todo(id):
db.session.delete(Todo.query.filter_by(id=id).first())
db.session.commit()
return redirect(url_for('index'))

# Show AI recommendations
@app.route('/recommend/<int:id>', methods=['GET'])
@app.route('/recommend/<int:id>/<refresh>', methods=['GET'])
async def recommend(id, refresh=False):
g.selectedTab = Tab.RECOMMENDATIONS
recommendation_engine = RecommendationEngine()
g.todo = db.session.query(Todo).filter_by(id=id).first()

if g.todo and not refresh:
try:
#attempt to load any saved recommendation from the DB
if g.todo.recommendations_json is not None:
g.todo.recommendations = json.loads(g.todo.recommendations_json)
return render_template('index.html')
except ValueError as e:
print("Error:", e)

previous_links_str = None
if refresh:
g.todo.recommendations = json.loads(g.todo.recommendations_json)
# Extract links
links = [item["link"] for item in g.todo.recommendations]
# Convert list of links to a single string
previous_links_str = ", ".join(links)

g.todo.recommendations = await recommendation_engine.get_recommendations(g.todo.name, previous_links_str)

# Save the recommendations to the database
try:
g.todo.recommendations_json = json.dumps(g.todo.recommendations)
db.session.add(g.todo)
db.session.commit()
except Exception as e:
print(f"Error adding and committing todo: {e}")
return

return render_template('index.html')


if __name__ == "__main__":
app.run(debug=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Integer, String, Boolean, JSON, func
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
pass

db = SQLAlchemy(model_class=Base)

class Todo(db.Model):
id = db.Column(Integer, primary_key=True)
name = db.Column(String(100), nullable=False)
notes = db.Column(String(100))
priority = db.Column(Integer, default=0)
completed = db.Column(Boolean, default=False)
recommendations_json = db.Column(db.JSON) #json serialized version of recommendations for storing in DB
due_date = db.Column(String(50))

#transient variables (i.e., not stored in db)
recommendations = [] #recommendations as a collection

def __str__(self):
return self.name

def priority_str(self):
"""
Returns the priority as a string.
"""
str = "Not Set"
if self.priority == 1:
str = "High"
elif self.priority == 2:
str = "Medium"
elif self.priority == 3:
str = "Low"

return str

def completed_str(self):
"""
Returns the completed status as a string.
"""
if self.completed:
return "Yes"
else:
return "No"



Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from enum import Enum

class Priority(Enum):
NONE = 0,
HIGH = 1,
MEDIUM = 2,
LOW = 3
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import json
import asyncio
import semantic_kernel as sk
from services import Service
from openai import AzureOpenAI
from dotenv import dotenv_values

config = dotenv_values(".env")

#uses the USE_AZURE_OPENAI variable from the .env file to determine which AI service to use
#False means use OpenAI, True means use Azure OpenAI
selectedService = Service.AzureOpenAI if config.get("USE_AZURE_OPENAI") == "True" else Service.OpenAI
deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()

class RecommendationEngine:
def __init__(self):
deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()

self.client = AzureOpenAI(azure_endpoint = endpoint,
api_key=api_key,
api_version="2024-02-15-preview"
)


async def get_recommendations(self, keyword, previous_links_str=None):
prompt = f"""Please return 5 recommendations based on the input string: '{keyword}' using correct JSON syntax that contains a title and a hyperlink back to the supporting website. RETURN ONLY JSON AND NOTHING ELSE"""
system_prompt = """You are an administrative assistant bot who is good at giving
recommendations for tasks that need to be done by referencing website links that can provide
assistance to helping complete the task.
If there are not any recommendations simply return an empty collection.
EXPECTED OUTPUT:
Provide your response as a JSON object with the following schema:
[{"title": "...", "link": "..."},
{"title": "...", "link": "..."},
{"title": "...", "link": "..."}]
"""

if previous_links_str is not None:
prompt = prompt + f". EXCLUDE the following links from your recommendations: {previous_links_str}"

message_text = [{"role":"system","content":system_prompt},
{"role":"user","content":prompt},]

response = self.client.chat.completions.create(
model=deployment,
messages = message_text,
temperature=0.14,
max_tokens=800,
top_p=0.17,
frequency_penalty=0,
presence_penalty=0,
stop=None
)

result = response.choices[0].message.content
print(result)

try:
recommendation = json.loads(result)
except Exception as e:
print(f"Error loading recommendations: {e}")
recommendation = [{"title": "Sorry, unable to recommendation at this time", "link": ""}]

return recommendation

async def test_recommendation_engine():
engine = RecommendationEngine()
recommendations = await engine.get_recommendations("Buy a birthday gift for mom")
count = 1
for recommendation in recommendations:
print(f"{count} - {recommendation['title']}: {recommendation['link']}")
count += 1

if __name__ == "__main__":
asyncio.run(test_recommendation_engine())
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
This module defines an enumeration representing different services.
"""

from enum import Enum


class Service(Enum):
"""
Attributes:
OpenAI (str): Represents the OpenAI service.
AzureOpenAI (str): Represents the Azure OpenAI service.
HuggingFace (str): Represents the HuggingFace service.
"""

OpenAI = "openai"
AzureOpenAI = "azureopenai"
HuggingFace = "huggingface"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
body {
background-color: f0f0f0; /* light grey */
color: darkslategray; /* default font color */
font-family: Arial, sans-serif;
background-image: url("../images/Designer02.jpeg");
background-repeat: no-repeat;
background-position: center;
background-size:cover;
}

h1 {
color: darkgray; /* font for the h1 header*/
}

.list-group-item {
color: #333; /* dark grey */
}



Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
document.addEventListener("DOMContentLoaded", function() {
const nameInput = document.getElementById("todo");

//add javascript to support speech recognition for the todo input field
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.lang = "en-US";
recognition.interimResults = false;

window.captureVoice = function() {
recognition.start();
nameInput.value = "Your microphone is activated, speak to record voice";
};

recognition.onresult = function(event) {
const transcript = event.results[0][0].transcript;
const recognizedText = transcript.endsWith('.') ? transcript.slice(0, -1) : transcript;
nameInput.value = recognizedText;
};

recognition.onspeechend = function() {
recognition.stop();
};

recognition.onnomatch = function(event) {
nameInput.value = "I didn't recognize that prompt.";
};

recognition.onerror = function(event) {
nameInput.value = "Error occurred in recognition: " + event.error;
};
});
Loading

0 comments on commit d0faa0f

Please sign in to comment.