├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codeql.yml │ ├── pylint.yml │ ├── python-package.yml │ └── python-publish.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── config.json.example ├── logo.png ├── setup.cfg ├── setup.py ├── src ├── __init__.py └── revChatGPT │ ├── Exceptions.py │ ├── __init__.py │ ├── __main__.py │ └── revChatGPT.py └── wiki ├── CLI-use.md ├── Contributors.md ├── Developer-Docs.md ├── Home.md ├── OpenAIAuth.md ├── Setup.md ├── Star-history.md └── revChatGPT.md /.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 | **Output** 24 | In the correct directory, run `python3 -m revChatGPT --debug` 25 | 26 | **Environment (please complete the following information):** 27 | 28 | Please update your packages before reporting! `pip3 install --upgrade OpenAIAuth revChatGPT` 29 | - OS: [e.g. Linux, MacOS, Windows] 30 | - Python version: `python -V` 31 | - ChatGPT Version: `pip3 show revChatGPT` 32 | - OpenAI Version: `pip3 show OpenAIAuth` 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.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/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | 2 | name: "Code Scanning - Action" 3 | 4 | on: 5 | release: 6 | types: [published] 7 | schedule: 8 | # ┌───────────── minute (0 - 59) 9 | # │ ┌───────────── hour (0 - 23) 10 | # │ │ ┌───────────── day of the month (1 - 31) 11 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 12 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 13 | # │ │ │ │ │ 14 | # │ │ │ │ │ 15 | # │ │ │ │ │ 16 | # * * * * * 17 | - cron: '30 1 * * 0' 18 | 19 | jobs: 20 | CodeQL-Build: 21 | runs-on: ubuntu-latest 22 | 23 | permissions: 24 | # required for all workflows 25 | security-events: write 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v3 29 | 30 | # Initializes the CodeQL tools for scanning. 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v2 33 | with: 34 | languages: python 35 | 36 | - name: Perform CodeQL Analysis 37 | uses: github/codeql-action/analyze@v2 38 | -------------------------------------------------------------------------------- /.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@v4 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 revChatGPT 21 | - name: Analysing the code with pylint 22 | run: | 23 | pylint $(git ls-files '*.py') 24 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run build and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.8", "3.9", "3.10"] 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v4 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install flake8 31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Try to build the package 39 | run: | 40 | python -m pip install . 41 | -------------------------------------------------------------------------------- /.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@v4 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 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: acheong08 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | -------------------------------------------------------------------------------- /.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 | 133 | # JetBrains IDEs configuration 134 | .idea/ 135 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.4.0 5 | hooks: 6 | - id: trailing-whitespace 7 | - id: end-of-file-fixer 8 | - id: check-yaml 9 | - id: debug-statements 10 | - id: double-quote-string-fixer 11 | - id: name-tests-test 12 | - id: requirements-txt-fixer 13 | - repo: https://github.com/psf/black 14 | rev: 22.10.0 15 | hooks: 16 | - id: black 17 | - repo: https://github.com/asottile/reorder_python_imports 18 | rev: v3.9.0 19 | hooks: 20 | - id: reorder-python-imports 21 | args: [--py37-plus] 22 | - repo: https://github.com/asottile/add-trailing-comma 23 | rev: v2.3.0 24 | hooks: 25 | - id: add-trailing-comma 26 | args: [--py36-plus] 27 | - repo: https://github.com/asottile/pyupgrade 28 | rev: v3.3.1 29 | hooks: 30 | - id: pyupgrade 31 | args: [--py37-plus] 32 | - repo: https://github.com/pre-commit/mirrors-autopep8 33 | rev: v2.0.0 34 | hooks: 35 | - id: autopep8 36 | args: 37 | - --aggressive 38 | - --verbose 39 | - -d 40 | - repo: https://github.com/PyCQA/flake8 41 | rev: 6.0.0 42 | hooks: 43 | - id: flake8 44 | - repo: https://github.com/pre-commit/mirrors-mypy 45 | rev: v0.991 46 | hooks: 47 | - id: mypy 48 | additional_dependencies: [types-all] 49 | - repo: https://github.com/pycqa/pylint 50 | rev: v2.15.8 51 | hooks: 52 | - id: pylint 53 | args: 54 | - --max-line-length=80 55 | - --ignore-imports=yes 56 | - -d duplicate-code 57 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.linting.enabled": true 4 | } 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | [![Python package](https://github.com/acheong08/ChatGPT/actions/workflows/python-package.yml/badge.svg)](https://github.com/acheong08/ChatGPT/actions/workflows/python-package.yml) 5 | 6 | Reverse Engineered ChatGPT by OpenAI. Extensible for chatbots etc. 7 | 8 | # Instructions 9 | Instructions have been moved to the [Wiki](https://github.com/acheong08/ChatGPT/wiki). 10 | 11 | If you were using this prior to version 0.0.31, please update immediately. `pip3 install revChatGPT --upgrade`. Fixes has been done to avoid bot blocking 12 | 13 | # Features 14 | ![image](https://user-images.githubusercontent.com/36258159/205534498-acc59484-c4b4-487d-89a7-d7b884af709b.png) 15 | - No moderation 16 | - Programmable. 17 | - Async version 18 | - Email/password authentication 19 | - Cookie based authentication 20 | - Access Token authentication 21 | - Captcha support 22 | 23 | # Flaws 24 | - No ARM support for email/password. Use session token authentication if on Raspberry Pi 25 | 26 | # Help needed 27 | - Documentation for [OpenAIAuth](https://github.com/acheong08/OpenAIAuth) 28 | - Update documentation for developers (with examples) 29 | 30 | # Awesome ChatGPT 31 | [My list](https://github.com/stars/acheong08/lists/awesome-chatgpt) 32 | 33 | If you have a cool project you want added to the list, open an issue. 34 | 35 | # Disclaimers 36 | 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 37 | 38 | # Credits 39 | - [rawandahmad698](https://github.com/rawandahmad698) - Reverse engineering Auth0 40 | - [FlorianREGAZ](https://github.com/FlorianREGAZ) - TLS client 41 | - [PyRo1121](https://github.com/PyRo1121) - Linting 42 | - [Harry-Jing](https://github.com/Harry-Jing) - Async support 43 | - [Ukenn2112](https://github.com/Ukenn2112) - Documentation 44 | - [aliferouss19](https://github.com/aliferouss19) - Logo 45 | - [All other contributors](https://github.com/acheong08/ChatGPT/graphs/contributors) 46 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "email":"", 3 | "password": "" 4 | } 5 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sickcodes/ChatGPT/7be51f67fd1087d1c4d0672f40b225d8c57bdf2f/logo.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | [metadata] 3 | description_file=README.md 4 | license_files=LICENSE 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages 2 | from setuptools import setup 3 | 4 | setup( 5 | name="revChatGPT", 6 | version="0.0.38.1", 7 | license="GNU General Public License v2.0", 8 | author="Antonio Cheong", 9 | author_email="acheong@student.dalat.org", 10 | description="ChatGPT is a reverse engineering of OpenAI's ChatGPT API", 11 | packages=find_packages("src"), 12 | package_dir={"": "src"}, 13 | py_modules=["revChatGPT"], 14 | url="https://github.com/acheong08/ChatGPT", 15 | install_requires=[ 16 | "httpx", 17 | "OpenAIAuth>=0.0.6", 18 | "svglib" 19 | ], 20 | long_description=open("README.md", encoding="utf-8").read(), 21 | long_description_content_type="text/markdown", 22 | entry_points={ 23 | "console_scripts": [ 24 | "revChatGPT = revChatGPT.__main__:main", 25 | ] 26 | }, 27 | ) 28 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sickcodes/ChatGPT/7be51f67fd1087d1c4d0672f40b225d8c57bdf2f/src/__init__.py -------------------------------------------------------------------------------- /src/revChatGPT/Exceptions.py: -------------------------------------------------------------------------------- 1 | class ChatGPTException(Exception): 2 | def __init__(self, message): 3 | self.message = message 4 | 5 | def __str__(self): 6 | return self.message 7 | 8 | 9 | class AuthError(ChatGPTException): 10 | pass 11 | 12 | 13 | class ExpiredAccessToken(AuthError): 14 | pass 15 | 16 | 17 | class InvalidAccessToken(AuthError): 18 | pass 19 | 20 | 21 | class InvalidCredentials(AuthError): 22 | pass 23 | 24 | 25 | class APIError(ChatGPTException): 26 | pass 27 | 28 | 29 | class NetworkError(ChatGPTException): 30 | pass 31 | 32 | 33 | class HTTPError(NetworkError): 34 | pass 35 | 36 | 37 | class HTTPStatusError(HTTPError): 38 | def __init__(self, message, status_code): 39 | super().__init__(message) 40 | self.status_code = status_code 41 | -------------------------------------------------------------------------------- /src/revChatGPT/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sickcodes/ChatGPT/7be51f67fd1087d1c4d0672f40b225d8c57bdf2f/src/revChatGPT/__init__.py -------------------------------------------------------------------------------- /src/revChatGPT/__main__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import textwrap 3 | from os.path import exists 4 | from os import getenv 5 | from sys import argv, exit 6 | from svglib.svglib import svg2rlg 7 | 8 | from revChatGPT.revChatGPT import Chatbot 9 | 10 | 11 | class CaptchaSolver: 12 | """ 13 | Captcha solver 14 | """ 15 | @staticmethod 16 | def solve_captcha(raw_svg): 17 | """ 18 | Solves the captcha 19 | 20 | :param raw_svg: The raw SVG 21 | :type raw_svg: :obj:`str` 22 | 23 | :return: The solution 24 | :rtype: :obj:`str` 25 | """ 26 | # Get the SVG 27 | svg = raw_svg 28 | # Save the SVG 29 | with open("captcha.png", "w", encoding="utf-8") as f: 30 | print("Captcha saved to captcha.png") 31 | png = svg2rlg(svg) 32 | f.write(png) 33 | # Get input 34 | solution = input("Please solve the captcha: ") 35 | # Return the solution 36 | return solution 37 | 38 | 39 | def get_input(prompt): 40 | # prompt for input 41 | lines = [] 42 | print(prompt, end="") 43 | while True: 44 | line = input() 45 | if line == "": 46 | break 47 | lines.append(line) 48 | 49 | # Join the lines, separated by newlines, and print the result 50 | user_input = "\n".join(lines) 51 | # print(user_input) 52 | return user_input 53 | 54 | 55 | def main(): 56 | if "--help" in argv: 57 | print( 58 | """ 59 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 60 | Repo: github.com/acheong08/ChatGPT 61 | Run with --debug to enable debugging 62 | """, 63 | ) 64 | exit() 65 | try: 66 | print( 67 | """ 68 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 69 | Repo: github.com/acheong08/ChatGPT 70 | Run with --debug to enable debugging 71 | """, 72 | ) 73 | print("Type '!help' to show commands") 74 | print("Press enter twice to submit your question.\n") 75 | 76 | config_files = ["config.json"] 77 | xdg_config_home = getenv("XDG_CONFIG_HOME") 78 | if xdg_config_home: 79 | config_files.append(f"{xdg_config_home}/revChatGPT/config.json") 80 | user_home = getenv("HOME") 81 | if user_home: 82 | config_files.append(f"{user_home}/.config/revChatGPT/config.json") 83 | 84 | config_file = next((f for f in config_files if exists(f)), None) 85 | if not config_file: 86 | print("Please create and populate ./config.json, $XDG_CONFIG_HOME/revChatGPT/config.json, or ~/.config/revChatGPT/config.json to continue") 87 | exit() 88 | 89 | with open(config_file, encoding="utf-8") as f: 90 | config = json.load(f) 91 | if "--debug" in argv: 92 | print("Debugging enabled.") 93 | debug = True 94 | else: 95 | debug = False 96 | print("Logging in...") 97 | chatbot = Chatbot(config, debug=debug, 98 | captcha_solver=CaptchaSolver()) 99 | 100 | while True: 101 | prompt = get_input("\nYou:\n") 102 | if prompt.startswith("!"): 103 | if prompt == "!help": 104 | print( 105 | """ 106 | !help - Show this message 107 | !reset - Forget the current conversation 108 | !refresh - Refresh the session authentication 109 | !rollback - Rollback the conversation by 1 message 110 | !config - Show the current configuration 111 | !exit - Exit the program 112 | """, 113 | ) 114 | continue 115 | elif prompt == "!reset": 116 | chatbot.reset_chat() 117 | print("Chat session reset.") 118 | continue 119 | elif prompt == "!refresh": 120 | chatbot.refresh_session() 121 | print("Session refreshed.\n") 122 | continue 123 | elif prompt == "!rollback": 124 | chatbot.rollback_conversation() 125 | print("Chat session rolled back.") 126 | continue 127 | elif prompt == "!config": 128 | print(json.dumps(config, indent=4)) 129 | continue 130 | elif prompt == "!exit": 131 | break 132 | 133 | if "--text" not in argv: 134 | lines_printed = 0 135 | 136 | try: 137 | print("Chatbot: ") 138 | formatted_parts = [] 139 | for message in chatbot.get_chat_response(prompt, output="stream"): 140 | # Split the message by newlines 141 | message_parts = message["message"].split("\n") 142 | 143 | # Wrap each part separately 144 | formatted_parts = [] 145 | for part in message_parts: 146 | formatted_parts.extend( 147 | textwrap.wrap(part, width=80)) 148 | for _ in formatted_parts: 149 | if len(formatted_parts) > lines_printed + 1: 150 | print(formatted_parts[lines_printed]) 151 | lines_printed += 1 152 | print(formatted_parts[lines_printed]) 153 | except Exception as exc: 154 | print("Response not in correct format!") 155 | print(exc) 156 | continue 157 | else: 158 | try: 159 | print("Chatbot: ") 160 | message = chatbot.get_chat_response(prompt) 161 | print(message["message"]) 162 | except Exception as exc: 163 | print("Something went wrong!") 164 | print(exc) 165 | continue 166 | except KeyboardInterrupt: 167 | print("\nGoodbye!") 168 | exit() 169 | except Exception as exc: 170 | print("Something went wrong! Please run with --debug to see the error.") 171 | print(exc) 172 | exit() 173 | 174 | 175 | if __name__ == "__main__": 176 | main() 177 | -------------------------------------------------------------------------------- /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 asyncio 7 | 8 | import httpx 9 | 10 | from OpenAIAuth.OpenAIAuth import OpenAIAuth, Debugger 11 | 12 | 13 | def generate_uuid() -> str: 14 | """ 15 | Generate a UUID for the session -- Internal use only 16 | 17 | :return: a random UUID 18 | :rtype: :obj:`str` 19 | """ 20 | uid = str(uuid.uuid4()) 21 | return uid 22 | 23 | 24 | class AsyncChatbot: 25 | """ 26 | Initialize the AsyncChatbot. 27 | 28 | See wiki for the configuration json: 29 | https://github.com/acheong08/ChatGPT/wiki/Setup 30 | 31 | :param config: The configuration json 32 | :type config: :obj:`json` 33 | 34 | :param conversation_id: The conversation ID 35 | :type conversation_id: :obj:`str`, optional 36 | 37 | :param parent_id: The parent ID 38 | :type parent_id: :obj:`str`, optional 39 | 40 | :param debug: Whether to enable debug mode 41 | :type debug: :obj:`bool`, optional 42 | 43 | :param refresh: Whether to refresh the session 44 | :type refresh: :obj:`bool`, optional 45 | 46 | :param request_timeout: The network request timeout seconds 47 | :type request_timeout: :obj:`int`, optional 48 | 49 | :param base_url: The base url to chat.openai.com backend server, 50 | useful when set up a reverse proxy to avoid network issue. 51 | :type base_url: :obj:`str`, optional 52 | 53 | :return: The Chatbot object 54 | :rtype: :obj:`Chatbot` 55 | """ 56 | config: json 57 | conversation_id: str 58 | parent_id: str 59 | base_url: str 60 | headers: dict 61 | conversation_id_prev: str 62 | parent_id_prev: str 63 | request_timeout: int 64 | captcha_solver: any 65 | 66 | def __init__(self, config, conversation_id=None, parent_id=None, debug=False, refresh=True, request_timeout=100, captcha_solver=None, base_url="https://chat.openai.com/"): 67 | self.debugger = Debugger(debug) 68 | self.debug = debug 69 | self.config = config 70 | self.conversation_id = conversation_id 71 | self.parent_id = parent_id if parent_id else generate_uuid() 72 | self.base_url = base_url 73 | self.request_timeout = request_timeout 74 | self.captcha_solver = captcha_solver 75 | self.config["accept_language"] = 'en-US,en' if "accept_language" not in self.config.keys( 76 | ) else self.config["accept_language"] 77 | self.headers = { 78 | "Accept": "text/event-stream", 79 | "Authorization": "Bearer ", 80 | "Content-Type": "application/json", 81 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) " 82 | "Version/16.1 Safari/605.1.15", 83 | "X-Openai-Assistant-App-Id": "", 84 | "Connection": "close", 85 | "Accept-Language": self.config["accept_language"]+";q=0.9", 86 | "Referer": "https://chat.openai.com/chat", 87 | } 88 | if ("session_token" in config or ("email" in config and "password" in config)) and refresh: 89 | self.refresh_session() 90 | if "Authorization" in config: 91 | self.__refresh_headers() 92 | 93 | def reset_chat(self) -> None: 94 | """ 95 | Reset the conversation ID and parent ID. 96 | 97 | :return: None 98 | """ 99 | self.conversation_id = None 100 | self.parent_id = generate_uuid() 101 | 102 | def __refresh_headers(self) -> None: 103 | """ 104 | Refresh the headers -- Internal use only 105 | 106 | :return: None 107 | """ 108 | if not self.config.get("Authorization"): 109 | self.config["Authorization"] = "" 110 | self.headers["Authorization"] = "Bearer " + \ 111 | self.config["Authorization"] 112 | 113 | async def __get_chat_stream(self, data) -> None: 114 | """ 115 | Generator for the chat stream -- Internal use only 116 | 117 | :param data: The data to send 118 | :type data: :obj:`dict` 119 | 120 | :return: None 121 | """ 122 | s = httpx.AsyncClient() 123 | async with s.stream( 124 | 'POST', 125 | self.base_url + "backend-api/conversation", 126 | headers=self.headers, 127 | data=json.dumps(data), 128 | timeout=self.request_timeout, 129 | ) as response: 130 | async for line in response.aiter_lines(): 131 | try: 132 | line = line[:-1] 133 | if line == "" or line == "data: [DONE]": 134 | continue 135 | line = line[6:] 136 | line = json.loads(line) 137 | if len(line["message"]["content"]["parts"]) == 0: 138 | continue 139 | message = line["message"]["content"]["parts"][0] 140 | self.conversation_id = line["conversation_id"] 141 | self.parent_id = line["message"]["id"] 142 | yield { 143 | "message": message, 144 | "conversation_id": self.conversation_id, 145 | "parent_id": self.parent_id, 146 | } 147 | except Exception as exc: 148 | self.debugger.log( 149 | f"Error when handling response, got values{line}") 150 | raise Exception( 151 | f"Error when handling response, got values{line}") from exc 152 | 153 | async def __get_chat_text(self, data) -> dict: 154 | """ 155 | Get the chat response as text -- Internal use only 156 | :param data: The data to send 157 | :type data: :obj:`dict` 158 | :return: The chat response 159 | :rtype: :obj:`dict` 160 | """ 161 | # Create request session 162 | async with httpx.AsyncClient() as s: 163 | # set headers 164 | s.headers = self.headers 165 | # Set multiple cookies 166 | if "session_token" in self.config: 167 | s.cookies.set( 168 | "__Secure-next-auth.session-token", 169 | self.config["session_token"], 170 | ) 171 | s.cookies.set( 172 | "__Secure-next-auth.callback-url", 173 | self.base_url, 174 | ) 175 | # Set proxies 176 | if self.config.get("proxy", "") != "": 177 | s.proxies = { 178 | "http": self.config["proxy"], 179 | "https": self.config["proxy"], 180 | } 181 | response = await s.post( 182 | self.base_url + "backend-api/conversation", 183 | data=json.dumps(data), 184 | timeout=self.request_timeout, 185 | ) 186 | try: 187 | response = response.text.splitlines()[-4] 188 | response = response[6:] 189 | except Exception as exc: 190 | self.debugger.log("Incorrect response from OpenAI API") 191 | try: 192 | resp = response.json() 193 | self.debugger.log(resp) 194 | if resp['detail']['code'] == "invalid_api_key" or resp['detail']['code'] == "token_expired": 195 | self.refresh_session() 196 | except Exception as exc2: 197 | self.debugger.log(response.text) 198 | raise Exception("Not a JSON response") from exc2 199 | raise Exception("Incorrect response from OpenAI API") from exc 200 | response = json.loads(response) 201 | self.parent_id = response["message"]["id"] 202 | self.conversation_id = response["conversation_id"] 203 | message = response["message"]["content"]["parts"][0] 204 | return { 205 | "message": message, 206 | "conversation_id": self.conversation_id, 207 | "parent_id": self.parent_id, 208 | } 209 | 210 | async def get_chat_response(self, prompt: str, output="text", conversation_id=None, parent_id=None) -> dict or None: 211 | """ 212 | Get the chat response. 213 | 214 | :param prompt: The message sent to the chatbot 215 | :type prompt: :obj:`str` 216 | 217 | :param output: The output type `text` or `stream` 218 | :type output: :obj:`str`, optional 219 | 220 | :return: The chat response `{"message": "Returned messages", "conversation_id": "conversation ID", "parent_id": "parent ID"}` or None 221 | :rtype: :obj:`dict` or :obj:`None` 222 | """ 223 | data = { 224 | "action": "next", 225 | "messages": [ 226 | { 227 | "id": str(generate_uuid()), 228 | "role": "user", 229 | "content": {"content_type": "text", "parts": [prompt]}, 230 | }, 231 | ], 232 | "conversation_id": conversation_id or self.conversation_id, 233 | "parent_message_id": parent_id or self.parent_id, 234 | "model": "text-davinci-002-render", 235 | } 236 | self.conversation_id_prev = self.conversation_id 237 | self.parent_id_prev = self.parent_id 238 | if output == "text": 239 | return await self.__get_chat_text(data) 240 | elif output == "stream": 241 | return self.__get_chat_stream(data) 242 | else: 243 | raise ValueError("Output must be either 'text' or 'stream'") 244 | 245 | def rollback_conversation(self) -> None: 246 | """ 247 | Rollback the conversation. 248 | 249 | :return: None 250 | """ 251 | self.conversation_id = self.conversation_id_prev 252 | self.parent_id = self.parent_id_prev 253 | 254 | def refresh_session(self) -> None: 255 | """ 256 | Refresh the session. 257 | 258 | :return: None 259 | """ 260 | # Either session_token, email and password or Authorization is required 261 | if self.config.get("session_token"): 262 | s = httpx.Client() 263 | if self.config.get("proxy"): 264 | s.proxies = { 265 | "http": self.config["proxy"], 266 | "https": self.config["proxy"], 267 | } 268 | # Set cookies 269 | s.cookies.set( 270 | "__Secure-next-auth.session-token", 271 | self.config["session_token"], 272 | ) 273 | # s.cookies.set("__Secure-next-auth.csrf-token", self.config['csrf_token']) 274 | response = s.get( 275 | self.base_url + "api/auth/session", 276 | headers={ 277 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, " 278 | "like Gecko) Version/16.1 Safari/605.1.15 ", 279 | }, 280 | ) 281 | # Check the response code 282 | if response.status_code != 200: 283 | self.debugger.log( 284 | f"Invalid status code: {response.status_code}") 285 | raise Exception("Wrong response code") 286 | # Try to get new session token and Authorization 287 | try: 288 | if 'error' in response.json(): 289 | self.debugger.log("Error in response JSON") 290 | self.debugger.log(response.json()['error']) 291 | raise Exception 292 | self.config["session_token"] = response.cookies.get( 293 | "__Secure-next-auth.session-token", 294 | ) 295 | self.config["Authorization"] = response.json()["accessToken"] 296 | self.__refresh_headers() 297 | # If it fails, try to login with email and password to get tokens 298 | except Exception: 299 | # Check if response JSON is empty 300 | if response.json() == {}: 301 | self.debugger.log("Empty response") 302 | self.debugger.log("Probably invalid session token") 303 | # Check if ['detail']['code'] == 'token_expired' in response JSON 304 | # First check if detail is in response JSON 305 | elif 'detail' in response.json(): 306 | # Check if code is in response JSON 307 | if 'code' in response.json()['detail']: 308 | # Check if code is token_expired 309 | if response.json()['detail']['code'] == 'token_expired': 310 | self.debugger.log("Token expired") 311 | else: 312 | self.debugger.log(f"Response: '{response.text}'") 313 | self.debugger.log("Cannot refresh the session, try to login") 314 | # Try to login 315 | if 'email' in self.config and 'password' in self.config: 316 | del self.config['session_token'] 317 | self.login(self.config['email'], 318 | self.config['password']) 319 | else: 320 | self.debugger.log( 321 | "Invalid token and no email and password provided") 322 | raise ValueError( 323 | "Error refreshing session: No email and password provided") 324 | elif "email" in self.config and "password" in self.config: 325 | try: 326 | self.login(self.config["email"], self.config["password"]) 327 | except Exception as exc: 328 | self.debugger.log("Login failed") 329 | raise exc 330 | elif "Authorization" in self.config: 331 | self.__refresh_headers() 332 | else: 333 | self.debugger.log( 334 | "No session_token, email and password or Authorization provided") 335 | raise ValueError( 336 | "No session_token, email and password or Authorization provided") 337 | 338 | def login(self, email: str, password: str) -> None: 339 | """ 340 | Log in to OpenAI. 341 | 342 | :param email: The email 343 | :type email: :obj:`str` 344 | 345 | :param password: The password 346 | :type password: :obj:`str` 347 | 348 | :return: None 349 | """ 350 | self.debugger.log("Logging in...") 351 | proxy = self.config.get("proxy") 352 | auth = OpenAIAuth(email, password, bool( 353 | proxy), proxy, debug=self.debug, use_captcha=True, captcha_solver=self.captcha_solver) 354 | try: 355 | auth.begin() 356 | except Exception as exc: 357 | # if ValueError with e as "Captcha detected" fail 358 | if exc == "Captcha detected": 359 | self.debugger.log( 360 | "Captcha not supported. Use session tokens instead.") 361 | raise ValueError("Captcha detected") from exc 362 | raise exc 363 | if auth.access_token is not None: 364 | self.config["Authorization"] = auth.access_token 365 | if auth.session_token is not None: 366 | self.config["session_token"] = auth.session_token 367 | else: 368 | possible_tokens = auth.session.cookies.get( 369 | "__Secure-next-auth.session-token", 370 | ) 371 | if possible_tokens is not None: 372 | if len(possible_tokens) > 1: 373 | self.config["session_token"] = possible_tokens[0] 374 | else: 375 | self.config["session_token"] = possible_tokens 376 | self.__refresh_headers() 377 | else: 378 | raise Exception("Error logging in") 379 | 380 | def send_feedback( 381 | self, 382 | is_good: bool, 383 | is_harmful=False, 384 | is_not_true=False, 385 | is_not_helpful=False, 386 | description=None, 387 | ): 388 | from dataclasses import dataclass 389 | 390 | @dataclass 391 | class ChatGPTTags: 392 | Harmful = "harmful" 393 | NotTrue = "false" 394 | NotHelpful = "not-helpful" 395 | 396 | url = self.base_url + "backend-api/conversation/message_feedback" 397 | 398 | data = { 399 | "conversation_id": self.conversation_id, 400 | "message_id": self.parent_id, 401 | "rating": "thumbsUp" if is_good else "thumbsDown", 402 | } 403 | 404 | if not is_good: 405 | tags = list() 406 | if is_harmful: 407 | tags.append(ChatGPTTags.Harmful) 408 | if is_not_true: 409 | tags.append(ChatGPTTags.NotTrue) 410 | if is_not_helpful: 411 | tags.append(ChatGPTTags.NotHelpful) 412 | data["tags"] = tags 413 | 414 | if description is not None: 415 | data["text"] = description 416 | 417 | response = httpx.post( 418 | url, 419 | headers=self.headers, 420 | data=json.dumps(data), 421 | timeout=self.request_timeout, 422 | ) 423 | 424 | return response 425 | 426 | 427 | class Chatbot(AsyncChatbot): 428 | """ 429 | Initialize the Chatbot. 430 | 431 | See wiki for the configuration json: 432 | https://github.com/acheong08/ChatGPT/wiki/Setup 433 | 434 | :param config: The configuration json 435 | :type config: :obj:`json` 436 | 437 | :param conversation_id: The conversation ID 438 | :type conversation_id: :obj:`str`, optional 439 | 440 | :param parent_id: The parent ID 441 | :type parent_id: :obj:`str`, optional 442 | 443 | :param debug: Whether to enable debug mode 444 | :type debug: :obj:`bool`, optional 445 | 446 | :param refresh: Whether to refresh the session 447 | :type refresh: :obj:`bool`, optional 448 | 449 | :param request_timeout: The network request timeout seconds 450 | :type request_timeout: :obj:`int`, optional 451 | 452 | :param base_url: The base url to chat.openai.com backend server, 453 | useful when set up a reverse proxy to avoid network issue. 454 | :type base_url: :obj:`str`, optional 455 | 456 | :return: The Chatbot object 457 | :rtype: :obj:`Chatbot` 458 | """ 459 | 460 | def __get_chat_stream(self, data) -> None: 461 | """ 462 | Generator for the chat stream -- Internal use only 463 | 464 | :param data: The data to send 465 | :type data: :obj:`dict` 466 | 467 | :return: None 468 | """ 469 | s = httpx.Client() 470 | with s.stream( 471 | 'POST', 472 | self.base_url + "backend-api/conversation", 473 | headers=self.headers, 474 | data=json.dumps(data), 475 | timeout=self.request_timeout, 476 | ) as response: 477 | for line in response.iter_lines(): 478 | try: 479 | line = line[:-1] 480 | if line == "" or line == "data: [DONE]": 481 | continue 482 | line = line[6:] 483 | line = json.loads(line) 484 | if len(line["message"]["content"]["parts"]) == 0: 485 | continue 486 | message = line["message"]["content"]["parts"][0] 487 | self.conversation_id = line["conversation_id"] 488 | self.parent_id = line["message"]["id"] 489 | yield { 490 | "message": message, 491 | "conversation_id": self.conversation_id, 492 | "parent_id": self.parent_id, 493 | } 494 | except Exception as exc: 495 | self.debugger.log( 496 | f"Error when handling response, got values{line}") 497 | raise Exception( 498 | f"Error when handling response, got values{line}") from exc 499 | 500 | def get_chat_response(self, prompt: str, output="text", conversation_id=None, parent_id=None) -> dict or None: 501 | """ 502 | Get the chat response. 503 | 504 | :param prompt: The message sent to the chatbot 505 | :type prompt: :obj:`str` 506 | 507 | :param output: The output type `text` or `stream` 508 | :type output: :obj:`str`, optional 509 | 510 | :return: The chat response `{"message": "Returned messages", "conversation_id": "conversation ID", "parent_id": "parent ID"}` or None 511 | :rtype: :obj:`dict` or :obj:`None` 512 | """ 513 | if output == "text": 514 | coroutine_object = super().get_chat_response( 515 | prompt, output, conversation_id, parent_id) 516 | return asyncio.run(coroutine_object) 517 | if output == "stream": 518 | data = { 519 | "action": "next", 520 | "messages": [ 521 | { 522 | "id": str(generate_uuid()), 523 | "role": "user", 524 | "content": {"content_type": "text", "parts": [prompt]}, 525 | }, 526 | ], 527 | "conversation_id": conversation_id or self.conversation_id, 528 | "parent_message_id": parent_id or self.parent_id, 529 | "model": "text-davinci-002-render", 530 | } 531 | return self.__get_chat_stream(data) 532 | -------------------------------------------------------------------------------- /wiki/CLI-use.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ python3 -m revChatGPT --debug 3 | 4 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 5 | Repo: github.com/acheong08/ChatGPT 6 | Run with --debug to enable debugging 7 | 8 | Type '!help' to show commands 9 | Press enter twice to submit your question. 10 | 11 | Logging in... 12 | 13 | You: 14 | !help 15 | 16 | 17 | !help - Show this message 18 | !reset - Forget the current conversation 19 | !refresh - Refresh the session authentication 20 | !rollback - Rollback the conversation by 1 message 21 | !config - Show the current configuration 22 | !exit - Exit the program 23 | ``` 24 | 25 | Refresh every so often in case the token expires. 26 | 27 | # Captcha 28 | If you encounter captcha, it saves the image to `captcha.svg` which you can open with your browser. You can then enter the code into the terminal where it asks. -------------------------------------------------------------------------------- /wiki/Contributors.md: -------------------------------------------------------------------------------- 1 | # Where to contribute: 2 | If you know how to reverse Engineer APIs, check out [OpenAIAuth](https://github.com/acheong08/OpenAIAuth) where captcha support and error handling has yet to be perfected 3 | 4 | If you are interested in extending this project for other features, simply create your own repository and import this library. 5 | 6 | If you aren't a coder, you can still write some documentation for us. 7 | 8 | # Contributing to ChatGPT 9 | 10 | We welcome contributions to ChatGPT! Here are some guidelines to help you get started. 11 | 12 | ## Types of contributions we are looking for 13 | 14 | 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: 15 | 16 | - Code patches 17 | - Documentation improvements 18 | - Bug reports and fixes 19 | - Feature requests and suggestions 20 | 21 | Please note that ChatGPT is intended to be used as a development library, so contributions should stay within this scope. 22 | 23 | ## How to submit a contribution 24 | 25 | If you would like to contribute to ChatGPT, follow these steps: 26 | 27 | 1. Fork the ChatGPT repository. 28 | 2. Create a new branch in your fork to make your changes. 29 | 3. Commit your changes to your new branch. 30 | 4. Push your changes to your fork on GitHub. 31 | 5. Submit a pull request from your branch to the ChatGPT repository. 32 | 33 | We will review your pull request and, if everything looks good, merge it into the main codebase. 34 | 35 | ## Questions 36 | 37 | If you have any questions about contributing to ChatGPT, feel free to open an issue in the ChatGPT repository and ask. 38 | 39 | Thank you for considering a contribution to ChatGPT! -------------------------------------------------------------------------------- /wiki/Developer-Docs.md: -------------------------------------------------------------------------------- 1 | # Development 2 | Full API docs: [here](https://github.com/acheong08/ChatGPT/wiki/revChatGPT) 3 | 4 | ## Standard use 5 | 6 | ### Initial setup 7 | 8 | `pip3 install revChatGPT --upgrade` 9 | 10 | ```python 11 | from revChatGPT.revChatGPT import Chatbot 12 | 13 | # For the config please go here: 14 | # https://github.com/acheong08/ChatGPT/wiki/Setup 15 | config = { 16 | "email": "", 17 | "password": "", 18 | #"session_token": "", # Deprecated. Use only if you encounter captcha with email/password 19 | #"proxy": "" 20 | } 21 | 22 | chatbot = Chatbot(config, conversation_id=None) 23 | ``` 24 | 25 | ## Getting responses 26 | 27 | Output options: `text`, `stream` 28 | 29 | ```python 30 | ... # After the initial setup 31 | # The text output 32 | 33 | response = chatbot.get_chat_response("Hello world", output="text") 34 | print(response) 35 | 36 | # returns {'message':message, 'conversation_id':self.conversation_id, 'parent_id':self.parent_id} 37 | ``` 38 | 39 | ```python 40 | # The stream output 41 | response = chatbot.get_chat_response("Hello world", output="stream") 42 | for res in response: 43 | print(res['message']) 44 | 45 | # returns {'message':message, 'conversation_id':self.conversation_id, 'parent_id':self.parent_id} 46 | ``` 47 | 48 | ## Async use 49 | 50 | ### Initial setup 51 | 52 | `pip3 install revChatGPT --upgrade` 53 | 54 | ```python 55 | from revChatGPT.revChatGPT import AsyncChatbot as Chatbot 56 | 57 | # For the config please go here: 58 | # https://github.com/acheong08/ChatGPT/wiki/Setup 59 | config = { 60 | "email": "", 61 | "password": "", 62 | #"session_token": "", # Deprecated. Use only if you encounter captcha with email/password 63 | #"proxy": "" 64 | } 65 | 66 | chatbot = Chatbot(config, conversation_id=None) 67 | ``` 68 | 69 |
70 | 71 | 72 | ### Get text response 73 | 74 | 75 | 76 | example use: 77 | 78 | ```python 79 | ... # After the initial setup 80 | import asyncio 81 | message = asyncio.run(chatbot.get_chat_response("Hello world"))['message'] 82 | print(message) 83 | ``` 84 | 85 |
86 | 87 |
88 | 89 | 90 | ### Get streaming response 91 | 92 | 93 | 94 | example use: 95 | 96 | ```python 97 | ... # After the initial setup 98 | import asyncio 99 | async def printMessage(): 100 | async for i in await chatbot.get_chat_response("hello", output="stream"): 101 | print(i['message']) 102 | asyncio.run(printMessage()) 103 | ``` 104 | 105 |
106 | -------------------------------------------------------------------------------- /wiki/Home.md: -------------------------------------------------------------------------------- 1 | Welcome to the ChatGPT wiki! 2 | 3 | - [Installation and setup](https://github.com/acheong08/ChatGPT/wiki/Setup) 4 | - [CLI usage](https://github.com/acheong08/ChatGPT/wiki/CLI-use) 5 | - [Developing with ChatGPT](https://github.com/acheong08/ChatGPT/wiki/Developer-Docs) 6 | - [Contributing](https://github.com/acheong08/ChatGPT/wiki/Contributors) 7 | 8 | WIP. Please add more docs -------------------------------------------------------------------------------- /wiki/OpenAIAuth.md: -------------------------------------------------------------------------------- 1 | https://github.com/acheong08/OpenAIAuth -------------------------------------------------------------------------------- /wiki/Setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | ## Install 3 | `pip3 install revChatGPT --upgrade` 4 | 5 | Make the necessary changes in `config.json.example` and save as `config.json` in the current working directory, in `$XDG_CONFIG_HOME/revChatGPT/config.json`, or in `$HOME/revChatGPT/config.json`. 6 | 7 |
8 | 9 | 10 | ## Email and password authentication 11 | 12 | 13 | ```json 14 | { 15 | "email": "", 16 | "password": "" 17 | } 18 | ``` 19 | Save this in `config.json` in current working directory, in `$XDG_CONFIG_HOME/revChatGPT/config.json`, or in `$HOME/revChatGPT/config.json`. 20 | 21 |
22 | 23 |
24 | 25 | 26 | ## Session Token Authentication 27 | Use if using third-party providers (Google / Microsoft Auth) or if email/password rate limited 28 | 29 | 30 | Go to https://chat.openai.com/chat and log in or sign up 31 | 32 | 1. Open console with `F12` 33 | 2. Open `Application` tab > Cookies 34 | ![image](https://user-images.githubusercontent.com/36258159/205494773-32ef651a-994d-435a-9f76-a26699935dac.png) 35 | 3. Copy the value for `__Secure-next-auth.session-token` and paste it into `config.json.example` under `session_token`. You do not need to fill out `Authorization` 36 | ![image](https://user-images.githubusercontent.com/36258159/205495076-664a8113-eda5-4d1e-84d3-6fad3614cfd8.png) 37 | 4. Save the modified file as `config.json` in the current working directory, as `$XDG_CONFIG_HOME/revChatGPT/config.json`, or as `$HOME/revChatGPT/config.json`. 38 | 39 | ```json 40 | { 41 | "session_token": "" 42 | } 43 | ``` 44 | Do not put email/password as that overrides tokens 45 | 46 |
47 | 48 |
49 | 50 | 51 | ## Access Token Authentication 52 | Use this only if all else fails. Refreshing the session does not work here. You have to refresh manually. 53 | 54 | 55 | 1. Log in to https://chat.openai.com/ 56 | 2. Go to https://chat.openai.com/api/auth/session 57 | 3. Copy the `accessToken` 58 | 4. Replace the with the accessToken value using the below format 59 | ```json 60 | { 61 | "Authorization":"" 62 | } 63 | ``` 64 | 5. Save as `config.json` in the current working directory, as `$XDG_CONFIG_HOME/revChatGPT/config.json`, or as `$HOME/revChatGPT/config.json`. 65 | 66 |
67 | -------------------------------------------------------------------------------- /wiki/Star-history.md: -------------------------------------------------------------------------------- 1 | This is just for me to keep track so I can show off to my friends (If I had any...) 2 | 3 | [![Star History Chart](https://api.star-history.com/svg?repos=acheong08/ChatGPT&type=Date)](https://star-history.com/#acheong08/ChatGPT&Date) -------------------------------------------------------------------------------- /wiki/revChatGPT.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # revChatGPT 4 | 5 | 6 | 7 | # revChatGPT.Exceptions 8 | 9 | 10 | 11 | # revChatGPT.\_\_main\_\_ 12 | 13 | 14 | 15 | ## CaptchaSolver Objects 16 | 17 | ```python 18 | class CaptchaSolver() 19 | ``` 20 | 21 | Captcha solver 22 | 23 | 24 | 25 | #### solve\_captcha 26 | 27 | ```python 28 | @staticmethod 29 | def solve_captcha(raw_svg) 30 | ``` 31 | 32 | Solves the captcha 33 | 34 | **Arguments**: 35 | 36 | - `raw_svg` (`:obj:`str``): The raw SVG 37 | 38 | **Returns**: 39 | 40 | `:obj:`str``: The solution 41 | 42 | 43 | 44 | # revChatGPT.revChatGPT 45 | 46 | 47 | 48 | #### generate\_uuid 49 | 50 | ```python 51 | def generate_uuid() -> str 52 | ``` 53 | 54 | Generate a UUID for the session -- Internal use only 55 | 56 | **Returns**: 57 | 58 | `:obj:`str``: a random UUID 59 | 60 | 61 | 62 | ## AsyncChatbot Objects 63 | 64 | ```python 65 | class AsyncChatbot() 66 | ``` 67 | 68 | Initialize the AsyncChatbot. 69 | 70 | See wiki for the configuration json: 71 | https://github.com/acheong08/ChatGPT/wiki/Setup 72 | 73 | **Arguments**: 74 | 75 | - `config` (`:obj:`json``): The configuration json 76 | - `conversation_id` (`:obj:`str`, optional`): The conversation ID 77 | - `parent_id` (`:obj:`str`, optional`): The parent ID 78 | - `debug` (`:obj:`bool`, optional`): Whether to enable debug mode 79 | - `refresh` (`:obj:`bool`, optional`): Whether to refresh the session 80 | - `request_timeout` (`:obj:`int`, optional`): The network request timeout seconds 81 | - `base_url` (`:obj:`str`, optional`): The base url to chat.openai.com backend server, 82 | useful when set up a reverse proxy to avoid network issue. 83 | 84 | **Returns**: 85 | 86 | `:obj:`Chatbot``: The Chatbot object 87 | 88 | 89 | 90 | #### reset\_chat 91 | 92 | ```python 93 | def reset_chat() -> None 94 | ``` 95 | 96 | Reset the conversation ID and parent ID. 97 | 98 | **Returns**: 99 | 100 | None 101 | 102 | 103 | 104 | #### get\_chat\_response 105 | 106 | ```python 107 | async def get_chat_response(prompt: str, 108 | output="text", 109 | conversation_id=None, 110 | parent_id=None) -> dict or None 111 | ``` 112 | 113 | Get the chat response. 114 | 115 | **Arguments**: 116 | 117 | - `prompt` (`:obj:`str``): The message sent to the chatbot 118 | - `output` (`:obj:`str`, optional`): The output type `text` or `stream` 119 | 120 | **Returns**: 121 | 122 | `:obj:`dict` or :obj:`None``: The chat response `{"message": "Returned messages", "conversation_id": "conversation ID", "parent_id": "parent ID"}` or None 123 | 124 | 125 | 126 | #### rollback\_conversation 127 | 128 | ```python 129 | def rollback_conversation() -> None 130 | ``` 131 | 132 | Rollback the conversation. 133 | 134 | **Returns**: 135 | 136 | None 137 | 138 | 139 | 140 | #### refresh\_session 141 | 142 | ```python 143 | def refresh_session() -> None 144 | ``` 145 | 146 | Refresh the session. 147 | 148 | **Returns**: 149 | 150 | None 151 | 152 | 153 | 154 | #### login 155 | 156 | ```python 157 | def login(email: str, password: str) -> None 158 | ``` 159 | 160 | Log in to OpenAI. 161 | 162 | **Arguments**: 163 | 164 | - `email` (`:obj:`str``): The email 165 | - `password` (`:obj:`str``): The password 166 | 167 | **Returns**: 168 | 169 | None 170 | 171 | 172 | 173 | ## Chatbot Objects 174 | 175 | ```python 176 | class Chatbot(AsyncChatbot) 177 | ``` 178 | 179 | Initialize the AsyncChatbot. 180 | 181 | See wiki for the configuration json: 182 | https://github.com/acheong08/ChatGPT/wiki/Setup 183 | 184 | **Arguments**: 185 | 186 | - `config` (`:obj:`json``): The configuration json 187 | - `conversation_id` (`:obj:`str`, optional`): The conversation ID 188 | - `parent_id` (`:obj:`str`, optional`): The parent ID 189 | - `debug` (`:obj:`bool`, optional`): Whether to enable debug mode 190 | - `refresh` (`:obj:`bool`, optional`): Whether to refresh the session 191 | - `request_timeout` (`:obj:`int`, optional`): The network request timeout seconds 192 | - `base_url` (`:obj:`str`, optional`): The base url to chat.openai.com backend server, 193 | useful when set up a reverse proxy to avoid network issue. 194 | 195 | **Returns**: 196 | 197 | `:obj:`Chatbot``: The Chatbot object 198 | 199 | 200 | 201 | #### get\_chat\_response 202 | 203 | ```python 204 | def get_chat_response(prompt: str, 205 | output="text", 206 | conversation_id=None, 207 | parent_id=None) -> dict or None 208 | ``` 209 | 210 | Get the chat response. 211 | 212 | **Arguments**: 213 | 214 | - `prompt` (`:obj:`str``): The message sent to the chatbot 215 | - `output` (`:obj:`str`, optional`): The output type `text` or `stream` 216 | 217 | **Returns**: 218 | 219 | `:obj:`dict` or :obj:`None``: The chat response `{"message": "Returned messages", "conversation_id": "conversation ID", "parent_id": "parent ID"}` or None 220 | 221 | --------------------------------------------------------------------------------