File size: 6,147 Bytes
e9e73c3
 
 
 
 
 
 
 
 
 
456e90c
e9e73c3
 
 
 
 
cbe2c52
e9e73c3
 
cbe2c52
e9e73c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456e90c
e9e73c3
 
 
 
 
 
 
 
 
 
b413c92
e9e73c3
 
b413c92
 
 
 
 
 
e9e73c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b413c92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e9e73c3
b413c92
 
 
 
e9e73c3
b413c92
 
e9e73c3
 
b413c92
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import pickle
import streamlit as st
import numpy as np
import pandas as pd
import re
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.sequence import pad_sequences
from nltk.corpus import stopwords
from sklearn.preprocessing import StandardScaler
import nltk
import time

# Download required NLTK data (for stopwords only)
nltk.download('stopwords')

# Load the trained model
model = load_model("./best_model.keras")

# Load the tokenizer
with open("./tokenizer.pkl", "rb") as f:
    tokenizer = pickle.load(f)

# Ensure the tokenizer is valid
if not hasattr(tokenizer, 'texts_to_sequences'):
    raise ValueError("Loaded tokenizer is not a valid Keras Tokenizer object.")

# Define constants
MAX_SEQUENCE_LENGTH = 100

# Simple tokenizer function
def simple_tokenizer(text):
    text = text.lower()
    text = re.sub(r'[^a-zA-Z\s]', '', text)
    tokens = text.split()  # Split by whitespace
    return tokens

# Preprocessing function for input review
def preprocess_input_review(review_text):
    tokens = simple_tokenizer(review_text)
    stop_words = set(stopwords.words('english'))
    tokens = [word for word in tokens if word not in stop_words]
    processed_review = ' '.join(tokens)
    return processed_review

# Convert simplified time strings (e.g., 2H30M or 15M) to minutes
def time_to_minutes(time_str):
    if not time_str or pd.isna(time_str):
        return 0
    hours, minutes = 0, 0
    if 'H' in time_str:
        parts = time_str.split('H')
        hours = int(parts[0]) if parts[0].isdigit() else 0
        time_str = parts[1] if len(parts) > 1 else ''
    if 'M' in time_str and time_str.split('M')[0].isdigit():
        minutes = int(time_str.split('M')[0])
    return hours * 60 + minutes

# Prediction function
def predict_menu_inclusion(food_name, review_text, cook_time, prep_time, total_time, protein, carbs, fat):
    # Preprocess the review
    processed_review = preprocess_input_review(review_text)
    
    # Tokenize and pad the review
    review_sequence = tokenizer.texts_to_sequences([processed_review])
    padded_review = pad_sequences(review_sequence, maxlen=MAX_SEQUENCE_LENGTH)
    
    # Prepare numerical features
    numerical_features = np.array([[time_to_minutes(cook_time), 
                                     time_to_minutes(prep_time), 
                                     time_to_minutes(total_time), 
                                     protein, carbs, fat]])
    
    # Normalize numerical features
    scaler = StandardScaler()
    numerical_features = scaler.fit_transform(numerical_features)
    
    # Predict the rating
    predicted_rating = model.predict([padded_review, numerical_features]).flatten()[0]
    
    # Decide whether to include the item on the menu
    include_on_menu = predicted_rating > 3.5  # Threshold for inclusion
    
    return {
        "FoodName": food_name,
        "PredictedRating": round(predicted_rating, 2),
        "IncludeOnMenu": include_on_menu
    }

# Streamlit app with enhanced UI
st.set_page_config(page_title="Recipe Rating & Menu Optimization", layout="wide")

st.title("๐Ÿฒ๐ŸŒŸ Recipe Rating & Menu Optimization ๐Ÿš€")
st.markdown(
    """
    Welcome to the **Recipe Rating & Menu Optimization** app! ๐ŸŽ‰  
    This tool uses cutting-edge **AI and machine learning** ๐Ÿง  to help chefs, restaurateurs, and food enthusiasts ๐Ÿฝ๏ธ predict recipe ratings and decide if a dish deserves a place on the menu. ๐Ÿ†

   
    Let's get started and create culinary magic! โœจ
    """
)


st.sidebar.header("๐Ÿ“‹ Enter Recipe Details")
food_name = st.sidebar.text_input("๐Ÿด Food Name", value="Paneer Butter Masala")
review_text = st.sidebar.text_area("๐Ÿ“ Review Text", value="This dish is delicious, rich in flavor, and a favorite among customers!")
cook_time = st.sidebar.text_input("โณ Cooking Time (e.g., 15M or 2H30M)", value="30M")
prep_time = st.sidebar.text_input("๐Ÿ•’ Preparation Time (e.g., 15M or 1H15M)", value="15M")
total_time = st.sidebar.text_input("๐Ÿ“… Total Time (e.g., 45M or 1H45M)", value="45M")
protein = st.sidebar.number_input("๐Ÿ’ช Protein (grams)", min_value=0.0, step=1.0, value=20.0)
carbs = st.sidebar.number_input("๐Ÿž Carbohydrates (grams)", min_value=0.0, step=1.0, value=10.0)
fat = st.sidebar.number_input("๐ŸŸ Fat (grams)", min_value=0.0, step=1.0, value=15.0)

if st.sidebar.button("๐Ÿ”ฎ Predict"):
    result = predict_menu_inclusion(food_name, review_text, cook_time, prep_time, total_time, protein, carbs, fat)
    predicted_rating = result["PredictedRating"]
    include_on_menu = result["IncludeOnMenu"]

    # Custom progress bar with color based on inclusion
    bar_color = "green" if include_on_menu else "red"
    progress_percentage = int(predicted_rating * 20)  # Convert rating (0-5) to percentage (0-100)

    # Display animated progress bar
    st.markdown(
        f"""
        <div style="
            width: 100%;
            background-color: #ddd;
            border-radius: 10px;
            margin-bottom: 15px;
        ">
            <div style="
                width: {progress_percentage}%;
                height: 25px;
                background-color: {bar_color};
                border-radius: 10px;
                text-align: center;
                color: white;
                line-height: 25px;
                font-weight: bold;
                animation: growBar 2s;
            ">
                {progress_percentage}%
            </div>
        </div>
        <style>
        @keyframes growBar {{
            from {{ width: 0%; }}
            to {{ width: {progress_percentage}%; }}
        }}
        </style>
        """,
        unsafe_allow_html=True,
    )

    # Display prediction results
    st.subheader("Prediction Results")
    st.markdown(f"**๐Ÿด Food Name:** {result['FoodName']}")
    st.markdown(f"**โญ Predicted Rating:** {result['PredictedRating']:.1f}")

    st.markdown(
        f"**๐Ÿฝ๏ธ Include on Menu:** "
        f"<span style='color: {'green' if include_on_menu else 'red'}; font-weight: bold;'>"
        f"{'Yes' if include_on_menu else 'No'}</span>",
        unsafe_allow_html=True,
    )