Update app.py
Browse files
app.py
CHANGED
|
@@ -1,17 +1,20 @@
|
|
| 1 |
-
|
| 2 |
-
from flask import Flask, render_template, request, url_for, session
|
| 3 |
import random
|
| 4 |
import os
|
| 5 |
from proof_generator import generate_fake_proof
|
| 6 |
from datetime import datetime
|
| 7 |
from googletrans import Translator
|
| 8 |
-
|
| 9 |
-
|
| 10 |
|
| 11 |
app = Flask(__name__)
|
| 12 |
app.secret_key = "your-secret-key"
|
| 13 |
translator = Translator()
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
translations = {
|
| 17 |
'en': {
|
|
@@ -26,8 +29,8 @@ translations = {
|
|
| 26 |
'family': "Family",
|
| 27 |
'history': "History",
|
| 28 |
'favorites': "Favorites",
|
| 29 |
-
|
| 30 |
-
'fake_proof': "
|
| 31 |
'top_excuses': "Top Excuses:",
|
| 32 |
'prediction': "Prediction: Based on your history, you may need your next excuse on:",
|
| 33 |
'play_excuse': "▶️ Play Excuse"
|
|
@@ -45,7 +48,7 @@ translations = {
|
|
| 45 |
'history': "Historial",
|
| 46 |
'favorites': "Favoritos",
|
| 47 |
'your_excuse': "Tu excusa:",
|
| 48 |
-
'fake_proof': "Prueba
|
| 49 |
'top_excuses': "Principales excusas:",
|
| 50 |
'prediction': "Predicción: Según tu historial, podrías necesitar tu próxima excusa el:",
|
| 51 |
'play_excuse': "▶️ Reproducir excusa"
|
|
@@ -62,8 +65,8 @@ translations = {
|
|
| 62 |
'family': "Famille",
|
| 63 |
'history': "Historique",
|
| 64 |
'favorites': "Favoris",
|
| 65 |
-
|
| 66 |
-
'fake_proof': "
|
| 67 |
'top_excuses': "Meilleures excuses:",
|
| 68 |
'prediction': "Prévision : Basé sur votre historique, vous pourriez avoir besoin de votre prochaine excuse le:",
|
| 69 |
'play_excuse': "▶️ Lire l'excuse"
|
|
@@ -80,8 +83,8 @@ translations = {
|
|
| 80 |
'family': "परिवार",
|
| 81 |
'history': "इतिहास",
|
| 82 |
'favorites': "पसंदीदा",
|
| 83 |
-
|
| 84 |
-
'fake_proof': "
|
| 85 |
'top_excuses': "शीर्ष बहाने:",
|
| 86 |
'prediction': "भविष्यवाणी: आपके इतिहास के आधार पर, अगला बहाना आपको इस दिन ज़रूरत पड़ सकती है:",
|
| 87 |
'play_excuse': "▶️ बहाना सुनें"
|
|
@@ -98,16 +101,14 @@ translations = {
|
|
| 98 |
'family': "కుటుంబం",
|
| 99 |
'history': "చరిత్ర",
|
| 100 |
'favorites': "ఇష్టమైనవి",
|
| 101 |
-
|
| 102 |
-
'fake_proof': "
|
| 103 |
'top_excuses': "అగ్ర నెపాలు:",
|
| 104 |
'prediction': "అంచనా: మీ చరిత్ర ఆధారంగా, మీకు వచ్చే నెపం అవసరం అయ్యే రోజు:",
|
| 105 |
'play_excuse': "▶️ నెపం వినండి"
|
| 106 |
}
|
| 107 |
}
|
| 108 |
|
| 109 |
-
|
| 110 |
-
# --- Excuse + Proof Mappings ---
|
| 111 |
excuse_proofs = {
|
| 112 |
"Work": [
|
| 113 |
("I'm feeling unwell and didn’t want to risk spreading anything.", "proof6.jpg"),
|
|
@@ -135,7 +136,6 @@ excuse_proofs = {
|
|
| 135 |
]
|
| 136 |
}
|
| 137 |
|
| 138 |
-
# --- Apology Templates ---
|
| 139 |
apology_templates = {
|
| 140 |
"Work": [
|
| 141 |
"I'm truly sorry for missing work. It wasn’t my intention to let anyone down.",
|
|
@@ -158,12 +158,10 @@ apology_templates = {
|
|
| 158 |
"Please know I regret not showing up — it wasn’t intentional."
|
| 159 |
]
|
| 160 |
}
|
| 161 |
-
top_excuses = []
|
| 162 |
-
scheduled_excuses = []
|
| 163 |
|
| 164 |
-
def rank_excuses(
|
| 165 |
ranked = []
|
| 166 |
-
for excuse in
|
| 167 |
score = 0
|
| 168 |
if "emergency" in excuse.lower():
|
| 169 |
score += 5
|
|
@@ -175,11 +173,9 @@ def rank_excuses(excuse_list):
|
|
| 175 |
score += 2
|
| 176 |
if "family" in excuse.lower():
|
| 177 |
score += 1
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
ranked.sort(reverse=True)
|
| 182 |
-
return [exc for score, exc in ranked]
|
| 183 |
|
| 184 |
def predict_next_excuse_time(history):
|
| 185 |
from collections import Counter
|
|
@@ -189,118 +185,91 @@ def predict_next_excuse_time(history):
|
|
| 189 |
return "No data to predict."
|
| 190 |
|
| 191 |
valid_entries = [entry for entry in history if isinstance(entry, dict) and "timestamp" in entry]
|
| 192 |
-
|
| 193 |
if not valid_entries:
|
| 194 |
return "No valid history entries."
|
| 195 |
|
| 196 |
-
times = [datetime.strptime(entry["timestamp"], "%Y-%m-%d %H:%M:%S") for entry in
|
| 197 |
-
days_of_week = [time.weekday() for time in times]
|
| 198 |
-
|
| 199 |
-
# Most common day
|
| 200 |
common_day = Counter(days_of_week).most_common(1)[0][0]
|
| 201 |
-
|
| 202 |
-
# Estimate next occurrence of that weekday
|
| 203 |
today = datetime.now()
|
| 204 |
days_until_next = (common_day - today.weekday()) % 7
|
| 205 |
predicted_date = today + timedelta(days=days_until_next)
|
| 206 |
-
|
| 207 |
-
# Predict similar time based on average hour
|
| 208 |
avg_hour = sum(time.hour for time in times) / len(times)
|
| 209 |
predicted_time = predicted_date.replace(hour=int(avg_hour), minute=0, second=0, microsecond=0)
|
| 210 |
-
|
| 211 |
return predicted_time.strftime("%A, %Y-%m-%d at %I:%M %p")
|
| 212 |
|
| 213 |
-
|
| 214 |
@app.route('/', methods=['GET', 'POST'])
|
| 215 |
def index():
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
if not selected_language:
|
| 219 |
-
selected_language = request.args.get('lang')
|
| 220 |
-
if not selected_language:
|
| 221 |
-
selected_language = 'en-US'
|
| 222 |
-
lang_code = selected_language.split('-')[0] # en-US -> en
|
| 223 |
language_dict = translations.get(lang_code, translations['en'])
|
| 224 |
|
| 225 |
-
|
| 226 |
if "history" not in session:
|
| 227 |
session["history"] = []
|
| 228 |
if "favorites" not in session:
|
| 229 |
session["favorites"] = []
|
| 230 |
|
| 231 |
-
session["history"] = []
|
| 232 |
-
|
| 233 |
excuse = None
|
| 234 |
proof = None
|
|
|
|
| 235 |
top_3_excuses = []
|
| 236 |
-
|
| 237 |
-
#selected_language = request.form.get('language', 'en-US') # default language
|
| 238 |
-
|
| 239 |
|
| 240 |
if request.method == 'POST':
|
| 241 |
scenario = request.form.get('scenario')
|
| 242 |
urgency = request.form.get('urgency')
|
| 243 |
selected_language = request.form.get('language', 'en-US')
|
| 244 |
-
|
| 245 |
-
if scenario in excuse_proofs:
|
| 246 |
-
# Fetch all excuses for the selected scenario
|
| 247 |
-
all_excuses_proofs = excuse_proofs[scenario]
|
| 248 |
-
|
| 249 |
-
# Extract only excuses (texts) for ranking
|
| 250 |
-
all_excuses = [exc for exc, proof_file in all_excuses_proofs]
|
| 251 |
-
|
| 252 |
-
# Rank excuses
|
| 253 |
-
ranked_excuses = rank_excuses(all_excuses)
|
| 254 |
-
|
| 255 |
-
# Pick the best excuse (top-ranked)
|
| 256 |
-
best_excuse = ranked_excuses[0]
|
| 257 |
-
top_3_excuses = ranked_excuses[:3]
|
| 258 |
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
|
| 288 |
-
language_dict = translations.get(selected_language[:2], translations['en'])
|
| 289 |
predicted_schedule = predict_next_excuse_time(session.get("history", []))
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
|
| 295 |
@app.route("/history")
|
| 296 |
def history():
|
| 297 |
lang = request.args.get('lang', 'en')
|
| 298 |
language_dict = translations.get(lang, translations['en'])
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
history=session.get("history", []),
|
| 302 |
-
favorites=session.get("favorites", []),
|
| 303 |
-
language_dict=language_dict)
|
| 304 |
|
| 305 |
@app.route("/favorite", methods=["POST"])
|
| 306 |
def favorite():
|
|
@@ -308,8 +277,7 @@ def favorite():
|
|
| 308 |
if excuse and excuse not in session["favorites"]:
|
| 309 |
session["favorites"].append(excuse)
|
| 310 |
session.modified = True
|
| 311 |
-
return
|
| 312 |
-
|
| 313 |
|
| 314 |
@app.route('/apology', methods=['GET', 'POST'])
|
| 315 |
def apology():
|
|
@@ -318,12 +286,10 @@ def apology():
|
|
| 318 |
lang = request.args.get('lang', 'en')
|
| 319 |
language_dict = translations.get(lang, translations['en'])
|
| 320 |
|
| 321 |
-
|
| 322 |
if request.method == 'POST':
|
| 323 |
scenario = request.form.get('scenario')
|
| 324 |
urgency = request.form.get("urgency")
|
| 325 |
tone = request.form.get('tone')
|
| 326 |
-
|
| 327 |
if scenario in apology_templates:
|
| 328 |
apology_message = random.choice(apology_templates[scenario])
|
| 329 |
proof = generate_fake_proof(urgency)
|
|
@@ -331,4 +297,4 @@ def apology():
|
|
| 331 |
return render_template('apology.html', apology=apology_message, proof=proof, language_dict=language_dict)
|
| 332 |
|
| 333 |
if __name__ == '__main__':
|
| 334 |
-
app.run(host='0.0.0.0', port=7860, debug=True)
|
|
|
|
| 1 |
+
from flask import Flask, render_template, request, url_for, session
|
|
|
|
| 2 |
import random
|
| 3 |
import os
|
| 4 |
from proof_generator import generate_fake_proof
|
| 5 |
from datetime import datetime
|
| 6 |
from googletrans import Translator
|
| 7 |
+
from werkzeug.utils import secure_filename
|
| 8 |
+
import uuid
|
| 9 |
|
| 10 |
app = Flask(__name__)
|
| 11 |
app.secret_key = "your-secret-key"
|
| 12 |
translator = Translator()
|
| 13 |
|
| 14 |
+
# Configure upload folder
|
| 15 |
+
app.config['UPLOAD_FOLDER'] = 'static/uploads'
|
| 16 |
+
if not os.path.exists(app.config['UPLOAD_FOLDER']):
|
| 17 |
+
os.makedirs(app.config['UPLOAD_FOLDER'])
|
| 18 |
|
| 19 |
translations = {
|
| 20 |
'en': {
|
|
|
|
| 29 |
'family': "Family",
|
| 30 |
'history': "History",
|
| 31 |
'favorites': "Favorites",
|
| 32 |
+
'your_excuse': "Your Excuse:",
|
| 33 |
+
'fake_proof': "Proof:",
|
| 34 |
'top_excuses': "Top Excuses:",
|
| 35 |
'prediction': "Prediction: Based on your history, you may need your next excuse on:",
|
| 36 |
'play_excuse': "▶️ Play Excuse"
|
|
|
|
| 48 |
'history': "Historial",
|
| 49 |
'favorites': "Favoritos",
|
| 50 |
'your_excuse': "Tu excusa:",
|
| 51 |
+
'fake_proof': "Prueba:",
|
| 52 |
'top_excuses': "Principales excusas:",
|
| 53 |
'prediction': "Predicción: Según tu historial, podrías necesitar tu próxima excusa el:",
|
| 54 |
'play_excuse': "▶️ Reproducir excusa"
|
|
|
|
| 65 |
'family': "Famille",
|
| 66 |
'history': "Historique",
|
| 67 |
'favorites': "Favoris",
|
| 68 |
+
'your_excuse': "Votre excuse:",
|
| 69 |
+
'fake_proof': "Preuve:",
|
| 70 |
'top_excuses': "Meilleures excuses:",
|
| 71 |
'prediction': "Prévision : Basé sur votre historique, vous pourriez avoir besoin de votre prochaine excuse le:",
|
| 72 |
'play_excuse': "▶️ Lire l'excuse"
|
|
|
|
| 83 |
'family': "परिवार",
|
| 84 |
'history': "इतिहास",
|
| 85 |
'favorites': "पसंदीदा",
|
| 86 |
+
'your_excuse': "आपका बहाना:",
|
| 87 |
+
'fake_proof': "सबूत:",
|
| 88 |
'top_excuses': "शीर्ष बहाने:",
|
| 89 |
'prediction': "भविष्यवाणी: आपके इतिहास के आधार पर, अगला बहाना आपको इस दिन ज़रूरत पड़ सकती है:",
|
| 90 |
'play_excuse': "▶️ बहाना सुनें"
|
|
|
|
| 101 |
'family': "కుటుంబం",
|
| 102 |
'history': "చరిత్ర",
|
| 103 |
'favorites': "ఇష్టమైనవి",
|
| 104 |
+
'your_excuse': "మీ నెపం:",
|
| 105 |
+
'fake_proof': "ఆధారం:",
|
| 106 |
'top_excuses': "అగ్ర నెపాలు:",
|
| 107 |
'prediction': "అంచనా: మీ చరిత్ర ఆధారంగా, మీకు వచ్చే నెపం అవసరం అయ్యే రోజు:",
|
| 108 |
'play_excuse': "▶️ నెపం వినండి"
|
| 109 |
}
|
| 110 |
}
|
| 111 |
|
|
|
|
|
|
|
| 112 |
excuse_proofs = {
|
| 113 |
"Work": [
|
| 114 |
("I'm feeling unwell and didn’t want to risk spreading anything.", "proof6.jpg"),
|
|
|
|
| 136 |
]
|
| 137 |
}
|
| 138 |
|
|
|
|
| 139 |
apology_templates = {
|
| 140 |
"Work": [
|
| 141 |
"I'm truly sorry for missing work. It wasn’t my intention to let anyone down.",
|
|
|
|
| 158 |
"Please know I regret not showing up — it wasn’t intentional."
|
| 159 |
]
|
| 160 |
}
|
|
|
|
|
|
|
| 161 |
|
| 162 |
+
def rank_excuses(excuse_proof_list):
|
| 163 |
ranked = []
|
| 164 |
+
for excuse, proof in excuse_proof_list:
|
| 165 |
score = 0
|
| 166 |
if "emergency" in excuse.lower():
|
| 167 |
score += 5
|
|
|
|
| 173 |
score += 2
|
| 174 |
if "family" in excuse.lower():
|
| 175 |
score += 1
|
| 176 |
+
ranked.append((score, (excuse, proof)))
|
| 177 |
+
ranked.sort(reverse=True, key=lambda x: x[0])
|
| 178 |
+
return [item[1] for item in ranked]
|
|
|
|
|
|
|
| 179 |
|
| 180 |
def predict_next_excuse_time(history):
|
| 181 |
from collections import Counter
|
|
|
|
| 185 |
return "No data to predict."
|
| 186 |
|
| 187 |
valid_entries = [entry for entry in history if isinstance(entry, dict) and "timestamp" in entry]
|
|
|
|
| 188 |
if not valid_entries:
|
| 189 |
return "No valid history entries."
|
| 190 |
|
| 191 |
+
times = [datetime.strptime(entry["timestamp"], "%Y-%m-%d %H:%M:%S") for entry in valid_entries]
|
| 192 |
+
days_of_week = [time.weekday() for time in times]
|
|
|
|
|
|
|
| 193 |
common_day = Counter(days_of_week).most_common(1)[0][0]
|
|
|
|
|
|
|
| 194 |
today = datetime.now()
|
| 195 |
days_until_next = (common_day - today.weekday()) % 7
|
| 196 |
predicted_date = today + timedelta(days=days_until_next)
|
|
|
|
|
|
|
| 197 |
avg_hour = sum(time.hour for time in times) / len(times)
|
| 198 |
predicted_time = predicted_date.replace(hour=int(avg_hour), minute=0, second=0, microsecond=0)
|
|
|
|
| 199 |
return predicted_time.strftime("%A, %Y-%m-%d at %I:%M %p")
|
| 200 |
|
|
|
|
| 201 |
@app.route('/', methods=['GET', 'POST'])
|
| 202 |
def index():
|
| 203 |
+
selected_language = request.form.get('language') or request.args.get('lang') or 'en-US'
|
| 204 |
+
lang_code = selected_language.split('-')[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
language_dict = translations.get(lang_code, translations['en'])
|
| 206 |
|
|
|
|
| 207 |
if "history" not in session:
|
| 208 |
session["history"] = []
|
| 209 |
if "favorites" not in session:
|
| 210 |
session["favorites"] = []
|
| 211 |
|
|
|
|
|
|
|
| 212 |
excuse = None
|
| 213 |
proof = None
|
| 214 |
+
proof_label = ""
|
| 215 |
top_3_excuses = []
|
|
|
|
|
|
|
|
|
|
| 216 |
|
| 217 |
if request.method == 'POST':
|
| 218 |
scenario = request.form.get('scenario')
|
| 219 |
urgency = request.form.get('urgency')
|
| 220 |
selected_language = request.form.get('language', 'en-US')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
+
if scenario in excuse_proofs:
|
| 223 |
+
all_excuses_proofs = excuse_proofs[scenario]
|
| 224 |
+
ranked_excuses_proofs = rank_excuses(all_excuses_proofs)
|
| 225 |
+
top_3_excuses_proofs = ranked_excuses_proofs[:3]
|
| 226 |
+
if top_3_excuses_proofs:
|
| 227 |
+
selected_excuse, selected_proof_filename = random.choice(top_3_excuses_proofs)
|
| 228 |
+
else:
|
| 229 |
+
selected_excuse, selected_proof_filename = ranked_excuses_proofs[0]
|
| 230 |
+
excuse = selected_excuse
|
| 231 |
+
top_3_excuses = [exc for exc, proof in ranked_excuses_proofs[:3]]
|
| 232 |
+
|
| 233 |
+
# Handle proof upload
|
| 234 |
+
if 'proof_image' in request.files and request.files['proof_image'].filename != '':
|
| 235 |
+
file = request.files['proof_image']
|
| 236 |
+
ext = os.path.splitext(file.filename)[1]
|
| 237 |
+
filename = str(uuid.uuid4()) + ext
|
| 238 |
+
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
|
| 239 |
+
proof = url_for('static', filename=f'uploads/{filename}')
|
| 240 |
+
is_fake = random.choice(["fake", "real"])
|
| 241 |
+
proof_label = f"This proof is likely {is_fake}"
|
| 242 |
+
else:
|
| 243 |
+
proof = url_for('static', filename=f'proofs/{selected_proof_filename}')
|
| 244 |
+
proof_label = ""
|
| 245 |
+
|
| 246 |
+
# Translate excuse if not English
|
| 247 |
+
target_lang = selected_language.split('-')[0]
|
| 248 |
+
if target_lang != 'en':
|
| 249 |
+
try:
|
| 250 |
+
translation = translator.translate(excuse, dest=target_lang)
|
| 251 |
+
excuse = translation.text
|
| 252 |
+
except Exception as e:
|
| 253 |
+
print("Translation error:", e)
|
| 254 |
+
|
| 255 |
+
# Save to history
|
| 256 |
+
session["history"].append({
|
| 257 |
+
"excuse": excuse,
|
| 258 |
+
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 259 |
+
})
|
| 260 |
+
session.modified = True
|
| 261 |
|
|
|
|
| 262 |
predicted_schedule = predict_next_excuse_time(session.get("history", []))
|
| 263 |
+
return render_template('index.html', excuse=excuse, proof=proof, proof_label=proof_label,
|
| 264 |
+
selected_language=selected_language, language_dict=language_dict,
|
| 265 |
+
top_excuses=top_3_excuses, predicted_schedule=predicted_schedule)
|
|
|
|
| 266 |
|
| 267 |
@app.route("/history")
|
| 268 |
def history():
|
| 269 |
lang = request.args.get('lang', 'en')
|
| 270 |
language_dict = translations.get(lang, translations['en'])
|
| 271 |
+
return render_template("history.html", history=session.get("history", []),
|
| 272 |
+
favorites=session.get("favorites", []), language_dict=language_dict)
|
|
|
|
|
|
|
|
|
|
| 273 |
|
| 274 |
@app.route("/favorite", methods=["POST"])
|
| 275 |
def favorite():
|
|
|
|
| 277 |
if excuse and excuse not in session["favorites"]:
|
| 278 |
session["favorites"].append(excuse)
|
| 279 |
session.modified = True
|
| 280 |
+
return url_for("history")
|
|
|
|
| 281 |
|
| 282 |
@app.route('/apology', methods=['GET', 'POST'])
|
| 283 |
def apology():
|
|
|
|
| 286 |
lang = request.args.get('lang', 'en')
|
| 287 |
language_dict = translations.get(lang, translations['en'])
|
| 288 |
|
|
|
|
| 289 |
if request.method == 'POST':
|
| 290 |
scenario = request.form.get('scenario')
|
| 291 |
urgency = request.form.get("urgency")
|
| 292 |
tone = request.form.get('tone')
|
|
|
|
| 293 |
if scenario in apology_templates:
|
| 294 |
apology_message = random.choice(apology_templates[scenario])
|
| 295 |
proof = generate_fake_proof(urgency)
|
|
|
|
| 297 |
return render_template('apology.html', apology=apology_message, proof=proof, language_dict=language_dict)
|
| 298 |
|
| 299 |
if __name__ == '__main__':
|
| 300 |
+
app.run(host='0.0.0.0', port=7860, debug=True)
|