├── .idea ├── .gitignore ├── ToDoFlask.iml ├── dataSources.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── ppt-api.iml └── vcs.xml ├── README.md ├── __pycache__ ├── app.cpython-310.pyc ├── chat.cpython-310.pyc └── ppt.cpython-310.pyc ├── app.py ├── chat.py ├── instance └── database.db ├── ppt.py ├── requirements.txt └── templates ├── base.html ├── dashboard.html ├── home.html ├── login.html └── register.html /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/ToDoFlask.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:$PROJECT_DIR$/database.db 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/ppt-api.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PPT maker using ChatGPT 2 | 3 | ### EDIT: 4 | My free Open AI API token expired the first of this month when I had just started working on the app. As a result, I will not be working on this anymore for quite some time. 5 | 6 | ## Goal 7 | 8 | 1) To be able to generate a powerpoint presentation just from the prompt given. 9 | 2) Make a web application for easy access 10 | 11 | ## Current Status 12 | 13 | Lots of bugs to fix but made a start. Made a web application where you can give a prompt and generate (and download) a pptx file prepared from chat gpt's response. 14 | 15 | ## USAGE 16 | 17 | 1) Register 18 | 2) Login 19 | 3) navigate to /dashboard 20 | 4) Write your prompt. Don't forget to mention: `Write a ppt` in the starting. 21 | 5) Generate your ppt. Download starts automatically! 22 | 23 | ## Setup Instructions: 24 | 25 | 1) `git clone https://github.com/MSSRPRAD/ppt-api.git` 26 | 2) `cd ppt-api` 27 | 3) `virtualenv venv` 28 | 4) (from bash terminal) `source venv/bin/activate` 29 | 5) `pip install -r requirements.txt` 30 | 6) `python app.py` 31 | 32 | NOTE: You have to set your own OPENAI API KEY. Go to https://platform.openai.com/account/api-keys to generate one if you don't have one. 33 | 34 | 35 | -------------------------------------------------------------------------------- /__pycache__/app.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSSRPRAD/ppt-api/02ae2b7323de05a1472b518a09033981a9b87c64/__pycache__/app.cpython-310.pyc -------------------------------------------------------------------------------- /__pycache__/chat.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSSRPRAD/ppt-api/02ae2b7323de05a1472b518a09033981a9b87c64/__pycache__/chat.cpython-310.pyc -------------------------------------------------------------------------------- /__pycache__/ppt.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSSRPRAD/ppt-api/02ae2b7323de05a1472b518a09033981a9b87c64/__pycache__/ppt.cpython-310.pyc -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import string 2 | import sys 3 | 4 | from flask import Flask, render_template, redirect, url_for, flash, session, request, send_file 5 | from flask_sqlalchemy import SQLAlchemy 6 | from flask_login import UserMixin, login_required, login_user, LoginManager, current_user, logout_user 7 | import os 8 | from flask_bcrypt import Bcrypt 9 | 10 | import chat 11 | import ppt 12 | 13 | app = Flask(__name__) 14 | 15 | bcrypt = Bcrypt(app) 16 | 17 | basedir = os.path.abspath(os.path.dirname(__file__)) 18 | 19 | # app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' 20 | app.config['SQLALCHEMY_DATABASE_URI'] =\ 21 | 'sqlite:///' + os.path.join(basedir, 'database.db') 22 | 23 | app.config['SECRET_KEY'] = "secretkey" 24 | 25 | db = SQLAlchemy(app) 26 | 27 | login_manager = LoginManager() 28 | login_manager.init_app(app) 29 | login_manager.login_view = 'login' 30 | 31 | class Error: 32 | message = string 33 | 34 | @login_manager.user_loader 35 | def load_user(user_id): 36 | return User.query.get(int(user_id)) 37 | 38 | class User(db.Model, UserMixin): 39 | id = db.Column(db.Integer, primary_key=True) 40 | username = db.Column(db.String(20), nullable = False) 41 | password = db.Column(db.String(100), nullable = False) 42 | requests = db.relationship('Request', backref = 'user') 43 | 44 | class Request(db.Model): 45 | id = db.Column(db.Integer, primary_key=True) 46 | userId = db.Column(db.Integer, db.ForeignKey('user.id')) 47 | content = db.Column(db.String(5000), nullable = True) 48 | 49 | @app.route('/') 50 | def home(): 51 | return render_template('home.html') 52 | 53 | @app.route('/login', methods = ['GET', 'POST']) 54 | def login(): 55 | if current_user: 56 | session.clear() 57 | flash("If you try to open this page after logging in you will be logged out automatically!") 58 | logout_user() 59 | redirect(url_for('login')) 60 | if request.method == 'POST': 61 | username = request.form['username'] 62 | password = request.form['password'] 63 | user = User.query.filter_by(username=username).first() 64 | if user: 65 | if bcrypt.check_password_hash(user.password, password): 66 | login_user(user) 67 | flash("") 68 | return redirect(url_for('dashboard')) 69 | else: 70 | flash("Wrong Password. Please Try Again!") 71 | else: 72 | flash("Invalid Credentials. Please Try Again!") 73 | return render_template('login.html') 74 | 75 | @app.route('/logout', methods = ['GET', 'POST']) 76 | def logout(): 77 | logout_user() 78 | return redirect(url_for('login')) 79 | 80 | @app.route('/dashboard', methods = ['GET', 'POST']) 81 | @login_required 82 | def dashboard(): 83 | return render_template('dashboard.html') 84 | 85 | @app.route('/register', methods = ['GET', 'POST']) 86 | def register(): 87 | if request.method == 'POST': 88 | username = request.form['username'] 89 | password = request.form['password'] 90 | hashed_password = bcrypt.generate_password_hash(password) 91 | new_user = User(username=username, password = hashed_password) 92 | existing_user = User.query.filter_by(username=username).first() 93 | if (existing_user): 94 | # print('\nAlready Exists Error!\n', file=sys.stderr) 95 | flash("That name is already taken, please choose another") 96 | return render_template('register.html') 97 | else: 98 | db.session.add(new_user) 99 | db.session.commit() 100 | flash("") 101 | return redirect(url_for('login')) 102 | return render_template('register.html') 103 | 104 | @app.route('/delete/user') 105 | @login_required 106 | def deleteUser(): 107 | user = current_user 108 | if user: 109 | User.query.filter_by(id=user.id).delete() 110 | logout_user() 111 | db.session.commit() 112 | return redirect(url_for('home')) 113 | 114 | @app.route('/dashboard/create', methods=['POST','GET']) 115 | @login_required 116 | def create(): 117 | if request.method == 'POST': 118 | req = Request() 119 | req.user=current_user 120 | content=request.form['content'] 121 | content = chat.chat(content, current_user.username) 122 | req.content=content 123 | db.session.add(req) 124 | db.session.commit() 125 | ppt.ppt(current_user.username) 126 | path = current_user.username+".pptx" 127 | return send_file(path, as_attachment=True) 128 | return "THERE WAS AN ERROR WHILE ADDING THE TASK!" 129 | 130 | if __name__ == '__main__': 131 | with app.app_context(): 132 | db.create_all() 133 | app.run(debug=True) 134 | -------------------------------------------------------------------------------- /chat.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | import json 4 | import re 5 | 6 | # set your OpenAI API key 7 | openai.api_key = "" 8 | def chat(req, username): 9 | # define the prompt for the text generation 10 | s2 = " Answer should be as a valid json object with this structure: 1) 'title' field representing title of ppt 2) 'slides' field representing array of slides 3) Each 'slide' having: 'title', 'content' fields. Also, 'content' is a list of strings representing points each not having more than 20 words. Double Check that output is a valid json and that the number of slides is correct." 11 | # req = "Make a powerpoint presentation with five slides for a programmer audience on technical and ethical advantages of linux vs windows with each slide having around 200 words. It should be technical and complex." 12 | prompt = req + s2 13 | 14 | 15 | # define the model and parameters 16 | model_engine = "text-davinci-002" 17 | parameters = { 18 | "temperature": 0.5, 19 | "max_tokens": 3000, 20 | "top_p": 1, 21 | "frequency_penalty": 0, 22 | "presence_penalty": 0 23 | } 24 | 25 | # generate text using the model and prompt 26 | response = openai.Completion.create( 27 | engine=model_engine, 28 | prompt=prompt, 29 | max_tokens=parameters["max_tokens"], 30 | temperature=parameters["temperature"], 31 | top_p=parameters["top_p"], 32 | frequency_penalty=parameters["frequency_penalty"], 33 | presence_penalty=parameters["presence_penalty"] 34 | ) 35 | 36 | result = response["choices"][0]["text"] 37 | 38 | output = re.sub(r'^.*?{', '{', result) 39 | 40 | # Save the JSON data string to a file 41 | with open("ppt-api/"+username+"ppt.json", "w") as json_file: 42 | json_file.write(output) 43 | 44 | 45 | with open("ppt-api/"+username+"ppt.json", "r") as f: 46 | # Read the lines of the file into a list 47 | lines = f.readlines() 48 | 49 | delimiter = "{" 50 | for i in range(len(lines)): 51 | # Find the index of the delimiter in the current line 52 | index = lines[i].find(delimiter) 53 | # If found.... 54 | if index != -1: 55 | # Remove characters before the delimiter and update the line 56 | lines[i] = lines[i][index:] 57 | break 58 | else: 59 | lines[i]="" 60 | 61 | # Write the updated lines to a new file 62 | with open("ppt-api/"+username+"ppt1.json", "w") as f: 63 | f.writelines(lines) 64 | 65 | return output -------------------------------------------------------------------------------- /instance/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSSRPRAD/ppt-api/02ae2b7323de05a1472b518a09033981a9b87c64/instance/database.db -------------------------------------------------------------------------------- /ppt.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import collections.abc 3 | import json 4 | from pptx import Presentation 5 | 6 | def ppt(username): 7 | prs = Presentation() 8 | 9 | # Read the JSON object from a file 10 | with open("ppt-api/"+username+"ppt1.json", 'r') as f: 11 | ppt = json.load(f) 12 | 13 | # Extract the title and slides fields from the JSON object 14 | title = ppt['title'] 15 | slides = ppt['slides'] 16 | 17 | # Add a title slide 18 | title_slide_layout = prs.slide_layouts[0] 19 | slide1 = prs.slides.add_slide(title_slide_layout) 20 | title1 = slide1.shapes.title 21 | subtitle = slide1.placeholders[1] 22 | title1.text = title 23 | subtitle.text = "By ChatGPT" 24 | 25 | # Loop through each slide and extract the title and content fields 26 | for slide in slides: 27 | slide_title = slide['title'] 28 | slide_content = slide['content'] 29 | print(f"Slide title: {slide_title}") 30 | print("Slide content:") 31 | 32 | # Add a bullet slide 33 | bullet_slide_layout = prs.slide_layouts[3] 34 | slide2 = prs.slides.add_slide(bullet_slide_layout) 35 | title2 = slide2.shapes.title 36 | body2 = slide2.shapes.placeholders[1] 37 | title2.text = slide_title 38 | tf = body2.text_frame 39 | 40 | for content_string in slide_content: 41 | p = tf.add_paragraph() 42 | p.text = content_string 43 | p.level = 1 44 | 45 | print("\n\n") 46 | 47 | 48 | 49 | prs.save("ppt-api/"+username+str('.pptx')) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.8.4 2 | aiosignal==1.3.1 3 | async-timeout==4.0.2 4 | attrs==22.2.0 5 | bcrypt==4.0.1 6 | certifi==2022.12.7 7 | charset-normalizer==3.1.0 8 | click==8.1.3 9 | Flask==2.2.3 10 | Flask-Bcrypt==1.0.1 11 | Flask-Login==0.6.2 12 | Flask-SQLAlchemy==3.0.3 13 | frozenlist==1.3.3 14 | greenlet==2.0.2 15 | idna==3.4 16 | itsdangerous==2.1.2 17 | Jinja2==3.1.2 18 | lxml==4.9.2 19 | MarkupSafe==2.1.2 20 | multidict==6.0.4 21 | openai==0.27.2 22 | Pillow==9.4.0 23 | python-pptx==0.6.21 24 | requests==2.28.2 25 | SQLAlchemy==2.0.7 26 | tqdm==4.65.0 27 | typing_extensions==4.5.0 28 | urllib3==1.26.15 29 | Werkzeug==2.2.3 30 | XlsxWriter==3.0.9 31 | yarl==1.8.2 32 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block head %} 10 | 11 | {% block title %} 12 | {% endblock %} 13 | 14 | {% endblock %} 15 | 49 | 50 | 51 | 52 | {% block body %} 53 | 54 | {% endblock %} 55 | 58 |
59 | {% block content %} 60 | 61 | {% endblock %} 62 |
63 | 68 | -------------------------------------------------------------------------------- /templates/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block head %} 4 | 5 | {% endblock %} 6 | 7 | {% block body %} 8 | 9 |
10 |

DASHBOARD

11 |
12 |
13 |
14 | 15 |

18 |
19 |



20 | 23 |
24 | 27 |
28 |
29 |
30 | 31 | 32 | 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends 'base.html' %} 4 | 5 | {% block head %} 6 | {% endblock %} 7 | 8 | {% block content %} 9 |
10 |
11 |

12 | This is a site created for learning purposes using the Flask Microframework and Tailwind CSS 13 |

14 |

15 | Created By:
Pradyumna Malladi 16 |

17 | 18 | 21 |
22 |
23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block body %} 4 |
5 |
6 |
7 |
8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 |
    12 | {% for message in messages %} 13 |
  • {{ message }}
  • 14 | {% endfor %} 15 |
16 | {% endif %} 17 | {% endwith %} 18 |
19 |
20 | 23 | 24 |
25 |
26 | 29 | 30 |

Please choose a password.

31 |
32 |
33 | 36 |
37 |
38 |
39 |
40 |
41 | {% endblock %} -------------------------------------------------------------------------------- /templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block body %} 4 |
5 |
6 |
7 |
8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 |
    12 | {% for message in messages %} 13 |
  • {{ message }}
  • 14 | {% endfor %} 15 |
16 | {% endif %} 17 | {% endwith %} 18 |
19 |
20 | 23 | 24 |
25 |
26 | 29 | 30 |

Please tell a bit about yourself and how you came to know about this website. Feel free to mention what all you are expecting also here.

31 |
32 |
33 | 36 | 37 |

Please choose a password.

38 |
39 |
40 | 43 |
44 |
45 |
46 |
47 |
48 | {% endblock %} 49 | --------------------------------------------------------------------------------