Skip to content

Commit

Permalink
Merge branch 'main' into tailwindformat
Browse files Browse the repository at this point in the history
  • Loading branch information
iLevyTate committed Aug 6, 2023
2 parents 0f1861d + 45e4d6a commit aabc5e0
Show file tree
Hide file tree
Showing 26 changed files with 198 additions and 68 deletions.
2 changes: 1 addition & 1 deletion backend/app/api/v1/routes/goal.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,4 @@ async def openai_goal(goal: GoalSuggestionCreate, current_user: CurrentUser) ->
detail="An error occurred while generating the goal suggestions",
)

return process_openai_to_smart_goal(response)
return process_openai_to_smart_goal(response, goal)
2 changes: 1 addition & 1 deletion backend/app/api/v1/routes/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ async def login_access_token(
@router.post("/test-token")
def test_token(current_user: CurrentUser) -> UserNoPassword:
"""Test access token."""
return UserNoPassword(**current_user.dict())
return UserNoPassword(**current_user.model_dump())
2 changes: 1 addition & 1 deletion backend/app/api/v1/routes/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async def get_users(_: CurrentAdminUser) -> list[UserNoPassword]:
@router.get("/me")
async def get_me(create_user: CurrentUser) -> UserNoPassword:
"""Retriever the logged in user's information."""
return UserNoPassword(**create_user.dict())
return UserNoPassword(**create_user.model_dump())


@router.get("/{user_id}")
Expand Down
29 changes: 22 additions & 7 deletions backend/app/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from app.api.deps import logger
from app.models.openai import GoalSuggestion
from app.models.smart_goal import SmartGoal
from app.models.smart_goal import GoalInfo, GoalSuggestionCreate, SmartGoal


class APIRouter(FastAPIRouter):
Expand All @@ -34,7 +34,9 @@ def decorator(func: DecoratedCallable) -> DecoratedCallable:
return decorator


def process_openai_to_smart_goal(goal: GoalSuggestion) -> SmartGoal:
def process_openai_to_smart_goal(
goal: GoalSuggestion, goal_create_info: GoalSuggestionCreate
) -> SmartGoal:
goal_info = goal.choices[0].message.content.split("\n")
smart_goal: dict[str, str] = {}
for info in goal_info:
Expand All @@ -44,15 +46,21 @@ def process_openai_to_smart_goal(goal: GoalSuggestion) -> SmartGoal:
case "SMART Goal":
smart_goal["goal"] = info_parts[1]
case "Specific":
smart_goal["specific"] = info_parts[1]
smart_goal["specific"] = _set_goal_info(info_parts[1], goal_create_info.specific)
case "Measurable":
smart_goal["measurable"] = info_parts[1]
smart_goal["measurable"] = _set_goal_info(
info_parts[1], goal_create_info.measurable
)
case "Achievable":
smart_goal["achievable"] = info_parts[1]
smart_goal["achievable"] = _set_goal_info(
info_parts[1], goal_create_info.achievable
)
case "Relevant":
smart_goal["relevant"] = info_parts[1]
smart_goal["relevant"] = _set_goal_info(info_parts[1], goal_create_info.relevant)
case "Time-bound":
smart_goal["time_bound"] = info_parts[1]
smart_goal["time_bound"] = _set_goal_info(
info_parts[1], goal_create_info.time_bound
)

return SmartGoal(**smart_goal)

Expand All @@ -63,3 +71,10 @@ def str_to_oid(id_str: str) -> ObjectId:
except InvalidId:
logger.info(f"{id_str} is not a valid ObjectId")
raise


def _set_goal_info(gpt_info: str, goal_info: GoalInfo | None) -> str:
if not goal_info or not goal_info.locked:
return gpt_info

return goal_info.info
10 changes: 10 additions & 0 deletions backend/app/models/smart_goal.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
from pydantic import BaseModel


class GoalInfo(BaseModel):
info: str
locked: bool = False


class GoalSuggestionCreate(BaseModel):
goal: str
model: str | None = None
temperature: float | None = None
specific: GoalInfo | None = None
measurable: GoalInfo | None = None
achievable: GoalInfo | None = None
relevant: GoalInfo | None = None
time_bound: GoalInfo | None = None


class SmartGoal(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion backend/app/services/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def get_user_no_goal(user_id: ObjectId | PydanticObjectId) -> UserNoGoals

async def get_users() -> list[UserNoPassword]:
users = await User.find_all().to_list()
return [UserNoPassword(**x.dict()) for x in users]
return [UserNoPassword(**x.model_dump()) for x in users]


async def update_me(update_info: UserUpdateMe) -> UserNoPassword:
Expand Down
48 changes: 46 additions & 2 deletions backend/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from app.core.utils import process_openai_to_smart_goal, str_to_oid
from app.models.openai import GoalSuggestion
from app.models.smart_goal import GoalInfo, GoalSuggestionCreate


def test_str_to_oid_bad_id():
Expand Down Expand Up @@ -30,13 +31,56 @@ def test_process_openai_to_smart_goal():
"usage": {"prompt_tokens": 174, "completion_tokens": 113, "total_tokens": 287},
}
)
result = process_openai_to_smart_goal(data)

assert result.dict() == {
create_goal_info = GoalSuggestionCreate(goal="Exercise")
result = process_openai_to_smart_goal(data, create_goal_info)

assert result.model_dump() == {
"goal": "Exercise",
"specific": "30 minutes of exercise, focusing on cardio and strength training, 5 days a week.",
"measurable": "Keep a workout log to track the number of days and duration of exercise each week.",
"achievable": "Start with shorter workout sessions and gradually increase duration and intensity as fitness improves. Incorporate activities that are enjoyable and suit individual abilities.",
"relevant": "Improve overall fitness, increase strength and endurance, and maintain a healthy lifestyle.",
"time_bound": "Maintain the exercise routine for at least 3 months, with continuous progress and improvement.",
}


def test_process_openai_to_smart_goal_locked():
data = GoalSuggestion(
**{
"id": "chatcmpl-7jtztRhmxfj32OGB6SD1O5scgcAJj",
"object": "chat.completion",
"created": 1691174369,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "SMART Goal: Exercise\nSpecific: 30 minutes of exercise, focusing on cardio and strength training, 5 days a week.\nMeasurable: Keep a workout log to track the number of days and duration of exercise each week.\nAchievable: Start with shorter workout sessions and gradually increase duration and intensity as fitness improves. Incorporate activities that are enjoyable and suit individual abilities.\nRelevant: Improve overall fitness, increase strength and endurance, and maintain a healthy lifestyle.\nTime-bound: Maintain the exercise routine for at least 3 months, with continuous progress and improvement.",
},
"finish_reason": "stop",
}
],
"usage": {"prompt_tokens": 174, "completion_tokens": 113, "total_tokens": 287},
}
)

create_goal_info = GoalSuggestionCreate(
goal="Exercise",
specific=GoalInfo(info="specific", locked=True),
measurable=GoalInfo(info="measurable", locked=True),
achievable=GoalInfo(info="achievable", locked=True),
relevant=GoalInfo(info="relevant", locked=True),
time_bound=GoalInfo(info="time bound", locked=True),
)
result = process_openai_to_smart_goal(data, create_goal_info)

assert result.model_dump() == {
"goal": "Exercise",
"specific": "specific",
"measurable": "measurable",
"achievable": "achievable",
"relevant": "relevant",
"time_bound": "time bound",
}
10 changes: 8 additions & 2 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { AxiosError } from 'axios';
import type { AxiosRequestConfig } from 'axios';
import { axiosInstance } from '$lib/axios-config';
import type { Goal, GoalCreate, UserCreate, UserNoPassword, UserUpdateMe } from '$lib/generated';
import type {
GoalOutput,
GoalCreate,
UserCreate,
UserNoPassword,
UserUpdateMe
} from '$lib/generated';
import type { AccessToken, UserLogin } from '$lib/types';
import { LoginError } from '$lib/errors';
import { accessToken } from '$lib/stores/stores';
Expand All @@ -23,7 +29,7 @@ async function authHeaders(): Promise<AxiosRequestConfig<any>> {
throw new Error('No access token found');
}

export const createGoal = async (payload: GoalCreate): Promise<Goal> => {
export const createGoal = async (payload: GoalCreate): Promise<GoalOutput> => {
const headers = await authHeaders();
const response = await axiosInstance.post('/goal', payload, headers);

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/DaysOfWeekSelector.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import type { DaysOfWeek } from '$lib/generated';
import type { DaysOfWeekInput } from '$lib/generated';
import { toTitleCase } from '$lib/utils';
export let daysOfWeek: DaysOfWeek;
export let daysOfWeek: DaysOfWeekInput;
export let readOnly = false;
// Function to prevent changes to the checkbox state
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/EditGoalComponent.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { DaysOfWeek, GoalCreate } from '$lib/generated';
import type { DaysOfWeekInput, GoalCreate } from '$lib/generated';
import DaysOfWeekSelector from '$lib/components/DaysOfWeekSelector.svelte';
import ErrorMessage from '$lib/components/ErrorMessage.svelte';
import { createGoal } from '$lib/api';
Expand Down Expand Up @@ -27,7 +27,7 @@
// goal.days_of_week! is because TypeScript sucks and won't believe days_of_week is not
// undefined even when it is checked first.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
goal.days_of_week![day as keyof DaysOfWeek] = selectAll;
goal.days_of_week![day as keyof DaysOfWeekInput] = selectAll;
});
}
};
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/lib/generated/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
/* eslint-disable */

export type { Body_login_access_token_api_v1_login_access_token_post } from './models/Body_login_access_token_api_v1_login_access_token_post';
export type { DaysOfWeek } from './models/DaysOfWeek';
export type { DesiredGoal } from './models/DesiredGoal';
export type { Goal } from './models/Goal';
export type { DaysOfWeekInput } from './models/DaysOfWeekInput';
export type { DaysOfWeekOutput } from './models/DaysOfWeekOutput';
export type { GoalCreate } from './models/GoalCreate';
export type { GoalInfo } from './models/GoalInfo';
export type { GoalInput } from './models/GoalInput';
export type { GoalOutput } from './models/GoalOutput';
export type { GoalSuggestionCreate } from './models/GoalSuggestionCreate';
export type { HTTPValidationError } from './models/HTTPValidationError';
export type { SmartGoal } from './models/SmartGoal';
export type { Token } from './models/Token';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
/* eslint-disable */

export type Body_login_access_token_api_v1_login_access_token_post = {
grant_type?: string;
grant_type?: string | null;
username: string;
password: string;
scope?: string;
client_id?: string;
client_secret?: string;
client_id?: string | null;
client_secret?: string | null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */

export type DaysOfWeek = {
export type DaysOfWeekInput = {
monday?: boolean;
tuesday?: boolean;
wednesday?: boolean;
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/lib/generated/models/DaysOfWeekOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

export type DaysOfWeekOutput = {
monday: boolean;
tuesday: boolean;
wednesday: boolean;
thursday: boolean;
friday: boolean;
saturday: boolean;
sunday: boolean;
};
20 changes: 0 additions & 20 deletions frontend/src/lib/generated/models/Goal.ts

This file was deleted.

22 changes: 11 additions & 11 deletions frontend/src/lib/generated/models/GoalCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
/* tslint:disable */
/* eslint-disable */

import type { DaysOfWeek } from './DaysOfWeek';
import type { DaysOfWeekInput } from './DaysOfWeekInput';

export type GoalCreate = {
goal?: string;
specific?: string;
measurable?: string;
attainable?: string;
relevant?: string;
time_bound?: string;
date_for_achievement?: string;
days_of_week?: DaysOfWeek;
time_of_day?: string;
progress?: number;
goal?: string | null;
specific?: string | null;
measurable?: string | null;
attainable?: string | null;
relevant?: string | null;
time_bound?: string | null;
date_for_achievement?: string | null;
days_of_week?: DaysOfWeekInput | null;
time_of_day?: string | null;
progress?: number | null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/* tslint:disable */
/* eslint-disable */

export type DesiredGoal = {
goal: string;
export type GoalInfo = {
info: string;
locked?: boolean;
};
20 changes: 20 additions & 0 deletions frontend/src/lib/generated/models/GoalInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

import type { DaysOfWeekInput } from './DaysOfWeekInput';

export type GoalInput = {
goal: string;
specific?: string | null;
measurable?: string | null;
attainable?: string | null;
relevant?: string | null;
time_bound?: string | null;
date_for_achievement?: string | null;
days_of_week?: DaysOfWeekInput | null;
time_of_day?: string | null;
progress?: number | null;
id: string;
};
20 changes: 20 additions & 0 deletions frontend/src/lib/generated/models/GoalOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

import type { DaysOfWeekOutput } from './DaysOfWeekOutput';

export type GoalOutput = {
goal: string;
specific: string | null;
measurable: string | null;
attainable: string | null;
relevant: string | null;
time_bound: string | null;
date_for_achievement: string | null;
days_of_week: DaysOfWeekOutput | null;
time_of_day: string | null;
progress: number | null;
id: string;
};
Loading

0 comments on commit aabc5e0

Please sign in to comment.