Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/yale-swe/s24-bluebook-ai in…
Browse files Browse the repository at this point in the history
…to michal-new-branch
  • Loading branch information
MLewkowicz committed Apr 16, 2024
2 parents c65b783 + 755788f commit 22e23a5
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 46 deletions.
2 changes: 2 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ def chat():
}

filtered_response = chat_completion_request(messages=user_messages, tools=tools)
print(filtered_response)

filtered_data = json.loads(
filtered_response.choices[0].message.tool_calls[0].function.arguments
)
Expand Down
70 changes: 70 additions & 0 deletions backend/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,76 @@ def test_no_need_for_query(client, mock_chat_completion_yes_no):
assert mock_chat_completion_yes_no.call_count == 3


@pytest.fixture
def mock_chat_completion_complete():
with patch("app.chat_completion_request") as mock:
# Prepare the function mock that includes tool calls with the arguments JSON string
function_mock = MagicMock()
function_mock.arguments = '{"season_code": "202303"}'

# Mock for tool_calls that uses the prepared function mock
tool_call_mock = MagicMock()
tool_call_mock.function = function_mock

# Mock for the message that includes the list of tool calls
message_mock_with_tool_calls = MagicMock()
message_mock_with_tool_calls.content = "yes"
message_mock_with_tool_calls.tool_calls = [tool_call_mock]

message_mock_mock_response = MagicMock()
message_mock_mock_response.content = "Mock response based on user message"
message_mock_mock_response.tool_calls = [tool_call_mock]

# Wrap these into the respective choice structures
responses = [
MagicMock(choices=[MagicMock(message=message_mock_with_tool_calls)]),
MagicMock(choices=[MagicMock(message=message_mock_with_tool_calls)]),
MagicMock(choices=[MagicMock(message=message_mock_with_tool_calls)]),
MagicMock(choices=[MagicMock(message=message_mock_with_tool_calls)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
MagicMock(choices=[MagicMock(message=message_mock_mock_response)]),
]

mock.side_effect = responses
yield mock


def test_with_frontend_filters(client, mock_chat_completion_complete):
request_data = {
"season_codes": ["bruh"],
"subject": ["bruh"],
"areas": ["WR", "Hu"],
"message": [
{"id": 123, "role": "user", "content": "msg"},
{"id": 123, "role": "ai", "content": "msg2"},
{"id": 123, "role": "user", "content": "Tell me about cs courses"},
],
}
response = client.post("/api/chat", json=request_data)
assert response.status_code == 200
data = response.get_json()
assert "Mock response based on user message" in data["response"]
assert mock_chat_completion_complete.call_count == 5


def test_no_user_message(client, mock_chat_completion_complete):
request_data = {
"season_codes": ["bruh"],
"subject": ["bruh"],
"areas": ["WR", "Hu"],
}
response = client.post("/api/chat", json=request_data)
assert response.status_code == 200
data = response.get_json()
assert "No message provided" in data["error"]
assert mock_chat_completion_complete.call_count == 0


def test_safty_violation(client, mock_chat_completion_no):
request_data = {
"message": [
Expand Down
40 changes: 0 additions & 40 deletions frontend/src/app/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -287,43 +287,3 @@
}
}

.floatingProfileButton {
position: fixed;
bottom: 770px;
right: 20px;
width: 50px;
height: 50px;
padding: 10px 15px;
border-radius: 50%;
background-color: #468ff2;
background-image: url('profile_icon.png');
background-repeat: no-repeat;
background-position: center;
background-size: 40%;
color: white;
border: none;
cursor: pointer;
box-shadow: 2px 2px 10px rgb(0 0 0 / 20%);
z-index: 1200;
}


.profileContainer {
position: fixed;
bottom: 600px; /* Adjust based on your design */
right: 20px;
width: 300px; /* Adjust size as needed */
background: white;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: right 0.3s ease-in-out;
/* More styles */
}


.profileVisible {
right: 10px; /* Adjust to make visible */
}

.closeButton {
/* Style the close button */
}
Binary file added frontend/src/app/profile-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 187 additions & 0 deletions frontend/src/app/profile.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
.floatingProfileButton {
position: fixed;
bottom: 20px;
right: 90px; /* Adjust based on chat button placement */
z-index: 1001;
background-image: url('profile-icon.png');
background-size: cover;
width: 50px;
height: 50px;
padding: 10px 15px;
border-radius: 50%;
background-color: white;
background-repeat: no-repeat;
background-position: center;
background-size: 130%;
color: white;
border: none;
cursor: pointer;
box-shadow: 2px 2px 10px rgb(0 0 0 / 20%);
}

/* Profile Popup styling */
.profileContainer {
background-color: #fff;
padding: 15px;
/* padding-top: 40px; */
border-radius: 8px;
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}

.profileHeader {
background-color: #468ff2; /* Lighter blue to match button */
color: white;
padding: 8px 20px;
border-radius: 8px 8px 0 0;
font-size: 1.1em;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-top: 10px;
margin-bottom: 10px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}

.profileDetails {
padding: 10px;
background-color: #f7f7f7; /* Softer background for contrast */
margin-top: -10px; /* Overlap with header */
border-radius: 0 0 8px 8px;
display: flex;
flex-direction: column;
gap: 10px; /* Consistent spacing between inputs */
}

.inputField, .searchInput {
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px 15px;
font-size: 1em;
box-shadow: inset 0 1px 2px rgba(0,0,0,0.05);
}

.button {
display: inline-block;
padding: 10px 20px;
margin-top: 10px;
font-size: 1em;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}

.saveButton {
background-color: #5C7AEA;
color: white;
}

.saveButton:hover {
background-color: #4a65d0;
}

.closeButton {
position: absolute;
top: 12px;
right: 20px;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
border-radius: 50%;
background-color: #ccc;
color: white;
font-size: 18px;
font-weight: bold;
border: none;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
align-items: center;
justify-content: center;
padding: 0; /* Remove padding to avoid offset */
}

.closeButton:hover {
background-color: #b1b1b1;
}

.courseSearch {
margin-top: 10px;
}

.saveButton::before {
/* content: url('save-icon.png'); */
margin-right: 8px;
}

.closeButton::before {
/* content: url('close-icon.png'); */
margin-right: 8px;
}

.profileContainer {
transform: scale(0.9);
opacity: 0;
transition: all 0.3s ease-in-out;
}

.profileVisible {
transform: scale(1);
opacity: 1;
}

.profileContainer {
position: fixed;
bottom: 80px;
right: 50px;
width: 300px; /* Adjust size as needed */
height: 400px;
background: white;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: right 0.3s ease-in-out;
border: 2px solid var(--color-border);
box-shadow: 0 0 10px 10px rgb(0 0 0 / 20%);
overflow-y: auto;
border-radius: 10px;
z-index: 1100;
}


.profileVisible {
right: 80px; /* Adjust to make visible */
}

.profileButton, .closeButton, .toggleChatHistoryButton, .sendButton {
padding: 6px 12px;
border: none;
border-radius: 20px;
background-color: #468ff2;
color: white;
font-weight: bold;
cursor: pointer;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
transition: background-color 0.3s;
}

.profileButton:hover, .closeButton:hover, .toggleChatHistoryButton:hover, .sendButton:hover {
background-color: #356ad2;
}

.inputField, .searchInput {
width: calc(100% - 32px);
padding: 10px 16px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 20px;
box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}

.profileDetails, .courseSearch {
padding: 10px;
background-color: #f9f9f9;
border-radius: 10px;
margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

Binary file removed frontend/src/app/profile_icon.png
Binary file not shown.
18 changes: 12 additions & 6 deletions frontend/src/app/profiles.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use client";

import React, { useState } from "react";
import styles from "./page.module.css";

import styles from "./profile.module.css";
import { json } from "stream/consumers";


const ProfilePopup = () => {
const [popupVisible, setPopupVisible] = useState(false);
const [chatHistoryVisible, setChatHistoryVisible] = useState(false);
Expand Down Expand Up @@ -86,15 +88,19 @@ const ProfilePopup = () => {

<div className={styles.profileHeader}>User Profile</div>
<div className={styles.profileDetails}>
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" />
<button onClick={handleSaveProfile}>Save</button>
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} className={styles.inputField} placeholder="Username" />
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className={styles.inputField} placeholder="Email" />
<button onClick={handleSaveProfile} className={styles.sendButton}>Save</button>

</div>
<div className={styles.courseSearch}>
<input type="text" value={search} onChange={(e) => setSearch(e.target.value)} placeholder="Search courses" />
<button onClick={handleAddCourse}>Add Course</button>
<input type="text" value={search} onChange={(e) => setSearch(e.target.value)} className={styles.inputField} placeholder="Search courses" />
<button onClick={handleAddCourse} className={styles.sendButton}>Add Course</button>
{courses.map(course => <div key={course}>{course}</div>)}
</div>
<button onClick={togglePopupVisibility} className={styles.closeButton}>Close</button>
<button onClick={togglePopupVisibility} className={styles.closeButton}>
&times;
</button>
</div>
)}

Expand Down

0 comments on commit 22e23a5

Please sign in to comment.