From 2e0b9c97af457da5c6afda611d48e59047d4cdb8 Mon Sep 17 00:00:00 2001
From: JJ
Date: Mon, 31 Mar 2025 21:08:41 +0100
Subject: Basic AI functionality
---
.Constants.py.swp | Bin 0 -> 12288 bytes
.gitignore | 1 +
AIParams.py | 25 ++++++++++++++++
scripts/database/mongo.py | 11 +++++--
scripts/recipes/handle_recipes.py | 2 ++
scripts/scraping/ai_scraping.py | 19 +++++++++++++
scripts/scraping/scraper.py | 3 +-
scripts/users/handle_users.py | 10 ++++++-
server.py | 28 +++++++++++++++---
static/images/bars.svg | 2 +-
static/scripts/index.js | 57 +++++++++++++++++++++++++++++++------
static/style/style.css | 8 ++++++
templates/base.html | 1 -
templates/pages/about.html | 9 ++++++
templates/pages/account.html | 21 ++++++++++++--
templates/pages/home.html | 2 +-
templates/pages/single-recipe.html | 14 +++++++--
17 files changed, 186 insertions(+), 27 deletions(-)
create mode 100644 .Constants.py.swp
create mode 100644 AIParams.py
create mode 100644 scripts/scraping/ai_scraping.py
diff --git a/.Constants.py.swp b/.Constants.py.swp
new file mode 100644
index 0000000..ffb1f96
Binary files /dev/null and b/.Constants.py.swp differ
diff --git a/.gitignore b/.gitignore
index e6a7493..7b214bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ htmlcov/
.tox/
docs/_build/
Constants.py
+AIParams.py
diff --git a/AIParams.py b/AIParams.py
new file mode 100644
index 0000000..aab8ac3
--- /dev/null
+++ b/AIParams.py
@@ -0,0 +1,25 @@
+RECIPE_SCHEMA = {
+ 'title': str,
+ 'slug': str,
+ 'image': str,
+ 'url': str,
+ 'tags': list[str],
+ 'ingredients': list[str],
+ 'instructions': list[str]
+}
+
+PROMPT = """
+Extract data from the following text in the schema format provided.
+
+SCHEMA:
+
+{schema}
+
+DATA:
+
+{markdown}
+"""
+
+SYSTEM_INSTRUCTIONS="You are responsible for taking the inputted markdown text and generating a structure response from it. See the Schema provided."
+
+
diff --git a/scripts/database/mongo.py b/scripts/database/mongo.py
index 3e97b0b..eaa2d97 100644
--- a/scripts/database/mongo.py
+++ b/scripts/database/mongo.py
@@ -3,7 +3,12 @@ from pymongo.server_api import ServerApi
import Constants
import certifi
-uri = Constants.MONGO_CONNECTION_STRING
+uri = Constants.MONGO_CONNECTION_STRING if Constants.MODE == "production" else Constants.MONGO_CONNECTION_STRING_DEV
+database_str = "index-cooking" if Constants.MODE == "production" else "recipedb"
-client = MongoClient(uri, server_api=ServerApi('1'), tlsCAFile=certifi.where())
-mongo_database = client["index-cooking"]
\ No newline at end of file
+if Constants.MODE == "production":
+ client = MongoClient(uri, server_api=ServerApi('1'), tlsCAFile=certifi.where())
+else:
+ client = MongoClient(uri)
+
+mongo_database = client["index-cooking"]
diff --git a/scripts/recipes/handle_recipes.py b/scripts/recipes/handle_recipes.py
index 22ba0a4..73d19be 100644
--- a/scripts/recipes/handle_recipes.py
+++ b/scripts/recipes/handle_recipes.py
@@ -1,10 +1,12 @@
from bson.objectid import ObjectId
+from flask import session
from scripts.database.mongo import mongo_database
from scripts.scraping.scraper import scrape
mongo_collection = mongo_database.get_collection("recipes")
def add_single_recipe(recipe):
+ recipe["user"] = session["username"]
added_recipe = mongo_collection.insert_one(recipe)
new_recipe = mongo_collection.find_one()
return added_recipe
diff --git a/scripts/scraping/ai_scraping.py b/scripts/scraping/ai_scraping.py
new file mode 100644
index 0000000..b11a12b
--- /dev/null
+++ b/scripts/scraping/ai_scraping.py
@@ -0,0 +1,19 @@
+from google import genai
+import json
+import requests
+import Constants
+import AIParams
+
+client = genai.Client(api_key="AIzaSyAdB7yo0qcnwHeC4T2rRaSXD588JRw94oQ")
+
+def run_ai_query(url):
+ req_url = f"https://r.jina.ai/{url}"
+ res = requests.get(req_url)
+ markdown_content = res.text
+
+ prompt = AIParams.PROMPT.format(schema=AIParams.RECIPE_SCHEMA, markdown=markdown_content)
+
+ ai_res = client.models.generate_content(model="gemini-2.0-flash", contents=prompt)
+ cleaned_text = ai_res.text.strip("```").strip("```json")
+ recipe_json = json.loads(cleaned_text)
+ return {"success": True, "data": recipe_json}
diff --git a/scripts/scraping/scraper.py b/scripts/scraping/scraper.py
index 8919d46..0e0b9c8 100644
--- a/scripts/scraping/scraper.py
+++ b/scripts/scraping/scraper.py
@@ -25,7 +25,7 @@ def extractInstructions(instructions):
return returnedInstructions
-def scrape(url, user_name):
+def scrape(url):
try:
data = requests.get(url, headers= {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"})
html = BeautifulSoup(data.text, 'html.parser')
@@ -43,7 +43,6 @@ def scrape(url, user_name):
slug = parse.quote(i["name"]).lower()
# The recipe
- recipe["user"] = user_name
recipe["slug"] = slug
recipe["title"] = i["name"]
recipe["image"] = i["image"][0]
diff --git a/scripts/users/handle_users.py b/scripts/users/handle_users.py
index 250c716..7a315f1 100644
--- a/scripts/users/handle_users.py
+++ b/scripts/users/handle_users.py
@@ -23,4 +23,12 @@ def delete_single_user(user):
mongo_collection.delete_one({"name": user})
return {"success": True, "user": user}
except:
- return {"success": False, "user": user}
\ No newline at end of file
+ return {"success": False, "user": user}
+
+def update_user(user, user_prefs):
+ print(user, user_prefs, "in user handler")
+ try:
+ res = mongo_collection.update_one({"name": user}, {"$set": user_prefs})
+ return {"success": True, "message": "user preferences successfully updated"}
+ except Exception as e:
+ return {"success": False, "message": str(e)}
diff --git a/server.py b/server.py
index 7840ea3..66c2d43 100644
--- a/server.py
+++ b/server.py
@@ -3,9 +3,11 @@ from flask_bcrypt import Bcrypt
import functools
import re
import Constants
+from urllib.parse import urlparse
from scripts.scraping.scraper import scrape
+from scripts.scraping.ai_scraping import run_ai_query
from scripts.recipes.handle_recipes import recipe_exists, add_single_recipe, get_all_recipes, get_single_recipe, get_facets, delete_single_recipe, search_recipes, delete_multiple_recipes
-from scripts.users.handle_users import user_exists, add_user, delete_single_user
+from scripts.users.handle_users import user_exists, add_user, delete_single_user, update_user
app = Flask(__name__)
bcrypt = Bcrypt(app)
@@ -25,7 +27,6 @@ def login_required(func):
@app.route("/home")
@login_required
def home_page():
- print(session["username"])
tags = get_facets(session["username"])
all_recipes = get_all_recipes(session["username"])
return render_template("/pages/home.html",recipes=all_recipes, facets=tags)
@@ -79,15 +80,22 @@ def add_recipe():
if does_recipe_exist:
return "Recipe already exists!", 422
else:
- response = scrape(submitted_url, session["username"])
+ response = scrape(submitted_url)
if response["success"]:
add_single_recipe(response["data"])
all_recipes = get_all_recipes(session["username"])
all_facets = get_facets(session["username"])
return render_template("/components/app.html", recipes=all_recipes, facets=all_facets)
+
+ elif not response["success"]:
+ ai_res = run_ai_query(submitted_url)
+ add_single_recipe(ai_res["data"])
+ all_recipes = get_all_recipes(session["username"])
+ all_facets = get_facets(session["username"])
+ return render_template("/components/app.html", recipes=all_recipes, facets=all_facets)
else:
- return f"Error processing recipe metadata, {response['error']} ", 422
+ return "something went wrong", 400
@app.post("/recipes/search")
@@ -168,6 +176,18 @@ def delete_user():
return Response(headers={"HX-Redirect": "/"})
else:
return "Something went wrong deleting the user and recipes"
+
+@app.post("/update-account")
+def update_account():
+ user_prefs = request.form.to_dict()
+ response = update_user(session["username"], user_prefs)
+
+ if response["success"]:
+ session["isAiSubscriber"] = True
+ return Response(headers={"HX-Redirect": "/account"})
+ else:
+ return f"{response["message"]}", 422
+
if __name__ == "__main__":
app.run(host="0.0.0.0")
diff --git a/static/images/bars.svg b/static/images/bars.svg
index 64dd5a8..8ce0f06 100644
--- a/static/images/bars.svg
+++ b/static/images/bars.svg
@@ -1,4 +1,4 @@
-
+
+Instructions
+
+Using the website is very simple. Once you login go to bad: www.example.com/awesome-recipe
+good: https://www.example.com/awesome-recipes
{% endblock %}
diff --git a/templates/pages/account.html b/templates/pages/account.html
index 10a3789..063d924 100644
--- a/templates/pages/account.html
+++ b/templates/pages/account.html
@@ -1,6 +1,4 @@
{% extends "base.html" %} {% block scripts %}
-
-
+
+{% endblock %}
+
+{% block heading %} {{ single_recipe.title }} {%
endblock %} {% block content %}
Source
- Ingredients
-
+ Ingredients📋
+
{% for ingredient in single_recipe.ingredients %}
- {{ ingredient }}
{% endfor %}
--
cgit v1.2.3