-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
920 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[[source]] | ||
name = "pypi" | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
|
||
[dev-packages] | ||
|
||
[packages] | ||
flask = "*" | ||
flask-sqlalchemy = "*" | ||
python-decouple = "*" | ||
scikit-learn = "*" | ||
gunicorn = "*" | ||
psycopg2-binary = "*" | ||
psycopg2 = "*" | ||
|
||
[requires] | ||
python_version = "3.7" |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
web: gunicorn -w 4 twittoff:APP -t 120 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 11, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from sklearn.datasets import load_iris" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 12, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from sklearn.linear_model import LogisticRegression" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 13, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"X,y = load_iris(return_X_y=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 20, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# clf = LogisticRegression(random_state=0, solver='lbfgs', multi_class='multinomial').fit(X,y)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 21, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# dir(clf)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 23, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"array([0, 0])" | ||
] | ||
}, | ||
"execution_count": 23, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"clf.predict(X[:2, :])" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 14, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"\n", | ||
"def create_app():\n", | ||
" \"\"\"Create and configure an instance of the Flask app..\"\"\"\n", | ||
"\n", | ||
" app = Flask(__name__)\n", | ||
" app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'\n", | ||
" DB.init.app(app) \n", | ||
"\n", | ||
" @app.route('/')\n", | ||
" def index():\n", | ||
" return 'Index Page'\n", | ||
"\n", | ||
" @app.route('/hello')\n", | ||
" def hello():\n", | ||
" return render_template('base.html', title='Eels for Hovercrafts', users=User.query.all())\n", | ||
" \n", | ||
" return app\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.7.6" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 4 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .app import create_app | ||
|
||
APP = create_app() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from decouple import config | ||
from flask import Flask, render_template, request | ||
|
||
from .models import DB, User | ||
from .predict import predict_user | ||
from .twitter import add_or_update_user, update_all_users | ||
|
||
|
||
def create_app(): | ||
"""Create and configure an instance of the Flask application""" | ||
app = Flask(__name__) | ||
app.config['SQLALCHEMY_DATABASE_URI'] = config('DATABASE_URL') | ||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | ||
DB.init_app(app) | ||
|
||
@app.route('/') | ||
def root(): | ||
DB.create_all() | ||
return render_template('base.html', title='Home', users=User.query.all()) | ||
|
||
@app.route('/user', methods=['POST']) | ||
@app.route('/user/<name>', methods=['GET']) | ||
def user(name=None, message=''): | ||
name = name or request.values['user_name'] | ||
try: | ||
if request.method == 'POST': | ||
add_or_update_user(name) | ||
message = "User {} successfully added!".format(name) | ||
tweets = User.query.filter(User.name == name).one().tweets | ||
except Exception as e: | ||
message = "Error adding {}: {}".format(name, e) | ||
tweets = [] | ||
return render_template('user.html', title=name, tweets=tweets, message=message) | ||
|
||
@app.route('/compare', methods=['POST']) | ||
def compare(message=''): | ||
user1 = request.values['user1'] | ||
user2 = request.values['user2'] | ||
tweet_text = request.values['tweet_text'] | ||
|
||
if user1 == user2: | ||
message = 'Cannot compare a user to themselves!' | ||
else: | ||
prediction = predict_user(user1, user2, tweet_text) | ||
message = '"{}" is more likely to be said by {} than {}'.format( | ||
request.values['tweet_text'], user1 if prediction else user2, | ||
user2 if prediction else user1) | ||
return render_template('prediction.html', title='Prediction', message=message) | ||
|
||
@app.route('/reset') | ||
def reset(): | ||
DB.drop_all() | ||
DB.create_all() | ||
return render_template('base.html', title='Reset database!') | ||
|
||
@app.route('/update') | ||
def update(): | ||
update_all_users() | ||
return render_template('base.html', users=User.query.all(), title='All Tweets updated!') | ||
|
||
return app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from flask_sqlalchemy import SQLAlchemy | ||
|
||
DB = SQLAlchemy() | ||
|
||
|
||
class User(DB.Model): | ||
id = DB.Column(DB.BigInteger, primary_key=True) | ||
# id = DB.Column(DB.Integer, primary_key=True) | ||
name = DB.Column(DB.String(20), nullable=False) | ||
newest_tweet_id = DB.Column(DB.BigInteger) | ||
|
||
def __repr__(self): | ||
return '<User {}>'.format(self.name) | ||
|
||
|
||
class Tweet(DB.Model): | ||
id = DB.Column(DB.BigInteger, primary_key=True) | ||
text = DB.Column(DB.Unicode(500), nullable=False) | ||
embedding = DB.Column(DB.PickleType, nullable=False) | ||
user_id = DB.Column(DB.BigInteger, DB.ForeignKey('user.id'), nullable=False) | ||
user = DB.relationship("User", backref=DB.backref('tweets', lazy=True)) | ||
|
||
def __repr__(self): | ||
return '<Tweet {}>'.format(self.text) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
"""Prediction of Users based on Tweet embeddings.""" | ||
import numpy as np | ||
#from sklearn.linear_model import LogisticRegression | ||
from sklearn.neighbors import KNeighborsClassifier | ||
from .models import User | ||
from .twitter import BASILICA | ||
|
||
|
||
def predict_user(user1_name, user2_name, tweet_text): | ||
"""Determine and return which user is more likely to say a given Tweet.""" | ||
|
||
user1 = User.query.filter(User.name == user1_name).one() | ||
user2 = User.query.filter(User.name == user2_name).one() | ||
user1_embeddings = np.array([tweet.embedding for tweet in user1.tweets]) | ||
user2_embeddings = np.array([tweet.embedding for tweet in user2.tweets]) | ||
embeddings = np.vstack([user1_embeddings, user2_embeddings]) | ||
labels = np.concatenate([np.ones(len(user1.tweets)), | ||
np.zeros(len(user2.tweets))]) | ||
|
||
knnc = KNeighborsClassifier(weights='distance', metric='cosine').fit(embeddings, labels) | ||
tweet_embedding = BASILICA.embed_sentence(tweet_text, model='twitter') | ||
return knnc.predict(np.array(tweet_embedding).reshape(1, -1)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>TwitOff - {{ title }}</title> | ||
<link rel="stylesheet" href="https://unpkg.com/picnic"/> | ||
</head> | ||
<body> | ||
<nav> | ||
<a href="/" class="brand"><span>TwitOff!</span></a> | ||
|
||
<div class="menu"> | ||
<a href="/update" class="button warning">Update Tweets</a> | ||
</div> | ||
</nav> | ||
|
||
<article class="flex two" style="padding: 3em 1em;"> | ||
{% block content %} | ||
<div> | ||
<h1>{{ title }}</h1> | ||
|
||
<p>Select two users to compare:</p> | ||
|
||
<form action="/compare" method="post"> | ||
|
||
<select name="user1"> | ||
{% for user in users %} | ||
<option value="{{ user.name }}">{{ user.name }}</option> | ||
{% endfor %} | ||
</select> | ||
|
||
<select name="user2"> | ||
{% for user in users %} | ||
<option value="{{ user.name }}">{{ user.name }}</option> | ||
{% endfor %} | ||
</select> | ||
|
||
<input type="text" name="tweet_text" placeholder="Tweet text to predict"> | ||
<input type="submit" value="Compare Users"> | ||
|
||
</form> | ||
</div> | ||
|
||
<div> | ||
<h2>Twitter Users</h2> | ||
{% for user in users %} | ||
<a href="/user/{{ user.name }}"><span class="stack">{{ user.name }}</span></a> | ||
{% endfor %} | ||
<form action="/user" method="post"> | ||
<input type="text" name="user_name" placeholder="User to add"> | ||
<input type="submit" value="Add User"> | ||
</form> | ||
</div> | ||
|
||
{% endblock %} | ||
</article> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{% extends "base.html" %} | ||
{% block content %} | ||
<div id="prediction"> | ||
<h2>{{ title }}</h2> | ||
<p>{{ message }}</p> | ||
</div> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{% extends "base.html" %} | ||
{% block content %} | ||
<div id="user-info"> | ||
<h2>User: {{ title }}</h2> | ||
<p>{{ message }}</p> | ||
{% for tweet in tweets %} | ||
<span class="stack"><li>{{ tweet.id }} - {{ tweet.text }}</li></span> | ||
{% endfor %} | ||
</div> | ||
{% endblock %} |
Oops, something went wrong.