Self Help AI - iOS Mobile App

View on App Store →

I developed the full software stack for Self Help AI, an iOS mobile app that integrates user data, function calling & personalization settings to create a ChatBot experience for the purpose of self-help. The end product uses ~30k lines of code across 24 files, and has amassed over 200 App Store downloads since launch.

App screenshot 1
App screenshot 2
App screenshot 3
App screenshot 4
App screenshot 5
App screenshot 6
App screenshot 7

Core Features

Notification System

Integrated LLM function calls which allows the LLM to set reminders for the user on request:

const AVAILABLE_FUNCTIONS = {
scheduleNotification: {
name: "scheduleNotification",
description: "Schedule a notification for the user",
parameters: {
type: "object",
properties: {
title: {
type: "string",
description: "The title of the notification"
},
body: {
type: "string",
description: "The body text of the notification"
},
timestamp: {
type: "string",
description: "The ISO timestamp when the notification should be sent"
}
},
required: ["title", "body", "timestamp"]
}
}
};

Integrated User Data

Developed a secure local storage system that collects and manages user data from the onboarding survey to create personalized chat sessions:

// AIManager.ts
export const constructSystemPrompt = (
values: Record<string, any>,
baseSystemPrompt: string
) => {
const name = values['First Name'] || 'there';
const age = values['Age'] || 'unknown age';
const gender = values['Gender'] || 'person';
const growthAreas = values['growth_areas'] || [];
const badHabits = values['bad_habits'] || [];
const relationshipStatus = values['relationship_status'] || 'unspecified';
const employmentStatus = values['employment_status'] || 'unspecified';
let motivationStylePrompt = 'Maintain a balanced coaching approach';
if (values['motivation_style']) {
const selectedStyle = MOTIVATION_STYLE_OPTIONS.find(
option => option.display === values['motivation_style']
);
if (selectedStyle) {
motivationStylePrompt = selectedStyle.systemPrompt;
}
}
return `You are a personal AI assistant focused on helping users
with their personal growth and development.
Here's information about the user:
Name: ${name}
Age: ${age}
Gender: ${gender}
Relationship Status: ${relationshipStatus}
Employment: ${employmentStatus}
Focus areas: ${growthAreas.join(', ')}
Bad habits to work on: ${badHabits.join(', ')}
Coaching Style Instructions: ${motivationStylePrompt}`;

Guided Exercises & Lessons

Custom chats for the purpose of achieving specific goals:

const EXERCISE_OPTIONS: Exercise[] = [
{
id: ' ',
title: 'Improve Focus',
description: 'Develop techniques to enhance concentration and mental clarity',
icon: 'brain',
},
{
id: 'procrastination',
title: 'Stop Procrastinating',
description: 'Break free from delay patterns and build productive habits',
icon: 'clock-time-four-outline',
},
{
id: 'stress',
title: 'Reduce Stress',
description: 'Learn effective strategies to manage and minimize stress',
icon: 'meditation',
},
{
id: 'relationships',
title: 'Navigate Relationships',
description: 'Improve communication and strengthen connections',
icon: 'account-group-outline',
},
{
id: 'recipes',
title: 'Meal Planning',
description: 'Get personalized healthy recipe suggestions and meal plans',
icon: 'food-variant',
},
{
id: 'workout',
title: 'Work Out Plan',
description: 'Create a customized fitness routine for your goals',
icon: 'dumbbell',
},
];

Personalization Settings

Managed data flow from the survey within personalization settings, allowing users to customize their experience:

export const handleSettingsUpdate = (
editableSettings: Record<string, any>,
setLocalSelectedValues: (values: Record<string, any>) => void,
setCurrentSystemPrompt: (prompt: string) => void,
setIsEditing: (value: boolean) => void,
setIsSettingsOpen: (value: boolean) => void,
systemPrompt: string
) => {
try {
const updatedSettings = {
...editableSettings,
'First Name': editableSettings['First Name'],
'Gender': editableSettings['Gender'],
'Age': editableSettings['Age'],
'growth_areas': editableSettings['growth_areas'] || [],
'relationship_status': editableSettings['relationship_status'],
'employment_status': editableSettings['employment_status'],
'bad_habits': editableSettings['bad_habits'] || []
};
updateSurveyResponses({
'First Name': updatedSettings['First Name'],
'Gender': updatedSettings['Gender'],
'Age': updatedSettings['Age'],
'growth_areas': updatedSettings['growth_areas'],
'relationship_status': updatedSettings['relationship_status'],
'employment_status': updatedSettings['employment_status'],
'bad_habits': updatedSettings['bad_habits']
});
setLocalSelectedValues(updatedSettings);
const newSystemPrompt = AIManager.constructSystemPrompt(updatedSettings, systemPrompt);
setCurrentSystemPrompt(newSystemPrompt);
setIsEditing(false);
setIsSettingsOpen(false);
} catch (error) {
console.error('Error saving settings:', error);
}
};

Custom Animations & UI

Custom animations & advanced styling techniques to present with a professional, polished user-interface:

// Transition effect
useEffect(() => {
if (isTransitioningOut) {
// Stop all floating animations
animationRefs.current.forEach(anim => anim.stop());
animationRefs.current = [];
// Start transition animations
backgroundDots.forEach(dot => {
const randomAngle = Math.random() * Math.PI * 2;
const distance = Math.max(width, height) * 1.5;
const targetX = Math.cos(randomAngle) * distance;
const targetY = Math.sin(randomAngle) * distance;
const transitionAnimation = Animated.parallel([
Animated.timing(dot.x, {
toValue: targetX,
duration: 1000,
useNativeDriver: true,
easing: Easing.easeOut,
}),
Animated.timing(dot.y, {
toValue: targetY,
duration: 1000,
useNativeDriver: true,
easing: Easing.easeOut,
}),
Animated.timing(dot.opacity, {
toValue: 0,
duration: 800,
useNativeDriver: true,
})
]);
animationRefs.current.push(transitionAnimation);
transitionAnimation.start();
});
}
}, [isTransitioningOut]);