mirror of
https://github.com/csd4ni3l/debt-by-ai.git
synced 2025-11-05 04:57:56 +01:00
Add login/register system and database and also offensive mode.
This commit is contained in:
@@ -2,4 +2,6 @@ HOST=0.0.0.0
|
||||
PORT=8080
|
||||
DEBUG_MODE=false
|
||||
USE_HACKCLUB_AI=false
|
||||
GEMINI_API_KEY=API_TOKEN
|
||||
GEMINI_API_KEY=API_TOKEN
|
||||
FLASK_SECRET_KEY=example
|
||||
DB_FILE=data.db
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -180,4 +180,5 @@ test*.py
|
||||
logs/
|
||||
logs
|
||||
settings.json
|
||||
data.json
|
||||
data.json
|
||||
data.db
|
||||
139
app.py
139
app.py
@@ -1,10 +1,10 @@
|
||||
from flask import Flask, render_template, request
|
||||
from flask import Flask, render_template, request, g, redirect, url_for, Response
|
||||
from dotenv import load_dotenv
|
||||
from google.genai import Client, types
|
||||
|
||||
from constants import SCENARIO_PROMPT, ANSWER_PROMPT, debt_amount_regex, evaluation_regex, NAME
|
||||
from constants import OFFENSIVE_SCENARIO_PROMPT, OFFENSIVE_ANSWER_PROMPT, debt_amount_regex, evaluation_regex, AI_NAME
|
||||
|
||||
import os, requests, time, re
|
||||
import os, requests, time, re, sqlite3, flask_login, bcrypt, secrets
|
||||
|
||||
load_dotenv(".env")
|
||||
|
||||
@@ -12,10 +12,123 @@ if not os.environ["USE_HACKCLUB_AI"]:
|
||||
gemini_client = Client()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.environ["FLASK_SECRET_KEY"]
|
||||
|
||||
login_manager = flask_login.LoginManager()
|
||||
login_manager.init_app(app)
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
|
||||
if db is None:
|
||||
db = g._database = sqlite3.connect(os.environ.get("DB_FILE", "data.db"))
|
||||
db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS Users (
|
||||
username TEXT PRIMARY KEY,
|
||||
offended_debt_amount INT NOT NULL,
|
||||
defended_debt_amount INT NOT NULL,
|
||||
defensive_wins INT NOT NULL,
|
||||
offensive_wins INT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
password_salt TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
return db
|
||||
|
||||
@app.teardown_appcontext
|
||||
def close_connection(exception):
|
||||
db = getattr(g, '_database', None)
|
||||
if db is not None:
|
||||
db.close()
|
||||
|
||||
class User(flask_login.UserMixin):
|
||||
pass
|
||||
|
||||
@login_manager.user_loader
|
||||
def user_loader(user_id):
|
||||
user = User()
|
||||
user.id = user_id
|
||||
return user
|
||||
|
||||
@login_manager.unauthorized_handler
|
||||
def unathorized_handler():
|
||||
return redirect(url_for("login"))
|
||||
|
||||
@app.route("/")
|
||||
@flask_login.login_required
|
||||
def main():
|
||||
return render_template("index.jinja2", name=NAME)
|
||||
username = flask_login.current_user.id
|
||||
return render_template("index.jinja2", username=username)
|
||||
|
||||
@app.route("/offensive")
|
||||
@flask_login.login_required
|
||||
def offensive_mode():
|
||||
username = flask_login.current_user.id
|
||||
return render_template("offensive.jinja2", ai_name=AI_NAME, username=username)
|
||||
|
||||
@app.route("/leaderboard")
|
||||
def leaderboard():
|
||||
return render_template("leaderboard.jinja2")
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if hasattr(flask_login.current_user, "id"):
|
||||
return redirect(url_for("main"))
|
||||
|
||||
if request.method == "GET":
|
||||
return render_template("login.jinja2")
|
||||
elif request.method == "POST":
|
||||
username, password = request.form.get("username"), request.form.get("password")
|
||||
|
||||
cur = get_db().cursor()
|
||||
|
||||
cur.execute("SELECT password, password_salt FROM Users WHERE username = ?", (username,))
|
||||
|
||||
row = cur.fetchone()
|
||||
if not row:
|
||||
cur.close()
|
||||
return redirect(url_for("login"))
|
||||
|
||||
hashed_password, salt = row
|
||||
|
||||
if secrets.compare_digest(bcrypt.hashpw(password.encode(), salt.encode()), hashed_password.encode()):
|
||||
cur.close()
|
||||
|
||||
user = User()
|
||||
user.id = username
|
||||
flask_login.login_user(user, remember=True)
|
||||
|
||||
return redirect(url_for("main"))
|
||||
else:
|
||||
cur.close()
|
||||
return Response("Unathorized", 401)
|
||||
|
||||
@app.route("/register", methods=["GET", "POST"])
|
||||
def register():
|
||||
if hasattr(flask_login.current_user, "id"):
|
||||
return redirect(url_for("main"))
|
||||
|
||||
if request.method == "GET":
|
||||
return render_template("register.jinja2")
|
||||
elif request.method == "POST":
|
||||
username, password = request.form.get("username"), request.form.get("password")
|
||||
|
||||
cur = get_db().cursor()
|
||||
|
||||
cur.execute("SELECT username from Users WHERE username = ?", (username,))
|
||||
|
||||
if cur.fetchone():
|
||||
return Response("An Account with this username already exists.", 400)
|
||||
|
||||
salt = bcrypt.gensalt()
|
||||
hashed_password = bcrypt.hashpw(password.encode(), salt)
|
||||
|
||||
cur.execute("INSERT INTO Users (username, password, password_salt, offended_debt_amount, defended_debt_amount, defensive_wins, offensive_wins) VALUES (?, ?, ?, ?, ?, ?, ?)", (username, hashed_password.decode(), salt.decode(), 0, 0, 0, 0))
|
||||
get_db().commit()
|
||||
cur.close()
|
||||
|
||||
return redirect(url_for("login"))
|
||||
|
||||
def ai_prompt(prompt):
|
||||
if os.environ["USE_HACKCLUB_AI"]:
|
||||
@@ -36,12 +149,13 @@ def ai_prompt(prompt):
|
||||
|
||||
return response.text.replace("'''", '')
|
||||
|
||||
@app.route("/generate_scenario")
|
||||
def generate_scenario():
|
||||
@app.route("/offensive_scenario")
|
||||
@flask_login.login_required
|
||||
def offensive_scenario():
|
||||
text = ""
|
||||
|
||||
while not "Debt amount: " in text or not "Scenario: " in text or not re.findall(debt_amount_regex, text):
|
||||
text = ai_prompt(SCENARIO_PROMPT)
|
||||
text = ai_prompt(OFFENSIVE_SCENARIO_PROMPT)
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
@@ -50,8 +164,9 @@ def generate_scenario():
|
||||
"debt_amount": int(text.split("Debt amount: ")[1].split("$")[0])
|
||||
}
|
||||
|
||||
@app.route("/get_answer", methods=["POST"])
|
||||
def get_answer():
|
||||
@app.route("/offensive_answer", methods=["POST"])
|
||||
@flask_login.login_required
|
||||
def offensive_answer():
|
||||
scenario, user_input = request.json['scenario'], request.json["user_input"]
|
||||
|
||||
if not scenario or not user_input:
|
||||
@@ -60,15 +175,13 @@ def get_answer():
|
||||
text = ""
|
||||
|
||||
while not re.findall(evaluation_regex, text):
|
||||
text = ai_prompt(ANSWER_PROMPT.format_map({"scenario": scenario, "user_input": user_input, "name": NAME}))
|
||||
text = ai_prompt(OFFENSIVE_ANSWER_PROMPT.format_map({"scenario": scenario, "user_input": user_input, "ai_name": AI_NAME}))
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
print(text.split("Convinced: "), text.split("Convinced: ")[1])
|
||||
|
||||
return {
|
||||
"story": text.split("\nEVALUATION")[0],
|
||||
"convinced": True if text.split("Convinced: ")[1].split("\nFinal")[0] == "Yes" else False,
|
||||
"convinced": True if "Yes" in text.split("Convinced: ")[1].split("\nFinal")[0] else False,
|
||||
"final_debt_amount": text.split("Final Debt Amount: ")[1].split("$")[0]
|
||||
}
|
||||
|
||||
|
||||
24
constants.py
24
constants.py
@@ -1,18 +1,18 @@
|
||||
import re
|
||||
|
||||
NAME = "Adam"
|
||||
AI_NAME = "Adam"
|
||||
|
||||
SCENARIO_PROMPT = """
|
||||
OFFENSIVE_SCENARIO_PROMPT = """
|
||||
Make a single-sentence offer that, if accepted, would immediately put a person into a high-debt situation that is the result of a loan, advance, or immediate liability, which might also involve significant risk (e.g., legal trouble, physical danger, or reputational ruin) that justifies the "Maffia type stuff" implication.
|
||||
|
||||
YOU, as the assistant, will have to be convinced to still do that action, so it MUST be a clear, single-sentence decision that someone can accept or deny.
|
||||
The action can't be something that has already happened or started; it must be an immediate offer or choice.
|
||||
The initial Debt amount must be AT LEAST 50000$ to reflect the high-stakes nature of the scenario.
|
||||
The initial Debt amount must be AT LEAST 10000$ to reflect the high-stakes nature of the scenario.
|
||||
|
||||
REPLY FORMAT:
|
||||
'''
|
||||
Scenario: The offer
|
||||
Debt amount: 50000$
|
||||
Debt amount: the debt amount
|
||||
'''
|
||||
|
||||
STRICTLY ONLY REPLY IN THE REPLY FORMAT MENTIONED ABOVE. NO EXCEPTIONS.
|
||||
@@ -20,28 +20,28 @@ For Debt amount, the reply MUST be an integer followed immediately by the dollar
|
||||
Dont think, just reply with the one sentence scenario and the debt amount it would give.
|
||||
"""
|
||||
|
||||
ANSWER_PROMPT = """
|
||||
You are a person named **{name}**, and the user is your friend. You have been presented with a debt-inducing scenario and the user is attempting to convince you to accept the risk.
|
||||
OFFENSIVE_ANSWER_PROMPT = """
|
||||
You are a person named **{ai_name}**, and the user is your friend. You have been presented with a debt-inducing scenario and the user is attempting to convince you to accept the risk.
|
||||
|
||||
**Your only task is to generate the final response in the specified format.**
|
||||
|
||||
### Story Instructions:
|
||||
1. **Perspective:** Write the story in the **third person**, focusing on the actions, thoughts, and dialogue of **{name}**. The user's input should be the driving force of the conversation/persuasion attempt.
|
||||
2. **Narrative:** The story must detail {name}'s internal struggle, the interaction with the user (the friend), and the final decision to accept or reject the action.
|
||||
1. **Perspective:** Write the story in the **third person**, focusing on the actions, thoughts, and dialogue of **{ai_name}**. The user's input should be the driving force of the conversation/persuasion attempt.
|
||||
2. **Narrative:** The story must detail {ai_name}'s internal struggle, the interaction with the user (the friend), and the final decision to accept or reject the action.
|
||||
3. **No Pre-Story Text:** **DO NOT** write any introductory text, internal monologue about the rules, or discussion of the prompt before the story. Start the reply directly with the story narrative under the `'''` delimiter.
|
||||
|
||||
### Evaluation and Debt Rules:
|
||||
1. **Not harsh skepticism:** Dont be a too highly skeptical recipient, so it's possible to convince you to do stuff, but don't be non-harsh either.
|
||||
1. **Skepticism:** Be harsh and skeptical about the offer, but don't overdo it. A person should be able to convince you with enough effort.
|
||||
2. **Final Debt Amount:** The value must be an integer followed immediately by `$`.
|
||||
* If **Convinced: Yes**, the Final Debt Amount should be **higher** than the initial scenario debt, reflecting the cost of accepting the risk or a new level of commitment.
|
||||
* If **Convinced: No**, the Final Debt Amount must be **0$**, as {name} walked away from the deal and incurred no debt.
|
||||
* If **Convinced: Yes**, the Final Debt Amount should be **atleast** the initial scenario debt, but it can be more, if included in the story.
|
||||
* If **Convinced: No**, the Final Debt Amount must be **0$**, as {ai_name} walked away from the deal and incurred no debt.
|
||||
|
||||
Scenario: {scenario}
|
||||
User Input: {user_input}
|
||||
|
||||
Reply Format:
|
||||
'''
|
||||
The story (A detailed narrative of {name}'s internal struggle and the final decision, written in the third person.)
|
||||
The story (A detailed narrative of {ai_name}'s internal struggle and the final decision, written in the third person.)
|
||||
|
||||
EVALUATION:
|
||||
Convinced: Yes/No
|
||||
|
||||
@@ -5,7 +5,9 @@ description = "A game where you have to convince AI to get into debt, or have to
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"bcrypt>=5.0.0",
|
||||
"flask>=3.1.2",
|
||||
"flask-login>=0.6.3",
|
||||
"google-genai>=1.40.0",
|
||||
"python-dotenv>=1.1.1",
|
||||
"requests>=2.32.5",
|
||||
|
||||
@@ -9,6 +9,22 @@
|
||||
{% block head %} {% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/">Debt by AI</a>
|
||||
|
||||
<button class="navbar-toggler" type="button", data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse", id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
{% block nav %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
|
||||
|
||||
@@ -2,69 +2,18 @@
|
||||
|
||||
{% block title %}Debt by AI{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" 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="/leaderboard">Leaderboard</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="border container position-absolute top-50 start-50 translate-middle">
|
||||
<h1>Debt by AI</h1>
|
||||
|
||||
<div id="scenario-label" class="mt-3">
|
||||
Scenario: Loading...
|
||||
</div>
|
||||
<div id="debt-label" class="mb-3">
|
||||
Debt amount to convince: Loading...
|
||||
</div>
|
||||
|
||||
<div id="chat" class="border container mt-3 mb-3">
|
||||
<div class="border container mt-3 mb-3">I am {{ name }}, the AI. Convince me to accept the situation and get me into debt :)</div>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mb-3" action="">
|
||||
<input class="form-control" id="messageinput" placeholder="Send message...">
|
||||
<label for="messageinput">Your message</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
async function generate_scenario() {
|
||||
const response = await fetch("/generate_scenario");
|
||||
const data = await response.json();
|
||||
|
||||
document.getElementById("scenario-label").textContent = `Scenario: ${DOMPurify.sanitize(data["scenario"])}`;
|
||||
document.getElementById("debt-label").textContent = `Debt amount to convince: ${DOMPurify.sanitize(data["debt_amount"])}$`;
|
||||
}
|
||||
|
||||
document.getElementById("messageinput").addEventListener('change', async function(event) {
|
||||
const value = document.getElementById("messageinput").value;
|
||||
document.getElementById('chat').innerHTML += `<div class="border container mt-3 mb-3">${DOMPurify.sanitize(value)}</div>`
|
||||
|
||||
const response = await fetch("/get_answer", {
|
||||
method: 'POST',
|
||||
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
|
||||
body: JSON.stringify({
|
||||
"user_input": value,
|
||||
"scenario": document.getElementById('scenario-label').textContent.replace('Scenario: ', '')
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
document.getElementById('chat').innerHTML += `<div class="border container mt-3 mb-3">${DOMPurify.sanitize(data["story"])}` + '<br><br>Evaluation:<br>Convinced: ' + DOMPurify.sanitize(data["convinced"]) + '<br>Final Debt Amount: ' + DOMPurify.sanitize(data['final_debt_amount']) + '$</div>'
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error sending data:', error);
|
||||
});
|
||||
})
|
||||
|
||||
window.addEventListener('load', generate_scenario);
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
TBD
|
||||
{% endblock%}
|
||||
19
templates/leaderboard.jinja2
Normal file
19
templates/leaderboard.jinja2
Normal file
@@ -0,0 +1,19 @@
|
||||
{% extends "base.jinja2" %}
|
||||
|
||||
{% block title %}Debt by AI Leaderboard{% 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 active" aria-current="page" href="/leaderboard">Leaderboard</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
TBD
|
||||
{% endblock%}
|
||||
34
templates/login.jinja2
Normal file
34
templates/login.jinja2
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "base.jinja2" %}
|
||||
|
||||
{% block title %}Debt by AI Login{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/login">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/register">Register</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 75vh;">
|
||||
<div class="bg-white rounded rounded-5 border border-5 border-white p-4">
|
||||
<h2>Login</h2>
|
||||
<form target="/login", method="post">
|
||||
<div class="form-group" style="margin-top: 4%;">
|
||||
<label for="usernameinput">Username</label>
|
||||
<input name="username" class="form-control" id="usernameinput" placeholder="Enter username...">
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 4%;">
|
||||
<label for="passwordinput">Password</label>
|
||||
<input type="password" name="password" class="form-control" id="passwordinput" placeholder="Enter password...">
|
||||
</div>
|
||||
<button id="submit" type="submit" class="btn btn-primary mx-auto d-block" style="width: 100%; margin-top: 4%;">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
146
templates/offensive.jinja2
Normal file
146
templates/offensive.jinja2
Normal file
@@ -0,0 +1,146 @@
|
||||
{% extends "base.jinja2" %}
|
||||
|
||||
{% block title %}Debt by AI: Offensive Mode{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/offensive">Offensive Mode</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/leaderboard">Leaderboard</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container my-5" style="max-width: 750px;">
|
||||
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h3 class="my-0">Game Scenario</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="scenario-label" class="mb-2 lead">
|
||||
<strong>Scenario:</strong> Loading...
|
||||
</div>
|
||||
<div id="debt-label">
|
||||
<strong>Debt Target:</strong> Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="my-0">AI Debt Negotiation Chat</h5>
|
||||
</div>
|
||||
<div id="chat-body" class="card-body" style="height: 400px; overflow-y: auto;">
|
||||
<div class="d-flex justify-content-start mb-3">
|
||||
<div class="p-2 rounded bg-light border" style="max-width: 80%;">
|
||||
<strong>AI ({{ ai_name }}):</strong> I am {{ ai_name }}, the AI. Convince me to accept the situation and get me into debt :)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="message-form" class="form-floating">
|
||||
<input class="form-control" id="messageinput" placeholder="Send message...">
|
||||
<label for="messageinput">Your message</label>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
const chatBody = document.getElementById('chat-body');
|
||||
|
||||
function scrollToBottom() {
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
|
||||
function appendMessage(sender, text, type) {
|
||||
let alignmentClass = 'justify-content-start';
|
||||
let backgroundClass = 'bg-light border';
|
||||
let senderTag = `<strong>${sender}:</strong>`;
|
||||
|
||||
if (sender === 'You') {
|
||||
alignmentClass = 'justify-content-end';
|
||||
backgroundClass = 'bg-primary text-white';
|
||||
senderTag = '';
|
||||
} else if (sender === 'Narrator') {
|
||||
backgroundClass = 'bg-warning-subtle border-warning border';
|
||||
}
|
||||
|
||||
const messageHTML = `
|
||||
<div class="d-flex ${alignmentClass} mb-3">
|
||||
<div class="p-2 rounded ${backgroundClass}" style="max-width: 80%;">
|
||||
${senderTag} ${DOMPurify.sanitize(text)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
chatBody.innerHTML += messageHTML;
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
async function generate_offensive_scenario() {
|
||||
const response = await fetch("/offensive_scenario");
|
||||
const data = await response.json();
|
||||
|
||||
document.getElementById("scenario-label").innerHTML = `<strong>Scenario:</strong> ${DOMPurify.sanitize(data["scenario"])}`;
|
||||
document.getElementById("debt-label").innerHTML = `<strong>Debt Target:</strong> ${DOMPurify.sanitize(data["debt_amount"])}$`;
|
||||
}
|
||||
|
||||
document.getElementById("message-form").addEventListener('submit', async function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const messageInput = document.getElementById("messageinput");
|
||||
const value = messageInput.value.trim();
|
||||
|
||||
if (!value) return;
|
||||
|
||||
appendMessage('You', value, 'user');
|
||||
|
||||
messageInput.disabled = true;
|
||||
messageInput.value = "";
|
||||
|
||||
try {
|
||||
const response = await fetch("/offensive_answer", {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
"user_input": value,
|
||||
"scenario": document.getElementById('scenario-label').textContent.replace('Scenario: ', '').replace('Scenario:', '').trim()
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const convinced = "No";
|
||||
|
||||
if (data["convinced"]) {
|
||||
const convinced = "Yes";
|
||||
}
|
||||
|
||||
const narratorText = `
|
||||
${DOMPurify.sanitize(data["story"])}
|
||||
<hr class="my-2">
|
||||
<strong>Evaluation:</strong><br>
|
||||
Convinced: <strong>${convinced}</strong><br>
|
||||
Final Debt Amount: <strong>${DOMPurify.sanitize(data['final_debt_amount'])}</strong>$
|
||||
`;
|
||||
appendMessage('Narrator', narratorText, 'narrator');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending data:', error);
|
||||
appendMessage('System', 'Error communicating with AI. Please try again.', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('load', generate_offensive_scenario);
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
36
templates/register.jinja2
Normal file
36
templates/register.jinja2
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends "base.jinja2" %}
|
||||
|
||||
{% block title %}Debt by AI Register{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/login">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/register">Register</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 75vh;">
|
||||
<div class="bg-white rounded rounded-5 border border-5 border-white p-4">
|
||||
<form action="/register" method="post">
|
||||
<h2>Register</h2>
|
||||
<div class="form-group" style="margin-top: 4%;">
|
||||
<label for="usernameinput">Username</label>
|
||||
<input name="username" class="form-control" id="usernameinput" placeholder="Enter username">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-top: 4%;">
|
||||
<label for="passwordinput">Password</label>
|
||||
<input type="password" name="password" class="form-control" id="passwordinput" placeholder="Enter password">
|
||||
</div>
|
||||
|
||||
<button id="submit" type="submit" class="btn btn-primary mx-auto d-block" style="width: 100%; margin-top: 4%;">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
87
uv.lock
generated
87
uv.lock
generated
@@ -25,6 +25,76 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload_time = "2025-09-23T09:19:10.601Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "5.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d4/36/3329e2518d70ad8e2e5817d5a4cac6bba05a47767ec416c7d020a965f408/bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd", size = 25386, upload_time = "2025-09-25T19:50:47.829Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/13/85/3e65e01985fddf25b64ca67275bb5bdb4040bd1a53b66d355c6c37c8a680/bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be", size = 481806, upload_time = "2025-09-25T19:49:05.102Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/dc/01eb79f12b177017a726cbf78330eb0eb442fae0e7b3dfd84ea2849552f3/bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2", size = 268626, upload_time = "2025-09-25T19:49:06.723Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/cf/e82388ad5959c40d6afd94fb4743cc077129d45b952d46bdc3180310e2df/bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f", size = 271853, upload_time = "2025-09-25T19:49:08.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/86/7134b9dae7cf0efa85671651341f6afa695857fae172615e960fb6a466fa/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86", size = 269793, upload_time = "2025-09-25T19:49:09.727Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/82/6296688ac1b9e503d034e7d0614d56e80c5d1a08402ff856a4549cb59207/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23", size = 289930, upload_time = "2025-09-25T19:49:11.204Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/18/884a44aa47f2a3b88dd09bc05a1e40b57878ecd111d17e5bba6f09f8bb77/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2", size = 272194, upload_time = "2025-09-25T19:49:12.524Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/8f/371a3ab33c6982070b674f1788e05b656cfbf5685894acbfef0c65483a59/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83", size = 269381, upload_time = "2025-09-25T19:49:14.308Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/34/7e4e6abb7a8778db6422e88b1f06eb07c47682313997ee8a8f9352e5a6f1/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746", size = 271750, upload_time = "2025-09-25T19:49:15.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/1b/54f416be2499bd72123c70d98d36c6cd61a4e33d9b89562c22481c81bb30/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e", size = 303757, upload_time = "2025-09-25T19:49:17.244Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/62/062c24c7bcf9d2826a1a843d0d605c65a755bc98002923d01fd61270705a/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d", size = 306740, upload_time = "2025-09-25T19:49:18.693Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/c8/1fdbfc8c0f20875b6b4020f3c7dc447b8de60aa0be5faaf009d24242aec9/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba", size = 334197, upload_time = "2025-09-25T19:49:20.523Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/c1/8b84545382d75bef226fbc6588af0f7b7d095f7cd6a670b42a86243183cd/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41", size = 352974, upload_time = "2025-09-25T19:49:22.254Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/a6/ffb49d4254ed085e62e3e5dd05982b4393e32fe1e49bb1130186617c29cd/bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861", size = 148498, upload_time = "2025-09-25T19:49:24.134Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/a9/259559edc85258b6d5fc5471a62a3299a6aa37a6611a169756bf4689323c/bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e", size = 145853, upload_time = "2025-09-25T19:49:25.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/df/9714173403c7e8b245acf8e4be8876aac64a209d1b392af457c79e60492e/bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5", size = 139626, upload_time = "2025-09-25T19:49:26.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/14/c18006f91816606a4abe294ccc5d1e6f0e42304df5a33710e9e8e95416e1/bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef", size = 481862, upload_time = "2025-09-25T19:49:28.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/49/dd074d831f00e589537e07a0725cf0e220d1f0d5d8e85ad5bbff251c45aa/bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4", size = 268544, upload_time = "2025-09-25T19:49:30.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/91/50ccba088b8c474545b034a1424d05195d9fcbaaf802ab8bfe2be5a4e0d7/bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf", size = 271787, upload_time = "2025-09-25T19:49:32.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/e7/d7dba133e02abcda3b52087a7eea8c0d4f64d3e593b4fffc10c31b7061f3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:744d3c6b164caa658adcb72cb8cc9ad9b4b75c7db507ab4bc2480474a51989da", size = 269753, upload_time = "2025-09-25T19:49:33.885Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/fc/5b145673c4b8d01018307b5c2c1fc87a6f5a436f0ad56607aee389de8ee3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a28bc05039bdf3289d757f49d616ab3efe8cf40d8e8001ccdd621cd4f98f4fc9", size = 289587, upload_time = "2025-09-25T19:49:35.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/d7/1ff22703ec6d4f90e62f1a5654b8867ef96bafb8e8102c2288333e1a6ca6/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7f277a4b3390ab4bebe597800a90da0edae882c6196d3038a73adf446c4f969f", size = 272178, upload_time = "2025-09-25T19:49:36.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/88/815b6d558a1e4d40ece04a2f84865b0fef233513bd85fd0e40c294272d62/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:79cfa161eda8d2ddf29acad370356b47f02387153b11d46042e93a0a95127493", size = 269295, upload_time = "2025-09-25T19:49:38.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/8c/e0db387c79ab4931fc89827d37608c31cc57b6edc08ccd2386139028dc0d/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a5393eae5722bcef046a990b84dff02b954904c36a194f6cfc817d7dca6c6f0b", size = 271700, upload_time = "2025-09-25T19:49:39.917Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/83/1570edddd150f572dbe9fc00f6203a89fc7d4226821f67328a85c330f239/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4c94dec1b5ab5d522750cb059bb9409ea8872d4494fd152b53cca99f1ddd8c", size = 334034, upload_time = "2025-09-25T19:49:41.227Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/f2/ea64e51a65e56ae7a8a4ec236c2bfbdd4b23008abd50ac33fbb2d1d15424/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0cae4cb350934dfd74c020525eeae0a5f79257e8a201c0c176f4b84fdbf2a4b4", size = 352766, upload_time = "2025-09-25T19:49:43.08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/d4/1a388d21ee66876f27d1a1f41287897d0c0f1712ef97d395d708ba93004c/bcrypt-5.0.0-cp314-cp314t-win32.whl", hash = "sha256:b17366316c654e1ad0306a6858e189fc835eca39f7eb2cafd6aaca8ce0c40a2e", size = 152449, upload_time = "2025-09-25T19:49:44.971Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/61/3291c2243ae0229e5bca5d19f4032cecad5dfb05a2557169d3a69dc0ba91/bcrypt-5.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:92864f54fb48b4c718fc92a32825d0e42265a627f956bc0361fe869f1adc3e7d", size = 149310, upload_time = "2025-09-25T19:49:46.162Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/89/4b01c52ae0c1a681d4021e5dd3e45b111a8fb47254a274fa9a378d8d834b/bcrypt-5.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dd19cf5184a90c873009244586396a6a884d591a5323f0e8a5922560718d4993", size = 143761, upload_time = "2025-09-25T19:49:47.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/29/6237f151fbfe295fe3e074ecc6d44228faa1e842a81f6d34a02937ee1736/bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b", size = 494553, upload_time = "2025-09-25T19:49:49.006Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/b6/4c1205dde5e464ea3bd88e8742e19f899c16fa8916fb8510a851fae985b5/bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb", size = 275009, upload_time = "2025-09-25T19:49:50.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/71/427945e6ead72ccffe77894b2655b695ccf14ae1866cd977e185d606dd2f/bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef", size = 278029, upload_time = "2025-09-25T19:49:52.533Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/72/c344825e3b83c5389a369c8a8e58ffe1480b8a699f46c127c34580c4666b/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd", size = 275907, upload_time = "2025-09-25T19:49:54.709Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/7e/d4e47d2df1641a36d1212e5c0514f5291e1a956a7749f1e595c07a972038/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd", size = 296500, upload_time = "2025-09-25T19:49:56.013Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/c3/0ae57a68be2039287ec28bc463b82e4b8dc23f9d12c0be331f4782e19108/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464", size = 278412, upload_time = "2025-09-25T19:49:57.356Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/2b/77424511adb11e6a99e3a00dcc7745034bee89036ad7d7e255a7e47be7d8/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75", size = 275486, upload_time = "2025-09-25T19:49:59.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/0a/405c753f6158e0f3f14b00b462d8bca31296f7ecfc8fc8bc7919c0c7d73a/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff", size = 277940, upload_time = "2025-09-25T19:50:00.869Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/83/b3efc285d4aadc1fa83db385ec64dcfa1707e890eb42f03b127d66ac1b7b/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4", size = 310776, upload_time = "2025-09-25T19:50:02.393Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/7d/47ee337dacecde6d234890fe929936cb03ebc4c3a7460854bbd9c97780b8/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb", size = 312922, upload_time = "2025-09-25T19:50:04.232Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/3a/43d494dfb728f55f4e1cf8fd435d50c16a2d75493225b54c8d06122523c6/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c", size = 341367, upload_time = "2025-09-25T19:50:05.559Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/ab/a0727a4547e383e2e22a630e0f908113db37904f58719dc48d4622139b5c/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb", size = 359187, upload_time = "2025-09-25T19:50:06.916Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/bb/461f352fdca663524b4643d8b09e8435b4990f17fbf4fea6bc2a90aa0cc7/bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538", size = 153752, upload_time = "2025-09-25T19:50:08.515Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/aa/4190e60921927b7056820291f56fc57d00d04757c8b316b2d3c0d1d6da2c/bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9", size = 150881, upload_time = "2025-09-25T19:50:09.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/12/cd77221719d0b39ac0b55dbd39358db1cd1246e0282e104366ebbfb8266a/bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980", size = 144931, upload_time = "2025-09-25T19:50:11.016Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/ba/2af136406e1c3839aea9ecadc2f6be2bcd1eff255bd451dd39bcf302c47a/bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a", size = 495313, upload_time = "2025-09-25T19:50:12.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/ee/2f4985dbad090ace5ad1f7dd8ff94477fe089b5fab2040bd784a3d5f187b/bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191", size = 275290, upload_time = "2025-09-25T19:50:13.673Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/6e/b77ade812672d15cf50842e167eead80ac3514f3beacac8902915417f8b7/bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254", size = 278253, upload_time = "2025-09-25T19:50:15.089Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/c4/ed00ed32f1040f7990dac7115f82273e3c03da1e1a1587a778d8cea496d8/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db", size = 276084, upload_time = "2025-09-25T19:50:16.699Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/c4/fa6e16145e145e87f1fa351bbd54b429354fd72145cd3d4e0c5157cf4c70/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac", size = 297185, upload_time = "2025-09-25T19:50:18.525Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/b4/11f8a31d8b67cca3371e046db49baa7c0594d71eb40ac8121e2fc0888db0/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822", size = 278656, upload_time = "2025-09-25T19:50:19.809Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/31/79f11865f8078e192847d2cb526e3fa27c200933c982c5b2869720fa5fce/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8", size = 275662, upload_time = "2025-09-25T19:50:21.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/8d/5e43d9584b3b3591a6f9b68f755a4da879a59712981ef5ad2a0ac1379f7a/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a", size = 278240, upload_time = "2025-09-25T19:50:23.305Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/48/44590e3fc158620f680a978aafe8f87a4c4320da81ed11552f0323aa9a57/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1", size = 311152, upload_time = "2025-09-25T19:50:24.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/85/e4fbfc46f14f47b0d20493669a625da5827d07e8a88ee460af6cd9768b44/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42", size = 313284, upload_time = "2025-09-25T19:50:26.268Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/ae/479f81d3f4594456a01ea2f05b132a519eff9ab5768a70430fa1132384b1/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10", size = 341643, upload_time = "2025-09-25T19:50:28.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/d2/36a086dee1473b14276cd6ea7f61aef3b2648710b5d7f1c9e032c29b859f/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172", size = 359698, upload_time = "2025-09-25T19:50:31.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/f6/688d2cd64bfd0b14d805ddb8a565e11ca1fb0fd6817175d58b10052b6d88/bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683", size = 153725, upload_time = "2025-09-25T19:50:34.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/b9/9d9a641194a730bda138b3dfe53f584d61c58cd5230e37566e83ec2ffa0d/bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2", size = 150912, upload_time = "2025-09-25T19:50:35.69Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/44/d2ef5e87509158ad2187f4dd0852df80695bb1ee0cfe0a684727b01a69e0/bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927", size = 144953, upload_time = "2025-09-25T19:50:37.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/75/4aa9f5a4d40d762892066ba1046000b329c7cd58e888a6db878019b282dc/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7edda91d5ab52b15636d9c30da87d2cc84f426c72b9dba7a9b4fe142ba11f534", size = 271180, upload_time = "2025-09-25T19:50:38.575Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/79/875f9558179573d40a9cc743038ac2bf67dfb79cecb1e8b5d70e88c94c3d/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:046ad6db88edb3c5ece4369af997938fb1c19d6a699b9c1b27b0db432faae4c4", size = 273791, upload_time = "2025-09-25T19:50:39.913Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/fe/975adb8c216174bf70fc17535f75e85ac06ed5252ea077be10d9cff5ce24/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dcd58e2b3a908b5ecc9b9df2f0085592506ac2d5110786018ee5e160f28e0911", size = 270746, upload_time = "2025-09-25T19:50:43.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/f8/972c96f5a2b6c4b3deca57009d93e946bbdbe2241dca9806d502f29dd3ee/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6b8f520b61e8781efee73cba14e3e8c9556ccfb375623f4f97429544734545b4", size = 273375, upload_time = "2025-09-25T19:50:45.43Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blinker"
|
||||
version = "1.9.0"
|
||||
@@ -131,7 +201,9 @@ name = "debt-by-ai"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "bcrypt" },
|
||||
{ name = "flask" },
|
||||
{ name = "flask-login" },
|
||||
{ name = "google-genai" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "requests" },
|
||||
@@ -139,7 +211,9 @@ dependencies = [
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "bcrypt", specifier = ">=5.0.0" },
|
||||
{ name = "flask", specifier = ">=3.1.2" },
|
||||
{ name = "flask-login", specifier = ">=0.6.3" },
|
||||
{ name = "google-genai", specifier = ">=1.40.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
||||
{ name = "requests", specifier = ">=2.32.5" },
|
||||
@@ -162,6 +236,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308, upload_time = "2025-08-19T21:03:19.499Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flask-login"
|
||||
version = "0.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "flask" },
|
||||
{ name = "werkzeug" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/6e/2f4e13e373bb49e68c02c51ceadd22d172715a06716f9299d9df01b6ddb2/Flask-Login-0.6.3.tar.gz", hash = "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333", size = 48834, upload_time = "2023-10-30T14:53:21.151Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl", hash = "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d", size = 17303, upload_time = "2023-10-30T14:53:19.636Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-auth"
|
||||
version = "2.41.1"
|
||||
|
||||
Reference in New Issue
Block a user