Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ cd w07-solution
```
2. Install dependencies:
```bash
pip install -r requirements.txt
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt
```

## Running the Application
Expand Down
59 changes: 59 additions & 0 deletions client/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,63 @@ header h1 {

.like-button.liked:hover {
background-color: rgba(255, 23, 68, 0.1);
}

/* Recommendation Banner Styles */
.recommendation-banner {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 0.75rem;
margin-bottom: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}

.recommendation-banner.loading {
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
animation: pulse 2s ease-in-out infinite alternate;
}

.recommendation-banner.empty {
background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
border: 2px dashed #d1d5db;
}

.recommendation-content {
padding: 1.5rem;
}

.recommendation-banner h3 {
color: white;
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}

.recommendation-banner.loading h3,
.recommendation-banner.empty h3 {
color: #4b5563;
}

.recommendation-banner p {
color: rgba(255, 255, 255, 0.9);
font-size: 0.95rem;
line-height: 1.5;
margin: 0;
}

.recommendation-banner.loading p,
.recommendation-banner.empty p {
color: #6b7280;
}

@keyframes pulse {
0% {
opacity: 1;
}
100% {
opacity: 0.7;
}
}
4 changes: 4 additions & 0 deletions client/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ export type Meal = {
export type UserPreferences = {
username: string;
favoriteMeals: string[];
};

export type Recommendation = {
recommendation: string;
};
24 changes: 22 additions & 2 deletions client/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import FoodCard from './FoodCard.svelte';
import type {Meal} from '$lib/types';
import type {PageProps} from "./$types";
import { BaseURL } from '$lib/env';
import { getCookie } from '$lib';

let {data}: PageProps = $props();

// For more information on runes and reactivity, see: https://svelte.dev/docs/svelte/what-are-runes
let meals: Meal[] = $state(data.meals);
let recommendation: string | undefined = data.recommendation?.recommendation;
</script>

<main>
Expand All @@ -18,14 +21,31 @@
<p>Today's menu offerings</p>
</header>

<!-- Recommendation Banner -->
{#if recommendation}
<div class="recommendation-banner">
<div class="recommendation-content">
<h3>🤖 AI Recommendation</h3>
<p>{recommendation}</p>
</div>
</div>
{:else}
<div class="recommendation-banner empty">
<div class="recommendation-content">
<h3>🤖 AI Recommendation</h3>
<p>No recommendations available. Try adding some favorite meals first!</p>
</div>
</div>
{/if}

{#if meals.length === 0}
<div class="no-results">
<p>Loading menu items...</p>
</div>
{:else}
<div class="food-grid">
{#each meals as meal}
<FoodCard {meal}/>
{#each meals as {}, i}
<FoodCard bind:meal={meals[i]}/>
{/each}
</div>
{/if}
Expand Down
19 changes: 13 additions & 6 deletions client/src/routes/+page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PageLoad } from './$types';
import { BaseURL} from '$lib/env';
import type { Meal, UserPreferences } from '$lib/types';
import type { Meal, Recommendation, UserPreferences } from '$lib/types';
import { getCookie, setCookie } from '$lib';

export const ssr = false;
Expand All @@ -22,19 +22,26 @@ export const load: PageLoad = async ({ fetch }) => {
}
}

const res = await fetch(`${BaseURL}/mensa-garching/today`);
const meals: Meal[] = await res.json();
// Execute all requests in parallel, don't wait for slow ones to complete
const [mealsResult, preferencesResult, recommendationResult] = await Promise.allSettled([
fetch(`${BaseURL}/mensa-garching/today`).then(res => res.json()),
fetch(`${BaseURL}/preferences/${username}`).then(res => res.json()),
fetch(`${BaseURL}/recommend/${username}`).then(res => res.json())
]);

const res2 = await fetch(`${BaseURL}/preferences/${username}`);
const preferences: UserPreferences = await res2.json();
// Extract successful results or provide defaults
const meals: Meal[] = mealsResult.status === 'fulfilled' ? mealsResult.value : [];
const preferences: UserPreferences = preferencesResult.status === 'fulfilled' ? preferencesResult.value : { favoriteMeals: [] };
const recommendation: Recommendation | null = recommendationResult.status === 'fulfilled' ? recommendationResult.value : null;

console.log('Meals:', meals);
console.log('Preferences:', preferences);
console.log('Recommendation:', recommendation);

// Set the boolean favorite property for each meal
meals.forEach((meal: any) => {
meal.favorite = preferences.favoriteMeals.includes(meal.name);
});

return { meals};
return { meals, recommendation };
};
2 changes: 1 addition & 1 deletion client/src/routes/FoodCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { BaseURL } from "$lib/env";
import { getCookie } from "$lib";

let { meal }: { meal: Meal } = $props(); // List of favorite meal
let { meal = $bindable() }: { meal: Meal } = $props(); // List of favorite meal

//toggle favorite when heart button is clicked
const toggleFavorite = async () => {
Expand Down
29 changes: 29 additions & 0 deletions docs/CanteenApp Bruno/Get LLM recommendation.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
meta {
name: Get LLM recommendation
type: http
seq: 5
}

post {
url: http://localhost:5000/recommend
body: json
auth: inherit
}

body:json {
{
"favorite_menu": [
"Chicken Alfredo",
"Caesar Salad",
"Margherita Pizza",
"Grilled Salmon"
],
"todays_menu": [
"Beef Tacos",
"Chicken Alfredo Pasta",
"Greek Salad",
"Vegetarian Pizza",
"Fish and Chips"
]
}
}
11 changes: 11 additions & 0 deletions docs/CanteenApp Bruno/Get recommendation.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: Get recommendation
type: http
seq: 6
}

get {
url: http://localhost:8080/api/recommend/test
body: none
auth: inherit
}
Loading