Skip to content

Commit

Permalink
Merge pull request #32 from avikalpg/akg/add_suggestions
Browse files Browse the repository at this point in the history
Add suggestions for free-time
  • Loading branch information
avikalpg authored Jan 17, 2025
2 parents e75fc34 + 1265fc0 commit b362581
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 21 deletions.
17 changes: 2 additions & 15 deletions src/HighLevelAssessment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,16 @@ import React from "react";
import { View, StyleSheet } from "react-native";
import { Caption, Headline } from 'react-native-paper';
import { ActivityPie } from "./analytics/ActivityPie";
import { validateHours } from "./utils/utils";
import { calculateRemainingTime, getDisplayHours, totalHoursInWeek, validateHours } from "./utils/utils";

export function HighLevelAssessment(props) {
const { activities } = props;
const validActivities = activities.filter((activity) => validateHours(activity).valid)

const totalHoursInWeek = 168;

const [hoursRemaining, setHoursRemaining] = React.useState(168);
const calculateRemainingTime = () => {
let totalOccupiedHours = 0;
for (const activity of validActivities) {
totalOccupiedHours += activity.hours * activity.duration.multiplier
}
setHoursRemaining(totalHoursInWeek - totalOccupiedHours)
}

const getDisplayHours = (hours) => (
Math.round(10 * hours) / 10
)

React.useEffect(() => {
calculateRemainingTime();
setHoursRemaining(calculateRemainingTime(validActivities));
}, [validActivities])

return (
Expand Down
19 changes: 17 additions & 2 deletions src/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import { HighLevelAssessment } from './HighLevelAssessment';
import { ActivityPeriods } from './EnumActivityPeriod';
import { Footer } from './Footer';
import { randomColor } from './utils/utils';
import { TimeUtilizationSuggestions } from './TimeUtilizationSuggestions';

function Home(props) {
ReactGA.send("pageview")
const [activities, setActivities] = useState([
const [activities, setActivitiesState] = useState([
{
name: "Full-time Job",
hours: 40,
Expand Down Expand Up @@ -41,11 +42,22 @@ function Home(props) {
]);
const styles = merge(commonStyles, useStylesheet(responsiveStyles));

const setActivities = (activities) => {
setActivitiesState(activities);
localStorage.setItem("activities", JSON.stringify(activities));
}

React.useEffect(() => {
const storedActivities = localStorage.getItem("activities");
console.log(`storedActivities: ${JSON.stringify(storedActivities)}`)
if (storedActivities && storedActivities !== "null") setActivitiesState(JSON.parse(storedActivities));
}, [])

return (
<ScrollView style={styles.container} contentContainerStyle={{ minHeight: '100%' }}>
<View style={styles.content}>
<View style={styles.description}>
<Paragraph>Do you know, we have 168 hours in a week. Most full time jobs demand only 40-48 hours of work in a week.
<Paragraph>Do you know, we have 168 hours in a week? Most full time jobs demand only 40-48 hours of work in a week.
This means that we have almost 3-times as much time in our week as we devote to our full-time jobs.
How do you spend this time?
</Paragraph>
Expand All @@ -55,6 +67,9 @@ function Home(props) {
<ActivityList activities={activities} setActivities={setActivities} style={styles.activityListStyle} />
<HighLevelAssessment activities={activities} style={styles.highLevelAssessmentStyle} />
</View>
<View>
<TimeUtilizationSuggestions activities={activities} style={styles.description} />
</View>
</View>
<Footer />
<StatusBar style="auto" />
Expand Down
116 changes: 116 additions & 0 deletions src/TimeUtilizationSuggestions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import Markdown from "react-native-markdown-renderer";
import { Button, Text, useTheme } from 'react-native-paper';
import { calculateRemainingTime, getDisplayHours, validateHours } from "./utils/utils";

export function TimeUtilizationSuggestions(props) {
const { activities } = props;
const validActivities = activities.filter((activity) => validateHours(activity).valid)

const [promptAISession, setPromptAISession] = React.useState(null);
const [hoursRemaining, setHoursRemaining] = React.useState(168);
const [aiSuggestion, setAiSuggestion] = React.useState("");
const [aiError, setAiError] = React.useState("");
const [loadingSuggestions, setLoadingSuggestions] = React.useState(false);

const theme = useTheme();
const styles = StyleSheet.create({
suggestionText: {
textAlign: 'left',
paddingHorizontal: 20,
paddingBottom: 10,
paddingTop: 20
},
buttonHelperText: {
textAlign: 'center',
paddingTop: '5px',
color: theme.colors.backdrop,
}
})

const generateAISuggestion = async (promptAISession, hoursRemaining) => {
if (!promptAISession) {
setAiError("PromptAPI not found in browser");
return;
}

try {
setLoadingSuggestions(true);
setAiError("");
const prompt = `Given ${getDisplayHours(hoursRemaining)} free hours in a week, suggest some meaningful activities or pursuits. The suggestion should be personal, motivating and specific. Here is the list of activities that the user indulges in during the week: ${validActivities.map(activity => `${activity.name} for ${activity.hours * activity.duration.multiplier} hours across the week`).join(",")}.`;
const stream = await promptAISession.promptStreaming(prompt);

const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
setLoadingSuggestions(false);
break; // Exit the loop when the stream is finished
}
setAiSuggestion(value)
}
} catch (error) {
console.error("Error generating AI suggestion:", error);
setAiError("Error generating AI suggestion")
setLoadingSuggestions(false);
}
};

React.useEffect(async () => {
if (window?.ai?.languageModel) {
const session = await window.ai.languageModel.create({
temperature: 0.1,
topK: 10,
initialPrompts: [
{ role: "system", content: "Start by providing feedback about the user's current time commitments. For example, tell them if they are packing their schedule too much or they have more free time than recommended. If the user has a lot of free time or no free time at all, help the user manage their time better through recommendations. Recommendations must strongly align with the activities that the user already indulges in. For example, if the user indulges in business or entrepreneural activities, then providing side hustle recommendations related to their existing hobbies would be well aligned. Respond without judgement or prejudices related to modern ethics and morality but a strong opinion about time management, maximizing focus time & productivity, while minimizing burnout. Output markdown. For each recommendation, provide the estimated amount of time investment required every week." },
{ role: "user", content: "I am looking for recommendations for things that I can either remove from my weekly schedule (by dropping those activities or outsourcing them to others) or things that I can add to my weekly schedule in order to live a more meaningful life." },
]
});
setPromptAISession(session);
} else {
setAiError("PromptAPI not found in browser");
}
}, [])

React.useEffect(() => {
setHoursRemaining(calculateRemainingTime(validActivities));
}, [validActivities])

const provideRecommendation = () => {
if (window?.ai?.languageModel) {
generateAISuggestion(promptAISession, hoursRemaining);
}
};

const getDefaultSuggestion = () => {
if (hoursRemaining > 40) return "You can take up another full time job";
if (hoursRemaining > 20) return "You can probably start a side hustle or a part-time job like Uber driving";
if (hoursRemaining > 5) return "You can probably schedule dedicated time to spend with your family, friends or hobbies";
return "Congratulations, you are making the most of your life. But if you are aren't happy, you should probably reassess the importance and priority of some of these activities and remove/outsource the ones that don't give you a lot of joy";
}

return (
<View style={props.style}>
<Button
mode="outlined"
onPress={provideRecommendation}
disabled={loadingSuggestions || !promptAISession}
loading={loadingSuggestions}
>
Generate recommendations
</Button>
<Text variant="labelSmall" style={styles.buttonHelperText}>
{aiError}
</Text>
<Text variant="bodyLarge" style={styles.suggestionText}>
<Markdown>
{(window?.ai?.languageModel && aiSuggestion) ?
aiSuggestion :
getDefaultSuggestion()
}
</Markdown>
</Text>
</View>
)
}
27 changes: 23 additions & 4 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
export const randomColor = () =>
('#' + ((Math.random() * 0xffffff) << 0).toString(16) + '000000').slice(0, 7)

export const totalHoursInWeek = 168;

/**
* Evaluates whether an activity has valid hours & period of activity
* @param {{name: string, hours: number, duration: {text: string, multiplier: number}, color: string, errorText: null}[]} validActivities
* @returns @number
*/
export const calculateRemainingTime = (validActivities) => {
let totalOccupiedHours = 0;
for (const activity of validActivities) {
totalOccupiedHours += activity.hours * activity.duration.multiplier
}
return totalHoursInWeek - totalOccupiedHours;
}

export const getDisplayHours = (hours) => (
Math.round(10 * hours) / 10
)

/**
* Evaluates whether an activity has valid hours & period of activity
* @param {{name: string, hours: number, duration: {text: string, multiplier: number}, color: string, errorText: null}} activity
* @returns {{valid: boolean, reason: string}}
*/
* Evaluates whether an activity has valid hours & period of activity
* @param {{name: string, hours: number, duration: {text: string, multiplier: number}, color: string, errorText: null}} activity
* @returns {{valid: boolean, reason: string}}
*/
export const validateHours = (activity) => {
// Check if the input is a valid number
if (isNaN(activity.hours)) {
Expand Down

0 comments on commit b362581

Please sign in to comment.