├── flaskSaaS-master ├── _gitignore ├── _dockerignore ├── _DS_Store ├── app │ ├── app.db │ ├── _DS_Store │ ├── forms │ │ ├── mmm.jpg │ │ ├── hqdefault.jpg │ │ ├── chest-example.png │ │ ├── __pycache__ │ │ │ ├── user.cpython-36.pyc │ │ │ └── __init__.cpython-36.pyc │ │ └── user.py │ ├── templates │ │ ├── _DS_Store │ │ ├── admin │ │ │ └── index.html │ │ ├── logo.png │ │ ├── user │ │ │ ├── account.html │ │ │ ├── buy.html │ │ │ ├── forgot.html │ │ │ ├── charge.html │ │ │ ├── reset.html │ │ │ ├── signup.html │ │ │ └── signin.html │ │ ├── email │ │ │ ├── reset.html │ │ │ └── confirm.html │ │ ├── contact.html │ │ ├── error.html │ │ ├── index.html │ │ ├── macros.html │ │ ├── uploaded.html │ │ ├── map.html │ │ └── layout.html │ ├── static │ │ ├── img │ │ │ ├── error.png │ │ │ └── favicon.ico │ │ └── css │ │ │ └── custom.css │ ├── __pycache__ │ │ ├── admin.cpython-36.pyc │ │ ├── config.cpython-36.pyc │ │ ├── models.cpython-36.pyc │ │ ├── __init__.cpython-36.pyc │ │ ├── logger_setup.cpython-36.pyc │ │ └── config_common.cpython-36.pyc │ ├── views │ │ ├── __pycache__ │ │ │ ├── main.cpython-36.pyc │ │ │ ├── user.cpython-36.pyc │ │ │ ├── error.cpython-36.pyc │ │ │ └── __init__.cpython-36.pyc │ │ ├── error.py │ │ ├── main.py │ │ └── user.py │ ├── toolbox │ │ ├── __pycache__ │ │ │ ├── email.cpython-36.pyc │ │ │ └── __init__.cpython-36.pyc │ │ └── email.py │ ├── config_common.py │ ├── config_prod.py │ ├── config.py │ ├── config_dev.py │ ├── admin.py │ ├── models.py │ ├── __init__.py │ └── logger_setup.py ├── hqdefault.jpg ├── screenshots │ ├── map.png │ ├── sign_in.png │ ├── sign_up.png │ ├── admin_auth.png │ └── admin_panel.png ├── nginx │ ├── Dockerfile │ └── sites-enabled │ │ └── api.openbikes.co ├── docker-compose.yml ├── _pylintrc ├── requirements.txt ├── Makefile ├── Dockerfile ├── manage.py ├── LICENSE └── README.md ├── app ├── app.db ├── _DS_Store ├── forms │ ├── mmm.jpg │ ├── hqdefault.jpg │ ├── chest-example.png │ ├── __pycache__ │ │ ├── user.cpython-36.pyc │ │ └── __init__.cpython-36.pyc │ └── user.py ├── templates │ ├── _DS_Store │ ├── logo.png │ ├── admin │ │ └── index.html │ ├── user │ │ ├── account.html │ │ ├── buy.html │ │ ├── forgot.html │ │ ├── charge.html │ │ ├── reset.html │ │ ├── signup.html │ │ └── signin.html │ ├── email │ │ ├── reset.html │ │ └── confirm.html │ ├── contact.html │ ├── error.html │ ├── index.html │ ├── macros.html │ ├── uploaded.html │ ├── map.html │ └── layout.html ├── static │ ├── img │ │ ├── error.png │ │ └── favicon.ico │ └── css │ │ └── custom.css ├── __pycache__ │ ├── admin.cpython-36.pyc │ ├── config.cpython-36.pyc │ ├── models.cpython-36.pyc │ ├── __init__.cpython-36.pyc │ ├── logger_setup.cpython-36.pyc │ └── config_common.cpython-36.pyc ├── views │ ├── __pycache__ │ │ ├── error.cpython-36.pyc │ │ ├── main.cpython-36.pyc │ │ ├── user.cpython-36.pyc │ │ └── __init__.cpython-36.pyc │ ├── error.py │ ├── main.py │ └── user.py ├── toolbox │ ├── __pycache__ │ │ ├── email.cpython-36.pyc │ │ └── __init__.cpython-36.pyc │ └── email.py ├── config_common.py ├── config_prod.py ├── config.py ├── config_dev.py ├── admin.py ├── models.py ├── __init__.py └── logger_setup.py ├── README.md ├── BuildanAIStartup.ipynb └── Transfer_Learning.ipynb /flaskSaaS-master/_gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.log 3 | *.pyc 4 | config.py 5 | -------------------------------------------------------------------------------- /flaskSaaS-master/_dockerignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.log 3 | *.pyc 4 | .git/ 5 | config.py 6 | -------------------------------------------------------------------------------- /app/app.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/app.db -------------------------------------------------------------------------------- /app/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/_DS_Store -------------------------------------------------------------------------------- /app/forms/mmm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/forms/mmm.jpg -------------------------------------------------------------------------------- /app/forms/hqdefault.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/forms/hqdefault.jpg -------------------------------------------------------------------------------- /app/templates/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/templates/_DS_Store -------------------------------------------------------------------------------- /app/templates/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/templates/logo.png -------------------------------------------------------------------------------- /app/static/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/static/img/error.png -------------------------------------------------------------------------------- /app/forms/chest-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/forms/chest-example.png -------------------------------------------------------------------------------- /app/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/static/img/favicon.ico -------------------------------------------------------------------------------- /flaskSaaS-master/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/_DS_Store -------------------------------------------------------------------------------- /flaskSaaS-master/app/app.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/app.db -------------------------------------------------------------------------------- /flaskSaaS-master/app/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/_DS_Store -------------------------------------------------------------------------------- /flaskSaaS-master/hqdefault.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/hqdefault.jpg -------------------------------------------------------------------------------- /app/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | Welcome admin. 5 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/mmm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/forms/mmm.jpg -------------------------------------------------------------------------------- /app/__pycache__/admin.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/admin.cpython-36.pyc -------------------------------------------------------------------------------- /app/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /app/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/screenshots/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/screenshots/map.png -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/hqdefault.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/forms/hqdefault.jpg -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/templates/_DS_Store -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | Welcome admin. 5 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/templates/logo.png -------------------------------------------------------------------------------- /flaskSaaS-master/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tutum/nginx 2 | RUN rm /etc/nginx/sites-enabled/default 3 | ADD sites-enabled/ /etc/nginx/sites-enabled 4 | -------------------------------------------------------------------------------- /flaskSaaS-master/screenshots/sign_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/screenshots/sign_in.png -------------------------------------------------------------------------------- /flaskSaaS-master/screenshots/sign_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/screenshots/sign_up.png -------------------------------------------------------------------------------- /app/__pycache__/logger_setup.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/logger_setup.cpython-36.pyc -------------------------------------------------------------------------------- /app/forms/__pycache__/user.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/forms/__pycache__/user.cpython-36.pyc -------------------------------------------------------------------------------- /app/views/__pycache__/error.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/views/__pycache__/error.cpython-36.pyc -------------------------------------------------------------------------------- /app/views/__pycache__/main.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/views/__pycache__/main.cpython-36.pyc -------------------------------------------------------------------------------- /app/views/__pycache__/user.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/views/__pycache__/user.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/static/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/static/img/error.png -------------------------------------------------------------------------------- /flaskSaaS-master/app/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/static/img/favicon.ico -------------------------------------------------------------------------------- /flaskSaaS-master/screenshots/admin_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/screenshots/admin_auth.png -------------------------------------------------------------------------------- /app/__pycache__/config_common.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/__pycache__/config_common.cpython-36.pyc -------------------------------------------------------------------------------- /app/forms/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/forms/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /app/toolbox/__pycache__/email.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/toolbox/__pycache__/email.cpython-36.pyc -------------------------------------------------------------------------------- /app/views/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/views/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/chest-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/forms/chest-example.png -------------------------------------------------------------------------------- /flaskSaaS-master/screenshots/admin_panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/screenshots/admin_panel.png -------------------------------------------------------------------------------- /app/toolbox/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/app/toolbox/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/admin.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/admin.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/__pycache__/user.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/forms/__pycache__/user.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/__pycache__/main.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/views/__pycache__/main.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/__pycache__/user.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/views/__pycache__/user.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/logger_setup.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/logger_setup.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/__pycache__/error.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/views/__pycache__/error.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/__pycache__/config_common.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/__pycache__/config_common.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/forms/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/toolbox/__pycache__/email.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/toolbox/__pycache__/email.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/views/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flaskSaaS-master/app/toolbox/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llSourcell/AI_Startup_Prototype/HEAD/flaskSaaS-master/app/toolbox/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /app/templates/user/account.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |

Hi {{ current_user.full_name }}!

10 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/email/reset.html: -------------------------------------------------------------------------------- 1 | Please click on the following link to reset your password: 2 | 3 |

4 | {{ reset_url }} 5 |

6 | 7 |

8 | --
9 | Flask boilerplate, by Max Halford. 10 |

-------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/account.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |

Hi {{ current_user.full_name }}!

10 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/email/confirm.html: -------------------------------------------------------------------------------- 1 | Please click on the following link to confirm your email address: 2 | 3 |

4 | {{ confirm_url }} 5 |

6 | 7 |

8 | --
9 | Flask boilerplate, by Max Halford. 10 |

-------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/email/reset.html: -------------------------------------------------------------------------------- 1 | Please click on the following link to reset your password: 2 | 3 |

4 | {{ reset_url }} 5 |

6 | 7 |

8 | --
9 | Flask boilerplate, by Max Halford. 10 |

-------------------------------------------------------------------------------- /flaskSaaS-master/docker-compose.yml: -------------------------------------------------------------------------------- 1 | web: 2 | restart: always 3 | build: ./ 4 | expose: 5 | - "8000" 6 | command: /usr/local/bin/gunicorn -w 2 -b :8000 app:app 7 | 8 | nginx: 9 | restart: always 10 | build: ./nginx/ 11 | ports: 12 | - "80:80" 13 | links: 14 | - web:web 15 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/email/confirm.html: -------------------------------------------------------------------------------- 1 | Please click on the following link to confirm your email address: 2 | 3 |

4 | {{ confirm_url }} 5 |

6 | 7 |

8 | --
9 | Flask boilerplate, by Max Halford. 10 |

-------------------------------------------------------------------------------- /flaskSaaS-master/_pylintrc: -------------------------------------------------------------------------------- 1 | [FORMAT] 2 | max-line-length=100 3 | indent-string=' ' 4 | 5 | [REPORTS] 6 | files-output=no 7 | reports=yes 8 | evaluation=10 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 9 | 10 | [TYPECHECK] 11 | ignored-modules=flask_sqlalchemy 12 | ignored-classes=SQLObject,SQLAlchemy,Base 13 | -------------------------------------------------------------------------------- /app/templates/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |

{{ title }}

10 | 11 | {% if current_user.is_authenticated %} 12 |

Hi {{ current_user.name }}!

13 | {% endif %} 14 | 15 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |

{{ title }}

10 | 11 | {% if current_user.is_authenticated %} 12 |

Hi {{ current_user.name }}!

13 | {% endif %} 14 | 15 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/nginx/sites-enabled/api.openbikes.co: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | server_name openbikes.co; 5 | charset utf-8; 6 | 7 | location / { 8 | proxy_pass http://web:8000; 9 | proxy_set_header Host $host; 10 | proxy_set_header X-Real-IP $remote_addr; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/templates/error.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 | 11 |

{{ message }}

12 |

13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/error.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 | 11 |

{{ message }}

12 |

13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/requirements.txt: -------------------------------------------------------------------------------- 1 | Tensorflow==1.13.1 2 | Keras==2.2.4 3 | Flask==0.10.1 4 | Flask-Admin==1.3.0 5 | Flask-Bcrypt==0.7.1 6 | Flask-DebugToolbar==0.10.0 7 | Flask-Login==0.3.2 8 | Flask-Mail==0.9.1 9 | Flask-Script==2.0.5 10 | Flask-SQLAlchemy==2.1 11 | Flask-WTF==0.12 12 | gunicorn==19.4.5 13 | itsdangerous==0.24 14 | pytz==2016.10 15 | structlog==16.1.0 16 | termcolor==1.1.0 17 | WTForms==2.1 18 | stripe==2.23.0 19 | -------------------------------------------------------------------------------- /flaskSaaS-master/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | ## Configuration 4 | 5 | BUILD_TIME := $(shell date +%FT%T%z) 6 | PROJECT := $(shell basename $(PWD)) 7 | 8 | 9 | ## Install dependencies 10 | .PHONY: install 11 | install: 12 | pip install -r requirements.txt 13 | 14 | ## Setup developpement environment 15 | .PHONY: dev 16 | dev: 17 | cd app && ln -sf config_dev.py config.py 18 | 19 | ## Setup production environment 20 | .PHONY: prod 21 | prod: 22 | cd app && ln -sf config_prod.py config.py 23 | -------------------------------------------------------------------------------- /app/templates/user/buy.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block content %} 3 |
4 |
5 | 8 |
9 | 10 | 16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/buy.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block content %} 3 |
4 |
5 | 8 |
9 | 10 | 16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/user/forgot.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Enter your email address so that we can send you a password reset link

12 | {{ m.render_field(form.email) }} 13 | {{ form.csrf_token }} 14 | 15 |
16 |
17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /app/views/error.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | from app import app 3 | 4 | 5 | @app.errorhandler(403) 6 | def forbidden(e): 7 | return render_template('error.html', message='403 forbidden'), 403 8 | 9 | 10 | @app.errorhandler(404) 11 | def page_not_found(e): 12 | return render_template('error.html', message='404 not found'), 404 13 | 14 | 15 | @app.errorhandler(410) 16 | def gone(e): 17 | return render_template('error.html', message='410 gone'), 410 18 | 19 | 20 | @app.errorhandler(500) 21 | def internal_error(e): 22 | return render_template('error.html', message='500 internal error'), 500 23 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/forgot.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Enter your email address so that we can send you a password reset link

12 | {{ m.render_field(form.email) }} 13 | {{ form.csrf_token }} 14 | 15 |
16 |
17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/user/charge.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block content %} 3 | 4 |

Thanks, you paid $10.00!

5 |

Upload your image below

6 |
7 | 8 |
10 | 11 | 12 |
13 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/user/reset.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Choose a new password

12 | {{ m.render_field(form.password) }} 13 | {{ m.render_field(form.confirm) }} 14 | {{ form.csrf_token }} 15 | 16 |
17 |
18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/error.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | from app import app 3 | 4 | 5 | @app.errorhandler(403) 6 | def forbidden(e): 7 | return render_template('error.html', message='403 forbidden'), 403 8 | 9 | 10 | @app.errorhandler(404) 11 | def page_not_found(e): 12 | return render_template('error.html', message='404 not found'), 404 13 | 14 | 15 | @app.errorhandler(410) 16 | def gone(e): 17 | return render_template('error.html', message='410 gone'), 410 18 | 19 | 20 | @app.errorhandler(500) 21 | def internal_error(e): 22 | return render_template('error.html', message='500 internal error'), 500 23 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/charge.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block content %} 3 | 4 |

Thanks, you paid $10.00!

5 |

Upload your image below

6 |
7 | 8 |
10 | 11 | 12 |
13 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/reset.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Choose a new password

12 | {{ m.render_field(form.password) }} 13 | {{ m.render_field(form.confirm) }} 14 | {{ form.csrf_token }} 15 | 16 |
17 |
18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /app/config_common.py: -------------------------------------------------------------------------------- 1 | TIMEZONE = 'Europe/Paris' 2 | 3 | # Secret key for generating tokens 4 | SECRET_KEY = 'houdini' 5 | 6 | # Admin credentials 7 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 8 | 9 | # Database choice 10 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 11 | SQLALCHEMY_TRACK_MODIFICATIONS = True 12 | 13 | # Configuration of a Gmail account for sending mails 14 | MAIL_SERVER = 'smtp.googlemail.com' 15 | MAIL_PORT = 465 16 | MAIL_USE_TLS = False 17 | MAIL_USE_SSL = True 18 | MAIL_USERNAME = 'flask.boilerplate' 19 | MAIL_PASSWORD = 'flaskboilerplate123' 20 | ADMINS = ['flask.boilerplate@gmail.com'] 21 | 22 | # Number of times a password is hashed 23 | BCRYPT_LOG_ROUNDS = 12 24 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/config_common.py: -------------------------------------------------------------------------------- 1 | TIMEZONE = 'Europe/Paris' 2 | 3 | # Secret key for generating tokens 4 | SECRET_KEY = 'houdini' 5 | 6 | # Admin credentials 7 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 8 | 9 | # Database choice 10 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 11 | SQLALCHEMY_TRACK_MODIFICATIONS = True 12 | 13 | # Configuration of a Gmail account for sending mails 14 | MAIL_SERVER = 'smtp.googlemail.com' 15 | MAIL_PORT = 465 16 | MAIL_USE_TLS = False 17 | MAIL_USE_SSL = True 18 | MAIL_USERNAME = 'flask.boilerplate' 19 | MAIL_PASSWORD = 'flaskboilerplate123' 20 | ADMINS = ['flask.boilerplate@gmail.com'] 21 | 22 | # Number of times a password is hashed 23 | BCRYPT_LOG_ROUNDS = 12 24 | -------------------------------------------------------------------------------- /app/templates/user/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 | 5 |
6 |
7 |

Sign up

8 | {{ m.render_field(form.first_name) }} 9 | {{ m.render_field(form.last_name) }} 10 | {{ m.render_field(form.phone) }} 11 | {{ m.render_field(form.email) }} 12 | {{ m.render_field(form.password) }} 13 | {{ m.render_field(form.confirm) }} 14 | {{ form.csrf_token }} 15 | 16 |
17 |
18 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 | 5 |
6 |
7 |

Sign up

8 | {{ m.render_field(form.first_name) }} 9 | {{ m.render_field(form.last_name) }} 10 | {{ m.render_field(form.phone) }} 11 | {{ m.render_field(form.email) }} 12 | {{ m.render_field(form.password) }} 13 | {{ m.render_field(form.confirm) }} 14 | {{ form.csrf_token }} 15 | 16 |
17 |
18 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | {% if current_user.is_authenticated %} 10 | 11 | 12 | 13 |
14 |
15 | 17 |
18 | 19 | 26 |
27 | 28 | {% endif %} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /app/toolbox/email.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from flask.ext.mail import Message 3 | from app import app, mail 4 | 5 | 6 | def send(recipient, subject, body): 7 | ''' 8 | Send a mail to a recipient. The body is usually a rendered HTML template. 9 | The sender's credentials has been configured in the config.py file. 10 | ''' 11 | sender = app.config['ADMINS'][0] 12 | message = Message(subject, sender=sender, recipients=[recipient]) 13 | message.html = body 14 | # Create a new thread 15 | thr = Thread(target=send_async, args=[app, message]) 16 | thr.start() 17 | 18 | 19 | def send_async(app, message): 20 | ''' Send the mail asynchronously. ''' 21 | with app.app_context(): 22 | mail.send(message) -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | {% if current_user.is_authenticated %} 10 | 11 | 12 | 13 |
14 |
15 | 17 |
18 | 19 | 26 |
27 | 28 | {% endif %} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /app/templates/user/signin.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Login

12 | {{ m.render_field(form.email) }} 13 | {{ m.render_field(form.password) }} 14 | {{ form.csrf_token }} 15 | 16 | 17 |
18 | I forgot my password 19 |
20 |
21 |
22 |
23 | 24 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/user/signin.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 |

Login

12 | {{ m.render_field(form.email) }} 13 | {{ m.render_field(form.password) }} 14 | {{ form.csrf_token }} 15 | 16 | 17 |
18 | I forgot my password 19 |
20 |
21 |
22 |
23 | 24 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/toolbox/email.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from flask.ext.mail import Message 3 | from app import app, mail 4 | 5 | 6 | def send(recipient, subject, body): 7 | ''' 8 | Send a mail to a recipient. The body is usually a rendered HTML template. 9 | The sender's credentials has been configured in the config.py file. 10 | ''' 11 | sender = app.config['ADMINS'][0] 12 | message = Message(subject, sender=sender, recipients=[recipient]) 13 | message.html = body 14 | # Create a new thread 15 | thr = Thread(target=send_async, args=[app, message]) 16 | thr.start() 17 | 18 | 19 | def send_async(app, message): 20 | ''' Send the mail asynchronously. ''' 21 | with app.app_context(): 22 | mail.send(message) -------------------------------------------------------------------------------- /flaskSaaS-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:0.9.19 2 | 3 | # Use baseimage-docker's init system. 4 | CMD ["/sbin/my_init"] 5 | 6 | ENV TERM=xterm-256color 7 | 8 | # Set the locale 9 | RUN locale-gen en_US.UTF-8 10 | ENV LANG en_US.UTF-8 11 | ENV LANGUAGE en_US:en 12 | ENV LC_ALL en_US.UTF-8 13 | 14 | # Install necessary packages 15 | RUN apt-get update && apt-get install -y \ 16 | build-essential \ 17 | python3-pip 18 | 19 | # Install Python requirements 20 | RUN mkdir -p /usr/src/app 21 | COPY requirements.txt /usr/src/app/ 22 | RUN pip3 install --upgrade pip 23 | RUN pip3 install -r /usr/src/app/requirements.txt 24 | 25 | # Copy the files from the host to the container 26 | COPY . /usr/src/app 27 | WORKDIR /usr/src/app 28 | RUN chmod 777 -R * 29 | 30 | # Clean up 31 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 32 | -------------------------------------------------------------------------------- /app/static/css/custom.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | 3 | html, 4 | body { 5 | margin:0; 6 | padding:0; 7 | height:100%; 8 | overflow-x: hidden; 9 | } 10 | 11 | #container { 12 | height: 100%; 13 | min-height: 100%; 14 | position: relative; 15 | } 16 | 17 | #body { 18 | margin: 20px; 19 | min-height: 100%; 20 | } 21 | 22 | #footer { 23 | bottom: 0; 24 | width: 100%; 25 | height: 50px; /* Height of the footer */ 26 | text-align: center; 27 | } 28 | 29 | /* Forms */ 30 | 31 | .form-user { 32 | width: 33% !important; 33 | margin: 0 auto !important; 34 | margin-top: 10% !important; 35 | } 36 | 37 | .form-error { 38 | color: #E50000 !important; 39 | } 40 | 41 | /* Flask flashes */ 42 | 43 | .flash { 44 | margin-right: 20px !important; 45 | } 46 | 47 | /* Errors */ 48 | 49 | .error-box { 50 | margin-top: 8%; 51 | } -------------------------------------------------------------------------------- /flaskSaaS-master/app/static/css/custom.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | 3 | html, 4 | body { 5 | margin:0; 6 | padding:0; 7 | height:100%; 8 | overflow-x: hidden; 9 | } 10 | 11 | #container { 12 | height: 100%; 13 | min-height: 100%; 14 | position: relative; 15 | } 16 | 17 | #body { 18 | margin: 20px; 19 | min-height: 100%; 20 | } 21 | 22 | #footer { 23 | bottom: 0; 24 | width: 100%; 25 | height: 50px; /* Height of the footer */ 26 | text-align: center; 27 | } 28 | 29 | /* Forms */ 30 | 31 | .form-user { 32 | width: 33% !important; 33 | margin: 0 auto !important; 34 | margin-top: 10% !important; 35 | } 36 | 37 | .form-error { 38 | color: #E50000 !important; 39 | } 40 | 41 | /* Flask flashes */ 42 | 43 | .flash { 44 | margin-right: 20px !important; 45 | } 46 | 47 | /* Errors */ 48 | 49 | .error-box { 50 | margin-top: 8%; 51 | } -------------------------------------------------------------------------------- /flaskSaaS-master/manage.py: -------------------------------------------------------------------------------- 1 | from flask.ext.script import Manager, prompt_bool, Shell, Server 2 | from termcolor import colored 3 | 4 | from app import app, db, models 5 | 6 | 7 | manager = Manager(app) 8 | 9 | 10 | def make_shell_context(): 11 | return dict(app=app) 12 | 13 | 14 | @manager.command 15 | def initdb(): 16 | ''' Create the SQL database. ''' 17 | db.create_all() 18 | print(colored('The SQL database has been created', 'green')) 19 | 20 | 21 | @manager.command 22 | def dropdb(): 23 | ''' Delete the SQL database. ''' 24 | if prompt_bool('Are you sure you want to lose all your SQL data?'): 25 | db.drop_all() 26 | print(colored('The SQL database has been deleted', 'green')) 27 | 28 | 29 | manager.add_command('runserver', Server()) 30 | manager.add_command('shell', Shell(make_context=make_shell_context)) 31 | 32 | if __name__ == '__main__': 33 | manager.run() 34 | -------------------------------------------------------------------------------- /app/config_prod.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG has to be to False in a production environment for security reasons 7 | DEBUG = False 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.INFO 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/config_prod.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG has to be to False in a production environment for security reasons 7 | DEBUG = False 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.INFO 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | -------------------------------------------------------------------------------- /app/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG can only be set to True in a development environment for security reasons 7 | DEBUG = True 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.DEBUG 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | 36 | 37 | UPLOAD_FOLDER = '/Users/sirajr/Downloads/flaskSaaS-master/app/forms' -------------------------------------------------------------------------------- /app/config_dev.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG can only be set to True in a development environment for security reasons 7 | DEBUG = True 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.DEBUG 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | 36 | 37 | UPLOAD_FOLDER = '/Users/sirajr/Downloads/flaskSaaS-master/app/forms' -------------------------------------------------------------------------------- /flaskSaaS-master/app/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG can only be set to True in a development environment for security reasons 7 | DEBUG = True 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.DEBUG 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | 36 | 37 | UPLOAD_FOLDER = '/Users/sirajr/Downloads/flaskSaaS-master/app/forms' -------------------------------------------------------------------------------- /app/templates/macros.html: -------------------------------------------------------------------------------- 1 | {# myapp/templates/macros.html #} 2 | 3 | 4 | {% macro nav_link(endpoint, text) %} 5 | {% if request.endpoint is not none %} 6 | {% if request.endpoint.endswith(endpoint) %} 7 | {{ text }} 8 | {% else %} 9 | {{ text }} 10 | {% endif %} 11 | {% else %} 12 | {{ text }} 13 | {% endif %} 14 | {% endmacro %} 15 | 16 | 17 | {% macro render_field(field) %} 18 |
19 | {{ field(name_=field.name, id=field.name, placeholder=field.description, class_="field") }} 20 |
21 | {% if field.errors %} 22 | 27 | {% endif %} 28 | {% endmacro %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/config_dev.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app.config_common import * 4 | 5 | 6 | # DEBUG can only be set to True in a development environment for security reasons 7 | DEBUG = True 8 | 9 | # Secret key for generating tokens 10 | SECRET_KEY = 'houdini' 11 | 12 | # Admin credentials 13 | ADMIN_CREDENTIALS = ('admin', 'pa$$word') 14 | 15 | # Database choice 16 | SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db' 17 | SQLALCHEMY_TRACK_MODIFICATIONS = True 18 | 19 | # Configuration of a Gmail account for sending mails 20 | MAIL_SERVER = 'smtp.googlemail.com' 21 | MAIL_PORT = 465 22 | MAIL_USE_TLS = False 23 | MAIL_USE_SSL = True 24 | MAIL_USERNAME = 'flask.boilerplate' 25 | MAIL_PASSWORD = 'flaskboilerplate123' 26 | ADMINS = ['flask.boilerplate@gmail.com'] 27 | 28 | # Number of times a password is hashed 29 | BCRYPT_LOG_ROUNDS = 12 30 | 31 | LOG_LEVEL = logging.DEBUG 32 | LOG_FILENAME = 'activity.log' 33 | LOG_MAXBYTES = 1024 34 | LOG_BACKUPS = 2 35 | 36 | 37 | UPLOAD_FOLDER = '/Users/sirajr/Downloads/flaskSaaS-master/app/forms' -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/macros.html: -------------------------------------------------------------------------------- 1 | {# myapp/templates/macros.html #} 2 | 3 | 4 | {% macro nav_link(endpoint, text) %} 5 | {% if request.endpoint is not none %} 6 | {% if request.endpoint.endswith(endpoint) %} 7 | {{ text }} 8 | {% else %} 9 | {{ text }} 10 | {% endif %} 11 | {% else %} 12 | {{ text }} 13 | {% endif %} 14 | {% endmacro %} 15 | 16 | 17 | {% macro render_field(field) %} 18 |
19 | {{ field(name_=field.name, id=field.name, placeholder=field.description, class_="field") }} 20 |
21 | {% if field.errors %} 22 | 27 | {% endif %} 28 | {% endmacro %} -------------------------------------------------------------------------------- /app/admin.py: -------------------------------------------------------------------------------- 1 | import os.path as op 2 | 3 | from flask import request, Response 4 | from werkzeug.exceptions import HTTPException 5 | from flask_admin import Admin 6 | from flask.ext.admin.contrib.sqla import ModelView 7 | from flask.ext.admin.contrib.fileadmin import FileAdmin 8 | 9 | from app import app, db 10 | from app.models import User 11 | 12 | 13 | admin = Admin(app, name='Admin', template_mode='bootstrap3') 14 | 15 | class ModelView(ModelView): 16 | 17 | def is_accessible(self): 18 | auth = request.authorization or request.environ.get('REMOTE_USER') # workaround for Apache 19 | if not auth or (auth.username, auth.password) != app.config['ADMIN_CREDENTIALS']: 20 | raise HTTPException('', Response('You have to an administrator.', 401, 21 | {'WWW-Authenticate': 'Basic realm="Login Required"'} 22 | )) 23 | return True 24 | 25 | # Users 26 | admin.add_view(ModelView(User, db.session)) 27 | 28 | # Static files 29 | path = op.join(op.dirname(__file__), 'static') 30 | admin.add_view(FileAdmin(path, '/static/', name='Static')) 31 | -------------------------------------------------------------------------------- /app/templates/uploaded.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | 10 | 11 | 12 | 13 | Italian Trulli 14 | 15 | 16 | 33 | 34 | 35 | 36 |

Results

37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
DiseasePercent Likelihood
Pneumonia98%
Fibrosis43%
52 | 53 | 54 | 55 | Index 56 | 57 | 58 | 59 | 60 | 61 | 62 | {% endblock %} 63 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/admin.py: -------------------------------------------------------------------------------- 1 | import os.path as op 2 | 3 | from flask import request, Response 4 | from werkzeug.exceptions import HTTPException 5 | from flask_admin import Admin 6 | from flask.ext.admin.contrib.sqla import ModelView 7 | from flask.ext.admin.contrib.fileadmin import FileAdmin 8 | 9 | from app import app, db 10 | from app.models import User 11 | 12 | 13 | admin = Admin(app, name='Admin', template_mode='bootstrap3') 14 | 15 | class ModelView(ModelView): 16 | 17 | def is_accessible(self): 18 | auth = request.authorization or request.environ.get('REMOTE_USER') # workaround for Apache 19 | if not auth or (auth.username, auth.password) != app.config['ADMIN_CREDENTIALS']: 20 | raise HTTPException('', Response('You have to an administrator.', 401, 21 | {'WWW-Authenticate': 'Basic realm="Login Required"'} 22 | )) 23 | return True 24 | 25 | # Users 26 | admin.add_view(ModelView(User, db.session)) 27 | 28 | # Static files 29 | path = op.join(op.dirname(__file__), 'static') 30 | admin.add_view(FileAdmin(path, '/static/', name='Static')) 31 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/uploaded.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | 10 | 11 | 12 | 13 | Italian Trulli 14 | 15 | 16 | 33 | 34 | 35 | 36 |

Results

37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
DiseasePercent Likelihood
Pneumonia98%
Fibrosis43%
52 | 53 | 54 | 55 | Index 56 | 57 | 58 | 59 | 60 | 61 | 62 | {% endblock %} 63 | -------------------------------------------------------------------------------- /flaskSaaS-master/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Max Halford 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.hybrid import hybrid_property 2 | from flask.ext.login import UserMixin 3 | 4 | from app import db, bcrypt 5 | 6 | 7 | class User(db.Model, UserMixin): 8 | 9 | ''' A user who has an account on the website. ''' 10 | 11 | __tablename__ = 'users' 12 | 13 | first_name = db.Column(db.String) 14 | last_name = db.Column(db.String) 15 | phone = db.Column(db.String) 16 | email = db.Column(db.String, primary_key=True) 17 | confirmation = db.Column(db.Boolean) 18 | paid = db.Column(db.Boolean) 19 | _password = db.Column(db.String) 20 | 21 | @property 22 | def full_name(self): 23 | return '{} {}'.format(self.first_name, self.last_name) 24 | 25 | @hybrid_property 26 | def password(self): 27 | return self._password 28 | 29 | @password.setter 30 | def password(self, plaintext): 31 | self._password = bcrypt.generate_password_hash(plaintext) 32 | 33 | def check_password(self, plaintext): 34 | return bcrypt.check_password_hash(self.password, plaintext) 35 | 36 | def get_id(self): 37 | return self.email 38 | 39 | def is_paid(self): 40 | return self.paid 41 | 42 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.hybrid import hybrid_property 2 | from flask.ext.login import UserMixin 3 | 4 | from app import db, bcrypt 5 | 6 | 7 | class User(db.Model, UserMixin): 8 | 9 | ''' A user who has an account on the website. ''' 10 | 11 | __tablename__ = 'users' 12 | 13 | first_name = db.Column(db.String) 14 | last_name = db.Column(db.String) 15 | phone = db.Column(db.String) 16 | email = db.Column(db.String, primary_key=True) 17 | confirmation = db.Column(db.Boolean) 18 | paid = db.Column(db.Boolean) 19 | _password = db.Column(db.String) 20 | 21 | @property 22 | def full_name(self): 23 | return '{} {}'.format(self.first_name, self.last_name) 24 | 25 | @hybrid_property 26 | def password(self): 27 | return self._password 28 | 29 | @password.setter 30 | def password(self, plaintext): 31 | self._password = bcrypt.generate_password_hash(plaintext) 32 | 33 | def check_password(self, plaintext): 34 | return bcrypt.check_password_hash(self.password, plaintext) 35 | 36 | def get_id(self): 37 | return self.email 38 | 39 | def is_paid(self): 40 | return self.paid 41 | 42 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | # Setup the app with the config.py file 6 | app.config.from_object('app.config') 7 | 8 | # Setup the logger 9 | from app.logger_setup import logger 10 | 11 | # Setup the database 12 | from flask.ext.sqlalchemy import SQLAlchemy 13 | db = SQLAlchemy(app) 14 | 15 | # Setup the mail server 16 | from flask.ext.mail import Mail 17 | mail = Mail(app) 18 | 19 | # Setup the debug toolbar 20 | from flask_debugtoolbar import DebugToolbarExtension 21 | app.config['DEBUG_TB_TEMPLATE_EDITOR_ENABLED'] = True 22 | app.config['DEBUG_TB_PROFILER_ENABLED'] = True 23 | toolbar = DebugToolbarExtension(app) 24 | 25 | # Setup the password crypting 26 | from flask.ext.bcrypt import Bcrypt 27 | bcrypt = Bcrypt(app) 28 | 29 | # Import the views 30 | from app.views import main, user, error 31 | app.register_blueprint(user.userbp) 32 | 33 | # Setup the user login process 34 | from flask.ext.login import LoginManager 35 | from app.models import User 36 | 37 | login_manager = LoginManager() 38 | login_manager.init_app(app) 39 | login_manager.login_view = 'userbp.signin' 40 | 41 | 42 | @login_manager.user_loader 43 | def load_user(email): 44 | return User.query.filter(User.email == email).first() 45 | 46 | from app import admin 47 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | # Setup the app with the config.py file 6 | app.config.from_object('app.config') 7 | 8 | # Setup the logger 9 | from app.logger_setup import logger 10 | 11 | # Setup the database 12 | from flask.ext.sqlalchemy import SQLAlchemy 13 | db = SQLAlchemy(app) 14 | 15 | # Setup the mail server 16 | from flask.ext.mail import Mail 17 | mail = Mail(app) 18 | 19 | # Setup the debug toolbar 20 | from flask_debugtoolbar import DebugToolbarExtension 21 | app.config['DEBUG_TB_TEMPLATE_EDITOR_ENABLED'] = True 22 | app.config['DEBUG_TB_PROFILER_ENABLED'] = True 23 | toolbar = DebugToolbarExtension(app) 24 | 25 | # Setup the password crypting 26 | from flask.ext.bcrypt import Bcrypt 27 | bcrypt = Bcrypt(app) 28 | 29 | # Import the views 30 | from app.views import main, user, error 31 | app.register_blueprint(user.userbp) 32 | 33 | # Setup the user login process 34 | from flask.ext.login import LoginManager 35 | from app.models import User 36 | 37 | login_manager = LoginManager() 38 | login_manager.init_app(app) 39 | login_manager.login_view = 'userbp.signin' 40 | 41 | 42 | @login_manager.user_loader 43 | def load_user(email): 44 | return User.query.filter(User.email == email).first() 45 | 46 | from app import admin 47 | -------------------------------------------------------------------------------- /app/views/main.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, jsonify, Flask, redirect, url_for, request 2 | from app import app 3 | import random 4 | import os 5 | from keras.applications.resnet50 import ResNet50 6 | from keras.preprocessing import image 7 | from keras.applications.resnet50 import preprocess_input, decode_predictions 8 | import numpy as np 9 | 10 | 11 | @app.route('/') 12 | 13 | #disease_list = ['Atelectasis', 'Consolidation', 'Infiltration', 'Pneumothorax', 'Edema', 'Emphysema', \ 14 | # 'Fibrosis', 'Effusion', 'Pneumonia', 'Pleural_Thickening', 'Cardiomegaly', 'Nodule', 'Mass', \ 15 | # 'Hernia'] 16 | 17 | @app.route('/upload') 18 | def upload_file2(): 19 | return render_template('index.html') 20 | 21 | @app.route('/uploaded', methods = ['GET', 'POST']) 22 | def upload_file(): 23 | if request.method == 'POST': 24 | f = request.files['file'] 25 | path = os.path.join(app.config['UPLOAD_FOLDER'], f.filename) 26 | model= ResNet50(weights='imagenet') 27 | img = image.load_img(path, target_size=(224,224)) 28 | x = image.img_to_array(img) 29 | x = np.expand_dims(x, axis=0) 30 | x = preprocess_input(x) 31 | preds = model.predict(x) 32 | preds_decoded = decode_predictions(preds, top=3)[0] 33 | print(decode_predictions(preds, top=3)[0]) 34 | f.save(path) 35 | return render_template('uploaded.html', title='Success', predictions=preds_decoded, user_image=f.filename) 36 | 37 | 38 | @app.route('/index') 39 | def index(): 40 | return render_template('index.html', title='Home') 41 | 42 | @app.route('/map') 43 | def map(): 44 | return render_template('map.html', title='Map') 45 | 46 | 47 | @app.route('/map/refresh', methods=['POST']) 48 | def map_refresh(): 49 | points = [(random.uniform(48.8434100, 48.8634100), 50 | random.uniform(2.3388000, 2.3588000)) 51 | for _ in range(random.randint(2, 9))] 52 | return jsonify({'points': points}) 53 | 54 | 55 | @app.route('/contact') 56 | def contact(): 57 | return render_template('contact.html', title='Contact') -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/main.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, jsonify, Flask, redirect, url_for, request 2 | from app import app 3 | import random 4 | import os 5 | from keras.applications.resnet50 import ResNet50 6 | from keras.preprocessing import image 7 | from keras.applications.resnet50 import preprocess_input, decode_predictions 8 | import numpy as np 9 | 10 | 11 | @app.route('/') 12 | 13 | #disease_list = ['Atelectasis', 'Consolidation', 'Infiltration', 'Pneumothorax', 'Edema', 'Emphysema', \ 14 | # 'Fibrosis', 'Effusion', 'Pneumonia', 'Pleural_Thickening', 'Cardiomegaly', 'Nodule', 'Mass', \ 15 | # 'Hernia'] 16 | 17 | @app.route('/upload') 18 | def upload_file2(): 19 | return render_template('index.html') 20 | 21 | @app.route('/uploaded', methods = ['GET', 'POST']) 22 | def upload_file(): 23 | if request.method == 'POST': 24 | f = request.files['file'] 25 | path = os.path.join(app.config['UPLOAD_FOLDER'], f.filename) 26 | model= ResNet50(weights='imagenet') 27 | img = image.load_img(path, target_size=(224,224)) 28 | x = image.img_to_array(img) 29 | x = np.expand_dims(x, axis=0) 30 | x = preprocess_input(x) 31 | preds = model.predict(x) 32 | preds_decoded = decode_predictions(preds, top=3)[0] 33 | print(decode_predictions(preds, top=3)[0]) 34 | f.save(path) 35 | return render_template('uploaded.html', title='Success', predictions=preds_decoded, user_image=f.filename) 36 | 37 | 38 | @app.route('/index') 39 | def index(): 40 | return render_template('index.html', title='Home') 41 | 42 | @app.route('/map') 43 | def map(): 44 | return render_template('map.html', title='Map') 45 | 46 | 47 | @app.route('/map/refresh', methods=['POST']) 48 | def map_refresh(): 49 | points = [(random.uniform(48.8434100, 48.8634100), 50 | random.uniform(2.3388000, 2.3588000)) 51 | for _ in range(random.randint(2, 9))] 52 | return jsonify({'points': points}) 53 | 54 | 55 | @app.route('/contact') 56 | def contact(): 57 | return render_template('contact.html', title='Contact') -------------------------------------------------------------------------------- /app/templates/map.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | 6 | 7 | 8 | 9 | 10 | 15 | {% endblock %} 16 | 17 | {% block content %} 18 | 19 |

{{ title }}

20 | 21 | {% if current_user.is_authenticated %} 22 |

Hi {{ current_user.name }}!

23 | {% endif %} 24 | 25 |
26 | 27 | 79 | 80 | {% endblock %} -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/map.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head %} 4 | {{ super() }} 5 | 6 | 7 | 8 | 9 | 10 | 15 | {% endblock %} 16 | 17 | {% block content %} 18 | 19 |

{{ title }}

20 | 21 | {% if current_user.is_authenticated %} 22 |

Hi {{ current_user.name }}!

23 | {% endif %} 24 | 25 |
26 | 27 | 79 | 80 | {% endblock %} -------------------------------------------------------------------------------- /app/forms/user.py: -------------------------------------------------------------------------------- 1 | from flask.ext.wtf import Form 2 | from wtforms import TextField, PasswordField 3 | from wtforms.validators import (Required, Length, Email, ValidationError, 4 | EqualTo) 5 | from app.models import User 6 | 7 | 8 | class Unique(object): 9 | 10 | ''' 11 | Custom validator to check an object's attribute 12 | is unique. For example users should not be able 13 | to create an account if the account's email 14 | address is already in the database. This class 15 | supposes you are using SQLAlchemy to query the 16 | database. 17 | ''' 18 | 19 | def __init__(self, model, field, message): 20 | self.model = model 21 | self.field = field 22 | self.message = message 23 | 24 | def __call__(self, form, field): 25 | check = self.model.query.filter(self.field == field.data).first() 26 | if check: 27 | raise ValidationError(self.message) 28 | 29 | 30 | class Forgot(Form): 31 | 32 | ''' User forgot password form. ''' 33 | 34 | email = TextField(validators=[Required(), Email()], 35 | description='Email address') 36 | 37 | 38 | class Reset(Form): 39 | 40 | ''' User reset password form. ''' 41 | 42 | password = PasswordField(validators=[ 43 | Required(), Length(min=6), 44 | EqualTo('confirm', message='Passwords must match.') 45 | ], description='Password') 46 | confirm = PasswordField(description='Confirm password') 47 | 48 | 49 | class Login(Form): 50 | 51 | ''' User login form. ''' 52 | 53 | email = TextField(validators=[Required(), Email()], 54 | description='Email address') 55 | password = PasswordField(validators=[Required()], 56 | description='Password') 57 | 58 | 59 | class SignUp(Form): 60 | 61 | ''' User sign up form. ''' 62 | 63 | first_name = TextField(validators=[Required(), Length(min=2)], 64 | description='Name') 65 | last_name = TextField(validators=[Required(), Length(min=2)], 66 | description='Surname') 67 | phone = TextField(validators=[Required(), Length(min=6)], 68 | description='Phone number') 69 | email = TextField(validators=[Required(), Email(), 70 | Unique(User, User.email, 71 | 'This email address is ' + 72 | 'already linked to an account.')], 73 | description='Email address') 74 | password = PasswordField(validators=[ 75 | Required(), Length(min=6), 76 | EqualTo('confirm', message='Passwords must match.') 77 | ], description='Password') 78 | confirm = PasswordField(description='Confirm password') 79 | -------------------------------------------------------------------------------- /app/logger_setup.py: -------------------------------------------------------------------------------- 1 | ''' 2 | logger_setup.py customizes the app's logging module. Each time an event is 3 | logged the logger checks the level of the event (eg. debug, warning, info...). 4 | If the event is above the approved threshold then it goes through. The handlers 5 | do the same thing; they output to a file/shell if the event level is above their 6 | threshold. 7 | :Example: 8 | >>> from website import logger 9 | >>> logger.info('event', foo='bar') 10 | **Levels**: 11 | - logger.debug('For debugging purposes') 12 | - logger.info('An event occured, for example a database update') 13 | - logger.warning('Rare situation') 14 | - logger.error('Something went wrong') 15 | - logger.critical('Very very bad') 16 | You can build a log incrementally as so: 17 | >>> log = logger.new(date='now') 18 | >>> log = log.bind(weather='rainy') 19 | >>> log.info('user logged in', user='John') 20 | ''' 21 | 22 | import datetime as dt 23 | import logging 24 | from logging.handlers import RotatingFileHandler 25 | import pytz 26 | 27 | from flask import request, session 28 | from structlog import wrap_logger 29 | from structlog.processors import JSONRenderer 30 | 31 | from app import app 32 | 33 | # Set the logging level 34 | app.logger.setLevel(app.config['LOG_LEVEL']) 35 | 36 | # Remove the stdout handler 37 | app.logger.removeHandler(app.logger.handlers[0]) 38 | 39 | TZ = pytz.timezone(app.config['TIMEZONE']) 40 | 41 | 42 | def add_fields(_, level, event_dict): 43 | ''' Add custom fields to each record. ''' 44 | now = dt.datetime.now() 45 | event_dict['timestamp'] = TZ.localize(now, True).astimezone(pytz.utc).isoformat() 46 | event_dict['level'] = level 47 | 48 | if session: 49 | event_dict['session_id'] = session.get('session_id') 50 | 51 | if request: 52 | try: 53 | event_dict['ip_address'] = request.headers['X-Forwarded-For'].split(',')[0].strip() 54 | except: 55 | event_dict['ip_address'] = 'unknown' 56 | 57 | return event_dict 58 | 59 | 60 | # Add a handler to write log messages to a file 61 | if app.config.get('LOG_FILENAME'): 62 | file_handler = RotatingFileHandler(filename=app.config['LOG_FILENAME'], 63 | maxBytes=app.config['LOG_MAXBYTES'], 64 | backupCount=app.config['LOG_BACKUPS'], 65 | mode='a', 66 | encoding='utf-8') 67 | file_handler.setLevel(logging.DEBUG) 68 | app.logger.addHandler(file_handler) 69 | 70 | # Wrap the application logger with structlog to format the output 71 | logger = wrap_logger( 72 | app.logger, 73 | processors=[ 74 | add_fields, 75 | JSONRenderer(indent=None) 76 | ] 77 | ) 78 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/forms/user.py: -------------------------------------------------------------------------------- 1 | from flask.ext.wtf import Form 2 | from wtforms import TextField, PasswordField 3 | from wtforms.validators import (Required, Length, Email, ValidationError, 4 | EqualTo) 5 | from app.models import User 6 | 7 | 8 | class Unique(object): 9 | 10 | ''' 11 | Custom validator to check an object's attribute 12 | is unique. For example users should not be able 13 | to create an account if the account's email 14 | address is already in the database. This class 15 | supposes you are using SQLAlchemy to query the 16 | database. 17 | ''' 18 | 19 | def __init__(self, model, field, message): 20 | self.model = model 21 | self.field = field 22 | self.message = message 23 | 24 | def __call__(self, form, field): 25 | check = self.model.query.filter(self.field == field.data).first() 26 | if check: 27 | raise ValidationError(self.message) 28 | 29 | 30 | class Forgot(Form): 31 | 32 | ''' User forgot password form. ''' 33 | 34 | email = TextField(validators=[Required(), Email()], 35 | description='Email address') 36 | 37 | 38 | class Reset(Form): 39 | 40 | ''' User reset password form. ''' 41 | 42 | password = PasswordField(validators=[ 43 | Required(), Length(min=6), 44 | EqualTo('confirm', message='Passwords must match.') 45 | ], description='Password') 46 | confirm = PasswordField(description='Confirm password') 47 | 48 | 49 | class Login(Form): 50 | 51 | ''' User login form. ''' 52 | 53 | email = TextField(validators=[Required(), Email()], 54 | description='Email address') 55 | password = PasswordField(validators=[Required()], 56 | description='Password') 57 | 58 | 59 | class SignUp(Form): 60 | 61 | ''' User sign up form. ''' 62 | 63 | first_name = TextField(validators=[Required(), Length(min=2)], 64 | description='Name') 65 | last_name = TextField(validators=[Required(), Length(min=2)], 66 | description='Surname') 67 | phone = TextField(validators=[Required(), Length(min=6)], 68 | description='Phone number') 69 | email = TextField(validators=[Required(), Email(), 70 | Unique(User, User.email, 71 | 'This email address is ' + 72 | 'already linked to an account.')], 73 | description='Email address') 74 | password = PasswordField(validators=[ 75 | Required(), Length(min=6), 76 | EqualTo('confirm', message='Passwords must match.') 77 | ], description='Password') 78 | confirm = PasswordField(description='Confirm password') 79 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/logger_setup.py: -------------------------------------------------------------------------------- 1 | ''' 2 | logger_setup.py customizes the app's logging module. Each time an event is 3 | logged the logger checks the level of the event (eg. debug, warning, info...). 4 | If the event is above the approved threshold then it goes through. The handlers 5 | do the same thing; they output to a file/shell if the event level is above their 6 | threshold. 7 | :Example: 8 | >>> from website import logger 9 | >>> logger.info('event', foo='bar') 10 | **Levels**: 11 | - logger.debug('For debugging purposes') 12 | - logger.info('An event occured, for example a database update') 13 | - logger.warning('Rare situation') 14 | - logger.error('Something went wrong') 15 | - logger.critical('Very very bad') 16 | You can build a log incrementally as so: 17 | >>> log = logger.new(date='now') 18 | >>> log = log.bind(weather='rainy') 19 | >>> log.info('user logged in', user='John') 20 | ''' 21 | 22 | import datetime as dt 23 | import logging 24 | from logging.handlers import RotatingFileHandler 25 | import pytz 26 | 27 | from flask import request, session 28 | from structlog import wrap_logger 29 | from structlog.processors import JSONRenderer 30 | 31 | from app import app 32 | 33 | # Set the logging level 34 | app.logger.setLevel(app.config['LOG_LEVEL']) 35 | 36 | # Remove the stdout handler 37 | app.logger.removeHandler(app.logger.handlers[0]) 38 | 39 | TZ = pytz.timezone(app.config['TIMEZONE']) 40 | 41 | 42 | def add_fields(_, level, event_dict): 43 | ''' Add custom fields to each record. ''' 44 | now = dt.datetime.now() 45 | event_dict['timestamp'] = TZ.localize(now, True).astimezone(pytz.utc).isoformat() 46 | event_dict['level'] = level 47 | 48 | if session: 49 | event_dict['session_id'] = session.get('session_id') 50 | 51 | if request: 52 | try: 53 | event_dict['ip_address'] = request.headers['X-Forwarded-For'].split(',')[0].strip() 54 | except: 55 | event_dict['ip_address'] = 'unknown' 56 | 57 | return event_dict 58 | 59 | 60 | # Add a handler to write log messages to a file 61 | if app.config.get('LOG_FILENAME'): 62 | file_handler = RotatingFileHandler(filename=app.config['LOG_FILENAME'], 63 | maxBytes=app.config['LOG_MAXBYTES'], 64 | backupCount=app.config['LOG_BACKUPS'], 65 | mode='a', 66 | encoding='utf-8') 67 | file_handler.setLevel(logging.DEBUG) 68 | app.logger.addHandler(file_handler) 69 | 70 | # Wrap the application logger with structlog to format the output 71 | logger = wrap_logger( 72 | app.logger, 73 | processors=[ 74 | add_fields, 75 | JSONRenderer(indent=None) 76 | ] 77 | ) 78 | -------------------------------------------------------------------------------- /flaskSaaS-master/README.md: -------------------------------------------------------------------------------- 1 | # flaskSaas 2 | 3 | ![License](http://img.shields.io/:license-mit-blue.svg) 4 | 5 | A fork of [Max Halford's](https://github.com/MaxHalford) [flask-boilerplate](https://github.com/MaxHalford/flask-boilerplate). I've noticed SaaS bootstraps/boilerplates being sold upwards of $1,000 per year and I think that's fucking ridiculous. This project will be my attempt to make a great starting point for your next big business as easy and efficent as possible. 6 | 7 | ## Features 8 | 9 | - [x] User account sign up, sign in, password reset, all through asynchronous email confirmation. 10 | - [x] Form generation. 11 | - [x] Error handling. 12 | - [x] HTML macros and layout file. 13 | - [x] "Functional" file structure. 14 | - [x] Python 3.x compliant. 15 | - [x] Asynchronous AJAX calls. 16 | - [x] Administration panel. 17 | - [x] Logging. 18 | - [ ] Stripe subscriptions. (WIP) 19 | - [ ] RESTful API for payments. 20 | - [ ] Simple RESTful API to communicate with your app. 21 | 22 | ## Libraries 23 | 24 | ### Backend 25 | 26 | - [Flask](http://flask.pocoo.org/), obviously. 27 | - [Flask-Login](https://flask-login.readthedocs.org/en/latest/) for the user accounts. 28 | - [Flask-SQLAlchemy](https://pythonhosted.org/Flask-SQLAlchemy/) interacting with the database. 29 | - [Flask-WTF](https://flask-wtf.readthedocs.org/en/latest/) and [WTForms](https://wtforms.readthedocs.org/en/latest/) for the form handling. 30 | - [Flask-Mail](https://pythonhosted.org/Flask-Mail/) for sending mails. 31 | - [itsdangerous](http://pythonhosted.org/itsdangerous/) for generating random tokens for the confirmation emails. 32 | - [Flask-Bcrypt](https://flask-bcrypt.readthedocs.org/en/latest/) for generating secret user passwords. 33 | - [Flask-Admin](https://flask-admin.readthedocs.org/en/latest/) for building an administration interface. 34 | - [Flask-Script](https://flask-script.readthedocs.io/en/latest/) for managing the app. 35 | - [structlog](http://structlog.readthedocs.io/en/stable/) for logging. 36 | - [Flask-DebugToolBar](https://flask-debugtoolbar.readthedocs.io/en/latest/) for adding a performance toolbar in development. 37 | - [gunicorn](http://gunicorn.org/) for acting as a reverse-proxy for Nginx. 38 | - [Flask-Stripe](http://stripe.com/) for subscription billing. 39 | 40 | ### Frontend 41 | 42 | - [Semantic UI](http://semantic-ui.com/) for the global style. Very similar to [Bootstrap](http://getbootstrap.com/). 43 | - [Leaflet JS](http://leafletjs.com/) for the map. I only added it for the sake of the example. 44 | 45 | ## Structure 46 | 47 | I did what most people recommend for the application's structure. Basically, everything is contained in the `app/` folder. 48 | 49 | - There you have the classic `static/` and `templates/` folders. The `templates/` folder contains macros, error views and a common layout. 50 | - I added a `views/` folder to separate the user and the website logic, which could be extended to the the admin views. 51 | - The same goes for the `forms/` folder, as the project grows it will be useful to split the WTForms code into separate files. 52 | - The `models.py` script contains the SQLAlchemy code, for the while it only contains the logic for a `users` table. 53 | - The `toolbox/` folder is a personal choice, in it I keep all the other code the application will need. 54 | - Management commands should be included in `manage.py`. Enter `python manage.py -?` to get a list of existing commands. 55 | - I added a Makefile for setup tasks, it can be quite useful once a project grows. 56 | 57 | 58 | ## Setup 59 | 60 | ### Vanilla 61 | 62 | - Install the requirements and setup the development environment. 63 | 64 | `make install && make dev` 65 | 66 | - Create the database. 67 | 68 | `python manage.py initdb` 69 | 70 | - Run the application. 71 | 72 | `python manage.py runserver` 73 | 74 | - Navigate to `localhost:5000`. 75 | 76 | ## Configuration 77 | 78 | The goal is to keep most of the application's configuration in a single file called `config.py`. I added a `config_dev.py` and a `config_prod.py` who inherit from `config_common.py`. The trick is to symlink either of these to `config.py`. This is done in by running `make dev` or `make prod`. 79 | 80 | I have included a working Gmail account to confirm user email addresses and reset user passwords, although in production you should't include the file if you push to GitHub because people can see it. The same goes for API keys, you should keep them secret. You can read more about secret configuration files [here](https://exploreflask.com/configuration.html). 81 | 82 | Read [this](http://flask.pocoo.org/docs/0.10/config/) for information on the possible configuration options. 83 | 84 | ## License 85 | 86 | The MIT License (MIT). Please see the [license file](LICENSE) for more information. 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI_Startup_Prototype 2 | This is the code for "Watch Me Build an AI Startup" By Siraj Raval on Youtube 3 | 4 | # Overview 5 | 6 | This is the code for [this](https://youtu.be/NzmoPqte4V4) video on Youtube by Siraj Raval on how to build an AI Startup. It contains the transfer learning notebook and the notes from the video as a notebook as well. 7 | 8 | 9 | 10 | ![License](http://img.shields.io/:license-mit-blue.svg) 11 | 12 | A fork of [Max Halford's](https://github.com/MaxHalford) [flask-boilerplate](https://github.com/MaxHalford/flask-boilerplate) and https://github.com/alectrocute/flaskSaaS/edit/master/README.md 13 | 14 | ## Features 15 | 16 | - [x] User account sign up, sign in, password reset, all through asynchronous email confirmation. 17 | - [x] Form generation. 18 | - [x] Error handling. 19 | - [x] HTML macros and layout file. 20 | - [x] "Functional" file structure. 21 | - [x] Python 3.x compliant. 22 | - [x] Asynchronous AJAX calls. 23 | - [x] Administration panel. 24 | - [x] Logging. 25 | - [ ] Stripe subscriptions. (WIP) 26 | - [ ] RESTful API for payments. 27 | - [ ] Simple RESTful API to communicate with your app. 28 | 29 | ## Libraries 30 | 31 | ### Backend 32 | 33 | - [Flask](http://flask.pocoo.org/), obviously. 34 | - [Flask-Login](https://flask-login.readthedocs.org/en/latest/) for the user accounts. 35 | - [Flask-SQLAlchemy](https://pythonhosted.org/Flask-SQLAlchemy/) interacting with the database. 36 | - [Flask-WTF](https://flask-wtf.readthedocs.org/en/latest/) and [WTForms](https://wtforms.readthedocs.org/en/latest/) for the form handling. 37 | - [Flask-Mail](https://pythonhosted.org/Flask-Mail/) for sending mails. 38 | - [itsdangerous](http://pythonhosted.org/itsdangerous/) for generating random tokens for the confirmation emails. 39 | - [Flask-Bcrypt](https://flask-bcrypt.readthedocs.org/en/latest/) for generating secret user passwords. 40 | - [Flask-Admin](https://flask-admin.readthedocs.org/en/latest/) for building an administration interface. 41 | - [Flask-Script](https://flask-script.readthedocs.io/en/latest/) for managing the app. 42 | - [structlog](http://structlog.readthedocs.io/en/stable/) for logging. 43 | - [Flask-DebugToolBar](https://flask-debugtoolbar.readthedocs.io/en/latest/) for adding a performance toolbar in development. 44 | - [gunicorn](http://gunicorn.org/) for acting as a reverse-proxy for Nginx. 45 | - [Flask-Stripe](http://stripe.com/) for subscription billing. 46 | 47 | ### Frontend 48 | 49 | - [Semantic UI](http://semantic-ui.com/) for the global style. Very similar to [Bootstrap](http://getbootstrap.com/). 50 | - [Leaflet JS](http://leafletjs.com/) for the map. I only added it for the sake of the example. 51 | 52 | ## Structure 53 | 54 | I did what most people recommend for the application's structure. Basically, everything is contained in the `app/` folder. 55 | 56 | - There you have the classic `static/` and `templates/` folders. The `templates/` folder contains macros, error views and a common layout. 57 | - I added a `views/` folder to separate the user and the website logic, which could be extended to the the admin views. 58 | - The same goes for the `forms/` folder, as the project grows it will be useful to split the WTForms code into separate files. 59 | - The `models.py` script contains the SQLAlchemy code, for the while it only contains the logic for a `users` table. 60 | - The `toolbox/` folder is a personal choice, in it I keep all the other code the application will need. 61 | - Management commands should be included in `manage.py`. Enter `python manage.py -?` to get a list of existing commands. 62 | - I added a Makefile for setup tasks, it can be quite useful once a project grows. 63 | 64 | 65 | ## Setup 66 | 67 | ### Vanilla 68 | 69 | - Install the requirements and setup the development environment. 70 | 71 | `make install && make dev` 72 | 73 | - Create the database. 74 | 75 | `python manage.py initdb` 76 | 77 | - Run the application. 78 | 79 | `python manage.py runserver` 80 | 81 | - Navigate to `localhost:5000`. 82 | 83 | ## Configuration 84 | 85 | The goal is to keep most of the application's configuration in a single file called `config.py`. I added a `config_dev.py` and a `config_prod.py` who inherit from `config_common.py`. The trick is to symlink either of these to `config.py`. This is done in by running `make dev` or `make prod`. 86 | 87 | I have included a working Gmail account to confirm user email addresses and reset user passwords, although in production you should't include the file if you push to GitHub because people can see it. The same goes for API keys, you should keep them secret. You can read more about secret configuration files [here](https://exploreflask.com/configuration.html). 88 | 89 | Read [this](http://flask.pocoo.org/docs/0.10/config/) for information on the possible configuration options. 90 | 91 | ## License 92 | 93 | The MIT License (MIT). Please see the [license file](LICENSE) for more information. 94 | -------------------------------------------------------------------------------- /app/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | {% import "macros.html" as m %} 3 | 4 | 5 | 51 | 52 | {% with messages = get_flashed_messages(with_categories=true) %} 53 | {% if messages %} 54 | 59 | {% endif %} 60 | {% endwith %} 61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 91 | 92 | 93 | 94 | {% block content %}{% endblock %} 95 | 96 | 97 |

Choose a Plan!

98 | 99 |
100 |
101 |

One-time

102 |

• 10 USD per automated diagnosis

103 |

• Email support

104 |

• Instant Delivery

105 | 106 | 113 | 114 | 115 |
116 |
117 |

Premium

118 |

• 1000 USD/month, up to 300 diagnoses

119 |

• 24/7 chat support

120 |

• Privacy Guaranteed

121 | 122 | 129 | 130 |
131 |
132 |

Enterprise

133 |

• Unlimited Diagnoses

134 |

• 24/7 Phone Support

135 |

• Custom Tooling

136 |

• Contact us for a price quote

137 | 138 | 145 | 146 |
147 |
148 | 149 | 150 |
151 | 152 |
153 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | {% import "macros.html" as m %} 3 | 4 | 5 | 51 | 52 | {% with messages = get_flashed_messages(with_categories=true) %} 53 | {% if messages %} 54 | 59 | {% endif %} 60 | {% endwith %} 61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 91 | 92 | 93 | 94 | {% block content %}{% endblock %} 95 | 96 | 97 |

Choose a Plan!

98 | 99 |
100 |
101 |

One-time

102 |

• 10 USD per automated diagnosis

103 |

• Email support

104 |

• Instant Delivery

105 | 106 | 113 | 114 | 115 |
116 |
117 |

Premium

118 |

• 1000 USD/month, up to 300 diagnoses

119 |

• 24/7 chat support

120 |

• Privacy Guaranteed

121 | 122 | 129 | 130 |
131 |
132 |

Enterprise

133 |

• Unlimited Diagnoses

134 |

• 24/7 Phone Support

135 |

• Custom Tooling

136 |

• Contact us for a price quote

137 | 138 | 145 | 146 |
147 |
148 | 149 | 150 |
151 | 152 |
153 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /app/views/user.py: -------------------------------------------------------------------------------- 1 | from flask import (Blueprint, render_template, redirect, request, url_for, 2 | abort, flash) 3 | from flask.ext.login import login_user, logout_user, login_required, current_user 4 | from itsdangerous import URLSafeTimedSerializer 5 | from app import app, models, db 6 | from app.forms import user as user_forms 7 | from app.toolbox import email 8 | # Setup Stripe integration 9 | import stripe 10 | import json 11 | from json import dumps 12 | 13 | stripe_keys = { 14 | 'secret_key': "sk_test_0VRS9K4LFsin7xx1cO1cBSip00W1BDqFRG", 15 | 'publishable_key': "pk_test_TQmy1LFbeJ6tgZLOdzT4pZRh00mJ3yq97c" 16 | } 17 | 18 | stripe.api_key = stripe_keys['secret_key'] 19 | 20 | # Serializer for generating random tokens 21 | ts = URLSafeTimedSerializer(app.config['SECRET_KEY']) 22 | 23 | # Create a user blueprint 24 | userbp = Blueprint('userbp', __name__, url_prefix='/user') 25 | 26 | 27 | @userbp.route('/signup', methods=['GET', 'POST']) 28 | def signup(): 29 | form = user_forms.SignUp() 30 | if form.validate_on_submit(): 31 | # Create a user who hasn't validated his email address 32 | user = models.User( 33 | first_name=form.first_name.data, 34 | last_name=form.last_name.data, 35 | phone=form.phone.data, 36 | email=form.email.data, 37 | confirmation=False, 38 | password=form.password.data, 39 | ) 40 | # Insert the user in the database 41 | db.session.add(user) 42 | db.session.commit() 43 | # Subject of the confirmation email 44 | subject = 'Please confirm your email address.' 45 | # Generate a random token 46 | token = ts.dumps(user.email, salt='email-confirm-key') 47 | # Build a confirm link with token 48 | confirmUrl = url_for('userbp.confirm', token=token, _external=True) 49 | # Render an HTML template to send by email 50 | html = render_template('email/confirm.html', 51 | confirm_url=confirmUrl) 52 | # Send the email to user 53 | email.send(user.email, subject, html) 54 | # Send back to the home page 55 | flash('Check your emails to confirm your email address.', 'positive') 56 | return redirect(url_for('index')) 57 | return render_template('user/signup.html', form=form, title='Sign up') 58 | 59 | 60 | @userbp.route('/confirm/', methods=['GET', 'POST']) 61 | def confirm(token): 62 | try: 63 | email = ts.loads(token, salt='email-confirm-key', max_age=86400) 64 | # The token can either expire or be invalid 65 | except: 66 | abort(404) 67 | # Get the user from the database 68 | user = models.User.query.filter_by(email=email).first() 69 | # The user has confirmed his or her email address 70 | user.confirmation = True 71 | # Update the database with the user 72 | db.session.commit() 73 | # Send to the signin page 74 | flash( 75 | 'Your email address has been confirmed, you can sign in.', 'positive') 76 | return redirect(url_for('userbp.signin')) 77 | 78 | 79 | @userbp.route('/signin', methods=['GET', 'POST']) 80 | def signin(): 81 | form = user_forms.Login() 82 | if form.validate_on_submit(): 83 | user = models.User.query.filter_by(email=form.email.data).first() 84 | # Check the user exists 85 | if user is not None: 86 | # Check the password is correct 87 | if user.check_password(form.password.data): 88 | login_user(user) 89 | # Send back to the home page 90 | flash('Succesfully signed in.', 'positive') 91 | return redirect(url_for('index')) 92 | else: 93 | flash('The password you have entered is wrong.', 'negative') 94 | return redirect(url_for('userbp.signin')) 95 | else: 96 | flash('Unknown email address.', 'negative') 97 | return redirect(url_for('userbp.signin')) 98 | return render_template('user/signin.html', form=form, title='Sign in') 99 | 100 | 101 | @userbp.route('/signout') 102 | def signout(): 103 | logout_user() 104 | flash('Succesfully signed out.', 'positive') 105 | return redirect(url_for('index')) 106 | 107 | 108 | @userbp.route('/account') 109 | @login_required 110 | def account(): 111 | return render_template('user/account.html', title='Account') 112 | 113 | 114 | @userbp.route('/forgot', methods=['GET', 'POST']) 115 | def forgot(): 116 | form = user_forms.Forgot() 117 | if form.validate_on_submit(): 118 | user = models.User.query.filter_by(email=form.email.data).first() 119 | # Check the user exists 120 | if user is not None: 121 | # Subject of the confirmation email 122 | subject = 'Reset your password.' 123 | # Generate a random token 124 | token = ts.dumps(user.email, salt='password-reset-key') 125 | # Build a reset link with token 126 | resetUrl = url_for('userbp.reset', token=token, _external=True) 127 | # Render an HTML template to send by email 128 | html = render_template('email/reset.html', reset_url=resetUrl) 129 | # Send the email to user 130 | email.send(user.email, subject, html) 131 | # Send back to the home page 132 | flash('Check your emails to reset your password.', 'positive') 133 | return redirect(url_for('index')) 134 | else: 135 | flash('Unknown email address.', 'negative') 136 | return redirect(url_for('userbp.forgot')) 137 | return render_template('user/forgot.html', form=form) 138 | 139 | 140 | @userbp.route('/reset/', methods=['GET', 'POST']) 141 | def reset(token): 142 | try: 143 | email = ts.loads(token, salt='password-reset-key', max_age=86400) 144 | # The token can either expire or be invalid 145 | except: 146 | abort(404) 147 | form = user_forms.Reset() 148 | if form.validate_on_submit(): 149 | user = models.User.query.filter_by(email=email).first() 150 | # Check the user exists 151 | if user is not None: 152 | user.password = form.password.data 153 | # Update the database with the user 154 | db.session.commit() 155 | # Send to the signin page 156 | flash('Your password has been reset, you can sign in.', 'positive') 157 | return redirect(url_for('userbp.signin')) 158 | else: 159 | flash('Unknown email address.', 'negative') 160 | return redirect(url_for('userbp.forgot')) 161 | return render_template('user/reset.html', form=form, token=token) 162 | 163 | @app.route('/user/pay') 164 | @login_required 165 | def pay(): 166 | user = models.User.query.filter_by(email=current_user.email).first() 167 | if user.paid == 0: 168 | return render_template('user/buy.html', key=stripe_keys['publishable_key'], email=current_user.email) 169 | return "You already paid." 170 | 171 | @app.route('/user/charge', methods=['POST']) 172 | @login_required 173 | def charge(): 174 | # Amount in cents 175 | amount = 500 176 | customer = stripe.Customer.create(email=current_user.email, source=request.form['stripeToken']) 177 | charge = stripe.Charge.create( 178 | customer=customer.id, 179 | amount=amount, 180 | currency='usd', 181 | description='Service Plan' 182 | ) 183 | user = models.User.query.filter_by(email=current_user.email).first() 184 | user.paid = 1 185 | db.session.commit() 186 | # do anything else, like execute shell command to enable user's service on your app 187 | return render_template('user/charge.html', amount=amount) 188 | 189 | @app.route('/api/payFail', methods=['POST', 'GET']) 190 | def payFail(): 191 | content = request.json 192 | stripe_email = content['data']['object']['email'] 193 | user = models.User.query.filter_by(email=stripe_email).first() 194 | if user is not None: 195 | user.paid = 0 196 | db.session.commit() 197 | # do anything else, like execute shell command to disable user's service on your app 198 | return "Response: User with associated email " + str(stripe_email) + " updated on our end (payment failure)." 199 | 200 | @app.route('/api/paySuccess', methods=['POST', 'GET']) 201 | def paySuccess(): 202 | content = request.json 203 | stripe_email = content['data']['object']['email'] 204 | user = models.User.query.filter_by(email=stripe_email).first() 205 | if user is not None: 206 | user.paid = 1 207 | db.session.commit() 208 | # do anything else on payment success, maybe send a thank you email or update more db fields? 209 | return "Response: User with associated email " + str(stripe_email) + " updated on our end (paid)." 210 | 211 | -------------------------------------------------------------------------------- /flaskSaaS-master/app/views/user.py: -------------------------------------------------------------------------------- 1 | from flask import (Blueprint, render_template, redirect, request, url_for, 2 | abort, flash) 3 | from flask.ext.login import login_user, logout_user, login_required, current_user 4 | from itsdangerous import URLSafeTimedSerializer 5 | from app import app, models, db 6 | from app.forms import user as user_forms 7 | from app.toolbox import email 8 | # Setup Stripe integration 9 | import stripe 10 | import json 11 | from json import dumps 12 | 13 | stripe_keys = { 14 | 'secret_key': "sk_test_0VRS9K4LFsin7xx1cO1cBSip00W1BDqFRG", 15 | 'publishable_key': "pk_test_TQmy1LFbeJ6tgZLOdzT4pZRh00mJ3yq97c" 16 | } 17 | 18 | stripe.api_key = stripe_keys['secret_key'] 19 | 20 | # Serializer for generating random tokens 21 | ts = URLSafeTimedSerializer(app.config['SECRET_KEY']) 22 | 23 | # Create a user blueprint 24 | userbp = Blueprint('userbp', __name__, url_prefix='/user') 25 | 26 | 27 | @userbp.route('/signup', methods=['GET', 'POST']) 28 | def signup(): 29 | form = user_forms.SignUp() 30 | if form.validate_on_submit(): 31 | # Create a user who hasn't validated his email address 32 | user = models.User( 33 | first_name=form.first_name.data, 34 | last_name=form.last_name.data, 35 | phone=form.phone.data, 36 | email=form.email.data, 37 | confirmation=False, 38 | password=form.password.data, 39 | ) 40 | # Insert the user in the database 41 | db.session.add(user) 42 | db.session.commit() 43 | # Subject of the confirmation email 44 | subject = 'Please confirm your email address.' 45 | # Generate a random token 46 | token = ts.dumps(user.email, salt='email-confirm-key') 47 | # Build a confirm link with token 48 | confirmUrl = url_for('userbp.confirm', token=token, _external=True) 49 | # Render an HTML template to send by email 50 | html = render_template('email/confirm.html', 51 | confirm_url=confirmUrl) 52 | # Send the email to user 53 | email.send(user.email, subject, html) 54 | # Send back to the home page 55 | flash('Check your emails to confirm your email address.', 'positive') 56 | return redirect(url_for('index')) 57 | return render_template('user/signup.html', form=form, title='Sign up') 58 | 59 | 60 | @userbp.route('/confirm/', methods=['GET', 'POST']) 61 | def confirm(token): 62 | try: 63 | email = ts.loads(token, salt='email-confirm-key', max_age=86400) 64 | # The token can either expire or be invalid 65 | except: 66 | abort(404) 67 | # Get the user from the database 68 | user = models.User.query.filter_by(email=email).first() 69 | # The user has confirmed his or her email address 70 | user.confirmation = True 71 | # Update the database with the user 72 | db.session.commit() 73 | # Send to the signin page 74 | flash( 75 | 'Your email address has been confirmed, you can sign in.', 'positive') 76 | return redirect(url_for('userbp.signin')) 77 | 78 | 79 | @userbp.route('/signin', methods=['GET', 'POST']) 80 | def signin(): 81 | form = user_forms.Login() 82 | if form.validate_on_submit(): 83 | user = models.User.query.filter_by(email=form.email.data).first() 84 | # Check the user exists 85 | if user is not None: 86 | # Check the password is correct 87 | if user.check_password(form.password.data): 88 | login_user(user) 89 | # Send back to the home page 90 | flash('Succesfully signed in.', 'positive') 91 | return redirect(url_for('index')) 92 | else: 93 | flash('The password you have entered is wrong.', 'negative') 94 | return redirect(url_for('userbp.signin')) 95 | else: 96 | flash('Unknown email address.', 'negative') 97 | return redirect(url_for('userbp.signin')) 98 | return render_template('user/signin.html', form=form, title='Sign in') 99 | 100 | 101 | @userbp.route('/signout') 102 | def signout(): 103 | logout_user() 104 | flash('Succesfully signed out.', 'positive') 105 | return redirect(url_for('index')) 106 | 107 | 108 | @userbp.route('/account') 109 | @login_required 110 | def account(): 111 | return render_template('user/account.html', title='Account') 112 | 113 | 114 | @userbp.route('/forgot', methods=['GET', 'POST']) 115 | def forgot(): 116 | form = user_forms.Forgot() 117 | if form.validate_on_submit(): 118 | user = models.User.query.filter_by(email=form.email.data).first() 119 | # Check the user exists 120 | if user is not None: 121 | # Subject of the confirmation email 122 | subject = 'Reset your password.' 123 | # Generate a random token 124 | token = ts.dumps(user.email, salt='password-reset-key') 125 | # Build a reset link with token 126 | resetUrl = url_for('userbp.reset', token=token, _external=True) 127 | # Render an HTML template to send by email 128 | html = render_template('email/reset.html', reset_url=resetUrl) 129 | # Send the email to user 130 | email.send(user.email, subject, html) 131 | # Send back to the home page 132 | flash('Check your emails to reset your password.', 'positive') 133 | return redirect(url_for('index')) 134 | else: 135 | flash('Unknown email address.', 'negative') 136 | return redirect(url_for('userbp.forgot')) 137 | return render_template('user/forgot.html', form=form) 138 | 139 | 140 | @userbp.route('/reset/', methods=['GET', 'POST']) 141 | def reset(token): 142 | try: 143 | email = ts.loads(token, salt='password-reset-key', max_age=86400) 144 | # The token can either expire or be invalid 145 | except: 146 | abort(404) 147 | form = user_forms.Reset() 148 | if form.validate_on_submit(): 149 | user = models.User.query.filter_by(email=email).first() 150 | # Check the user exists 151 | if user is not None: 152 | user.password = form.password.data 153 | # Update the database with the user 154 | db.session.commit() 155 | # Send to the signin page 156 | flash('Your password has been reset, you can sign in.', 'positive') 157 | return redirect(url_for('userbp.signin')) 158 | else: 159 | flash('Unknown email address.', 'negative') 160 | return redirect(url_for('userbp.forgot')) 161 | return render_template('user/reset.html', form=form, token=token) 162 | 163 | @app.route('/user/pay') 164 | @login_required 165 | def pay(): 166 | user = models.User.query.filter_by(email=current_user.email).first() 167 | if user.paid == 0: 168 | return render_template('user/buy.html', key=stripe_keys['publishable_key'], email=current_user.email) 169 | return "You already paid." 170 | 171 | @app.route('/user/charge', methods=['POST']) 172 | @login_required 173 | def charge(): 174 | # Amount in cents 175 | amount = 500 176 | customer = stripe.Customer.create(email=current_user.email, source=request.form['stripeToken']) 177 | charge = stripe.Charge.create( 178 | customer=customer.id, 179 | amount=amount, 180 | currency='usd', 181 | description='Service Plan' 182 | ) 183 | user = models.User.query.filter_by(email=current_user.email).first() 184 | user.paid = 1 185 | db.session.commit() 186 | # do anything else, like execute shell command to enable user's service on your app 187 | return render_template('user/charge.html', amount=amount) 188 | 189 | @app.route('/api/payFail', methods=['POST', 'GET']) 190 | def payFail(): 191 | content = request.json 192 | stripe_email = content['data']['object']['email'] 193 | user = models.User.query.filter_by(email=stripe_email).first() 194 | if user is not None: 195 | user.paid = 0 196 | db.session.commit() 197 | # do anything else, like execute shell command to disable user's service on your app 198 | return "Response: User with associated email " + str(stripe_email) + " updated on our end (payment failure)." 199 | 200 | @app.route('/api/paySuccess', methods=['POST', 'GET']) 201 | def paySuccess(): 202 | content = request.json 203 | stripe_email = content['data']['object']['email'] 204 | user = models.User.query.filter_by(email=stripe_email).first() 205 | if user is not None: 206 | user.paid = 1 207 | db.session.commit() 208 | # do anything else on payment success, maybe send a thank you email or update more db fields? 209 | return "Response: User with associated email " + str(stripe_email) + " updated on our end (paid)." 210 | 211 | -------------------------------------------------------------------------------- /BuildanAIStartup.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "BuildanAIStartup.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [] 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | } 14 | }, 15 | "cells": [ 16 | { 17 | "metadata": { 18 | "id": "IxwWtl97GQxa", 19 | "colab_type": "text" 20 | }, 21 | "cell_type": "markdown", 22 | "source": [ 23 | "# Watch Me Build an AI Startup (10 Steps)\n", 24 | "\n", 25 | "\n", 26 | "![alt text](https://i.imgur.com/h7mhRgZ.jpg)\n", 27 | "\n", 28 | "- **Step 1** List Personal Problems\n", 29 | "- **Step 2 ** Market Research (competing products)\n", 30 | "- **Step 3** Buy Domain\n", 31 | "- **Step 4** Create Landing Page\n", 32 | "- **Step 5** Share Landing Page\n", 33 | "- **Step 6** Create Business Plan \n", 34 | "- **Step 7** Design Pipeline \n", 35 | "- **Step 8** Transfer Learning (!) \n", 36 | "- **Step 9** Create Web App\n", 37 | "- **Step 10** Deploy! \n", 38 | "\n" 39 | ] 40 | }, 41 | { 42 | "metadata": { 43 | "id": "-ppEK1afHxkz", 44 | "colab_type": "text" 45 | }, 46 | "cell_type": "markdown", 47 | "source": [ 48 | "# Step 1 - List Personal Problems\n", 49 | "\n", 50 | "## The star is your next startup idea\n", 51 | "![alt text](https://static1.squarespace.com/static/52ed464fe4b0c88faa50c335/t/5616b3e5e4b0041a87d16720/1444328439304/)\n", 52 | "\n", 53 | "## This has actually been codified by the Japanese 100+ years ago. It's called \"Ikigai\"\n", 54 | "\n", 55 | "![alt text](https://www.bocahouse.com/wp-content/uploads/2018/03/Untitled-Design-5-1170x628.jpg)\n", 56 | "\n", 57 | "### What Industry excites you?\n", 58 | "\n", 59 | "![alt text](https://www.tractica.com/wp-content/uploads/2018/08/MD-AIMF-3Q18-chart.jpg)\n", 60 | "\n", 61 | "### My 3 passions (human enhancement)\n", 62 | "\n", 63 | "- Healthcare - Physical Enhancement via AI\n", 64 | "- Education - Intellectual Enhancement via AI\n", 65 | "- Scientific Research - Increasing human knowledge of this reality\n", 66 | "\n", 67 | "## Thought exercise \n", 68 | "\n", 69 | "1) Hey, this problem sucks! \n", 70 | "\n", 71 | "2) How many people have this problem?\n", 72 | "\n", 73 | "3) How many other ways are there to solve it or live with it?\n", 74 | "\n", 75 | "4) What would it cost to offer a solution?\n", 76 | "\n", 77 | "5) How does the cost compare with the pain of the problem, and the cost of other options (including 'doing nothing'!)?\n", 78 | "\n", 79 | "\n", 80 | "# Still can't find a problem you're passionate about? Live abroad for at least a month (increase training data via new culture, values, language, perspectives)\n" 81 | ] 82 | }, 83 | { 84 | "metadata": { 85 | "id": "czFrkP4xQejT", 86 | "colab_type": "text" 87 | }, 88 | "cell_type": "markdown", 89 | "source": [ 90 | "# Step 2 - Market Research (competing products)\n", 91 | "\n", 92 | "### AI can do so much! This is a subset of possibilities\n", 93 | "\n", 94 | "![alt text](https://meee-services.com/wp-content/uploads/2018/05/AI.jpg)\n", 95 | "\n", 96 | "### Lets do Automated Diagnosis using image classification technology\n", 97 | "\n", 98 | "![alt text](https://2.bp.blogspot.com/-xaPxe_KvLlM/WTMtxwUox6I/AAAAAAAALig/09b3GlXGlw0sjMkd9Ar3aTOnrAUqsN8CgCLcB/s1600/class5.jpg)\n", 99 | "\n", 100 | "### Competitor Landscape \n", 101 | "\n", 102 | "![alt text](https://cdn.nanalyze.com/uploads/2017/08/Medical-Imaging-AI-Startups.jpg)\n", 103 | "\n", 104 | "### The Lung Imaging Landscape looks easily disruptable (not specialized enough, pricing out lower end hospitals)" 105 | ] 106 | }, 107 | { 108 | "metadata": { 109 | "id": "FS-JjqgvTs_i", 110 | "colab_type": "text" 111 | }, 112 | "cell_type": "markdown", 113 | "source": [ 114 | "# Step 3 - Buy Domain\n", 115 | "\n", 116 | "1. Go to Godaddy.com\n", 117 | "2. Find an unused domain name (don't buy an existing one, not worth it)\n", 118 | "3. Buy it! \n", 119 | "\n", 120 | "# Order of Preference\n", 121 | "\n", 122 | "1. .com \n", 123 | "2. .ai" 124 | ] 125 | }, 126 | { 127 | "metadata": { 128 | "id": "5qIjHpeCUDsi", 129 | "colab_type": "text" 130 | }, 131 | "cell_type": "markdown", 132 | "source": [ 133 | "# Step 4 - Create Landing Page \n", 134 | "\n", 135 | "## We need a logo and style guide! Lets use AI to generate one (i used this for School of AI as well)\n", 136 | "\n", 137 | "[www.brandmark.io](https://www.brandmark.io)\n", 138 | "\n", 139 | "![alt text](https://i0.wp.com/ykubot.com/wp-content/uploads/2017/08/01_top.png?fit=1440%2C900)\n", 140 | "\n", 141 | "## Now we can instantly create an email landing page with Mailchimp \n", 142 | "\n", 143 | "[www.mailchimp.com](https://www.mailchimp.com)\n", 144 | "\n", 145 | "![alt text](https://www.growthmarketingpro.com/wp-content/uploads/2018/09/mailchimp-landing-page-builder-published-page.png)\n" 146 | ] 147 | }, 148 | { 149 | "metadata": { 150 | "id": "ngMDZ8hfWgjb", 151 | "colab_type": "text" 152 | }, 153 | "cell_type": "markdown", 154 | "source": [ 155 | "## Step 5 - Share Landing Page\n", 156 | "\n", 157 | "- Reach out to Social Networks to see if we get any signups\n", 158 | "- Reach out to nearby hospitals and other medical facitilies\n", 159 | "\n", 160 | "![alt text](https://i.imgur.com/irWN3Bv.png)\n" 161 | ] 162 | }, 163 | { 164 | "metadata": { 165 | "id": "gb_MNyqfYljC", 166 | "colab_type": "text" 167 | }, 168 | "cell_type": "markdown", 169 | "source": [ 170 | "# Step 6 - Create Business Plan\n", 171 | "\n", 172 | "![alt text](https://i.pinimg.com/originals/4a/f3/c3/4af3c33809719606882232131f768b8b.png)\n", 173 | "\n", 174 | "- Step 1 - Get 25 signups\n", 175 | "- Step 2 - Create SaaS\n", 176 | "- Step 3 - Convert signups to paid clients\n", 177 | "- Step 4 - Collect feedback\n", 178 | "- Step 5 - Improve app using feedback\n", 179 | "- Step 6 - Collect 100 more paid clients\n", 180 | "- Step 7 - Repeat Steps 4-6 until I hit a scaling limit\n", 181 | "- Step 8 - Make 2 hires (full stack engineer, sales)\n", 182 | "- Step 9 - Create more generalized offering\n", 183 | "- Step 10 - Raise a first round\n", 184 | "- Step 11 - Hire a larger team\n", 185 | "- Step 12 - ??? \n", 186 | "- Step 13 - Profit\n", 187 | "- Step 14 - Exit Strategy (Google buys us out. Actually, we'll buy Google out :) ) \n", 188 | "\n", 189 | "![alt text](https://images-na.ssl-images-amazon.com/images/I/81-QB7nDh4L.jpg)\n" 190 | ] 191 | }, 192 | { 193 | "metadata": { 194 | "id": "SYKzC4_aq0zY", 195 | "colab_type": "text" 196 | }, 197 | "cell_type": "markdown", 198 | "source": [ 199 | "# Step 7 Design Pipeline \n", 200 | "\n", 201 | "\n", 202 | "## Features we need \n", 203 | "\n", 204 | "- User Authentication (SQL)\n", 205 | "- Database (SQL)\n", 206 | "- Payment (Stripe)\n", 207 | "- Uploads (Flask native)\n", 208 | "- Inference (Keras)\n", 209 | "\n", 210 | "![alt text](https://i.imgur.com/d3jNLfN.jpg)\n", 211 | "\n", 212 | "#### OK so...\n", 213 | "\n", 214 | "- Authentication + Database + Payment functionality https://github.com/alectrocute/flasksaas \n", 215 | "- Upload functionality https://github.com/bboe/flask-image-uploader \n", 216 | "- Inference? Keras\n", 217 | "\n", 218 | "##### basically..\n", 219 | "\n", 220 | "If upload && paid == true, run inference, display result!\n", 221 | "\n", 222 | "\n" 223 | ] 224 | }, 225 | { 226 | "metadata": { 227 | "id": "eOiaMrTdaKNa", 228 | "colab_type": "text" 229 | }, 230 | "cell_type": "markdown", 231 | "source": [ 232 | "### Step 8 Transfer Learning (!)\n", 233 | "\n", 234 | "\n", 235 | "## Convolutional Networks do really well at Image classification \n", 236 | "\n", 237 | "![alt text](https://adeshpande3.github.io/assets/Cover.png)\n", 238 | "\n", 239 | "## I have a great video on how this works here\n", 240 | "\n", 241 | "[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/FTr3n7uBIuE/0.jpg)](https://youtu.be/FTr3n7uBIuE)\n", 242 | "\n", 243 | "## So we just need to train a model on labeled data\n", 244 | "\n", 245 | "![alt text](https://datawhatnow.com/wp-content/uploads/2017/08/pseudo-labeling-683x1024.png)\n", 246 | "\n", 247 | "## But that already exists! \n", 248 | "\n", 249 | "![alt text](https://www.topbots.com/wp-content/uploads/2017/06/nnarch1-1.png)\n", 250 | "\n", 251 | "## So we'll retrain an existing model (ResNet) on new data to leverage existing learnings and improve overall accuracy (transfer learning!)\n", 252 | "\n", 253 | "- 1: There is no need for an extremely large training dataset.\n", 254 | "\n", 255 | "- 2: Not much computational power is required. As we are using pre-trained weights and only have to learn the weights of the last few layers.\n" 256 | ] 257 | }, 258 | { 259 | "metadata": { 260 | "id": "lWErPieZra8h", 261 | "colab_type": "text" 262 | }, 263 | "cell_type": "markdown", 264 | "source": [ 265 | "# Step 9 - Write Web App\n", 266 | "\n" 267 | ] 268 | }, 269 | { 270 | "metadata": { 271 | "id": "a1GTps3xvxgv", 272 | "colab_type": "text" 273 | }, 274 | "cell_type": "markdown", 275 | "source": [ 276 | "# Step 10 - Deploy! " 277 | ] 278 | }, 279 | { 280 | "metadata": { 281 | "id": "21hh9tbGv09J", 282 | "colab_type": "text" 283 | }, 284 | "cell_type": "markdown", 285 | "source": [ 286 | "- Mobile app?\n", 287 | "- Continous Serving via Tensorflow Serving\n", 288 | "- Batch inference\n", 289 | "- Better Design\n" 290 | ] 291 | } 292 | ] 293 | } 294 | -------------------------------------------------------------------------------- /Transfer_Learning.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Transfer_Learning.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [] 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | } 14 | }, 15 | "cells": [ 16 | { 17 | "metadata": { 18 | "id": "9XGhEYxHkbRq", 19 | "colab_type": "code", 20 | "outputId": "ae6926e6-fdf8-4c4d-8f2b-02e671643296", 21 | "colab": { 22 | "base_uri": "https://localhost:8080/", 23 | "height": 34 24 | } 25 | }, 26 | "cell_type": "code", 27 | "source": [ 28 | "\n", 29 | "import pandas as pd\n", 30 | "import numpy as np\n", 31 | "import os\n", 32 | "import keras\n", 33 | "import matplotlib.pyplot as plt\n", 34 | "from keras.layers import Dense,GlobalAveragePooling2D\n", 35 | "from keras.applications import MobileNet\n", 36 | "from keras.preprocessing import image\n", 37 | "from keras.applications.mobilenet import preprocess_input\n", 38 | "from keras.preprocessing.image import ImageDataGenerator\n", 39 | "from keras.models import Model\n", 40 | "from keras.optimizers import Adam" 41 | ], 42 | "execution_count": 0, 43 | "outputs": [ 44 | { 45 | "output_type": "stream", 46 | "text": [ 47 | "Using TensorFlow backend.\n" 48 | ], 49 | "name": "stderr" 50 | } 51 | ] 52 | }, 53 | { 54 | "metadata": { 55 | "id": "-G17kVoXkhLi", 56 | "colab_type": "code", 57 | "outputId": "baab2612-cee0-46fa-d001-ff0502501bea", 58 | "colab": { 59 | "base_uri": "https://localhost:8080/", 60 | "height": 136 61 | } 62 | }, 63 | "cell_type": "code", 64 | "source": [ 65 | "base_model=MobileNet(weights='imagenet',include_top=False) #imports the mobilenet model and discards the last 1000 neuron layer.\n", 66 | "\n", 67 | "x=base_model.output\n", 68 | "x=GlobalAveragePooling2D()(x)\n", 69 | "x=Dense(1024,activation='relu')(x) #we add dense layers so that the model can learn more complex functions and classify for better results.\n", 70 | "x=Dense(1024,activation='relu')(x) #dense layer 2\n", 71 | "x=Dense(512,activation='relu')(x) #dense layer 3\n", 72 | "preds=Dense(3,activation='softmax')(x) #final layer with softmax activation" 73 | ], 74 | "execution_count": 0, 75 | "outputs": [ 76 | { 77 | "output_type": "stream", 78 | "text": [ 79 | "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n", 80 | "Instructions for updating:\n", 81 | "Colocations handled automatically by placer.\n" 82 | ], 83 | "name": "stdout" 84 | }, 85 | { 86 | "output_type": "stream", 87 | "text": [ 88 | "/usr/local/lib/python3.6/dist-packages/keras_applications/mobilenet.py:208: UserWarning: MobileNet shape is undefined. Weights for input shape (224, 224) will be loaded.\n", 89 | " warnings.warn('MobileNet shape is undefined.'\n" 90 | ], 91 | "name": "stderr" 92 | }, 93 | { 94 | "output_type": "stream", 95 | "text": [ 96 | "Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.6/mobilenet_1_0_224_tf_no_top.h5\n", 97 | "17227776/17225924 [==============================] - 0s 0us/step\n" 98 | ], 99 | "name": "stdout" 100 | } 101 | ] 102 | }, 103 | { 104 | "metadata": { 105 | "id": "R9INumO_kqLZ", 106 | "colab_type": "code", 107 | "colab": {} 108 | }, 109 | "cell_type": "code", 110 | "source": [ 111 | "model=Model(inputs=base_model.input,outputs=preds)" 112 | ], 113 | "execution_count": 0, 114 | "outputs": [] 115 | }, 116 | { 117 | "metadata": { 118 | "id": "4c9FnfM3ksr5", 119 | "colab_type": "code", 120 | "colab": {} 121 | }, 122 | "cell_type": "code", 123 | "source": [ 124 | "for layer in model.layers[:20]:\n", 125 | " layer.trainable=False\n", 126 | "for layer in model.layers[20:]:\n", 127 | " layer.trainable=True" 128 | ], 129 | "execution_count": 0, 130 | "outputs": [] 131 | }, 132 | { 133 | "metadata": { 134 | "id": "SN02f_Ztk2PR", 135 | "colab_type": "code", 136 | "outputId": "358eff3e-1b01-44f7-a542-9b0e2b55c435", 137 | "colab": { 138 | "resources": { 139 | "http://localhost:8080/nbextensions/google.colab/files.js": { 140 | "data": "Ly8gQ29weXJpZ2h0IDIwMTcgR29vZ2xlIExMQwovLwovLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKLy8geW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgovLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKLy8KLy8gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKLy8KLy8gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQovLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAovLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KLy8gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAovLyBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi8qKgogKiBAZmlsZW92ZXJ2aWV3IEhlbHBlcnMgZm9yIGdvb2dsZS5jb2xhYiBQeXRob24gbW9kdWxlLgogKi8KKGZ1bmN0aW9uKHNjb3BlKSB7CmZ1bmN0aW9uIHNwYW4odGV4dCwgc3R5bGVBdHRyaWJ1dGVzID0ge30pIHsKICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpOwogIGVsZW1lbnQudGV4dENvbnRlbnQgPSB0ZXh0OwogIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHN0eWxlQXR0cmlidXRlcykpIHsKICAgIGVsZW1lbnQuc3R5bGVba2V5XSA9IHN0eWxlQXR0cmlidXRlc1trZXldOwogIH0KICByZXR1cm4gZWxlbWVudDsKfQoKLy8gTWF4IG51bWJlciBvZiBieXRlcyB3aGljaCB3aWxsIGJlIHVwbG9hZGVkIGF0IGEgdGltZS4KY29uc3QgTUFYX1BBWUxPQURfU0laRSA9IDEwMCAqIDEwMjQ7Ci8vIE1heCBhbW91bnQgb2YgdGltZSB0byBibG9jayB3YWl0aW5nIGZvciB0aGUgdXNlci4KY29uc3QgRklMRV9DSEFOR0VfVElNRU9VVF9NUyA9IDMwICogMTAwMDsKCmZ1bmN0aW9uIF91cGxvYWRGaWxlcyhpbnB1dElkLCBvdXRwdXRJZCkgewogIGNvbnN0IHN0ZXBzID0gdXBsb2FkRmlsZXNTdGVwKGlucHV0SWQsIG91dHB1dElkKTsKICBjb25zdCBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQob3V0cHV0SWQpOwogIC8vIENhY2hlIHN0ZXBzIG9uIHRoZSBvdXRwdXRFbGVtZW50IHRvIG1ha2UgaXQgYXZhaWxhYmxlIGZvciB0aGUgbmV4dCBjYWxsCiAgLy8gdG8gdXBsb2FkRmlsZXNDb250aW51ZSBmcm9tIFB5dGhvbi4KICBvdXRwdXRFbGVtZW50LnN0ZXBzID0gc3RlcHM7CgogIHJldHVybiBfdXBsb2FkRmlsZXNDb250aW51ZShvdXRwdXRJZCk7Cn0KCi8vIFRoaXMgaXMgcm91Z2hseSBhbiBhc3luYyBnZW5lcmF0b3IgKG5vdCBzdXBwb3J0ZWQgaW4gdGhlIGJyb3dzZXIgeWV0KSwKLy8gd2hlcmUgdGhlcmUgYXJlIG11bHRpcGxlIGFzeW5jaHJvbm91cyBzdGVwcyBhbmQgdGhlIFB5dGhvbiBzaWRlIGlzIGdvaW5nCi8vIHRvIHBvbGwgZm9yIGNvbXBsZXRpb24gb2YgZWFjaCBzdGVwLgovLyBUaGlzIHVzZXMgYSBQcm9taXNlIHRvIGJsb2NrIHRoZSBweXRob24gc2lkZSBvbiBjb21wbGV0aW9uIG9mIGVhY2ggc3RlcCwKLy8gdGhlbiBwYXNzZXMgdGhlIHJlc3VsdCBvZiB0aGUgcHJldmlvdXMgc3RlcCBhcyB0aGUgaW5wdXQgdG8gdGhlIG5leHQgc3RlcC4KZnVuY3Rpb24gX3VwbG9hZEZpbGVzQ29udGludWUob3V0cHV0SWQpIHsKICBjb25zdCBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQob3V0cHV0SWQpOwogIGNvbnN0IHN0ZXBzID0gb3V0cHV0RWxlbWVudC5zdGVwczsKCiAgY29uc3QgbmV4dCA9IHN0ZXBzLm5leHQob3V0cHV0RWxlbWVudC5sYXN0UHJvbWlzZVZhbHVlKTsKICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5leHQudmFsdWUucHJvbWlzZSkudGhlbigodmFsdWUpID0+IHsKICAgIC8vIENhY2hlIHRoZSBsYXN0IHByb21pc2UgdmFsdWUgdG8gbWFrZSBpdCBhdmFpbGFibGUgdG8gdGhlIG5leHQKICAgIC8vIHN0ZXAgb2YgdGhlIGdlbmVyYXRvci4KICAgIG91dHB1dEVsZW1lbnQubGFzdFByb21pc2VWYWx1ZSA9IHZhbHVlOwogICAgcmV0dXJuIG5leHQudmFsdWUucmVzcG9uc2U7CiAgfSk7Cn0KCi8qKgogKiBHZW5lcmF0b3IgZnVuY3Rpb24gd2hpY2ggaXMgY2FsbGVkIGJldHdlZW4gZWFjaCBhc3luYyBzdGVwIG9mIHRoZSB1cGxvYWQKICogcHJvY2Vzcy4KICogQHBhcmFtIHtzdHJpbmd9IGlucHV0SWQgRWxlbWVudCBJRCBvZiB0aGUgaW5wdXQgZmlsZSBwaWNrZXIgZWxlbWVudC4KICogQHBhcmFtIHtzdHJpbmd9IG91dHB1dElkIEVsZW1lbnQgSUQgb2YgdGhlIG91dHB1dCBkaXNwbGF5LgogKiBAcmV0dXJuIHshSXRlcmFibGU8IU9iamVjdD59IEl0ZXJhYmxlIG9mIG5leHQgc3RlcHMuCiAqLwpmdW5jdGlvbiogdXBsb2FkRmlsZXNTdGVwKGlucHV0SWQsIG91dHB1dElkKSB7CiAgY29uc3QgaW5wdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaW5wdXRJZCk7CiAgaW5wdXRFbGVtZW50LmRpc2FibGVkID0gZmFsc2U7CgogIGNvbnN0IG91dHB1dEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChvdXRwdXRJZCk7CiAgb3V0cHV0RWxlbWVudC5pbm5lckhUTUwgPSAnJzsKCiAgY29uc3QgcGlja2VkUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICBpbnB1dEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKGUpID0+IHsKICAgICAgcmVzb2x2ZShlLnRhcmdldC5maWxlcyk7CiAgICB9KTsKICB9KTsKCiAgY29uc3QgY2FuY2VsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7CiAgaW5wdXRFbGVtZW50LnBhcmVudEVsZW1lbnQuYXBwZW5kQ2hpbGQoY2FuY2VsKTsKICBjYW5jZWwudGV4dENvbnRlbnQgPSAnQ2FuY2VsIHVwbG9hZCc7CiAgY29uc3QgY2FuY2VsUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICBjYW5jZWwub25jbGljayA9ICgpID0+IHsKICAgICAgcmVzb2x2ZShudWxsKTsKICAgIH07CiAgfSk7CgogIC8vIENhbmNlbCB1cGxvYWQgaWYgdXNlciBoYXNuJ3QgcGlja2VkIGFueXRoaW5nIGluIHRpbWVvdXQuCiAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgc2V0VGltZW91dCgoKSA9PiB7CiAgICAgIHJlc29sdmUobnVsbCk7CiAgICB9LCBGSUxFX0NIQU5HRV9USU1FT1VUX01TKTsKICB9KTsKCiAgLy8gV2FpdCBmb3IgdGhlIHVzZXIgdG8gcGljayB0aGUgZmlsZXMuCiAgY29uc3QgZmlsZXMgPSB5aWVsZCB7CiAgICBwcm9taXNlOiBQcm9taXNlLnJhY2UoW3BpY2tlZFByb21pc2UsIHRpbWVvdXRQcm9taXNlLCBjYW5jZWxQcm9taXNlXSksCiAgICByZXNwb25zZTogewogICAgICBhY3Rpb246ICdzdGFydGluZycsCiAgICB9CiAgfTsKCiAgaWYgKCFmaWxlcykgewogICAgcmV0dXJuIHsKICAgICAgcmVzcG9uc2U6IHsKICAgICAgICBhY3Rpb246ICdjb21wbGV0ZScsCiAgICAgIH0KICAgIH07CiAgfQoKICBjYW5jZWwucmVtb3ZlKCk7CgogIC8vIERpc2FibGUgdGhlIGlucHV0IGVsZW1lbnQgc2luY2UgZnVydGhlciBwaWNrcyBhcmUgbm90IGFsbG93ZWQuCiAgaW5wdXRFbGVtZW50LmRpc2FibGVkID0gdHJ1ZTsKCiAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7CiAgICBjb25zdCBsaSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7CiAgICBsaS5hcHBlbmQoc3BhbihmaWxlLm5hbWUsIHtmb250V2VpZ2h0OiAnYm9sZCd9KSk7CiAgICBsaS5hcHBlbmQoc3BhbigKICAgICAgICBgKCR7ZmlsZS50eXBlIHx8ICduL2EnfSkgLSAke2ZpbGUuc2l6ZX0gYnl0ZXMsIGAgKwogICAgICAgIGBsYXN0IG1vZGlmaWVkOiAkewogICAgICAgICAgICBmaWxlLmxhc3RNb2RpZmllZERhdGUgPyBmaWxlLmxhc3RNb2RpZmllZERhdGUudG9Mb2NhbGVEYXRlU3RyaW5nKCkgOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbi9hJ30gLSBgKSk7CiAgICBjb25zdCBwZXJjZW50ID0gc3BhbignMCUgZG9uZScpOwogICAgbGkuYXBwZW5kQ2hpbGQocGVyY2VudCk7CgogICAgb3V0cHV0RWxlbWVudC5hcHBlbmRDaGlsZChsaSk7CgogICAgY29uc3QgZmlsZURhdGFQcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHsKICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTsKICAgICAgcmVhZGVyLm9ubG9hZCA9IChlKSA9PiB7CiAgICAgICAgcmVzb2x2ZShlLnRhcmdldC5yZXN1bHQpOwogICAgICB9OwogICAgICByZWFkZXIucmVhZEFzQXJyYXlCdWZmZXIoZmlsZSk7CiAgICB9KTsKICAgIC8vIFdhaXQgZm9yIHRoZSBkYXRhIHRvIGJlIHJlYWR5LgogICAgbGV0IGZpbGVEYXRhID0geWllbGQgewogICAgICBwcm9taXNlOiBmaWxlRGF0YVByb21pc2UsCiAgICAgIHJlc3BvbnNlOiB7CiAgICAgICAgYWN0aW9uOiAnY29udGludWUnLAogICAgICB9CiAgICB9OwoKICAgIC8vIFVzZSBhIGNodW5rZWQgc2VuZGluZyB0byBhdm9pZCBtZXNzYWdlIHNpemUgbGltaXRzLiBTZWUgYi82MjExNTY2MC4KICAgIGxldCBwb3NpdGlvbiA9IDA7CiAgICB3aGlsZSAocG9zaXRpb24gPCBmaWxlRGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgIGNvbnN0IGxlbmd0aCA9IE1hdGgubWluKGZpbGVEYXRhLmJ5dGVMZW5ndGggLSBwb3NpdGlvbiwgTUFYX1BBWUxPQURfU0laRSk7CiAgICAgIGNvbnN0IGNodW5rID0gbmV3IFVpbnQ4QXJyYXkoZmlsZURhdGEsIHBvc2l0aW9uLCBsZW5ndGgpOwogICAgICBwb3NpdGlvbiArPSBsZW5ndGg7CgogICAgICBjb25zdCBiYXNlNjQgPSBidG9hKFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgY2h1bmspKTsKICAgICAgeWllbGQgewogICAgICAgIHJlc3BvbnNlOiB7CiAgICAgICAgICBhY3Rpb246ICdhcHBlbmQnLAogICAgICAgICAgZmlsZTogZmlsZS5uYW1lLAogICAgICAgICAgZGF0YTogYmFzZTY0LAogICAgICAgIH0sCiAgICAgIH07CiAgICAgIHBlcmNlbnQudGV4dENvbnRlbnQgPQogICAgICAgICAgYCR7TWF0aC5yb3VuZCgocG9zaXRpb24gLyBmaWxlRGF0YS5ieXRlTGVuZ3RoKSAqIDEwMCl9JSBkb25lYDsKICAgIH0KICB9CgogIC8vIEFsbCBkb25lLgogIHlpZWxkIHsKICAgIHJlc3BvbnNlOiB7CiAgICAgIGFjdGlvbjogJ2NvbXBsZXRlJywKICAgIH0KICB9Owp9CgpzY29wZS5nb29nbGUgPSBzY29wZS5nb29nbGUgfHwge307CnNjb3BlLmdvb2dsZS5jb2xhYiA9IHNjb3BlLmdvb2dsZS5jb2xhYiB8fCB7fTsKc2NvcGUuZ29vZ2xlLmNvbGFiLl9maWxlcyA9IHsKICBfdXBsb2FkRmlsZXMsCiAgX3VwbG9hZEZpbGVzQ29udGludWUsCn07Cn0pKHNlbGYpOwo=", 141 | "ok": true, 142 | "headers": [ 143 | [ 144 | "content-type", 145 | "application/javascript" 146 | ] 147 | ], 148 | "status": 200, 149 | "status_text": "" 150 | } 151 | }, 152 | "base_uri": "https://localhost:8080/", 153 | "height": 91 154 | } 155 | }, 156 | "cell_type": "code", 157 | "source": [ 158 | "!pip install -U -q kaggle\n", 159 | "!mkdir -p ~/.kaggle\n", 160 | "\n", 161 | "from google.colab import files\n", 162 | "files.upload()" 163 | ], 164 | "execution_count": 0, 165 | "outputs": [ 166 | { 167 | "output_type": "display_data", 168 | "data": { 169 | "text/html": [ 170 | "\n", 171 | " \n", 172 | " \n", 173 | " Upload widget is only available when the cell has been executed in the\n", 174 | " current browser session. Please rerun this cell to enable.\n", 175 | " \n", 176 | " " 177 | ], 178 | "text/plain": [ 179 | "" 180 | ] 181 | }, 182 | "metadata": { 183 | "tags": [] 184 | } 185 | }, 186 | { 187 | "output_type": "stream", 188 | "text": [ 189 | "Saving kaggle.json to kaggle.json\n" 190 | ], 191 | "name": "stdout" 192 | }, 193 | { 194 | "output_type": "execute_result", 195 | "data": { 196 | "text/plain": [ 197 | "{'kaggle.json': b'{\"username\":\"sirajr\",\"key\":\"df02ffd99acc284bf9472c08e61dec0a\"}'}" 198 | ] 199 | }, 200 | "metadata": { 201 | "tags": [] 202 | }, 203 | "execution_count": 7 204 | } 205 | ] 206 | }, 207 | { 208 | "metadata": { 209 | "id": "lcB8ITYMoVhx", 210 | "colab_type": "code", 211 | "colab": {} 212 | }, 213 | "cell_type": "code", 214 | "source": [ 215 | "!cp kaggle.json ~/.kaggle/\n", 216 | "\n", 217 | "!kaggle datasets download -d paultimothymooney/chest-xray-pneumonia" 218 | ], 219 | "execution_count": 0, 220 | "outputs": [] 221 | }, 222 | { 223 | "metadata": { 224 | "id": "PdoSkpMkopAR", 225 | "colab_type": "text" 226 | }, 227 | "cell_type": "markdown", 228 | "source": [ 229 | "\n", 230 | "\n" 231 | ] 232 | }, 233 | { 234 | "metadata": { 235 | "id": "R99OTrc_oYuR", 236 | "colab_type": "code", 237 | "colab": {} 238 | }, 239 | "cell_type": "code", 240 | "source": [ 241 | "import pandas as pd\n", 242 | "import formatter as fm\n", 243 | "df = pd.read_csv(BERT_MODEL)\n", 244 | "preprocess_input, test_data = fm(df)" 245 | ], 246 | "execution_count": 0, 247 | "outputs": [] 248 | }, 249 | { 250 | "metadata": { 251 | "id": "nNvVDZTfkx8B", 252 | "colab_type": "code", 253 | "colab": {} 254 | }, 255 | "cell_type": "code", 256 | "source": [ 257 | "train_datagen=ImageDataGenerator(preprocessing_function=preprocess_input) #included in our dependencies\n", 258 | "\n", 259 | "train_generator=train_datagen.flow_from_directory('./train/', # this is where you specify the path to the main data folder\n", 260 | " target_size=(224,224),\n", 261 | " color_mode='rgb',\n", 262 | " batch_size=32,\n", 263 | " class_mode='categorical',\n", 264 | " shuffle=True)\n", 265 | "\n", 266 | "model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])\n", 267 | "# Adam optimizer\n", 268 | "# loss function will be categorical cross entropy\n", 269 | "# evaluation metric will be accuracy\n", 270 | "\n", 271 | "step_size_train=train_generator.n//train_generator.batch_size\n", 272 | "model.fit_generator(generator=train_generator,\n", 273 | " steps_per_epoch=step_size_train,\n", 274 | " epochs=5)" 275 | ], 276 | "execution_count": 0, 277 | "outputs": [] 278 | }, 279 | { 280 | "metadata": { 281 | "id": "AvO6yOp-o7uQ", 282 | "colab_type": "text" 283 | }, 284 | "cell_type": "markdown", 285 | "source": [ 286 | "\n" 287 | ] 288 | }, 289 | { 290 | "metadata": { 291 | "id": "tnJHEADQqgEB", 292 | "colab_type": "text" 293 | }, 294 | "cell_type": "markdown", 295 | "source": [ 296 | "# Download the weights! " 297 | ] 298 | }, 299 | { 300 | "metadata": { 301 | "id": "0dQjZ5vqqfOZ", 302 | "colab_type": "code", 303 | "colab": {} 304 | }, 305 | "cell_type": "code", 306 | "source": [ 307 | "!pip install -U -q PyDrive\n", 308 | "from pydrive.auth import GoogleAuth\n", 309 | "from pydrive.drive import GoogleDrive\n", 310 | "from google.colab import auth\n", 311 | "from oauth2client.client import GoogleCredentials\n", 312 | "\n", 313 | "# 1. Authenticate and create the PyDrive client.\n", 314 | "auth.authenticate_user()\n", 315 | "gauth = GoogleAuth()\n", 316 | "gauth.credentials = GoogleCredentials.get_application_default()\n", 317 | "drive = GoogleDrive(gauth)\n", 318 | "\n", 319 | "# 2. Save Keras Model or weights on google drive\n", 320 | "\n", 321 | "# create on Colab directory\n", 322 | "model.save('model.h5') \n", 323 | "model_file = drive.CreateFile({'title' : 'model.h5'})\n", 324 | "model_file.SetContentFile('model.h5')\n", 325 | "model_file.Upload()\n", 326 | "\n", 327 | "# download to google drive\n", 328 | "drive.CreateFile({'id': model_file.get('id')})" 329 | ], 330 | "execution_count": 0, 331 | "outputs": [] 332 | } 333 | ] 334 | } --------------------------------------------------------------------------------