diff --git a/README.md b/README.md deleted file mode 100644 index 1fd837b..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# cmpe281-starks diff --git a/Recommendation System/Functional Flow b/Recommendation System/Functional Flow new file mode 100644 index 0000000..d9b46cc --- /dev/null +++ b/Recommendation System/Functional Flow @@ -0,0 +1 @@ +RE diff --git a/Recommendation System/app.py b/Recommendation System/app.py new file mode 100644 index 0000000..7e89198 --- /dev/null +++ b/Recommendation System/app.py @@ -0,0 +1,7 @@ +from re import app +import os + +app.secret_key = os.urandom(24) +port = int(os.environ.get('PORT', 5000)) +app.run(host='0.0.0.0', port=port) + diff --git a/Recommendation System/re/__init__.py b/Recommendation System/re/__init__.py new file mode 100644 index 0000000..11e246c --- /dev/null +++ b/Recommendation System/re/__init__.py @@ -0,0 +1,2 @@ +from .views import app +from .models import graph diff --git a/Recommendation System/re/models.py b/Recommendation System/re/models.py new file mode 100644 index 0000000..1f7700a --- /dev/null +++ b/Recommendation System/re/models.py @@ -0,0 +1,125 @@ +from py2neo import Graph, Node, Relationship +from passlib.hash import bcrypt +from datetime import datetime +import os +import uuid + +url = os.environ.get('GRAPHENEDB_URL', 'http://localhost:7474') +username = os.environ.get('NEO4J_USERNAME') +password = os.environ.get('NEO4J_PASSWORD') + +graph = Graph(url + '/db/data/', username=username, password=password) + +class User: + def __init__(self, username): + self.username = username + + def find(self): + user = graph.find_one('User', 'username', self.username) + return user + + def register(self, password): + if not self.find(): + user = Node('User', username=self.username, password=bcrypt.encrypt(password)) + graph.create(user) + return True + else: + return False + + def verify_password(self, password): + user = self.find() + if user: + return bcrypt.verify(password, user['password']) + else: + return False + + def add_post(self, title, tags, text): + user = self.find() + post = Node( + 'Post', + id=str(uuid.uuid4()), + title=title, + text=text, + timestamp=timestamp(), + date=date() + ) + rel = Relationship(user, 'PUBLISHED', post) + graph.create(rel) + + tags = [x.strip() for x in tags.lower().split(',')] + for name in set(tags): + tag = Node('Tag', name=name) + graph.merge(tag) + + rel = Relationship(tag, 'TAGGED', post) + graph.create(rel) + + def like_post(self, post_id): + user = self.find() + post = graph.find_one('Post', 'id', post_id) + graph.merge(Relationship(user, 'LIKED', post)) + + def get_recent_posts(self): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE user.username = {username} + RETURN post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, username=self.username) + + def get_products(self): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE user.username = {username} + RETURN post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, username=self.username) + + def get_similar_users(self): + + query = ''' + MATCH (you:User)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag:Tag), + (they:User)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag) + WHERE you.username = {username} AND you <> they + WITH they, COLLECT(DISTINCT tag.name) AS tags + ORDER BY SIZE(tags) DESC LIMIT 3 + RETURN they.username AS similar_user, tags + ''' + + return graph.run(query, username=self.username) + + def get_commonality_of_user(self, other): + + query = ''' + MATCH (they:User {username: {they} }) + MATCH (you:User {username: {you} }) + OPTIONAL MATCH (they)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag:Tag), + (you)-[:PUBLISHED]->(:Post)<-[:TAGGED]-(tag) + RETURN SIZE((they)-[:LIKED]->(:Post)<-[:PUBLISHED]-(you)) AS likes, + COLLECT(DISTINCT tag.name) AS tags + ''' + + return graph.run(query, they=other.username, you=self.username).next + +def get_todays_recent_posts(): + query = ''' + MATCH (user:User)-[:PUBLISHED]->(post:Post)<-[:TAGGED]-(tag:Tag) + WHERE post.date = {today} + RETURN user.username AS username, post, COLLECT(tag.name) AS tags + ORDER BY post.timestamp DESC LIMIT 5 + ''' + + return graph.run(query, today=date()) + +def timestamp(): + epoch = datetime.utcfromtimestamp(0) + now = datetime.now() + delta = now - epoch + return delta.total_seconds() + +def date(): + return datetime.now().strftime('%Y-%m-%d') diff --git a/Recommendation System/re/static/style.css b/Recommendation System/re/static/style.css new file mode 100644 index 0000000..c6b030f --- /dev/null +++ b/Recommendation System/re/static/style.css @@ -0,0 +1,15 @@ +body { font-family: sans-serif; background: #eee; } +a, h1, h3 { color: #377ba8; } +h1, h2, h3 { font-family: 'Georgia', serif; margin: 0; } +h1, h2 { border-bottom: 2px solid #eee; padding: 3px; } +h3 { padding: 3px; } +dd { display: block; margin-left: 0px; } +dl { font-weight: bold; } +a:visited { color: #800080; } +.page { margin: 2em auto; width: 35em; border: 5px solid #ccc; padding: 0.8em; background: white; } +.posts { list-style: none; margin: 0; padding: 0; } +.posts li { margin: 0.8em 1.2em; } +.posts li h2 { margin-left: -1em; } +.metanav { text-align: right; font-size: 0.8em; padding: 0.3em; margin-bottom: 1em; background: #fafafa; } +.flash { background: #cee5F5; padding: 0.5em; border: 1px solid #aacbe2; } +.error { background: #f0d6d6; padding: 0.5em; } diff --git a/Recommendation System/re/templates/display_host b/Recommendation System/re/templates/display_host new file mode 100644 index 0000000..c51578f --- /dev/null +++ b/Recommendation System/re/templates/display_host @@ -0,0 +1,15 @@ +
+ {{ user.similar_user }} + also purchased {{ ", ".join(user.tags) }} {{ ", ".join(user.posts) }} +
+ {% else %} +There aren't any users who've purchased products the same category as you!
+ {% endfor %} + ++ {{ product.post.title }} +
+ + + {% else %} +There aren't any users who've purchased products the same category as you!
+ {% endfor %} + +{{ username }} has liked {{ common.likes }} of your purchases and + {% if common.tags %} + also purchased {{ ", ".join(common.tags) }} + {% else %} + hasn't purchased any of the same category + {% endif %} +
+ +