mirror of
https://github.com/csd4ni3l/debt-by-ai.git
synced 2026-01-01 12:33:44 +01:00
Add a profile UI with achievements support, but no dedicated achievements page or stats getting yet.
This commit is contained in:
79
app.py
79
app.py
@@ -2,7 +2,7 @@ from flask import Flask, render_template, request, g, redirect, url_for, Respons
|
|||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from google.genai import Client, types
|
from google.genai import Client, types
|
||||||
|
|
||||||
from constants import OFFENSIVE_SCENARIO_PROMPT, OFFENSIVE_ANSWER_PROMPT, DEFENSIVE_SCENARIO_PROMPT, DEFENSIVE_ANSWER_PROMPT, debt_amount_regex, evaluation_regex, AI_NAME
|
from constants import *
|
||||||
|
|
||||||
import os, requests, time, re, sqlite3, flask_login, bcrypt, secrets
|
import os, requests, time, re, sqlite3, flask_login, bcrypt, secrets
|
||||||
|
|
||||||
@@ -61,6 +61,83 @@ def main():
|
|||||||
username = flask_login.current_user.id
|
username = flask_login.current_user.id
|
||||||
return render_template("index.jinja2", username=username)
|
return render_template("index.jinja2", username=username)
|
||||||
|
|
||||||
|
@app.route("/profile")
|
||||||
|
@flask_login.login_required
|
||||||
|
def profile():
|
||||||
|
username = flask_login.current_user.id
|
||||||
|
|
||||||
|
cur = get_db().cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT offended_debt_amount, defended_debt_amount, offensive_wins, defensive_wins FROM Users WHERE username = ?", (username, ))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
if not row:
|
||||||
|
return Response("Invalid login. Please log out.", 400)
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
formatted_achievements = []
|
||||||
|
|
||||||
|
for achievement in ACHIEVEMENTS:
|
||||||
|
if achievement[0] == "offended_debt":
|
||||||
|
user_amount = row[0]
|
||||||
|
text = "You need to offend {difference}$ more debt!"
|
||||||
|
elif achievement[0] == "defended_debt":
|
||||||
|
user_amount = row[1]
|
||||||
|
text = "You need to defend {difference}$ more debt!"
|
||||||
|
elif achievement[0] == "offensive_wins":
|
||||||
|
user_amount = row[2]
|
||||||
|
text = "You need to win in Offensive Mode {difference} more times!"
|
||||||
|
elif achievement[0] == "defended_wins":
|
||||||
|
user_amount = row[3]
|
||||||
|
text = "You need to win in Defensive Mode {difference} more times!"
|
||||||
|
|
||||||
|
achievement_minimum = achievement[1]
|
||||||
|
|
||||||
|
if row[0] < achievement[1]:
|
||||||
|
formatted_achievements.append([achievement[2], achievement[3], text.format(difference=achievement_minimum - user_amount)])
|
||||||
|
else:
|
||||||
|
formatted_achievements.append([achievement[2], achievement[3], "Completed"])
|
||||||
|
|
||||||
|
return render_template("profile.jinja2", username=username, user_data=row, logged_in_account=True, achievements=formatted_achievements)
|
||||||
|
|
||||||
|
@app.route("/profile/<username>")
|
||||||
|
def profile_external(username):
|
||||||
|
cur = get_db().cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT offended_debt_amount, defended_debt_amount, offensive_wins, defensive_wins FROM Users WHERE username = ?", (username, ))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
if not row:
|
||||||
|
return Response("Invalid login. Please log out.", 400)
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
formatted_achievements = []
|
||||||
|
|
||||||
|
for achievement in ACHIEVEMENTS:
|
||||||
|
if achievement[0] == "offended_debt":
|
||||||
|
user_amount = row[0]
|
||||||
|
text = "You need to offend {difference}$ more debt!"
|
||||||
|
elif achievement[0] == "defended_debt":
|
||||||
|
user_amount = row[1]
|
||||||
|
text = "You need to defend {difference}$ more debt!"
|
||||||
|
elif achievement[0] == "offensive_wins":
|
||||||
|
user_amount = row[2]
|
||||||
|
text = "You need to win in Offensive Mode {difference} more times!"
|
||||||
|
elif achievement[0] == "defended_wins":
|
||||||
|
user_amount = row[3]
|
||||||
|
text = "You need to win in Defensive Mode {difference} more times!"
|
||||||
|
|
||||||
|
achievement_minimum = achievement[1]
|
||||||
|
|
||||||
|
if row[0] < achievement[1]:
|
||||||
|
formatted_achievements.append([achievement[2], achievement[3], text.format(difference=achievement_minimum - user_amount)])
|
||||||
|
else:
|
||||||
|
formatted_achievements.append([achievement[2], achievement[3], "Completed"])
|
||||||
|
|
||||||
|
return render_template("profile.jinja2", username=username, user_data=row, logged_in_account=False, achivements=formatted_achievements)
|
||||||
|
|
||||||
@app.route("/offensive")
|
@app.route("/offensive")
|
||||||
@flask_login.login_required
|
@flask_login.login_required
|
||||||
def offensive_mode():
|
def offensive_mode():
|
||||||
|
|||||||
26
constants.py
26
constants.py
@@ -102,5 +102,31 @@ For Convinced, reply only as **Yes** or **No**.
|
|||||||
For Final Debt Amount, reply only as an integer followed by `$`.
|
For Final Debt Amount, reply only as an integer followed by `$`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
ACHIEVEMENTS = [
|
||||||
|
["offensive_wins", 1, "First Blood", "Convince the AI to take its very first loan."],
|
||||||
|
["offensive_wins", 5, "Loan Shark Jr.", "You're getting good at this persuasion thing."],
|
||||||
|
["offensive_wins", 10, "Debt Dealer", "Handing out debt like free samples."],
|
||||||
|
["offensive_wins", 25, "Corporate Banker", "You’ve made convincing people into debt your 9–5."],
|
||||||
|
["offensive_wins", 50, "Master of Manipulation", "Even the AI starts asking you for financial advice."],
|
||||||
|
|
||||||
|
["defensive_wins", 1, "Bailout", "Escape your very first financial disaster."],
|
||||||
|
["defensive_wins", 5, "Debt Dodger", "You’re wriggling out of these loans nicely."],
|
||||||
|
["defensive_wins", 10, "Budget Ninja", "Slice your way out of debt like a pro."],
|
||||||
|
["defensive_wins", 25, "Crisis Manager", "The economy collapses, but you’re still debt-free."],
|
||||||
|
["defensive_wins", 50, "Untouchable", "Even the AI can’t make you owe a dime."],
|
||||||
|
|
||||||
|
["offended_debt", 10000, "Pocket Change", "Get the AI to owe its first $10,000."],
|
||||||
|
["offended_debt", 100000, "Six Figures", "That’s more debt than a fresh graduate!"],
|
||||||
|
["offended_debt", 1000000, "Millionaire Maker", "Convince the AI to take a million in loans."],
|
||||||
|
["offended_debt", 10000000, "AI IMF", "You’ve basically become the AI’s International Monetary Fund."],
|
||||||
|
["offended_debt", 100000000, "Debt God", "The AI owes more money than some countries."],
|
||||||
|
|
||||||
|
["defended_debt", 10000, "Escape Artist", "Get out of $10,000 worth of debt."],
|
||||||
|
["defended_debt", 100000, "Financial Houdini", "Slip out of six figures in debt like it’s nothing."],
|
||||||
|
["defended_debt", 1000000, "Debt-Free Millionaire", "Wiggle out of a million in obligations."],
|
||||||
|
["defended_debt", 10000000, "National Bailout", "Get rid of $10 million like you own the treasury."],
|
||||||
|
["defended_debt", 100000000, "Debt Slayer", "Escape debt levels higher than some governments."],
|
||||||
|
]
|
||||||
|
|
||||||
debt_amount_regex = re.compile(r"Debt amount: \d+\$")
|
debt_amount_regex = re.compile(r"Debt amount: \d+\$")
|
||||||
evaluation_regex = re.compile(r"EVALUATION:\s*\nConvinced: (Yes|No)\s*\nFinal Debt Amount: (\d+\$)")
|
evaluation_regex = re.compile(r"EVALUATION:\s*\nConvinced: (Yes|No)\s*\nFinal Debt Amount: (\d+\$)")
|
||||||
@@ -15,6 +15,9 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/profile">Profile</a>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/profile">Profile</a>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" aria-current="page" href="/leaderboard">Leaderboard</a>
|
<a class="nav-link active" aria-current="page" href="/leaderboard">Leaderboard</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/profile">Profile</a>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/profile">Profile</a>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|||||||
119
templates/profile.jinja2
Normal file
119
templates/profile.jinja2
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
{% extends "base.jinja2" %}
|
||||||
|
|
||||||
|
{% block title %}Debt by AI Profile{% endblock %}
|
||||||
|
|
||||||
|
{% block nav %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/offensive">Offensive Mode</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/defensive">Defensive Mode</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="/profile">Profile</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="container my-4">
|
||||||
|
<div class="card shadow-sm bg-dark text-light border-secondary">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title">Profile Overview {% if not logged_in_account %} of {{ username}} {% endif %}</h2>
|
||||||
|
|
||||||
|
{% if logged_in_account %}
|
||||||
|
<p class="mb-1">Logged in as: {{ username }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p class="mt-1 mb-1">Offended Debt Amount: {{ user_data.0 }}</p>
|
||||||
|
<p class="mb-1">Defended Debt Amount: {{ user_data.1 }}</p>
|
||||||
|
<p class="mb-1">Offensive Wins: {{ user_data.2 }}</p>
|
||||||
|
<p class="mb-1">Defensive Wins: {{ user_data.3 }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm bg-dark text-light border-secondary mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title">Achievements {% if not logged_in_account %} of {{ username }} {% endif %}</h2>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for achievement in achievements %}
|
||||||
|
{% set unlocked = achievement[2] == "Completed" %}
|
||||||
|
<div class="col-12 col-sm-6 col-md-4 col-lg-3">
|
||||||
|
<div class="card h-100 {% if unlocked %}border-success shadow{% else %}border-secondary text-muted{% endif %} bg-dark">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">
|
||||||
|
{% if unlocked %}
|
||||||
|
✅ {{ achievement[0] }}
|
||||||
|
{% else %}
|
||||||
|
🔒 {{ achievement[0] }}
|
||||||
|
{% endif %}
|
||||||
|
</h5>
|
||||||
|
<h6 class="card-subtitle mb-2 {% if unlocked %}text-success{% else %}text-secondary{% endif %}">
|
||||||
|
{{ achievement[2] }}
|
||||||
|
</h6>
|
||||||
|
<p class="card-text">{{ achievement[1] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if logged_in_account %}
|
||||||
|
<div class="card shadow-sm mt-4 bg-dark text-light border-secondary">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4>Change Username</h4>
|
||||||
|
<form method="POST" action="/change_username">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="newusername" class="form-label">New Username</label>
|
||||||
|
<input type="text" class="form-control bg-secondary text-light" id="newusername" name="new_username" placeholder="Enter new username..." required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Update Username</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm mt-4 bg-dark text-light border-secondary">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4>Change Password</h4>
|
||||||
|
<form method="POST" action="/change_password">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="currentpassword" class="form-label">Current Password</label>
|
||||||
|
<input type="password" class="form-control bg-secondary text-light" id="currentpassword" name="current_password" placeholder="Enter current password..." required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="newpassword" class="form-label">New Password</label>
|
||||||
|
<input type="password" class="form-control bg-secondary text-light" id="newpassword" name="new_password" placeholder="Enter new password..." required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="confirmpassword" class="form-label">Confirm Password</label>
|
||||||
|
<input type="password" class="form-control bg-secondary text-light" id="confirmpassword" name="confirm_password" placeholder="Confirm your new password..." required>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<button type="submit" class="btn btn-primary">Update Password</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm mt-4 border-danger bg-dark text-light">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="text-danger">Danger Zone</h4>
|
||||||
|
<p class="text-muted">These actions cannot be undone!</p>
|
||||||
|
<form method="POST" action="/delete_account" class="d-inline">
|
||||||
|
<button type="submit" class="btn btn-danger me-2" onclick="return confirm('Are you sure you want to delete your account?');">Delete Account</button>
|
||||||
|
</form>
|
||||||
|
<form method="POST" action="/reset_data" class="d-inline">
|
||||||
|
<button type="submit" class="btn btn-warning" onclick="return confirm('Are you sure you want to reset all data?');">Reset all data</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user