moved to server
Update readme.md Signed-off-by: rasmus <rsbendtsen@gmail.com> Update readme.md Update Dockerfile Update Dockerfile
This commit is contained in:
207
app.py
Normal file
207
app.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from flask import Flask, render_template, redirect, url_for, request, flash
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_login import (
|
||||
LoginManager,
|
||||
UserMixin,
|
||||
login_user,
|
||||
login_required,
|
||||
logout_user,
|
||||
current_user,
|
||||
)
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from openai import OpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
OPENROUTER_API_KEY=os.environ.get("OPENROUTER_API_KEY")
|
||||
OPENROUTER_MODEL=os.environ.get("OPENROUTER_MODEL")
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///mealplan.db"
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
login_manager = LoginManager(app)
|
||||
login_manager.login_view = "login"
|
||||
|
||||
# Anvender Open-router
|
||||
client = OpenAI(
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
api_key=OPENROUTER_API_KEY,
|
||||
default_headers={
|
||||
"HTTP-Referer": "http://localhost:5000",
|
||||
"X-Title": "ChefGPT Meal Planner",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# --- Models ---
|
||||
class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(150), unique=True, nullable=False)
|
||||
password = db.Column(db.String(150), nullable=False)
|
||||
plans = db.relationship("MealPlan", backref="creator", lazy=True)
|
||||
|
||||
|
||||
class MealPlan(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
summary = db.Column(db.Text, nullable=False)
|
||||
shopping = db.Column(db.Text, nullable=False)
|
||||
recipes = db.Column(db.Text, nullable=False)
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
||||
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html",source_link=os.environ.get("SOURCECODE_LINK"))
|
||||
|
||||
@app.route("/about")
|
||||
def about():
|
||||
return render_template("about.html")
|
||||
|
||||
@app.route("/logout")
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/dashboard")
|
||||
@login_required
|
||||
def dashboard():
|
||||
# Show the user's previous plans
|
||||
plans = (
|
||||
MealPlan.query.filter_by(user_id=current_user.id)
|
||||
.order_by(MealPlan.id.desc())
|
||||
.limit(3)
|
||||
.all()
|
||||
)
|
||||
return render_template("dashboard.html", plans=plans)
|
||||
|
||||
|
||||
@app.route("/plan/<int:plan_id>")
|
||||
@login_required
|
||||
def view_plan(plan_id):
|
||||
plan = MealPlan.query.get_or_404(plan_id)
|
||||
if plan.user_id != current_user.id:
|
||||
flash("You do not have permission to view this plan.")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
return render_template("plan_result.html", plan=plan)
|
||||
|
||||
|
||||
@app.route("/generate", methods=["POST"])
|
||||
@login_required
|
||||
def generate():
|
||||
data = {
|
||||
"people_count": request.form.get("people_count"),
|
||||
"budget_level": request.form.get("budget_level"),
|
||||
"max_cooking_time": request.form.get("max_cooking_time"),
|
||||
"skill_level": request.form.get("skill_level"),
|
||||
"dietary_focus": request.form.get("dietary_focus"),
|
||||
"dietary_preference": request.form.get("dietary_preference"),
|
||||
"meal_strategy": request.form.get("meal_strategy"),
|
||||
"fridge_items": request.form.get("fridge_items") or "None (start from scratch)",
|
||||
"output_language": request.form.get("output_language", "English"),
|
||||
}
|
||||
|
||||
try:
|
||||
with open("system_prompt.txt", "r", encoding="utf-8") as f:
|
||||
prompt_template = f.read()
|
||||
|
||||
# indsætter formular parametre i systemprompt
|
||||
final_prompt = prompt_template.format(**data)
|
||||
except FileNotFoundError:
|
||||
flash("System prompt file missing. Please contact admin.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
# Anvender open-router free modeller
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model=OPENROUTER_MODEL,
|
||||
messages=[{"role": "system", "content": final_prompt}],
|
||||
temperature=0.7,
|
||||
)
|
||||
ai_output = response.choices[0].message.content
|
||||
|
||||
except Exception as e:
|
||||
flash(f"AI Service Error: {str(e)}", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
# begynder parsing af AI svaret. Svaret skal leve op til formatkravet for at det kan indlæses pænt
|
||||
def extract_section(text, start_tag, end_tag):
|
||||
start = text.find(start_tag)
|
||||
end = text.find(end_tag)
|
||||
|
||||
if start == -1 or end == -1 or end <= start:
|
||||
return None
|
||||
|
||||
return text[start + len(start_tag) : end].strip()
|
||||
|
||||
desc = extract_section(ai_output, "[[DESCRIPTION_START]]", "[[DESCRIPTION_END]]")
|
||||
summ = extract_section(ai_output, "[[SUMMARY_START]]", "[[SUMMARY_END]]")
|
||||
shop = extract_section(ai_output, "[[SHOPPING_START]]", "[[SHOPPING_END]]")
|
||||
reci = extract_section(ai_output, "[[RECIPES_START]]", "[[RECIPES_END]]")
|
||||
|
||||
if not all([desc, summ, shop, reci]):
|
||||
flash("The plan could not be generated. Please try generating again.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
# hvis AI svaret levede op til format kravet, gemmes det i db
|
||||
try:
|
||||
new_plan = MealPlan(
|
||||
description=desc,
|
||||
summary=summ,
|
||||
shopping=shop,
|
||||
recipes=reci,
|
||||
user_id=current_user.id,
|
||||
)
|
||||
db.session.add(new_plan)
|
||||
db.session.commit()
|
||||
|
||||
return redirect(url_for("view_plan", plan_id=new_plan.id))
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
flash(f"Database Error: {str(e)}", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if request.method == "POST":
|
||||
user = User.query.filter_by(username=request.form.get("username")).first()
|
||||
if user and check_password_hash(user.password, request.form.get("password")):
|
||||
login_user(user)
|
||||
return redirect(url_for("dashboard"))
|
||||
flash("Invalid credentials")
|
||||
return render_template("login.html")
|
||||
|
||||
|
||||
@app.route("/register", methods=["GET", "POST"])
|
||||
def register():
|
||||
if request.method == "POST":
|
||||
new_user = User(
|
||||
username=request.form.get("username"),
|
||||
password=generate_password_hash(
|
||||
request.form.get("password"), method="pbkdf2:sha256"
|
||||
),
|
||||
)
|
||||
db.session.add(new_user)
|
||||
db.session.commit()
|
||||
return redirect(url_for("/"))
|
||||
return render_template("register.html")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
app.run()
|
||||
Reference in New Issue
Block a user