├── src ├── __init__.py └── revChatGPT │ ├── __init__.py │ ├── __main__.py │ └── revChatGPT.py ├── config.json ├── setup.cfg ├── .vscode └── settings.json ├── .github ├── workflows │ ├── pylint.yml │ └── python-publish.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── setup.py ├── CONTRIBUTING.md ├── README.md ├── .gitignore └── LICENSE /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/revChatGPT/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "email":"", 3 | "password": "" 4 | } 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | [metadata] 3 | description_file=README.md 4 | license_files=LICENSE -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.linting.enabled": true 4 | } -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: Pylint 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: ["3.8", "3.9", "3.10"] 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up Python ${{ matrix.python-version }} 14 | uses: actions/setup-python@v3 15 | with: 16 | python-version: ${{ matrix.python-version }} 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install pylint 21 | - name: Analysing the code with pylint 22 | run: | 23 | pylint $(git ls-files '*.py') 24 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | setup( 3 | name="revChatGPT", 4 | version="0.0.31", 5 | license="GNU General Public License v2.0", 6 | author="Antonio Cheong", 7 | author_email="acheong@student.dalat.org", 8 | description="ChatGPT is a reverse engineering of OpenAI's ChatGPT API", 9 | packages=find_packages("src"), 10 | package_dir={'': 'src'}, 11 | url="https://github.com/acheong08/ChatGPT", 12 | install_requires=[ 13 | "requests", 14 | "tls-client", 15 | ], 16 | long_description=open('README.md', encoding='utf-8').read(), 17 | long_description_content_type='text/markdown', 18 | ) 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment (please complete the following information):** 27 | - OS: [e.g. Linux, MacOS, Windows] 28 | - Python version: `python -V` 29 | - Version: `pip3 show revChatGPT`` 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: '3.x' 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | pip install twine 34 | - name: Build package 35 | run: python -m build 36 | - name: Publish package 37 | uses: pypa/gh-action-pypi-publish@release/v1 38 | with: 39 | user: acheong08 40 | password: ${{ secrets.PYPI_API_TOKEN }} 41 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ChatGPT 2 | 3 | We welcome contributions to ChatGPT! Here are some guidelines to help you get started. 4 | 5 | ## Types of contributions we are looking for 6 | 7 | ChatGPT is an open-source project, and we welcome a wide range of contributions. Here are some examples of the types of contributions we are looking for: 8 | 9 | - Code patches 10 | - Documentation improvements 11 | - Bug reports and fixes 12 | - Feature requests and suggestions 13 | 14 | Please note that ChatGPT is intended to be used as a development library, so contributions should stay within this scope. 15 | 16 | ## How to submit a contribution 17 | 18 | If you would like to contribute to ChatGPT, follow these steps: 19 | 20 | 1. Fork the ChatGPT repository. 21 | 2. Create a new branch in your fork to make your changes. 22 | 3. Commit your changes to your new branch. 23 | 4. Push your changes to your fork on GitHub. 24 | 5. Submit a pull request from your branch to the ChatGPT repository. 25 | 26 | We will review your pull request and, if everything looks good, merge it into the main codebase. 27 | 28 | ## Questions 29 | 30 | If you have any questions about contributing to ChatGPT, feel free to open an issue in the ChatGPT repository and ask. 31 | 32 | Thank you for considering a contribution to ChatGPT! 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 3 | [![PyPi](https://img.shields.io/pypi/dm/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 4 | 5 | Reverse Engineered ChatGPT by OpenAI. Extensible for chatbots etc. 6 | 7 | # Instructions 8 | Instructions have been moved to the [Wiki](https://github.com/acheong08/ChatGPT/wiki). 9 | 10 | If you were using this prior to version 0.0.24, please update immediately. `pip3 install revChatGPT --upgrade`. Fixes has been done to avoid bot blocking 11 | 12 | # Features 13 | ![image](https://user-images.githubusercontent.com/36258159/205534498-acc59484-c4b4-487d-89a7-d7b884af709b.png) 14 | - No moderation 15 | - Programmable. 16 | 17 | # Urgent help needed 18 | - Writing tests 19 | - Decrecate bs4 in favor of pure requests 20 | - **Error handling** 21 | 22 | # Awesome ChatGPT 23 | [My list](https://github.com/stars/acheong08/lists/awesome-chatgpt) 24 | 25 | If you have a cool project you want added to the list, open an issue. 26 | 27 | # Disclaimers 28 | This is not an official OpenAI product. This is a personal project and is not affiliated with OpenAI in any way. Don't sue me 29 | 30 | ### This is a library and not intended for direct CLI use 31 | The CLI functionality is for demo and testing only. Captcha is not supported (For unclean IP addresses) 32 | 33 | ### CLI use 34 | [@rawandahmad698](https://github.com/rawandahmad698) has a much better CLI tool at 35 | 36 | **[PyChatGPT](https://github.com/rawandahmad698/PyChatGPT)** supports captcha! 37 | 38 | # Star History 39 | 40 | [![Star History Chart](https://api.star-history.com/svg?repos=acheong08/ChatGPT&type=Date)](https://star-history.com/#acheong08/ChatGPT&Date) 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Custom 2 | config.json 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 97 | __pypackages__/ 98 | 99 | # Celery stuff 100 | celerybeat-schedule 101 | celerybeat.pid 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | -------------------------------------------------------------------------------- /src/revChatGPT/__main__.py: -------------------------------------------------------------------------------- 1 | from revChatGPT.revChatGPT import Chatbot 2 | import json 3 | from sys import argv 4 | import textwrap 5 | from os.path import exists 6 | 7 | 8 | def get_input(prompt): 9 | # prompt for input 10 | lines = [] 11 | print(prompt, end="") 12 | while True: 13 | line = input() 14 | if line == "": 15 | break 16 | lines.append(line) 17 | 18 | # Join the lines, separated by newlines, and print the result 19 | user_input = "\n".join(lines) 20 | # print(user_input) 21 | return user_input 22 | 23 | 24 | if __name__ == "__main__": 25 | print(""" 26 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 27 | Repo: github.com/acheong08/ChatGPT 28 | """) 29 | print("Type '!help' to show commands") 30 | print("Press enter twice to submit your question.\n") 31 | 32 | if exists("config.json"): 33 | with open("config.json", "r", encoding='utf-8') as f: 34 | config = json.load(f) 35 | chatbot = Chatbot(config) 36 | else: 37 | print("Please create and populate config.json to continue") 38 | exit() 39 | 40 | while True: 41 | prompt = get_input("\nYou:\n") 42 | if prompt.startswith("!"): 43 | if prompt == "!help": 44 | print(""" 45 | !help - Show this message 46 | !reset - Forget the current conversation 47 | !refresh - Refresh the session authentication 48 | !rollback - Rollback the conversation by 1 message 49 | !config - Show the current configuration 50 | !exit - Exit the program 51 | """) 52 | continue 53 | elif prompt == "!reset": 54 | chatbot.reset_chat() 55 | print("Chat session reset.") 56 | continue 57 | elif prompt == "!refresh": 58 | chatbot.refresh_session() 59 | print("Session refreshed.\n") 60 | continue 61 | elif prompt == "!rollback": 62 | chatbot.rollback_conversation() 63 | print("Chat session rolled back.") 64 | continue 65 | elif prompt == "!config": 66 | print(json.dumps(config, indent=4)) 67 | continue 68 | elif prompt == "!exit": 69 | break 70 | 71 | if '--text' not in argv: 72 | messages = [] 73 | lines_printed = 0 74 | 75 | try: 76 | print("Chatbot: ") 77 | formatted_parts = [] 78 | for message in chatbot.get_chat_response(prompt, output="stream"): 79 | # Split the message by newlines 80 | message_parts = message['message'].split('\n') 81 | 82 | # Wrap each part separately 83 | formatted_parts = [] 84 | for part in message_parts: 85 | formatted_parts.extend(textwrap.wrap(part, width=80)) 86 | for formatted_line in formatted_parts: 87 | if len(formatted_parts) > lines_printed+1: 88 | print(formatted_parts[lines_printed]) 89 | lines_printed += 1 90 | print(formatted_parts[lines_printed]) 91 | except Exception as e: 92 | print("Something went wrong!") 93 | print(e) 94 | continue 95 | else: 96 | try: 97 | print("Chatbot: ") 98 | message = chatbot.get_chat_response(prompt) 99 | print(message['message']) 100 | except Exception as e: 101 | print("Something went wrong!") 102 | print(e) 103 | continue 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /src/revChatGPT/revChatGPT.py: -------------------------------------------------------------------------------- 1 | # Author: @acheong08@fosstodon.org 2 | # License: MIT 3 | # Description: A Python wrapper for OpenAI's chatbot API 4 | import json 5 | import uuid 6 | import re 7 | import urllib 8 | import tls_client 9 | import requests 10 | 11 | 12 | def generate_uuid() -> str: 13 | uid = str(uuid.uuid4()) 14 | return uid 15 | 16 | 17 | class Chatbot: 18 | config: json 19 | conversation_id: str 20 | parent_id: str 21 | headers: dict 22 | conversation_id_prev: str 23 | parent_id_prev: str 24 | 25 | def __init__(self, config, conversation_id=None): 26 | self.config = config 27 | self.conversation_id = conversation_id 28 | self.parent_id = generate_uuid() 29 | if 'session_token' in config or ('email' in config and 'password' in config): 30 | self.refresh_session() 31 | 32 | # Resets the conversation ID and parent ID 33 | def reset_chat(self) -> None: 34 | self.conversation_id = None 35 | self.parent_id = generate_uuid() 36 | 37 | # Refreshes the headers -- Internal use only 38 | def refresh_headers(self) -> None: 39 | if 'Authorization' not in self.config: 40 | self.config['Authorization'] = '' 41 | elif self.config['Authorization'] is None: 42 | self.config['Authorization'] = '' 43 | self.headers = { 44 | "Host": "chat.openai.com", 45 | "Accept": "text/event-stream", 46 | "Authorization": "Bearer " + self.config['Authorization'], 47 | "Content-Type": "application/json", 48 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 49 | 'Version/16.1 Safari/605.1.15', 50 | "X-Openai-Assistant-App-Id": "", 51 | "Connection": "close", 52 | 'Accept-Language': 'en-US,en;q=0.9', 53 | 'Referer': 'https://chat.openai.com/chat', 54 | } 55 | 56 | # Generates a UUID -- Internal use only 57 | 58 | # Generator for chat stream -- Internal use only 59 | def get_chat_stream(self, data) -> None: 60 | response = requests.post("https://chat.openai.com/backend-api/conversation", 61 | headers=self.headers, data=json.dumps(data), stream=True, timeout=20) 62 | for line in response.iter_lines(): 63 | try: 64 | line = line.decode('utf-8') 65 | if line == "": 66 | continue 67 | line = line[6:] 68 | line = json.loads(line) 69 | try: 70 | message = line["message"]["content"]["parts"][0] 71 | self.conversation_id = line["conversation_id"] 72 | self.parent_id = line["message"]["id"] 73 | except: 74 | continue 75 | yield {'message': message, 'conversation_id': self.conversation_id, 'parent_id': self.parent_id} 76 | except: 77 | continue 78 | 79 | # Gets the chat response as text -- Internal use only 80 | def get_chat_text(self, data) -> dict: 81 | # Create request session 82 | s = requests.Session() 83 | # set headers 84 | s.headers = self.headers 85 | # Set multiple cookies 86 | s.cookies.set("__Secure-next-auth.session-token", 87 | self.config['session_token']) 88 | s.cookies.set("__Secure-next-auth.callback-url", 89 | "https://chat.openai.com/") 90 | # Set proxies 91 | if self.config.get("proxy", "") != "": 92 | s.proxies = { 93 | "http": self.config["proxy"], 94 | "https": self.config["proxy"] 95 | } 96 | response = s.post( 97 | "https://chat.openai.com/backend-api/conversation", data=json.dumps(data)) 98 | 99 | error_desp = "" 100 | try: 101 | response = response.text.splitlines()[-4] 102 | response = response[6:] 103 | except Exception as exc: 104 | try: 105 | # Get the title text 106 | title_text = re.search( 107 | '(.*)', response.text).group(1) 108 | 109 | # Find all div elements and capture the id attribute and the contents of the element 110 | div_pattern = ']*id="([^"]*)">(.*)' 111 | div_elements = re.findall(div_pattern, response.text) 112 | 113 | # Loop through the div elements and find the one with the "message" id 114 | message_text = "" 115 | for div in div_elements: 116 | div_id = div[0] 117 | div_content = div[1] 118 | if div_id == "message": 119 | message_text = div_content 120 | break 121 | # Concatenate the title and message text 122 | error_desp = title_text + ": " + message_text 123 | 124 | except: 125 | error_desp = json.loads(response.text)["detail"] 126 | if "message" in error_desp: 127 | error_desp = error_desp["message"] 128 | finally: 129 | print(response.text) 130 | raise ValueError( 131 | "Response is not in the correct format", error_desp) from exc 132 | response = json.loads(response) 133 | self.parent_id = response["message"]["id"] 134 | self.conversation_id = response["conversation_id"] 135 | message = response["message"]["content"]["parts"][0] 136 | return {'message': message, 'conversation_id': self.conversation_id, 'parent_id': self.parent_id} 137 | 138 | # Gets the chat response 139 | def get_chat_response(self, prompt, output="text") -> dict or None: 140 | data = { 141 | "action": "next", 142 | "messages": [ 143 | {"id": str(generate_uuid()), 144 | "role": "user", 145 | "content": {"content_type": "text", "parts": [prompt]} 146 | }], 147 | "conversation_id": self.conversation_id, 148 | "parent_message_id": self.parent_id, 149 | "model": "text-davinci-002-render" 150 | } 151 | self.conversation_id_prev = self.conversation_id 152 | self.parent_id_prev = self.parent_id 153 | if output == "text": 154 | return self.get_chat_text(data) 155 | elif output == "stream": 156 | return self.get_chat_stream(data) 157 | else: 158 | raise ValueError("Output must be either 'text' or 'stream'") 159 | 160 | def rollback_conversation(self) -> None: 161 | self.conversation_id = self.conversation_id_prev 162 | self.parent_id = self.parent_id_prev 163 | 164 | def refresh_session(self) -> Exception: 165 | if 'session_token' not in self.config and ('email' not in self.config or 'password' not in self.config): 166 | raise ValueError("No tokens provided") 167 | elif 'session_token' in self.config: 168 | if self.config['session_token'] is None or self.config['session_token'] == "": 169 | raise ValueError("No tokens provided") 170 | s = requests.Session() 171 | if self.config.get("proxy", "") != "": 172 | s.proxies = { 173 | "http": self.config["proxy"], 174 | "https": self.config["proxy"] 175 | } 176 | # Set cookies 177 | s.cookies.set("__Secure-next-auth.session-token", 178 | self.config['session_token']) 179 | # s.cookies.set("__Secure-next-auth.csrf-token", self.config['csrf_token']) 180 | response = s.get("https://chat.openai.com/api/auth/session", headers={ 181 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, ' 182 | 'like Gecko) Version/16.1 Safari/605.1.15 ' 183 | }) 184 | try: 185 | self.config['session_token'] = response.cookies.get( 186 | "__Secure-next-auth.session-token") 187 | self.config['Authorization'] = response.json()["accessToken"] 188 | self.refresh_headers() 189 | except Exception as exc: 190 | print("Error refreshing session") 191 | print(response.text) 192 | raise Exception("Error refreshing session") from exc 193 | elif 'email' in self.config and 'password' in self.config: 194 | try: 195 | self.login(self.config['email'], self.config['password']) 196 | except Exception as exc: 197 | print("Error refreshing session: ") 198 | print(exc) 199 | return exc 200 | else: 201 | raise ValueError("No tokens provided") 202 | 203 | def login(self, email, password) -> None: 204 | print("Logging in...") 205 | use_proxy = False 206 | proxy = None 207 | if 'proxy' in self.config: 208 | if self.config['proxy'] != "": 209 | use_proxy = True 210 | proxy = self.config['proxy'] 211 | auth = OpenAIAuth(email, password, use_proxy, proxy) 212 | try: 213 | auth.begin() 214 | except Exception as exc: 215 | # if ValueError with e as "Captcha detected" fail 216 | if exc == "Captcha detected": 217 | print("Captcha not supported. Use session tokens instead.") 218 | raise ValueError("Captcha detected") from exc 219 | raise Exception("Error logging in") from exc 220 | if auth.access_token is not None: 221 | self.config['Authorization'] = auth.access_token 222 | if auth.session_token is not None: 223 | self.config['session_token'] = auth.session_token 224 | else: 225 | possible_tokens = auth.session.cookies.get( 226 | "__Secure-next-auth.session-token") 227 | if possible_tokens is not None: 228 | if len(possible_tokens) > 1: 229 | self.config['session_token'] = possible_tokens[0] 230 | else: 231 | try: 232 | self.config['session_token'] = possible_tokens 233 | except Exception as exc: 234 | raise Exception("Error logging in") from exc 235 | self.refresh_headers() 236 | else: 237 | raise Exception("Error logging in") 238 | 239 | 240 | # Credits to github.com/rawandahmad698/PyChatGPT 241 | 242 | 243 | class OpenAIAuth: 244 | def __init__(self, email_address: str, password: str, use_proxy: bool = False, proxy: str = None): 245 | self.session_token = None 246 | self.email_address = email_address 247 | self.password = password 248 | self.use_proxy = use_proxy 249 | self.proxy = proxy 250 | self.session = tls_client.Session( 251 | client_identifier="chrome_105" 252 | ) 253 | self.access_token: str = None 254 | 255 | @staticmethod 256 | def url_encode(string: str) -> str: 257 | """ 258 | URL encode a string 259 | :param string: 260 | :return: 261 | """ 262 | return urllib.parse.quote(string) 263 | 264 | def begin(self) -> None: 265 | """ 266 | Begin the auth process 267 | """ 268 | if not self.email_address or not self.password: 269 | return 270 | 271 | if self.use_proxy: 272 | if not self.proxy: 273 | return 274 | 275 | proxies = { 276 | "http": self.proxy, 277 | "https": self.proxy 278 | } 279 | self.session.proxies = proxies 280 | 281 | # First, make a request to https://chat.openai.com/auth/login 282 | url = "https://chat.openai.com/auth/login" 283 | headers = { 284 | "Host": "ask.openai.com", 285 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 286 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 287 | 'Version/16.1 Safari/605.1.15', 288 | "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", 289 | "Accept-Encoding": "gzip, deflate, br", 290 | "Connection": "keep-alive", 291 | } 292 | 293 | response = self.session.get(url=url, headers=headers) 294 | if response.status_code == 200: 295 | self.part_two() 296 | else: 297 | raise Exception("Error logging in") 298 | 299 | def part_two(self) -> None: 300 | """ 301 | In part two, We make a request to https://chat.openai.com/api/auth/csrf and grab a fresh csrf token 302 | """ 303 | 304 | url = "https://chat.openai.com/api/auth/csrf" 305 | headers = { 306 | "Host": "ask.openai.com", 307 | "Accept": "*/*", 308 | "Connection": "keep-alive", 309 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 310 | 'Version/16.1 Safari/605.1.15', 311 | "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", 312 | "Referer": "https://chat.openai.com/auth/login", 313 | "Accept-Encoding": "gzip, deflate, br", 314 | } 315 | response = self.session.get(url=url, headers=headers) 316 | if response.status_code == 200 and 'json' in response.headers['Content-Type']: 317 | csrf_token = response.json()["csrfToken"] 318 | self.part_three(token=csrf_token) 319 | else: 320 | raise Exception("Error logging in") 321 | 322 | def part_three(self, token: str) -> None: 323 | """ 324 | We reuse the token from part to make a request to /api/auth/signin/auth0?prompt=login 325 | """ 326 | url = "https://chat.openai.com/api/auth/signin/auth0?prompt=login" 327 | 328 | payload = f'callbackUrl=%2F&csrfToken={token}&json=true' 329 | headers = { 330 | 'Host': 'ask.openai.com', 331 | 'Origin': 'https://chat.openai.com', 332 | 'Connection': 'keep-alive', 333 | 'Accept': '*/*', 334 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 335 | 'Version/16.1 Safari/605.1.15', 336 | 'Referer': 'https://chat.openai.com/auth/login', 337 | 'Content-Length': '100', 338 | 'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8', 339 | 'Content-Type': 'application/x-www-form-urlencoded', 340 | } 341 | response = self.session.post(url=url, headers=headers, data=payload) 342 | if response.status_code == 200 and 'json' in response.headers['Content-Type']: 343 | url = response.json()["url"] 344 | self.part_four(url=url) 345 | elif response.status_code == 400: 346 | raise Exception("Invalid credentials") 347 | else: 348 | raise Exception("Unknown error") 349 | 350 | def part_four(self, url: str) -> None: 351 | """ 352 | We make a GET request to url 353 | :param url: 354 | :return: 355 | """ 356 | headers = { 357 | 'Host': 'auth0.openai.com', 358 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 359 | 'Connection': 'keep-alive', 360 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 361 | 'Version/16.1 Safari/605.1.15', 362 | 'Accept-Language': 'en-US,en;q=0.9', 363 | 'Referer': 'https://chat.openai.com/', 364 | } 365 | response = self.session.get(url=url, headers=headers) 366 | if response.status_code == 302: 367 | state = re.findall(r"state=(.*)", response.text)[0] 368 | state = state.split('"')[0] 369 | self.part_five(state=state) 370 | else: 371 | raise Exception("Unknown error") 372 | 373 | def part_five(self, state: str) -> None: 374 | """ 375 | We use the state to get the login page & check for a captcha 376 | """ 377 | url = f"https://auth0.openai.com/u/login/identifier?state={state}" 378 | 379 | headers = { 380 | 'Host': 'auth0.openai.com', 381 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 382 | 'Connection': 'keep-alive', 383 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 384 | 'Version/16.1 Safari/605.1.15', 385 | 'Accept-Language': 'en-US,en;q=0.9', 386 | 'Referer': 'https://chat.openai.com/', 387 | } 388 | response = self.session.get(url, headers=headers) 389 | if response.status_code == 200: 390 | if re.search(r']+alt="captcha"[^>]+>', response.text): 391 | print("Captcha detected") 392 | raise ValueError("Captcha detected") 393 | self.part_six(state=state, captcha=None) 394 | else: 395 | raise ValueError("Invalid response code") 396 | 397 | def part_six(self, state: str, captcha: str or None) -> None: 398 | """ 399 | We make a POST request to the login page with the captcha, email 400 | :param state: 401 | :param captcha: 402 | :return: 403 | """ 404 | url = f"https://auth0.openai.com/u/login/identifier?state={state}" 405 | email_url_encoded = self.url_encode(self.email_address) 406 | payload = f'state={state}&username={email_url_encoded}&captcha={captcha}&js-available=true&webauthn-available' \ 407 | f'=true&is-brave=false&webauthn-platform-available=true&action=default ' 408 | 409 | if captcha is None: 410 | payload = f'state={state}&username={email_url_encoded}&js-available=false&webauthn-available=true&is' \ 411 | f'-brave=false&webauthn-platform-available=true&action=default ' 412 | 413 | headers = { 414 | 'Host': 'auth0.openai.com', 415 | 'Origin': 'https://auth0.openai.com', 416 | 'Connection': 'keep-alive', 417 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 418 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 419 | 'Version/16.1 Safari/605.1.15', 420 | 'Referer': f'https://auth0.openai.com/u/login/identifier?state={state}', 421 | 'Accept-Language': 'en-US,en;q=0.9', 422 | 'Content-Type': 'application/x-www-form-urlencoded', 423 | } 424 | response = self.session.post(url, headers=headers, data=payload) 425 | if response.status_code == 302: 426 | self.part_seven(state=state) 427 | else: 428 | raise Exception("Unknown error") 429 | 430 | def part_seven(self, state: str) -> None: 431 | """ 432 | We enter the password 433 | :param state: 434 | :return: 435 | """ 436 | url = f"https://auth0.openai.com/u/login/password?state={state}" 437 | 438 | email_url_encoded = self.url_encode(self.email_address) 439 | password_url_encoded = self.url_encode(self.password) 440 | payload = f'state={state}&username={email_url_encoded}&password={password_url_encoded}&action=default' 441 | headers = { 442 | 'Host': 'auth0.openai.com', 443 | 'Origin': 'https://auth0.openai.com', 444 | 'Connection': 'keep-alive', 445 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 446 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 447 | 'Version/16.1 Safari/605.1.15', 448 | 'Referer': f'https://auth0.openai.com/u/login/password?state={state}', 449 | 'Accept-Language': 'en-US,en;q=0.9', 450 | 'Content-Type': 'application/x-www-form-urlencoded', 451 | } 452 | response = self.session.post(url, headers=headers, data=payload) 453 | is_302 = response.status_code == 302 454 | if is_302: 455 | new_state = re.findall(r"state=(.*)", response.text)[0] 456 | new_state = new_state.split('"')[0] 457 | self.part_eight(old_state=state, new_state=new_state) 458 | else: 459 | raise Exception("Unknown error") 460 | 461 | def part_eight(self, old_state: str, new_state) -> None: 462 | url = f"https://auth0.openai.com/authorize/resume?state={new_state}" 463 | headers = { 464 | 'Host': 'auth0.openai.com', 465 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 466 | 'Connection': 'keep-alive', 467 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) ' 468 | 'Version/16.1 Safari/605.1.15', 469 | 'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8', 470 | 'Referer': f'https://auth0.openai.com/u/login/password?state={old_state}', 471 | } 472 | response = self.session.get(url, headers=headers, allow_redirects=True) 473 | is_200 = response.status_code == 200 474 | if is_200: 475 | # Access Token 476 | access_token = re.findall( 477 | r"accessToken\":\"(.*)\"", response.text) 478 | if access_token: 479 | access_token = access_token[0] 480 | access_token = access_token.split('"')[0] 481 | # Save access_token and an hour from now on ./classes/auth.json 482 | self.save_access_token(access_token=access_token) 483 | else: 484 | print("Invalid credentials") 485 | raise Exception("Invalid credentials") 486 | else: 487 | print("Invalid credentials") 488 | raise Exception("Failed to find accessToken") 489 | 490 | def save_access_token(self, access_token: str) -> None: 491 | """ 492 | Save access_token and an hour from now on ./Classes/auth.json 493 | :param access_token: 494 | :return: 495 | """ 496 | if self.part_nine(): 497 | self.access_token = access_token 498 | else: 499 | print("Failed to login") 500 | raise Exception("Failed to login") 501 | 502 | def part_nine(self) -> bool: 503 | url = "https://chat.openai.com/api/auth/session" 504 | headers = { 505 | "Host": "ask.openai.com", 506 | "Connection": "keep-alive", 507 | "If-None-Match": "\"bwc9mymkdm2\"", 508 | "Accept": "*/*", 509 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) " 510 | "Version/16.1 Safari/605.1.15", 511 | "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", 512 | "Referer": "https://chat.openai.com/chat", 513 | "Accept-Encoding": "gzip, deflate, br", 514 | } 515 | response = self.session.get(url, headers=headers) 516 | is_200 = response.status_code == 200 517 | if is_200: 518 | # Get session token 519 | self.session_token = response.cookies.get( 520 | "__Secure-next-auth.session-token") 521 | return True 522 | self.session_token = None 523 | raise Exception("Failed to get session token") 524 | --------------------------------------------------------------------------------