├── .devcontainer └── devcontainer.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ ├── custom.md │ └── feature_request.yml └── workflows │ ├── codeql.yml │ └── python-publish.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── Makefile ├── config.json.example ├── docs ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── PRIVACY.md ├── README.md ├── README_ja.md ├── README_ko.md ├── README_sp.md ├── README_zh.md ├── SECURITY.md ├── plugins.json ├── view.gif └── wiki │ ├── Authentication.md │ ├── Code-examples.md │ ├── Home.md │ ├── Recipient.md │ ├── Star-history.md │ ├── V1.md │ └── V3.md ├── logo.png ├── requirements.txt ├── setup.cfg ├── setup.py ├── src └── revChatGPT │ ├── V1.py │ ├── V3.py │ ├── __init__.py │ ├── __main__.py │ ├── config │ └── enable_internet.json │ ├── typings.py │ ├── utils.py │ └── version.py └── tests ├── debug.bat └── test_recipient.py /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/universal:2", 3 | "features": { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://github.com/acheong08/ChatGPT/compare", "https://github.com/acheong08/ChatGPT/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22"] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: DO NOT OPEN A DUPLICATE 3 | title: "[Bug]: " 4 | 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is there an existing issue for this? 9 | description: Please search to see if an issue already exists for the bug you encountered, and that it hasn't been fixed in a recent build/commit. 10 | options: 11 | - label: I have searched the existing issues and checked the recent builds/commits 12 | required: true 13 | - type: markdown 14 | attributes: 15 | value: | 16 | *Please fill this form with as much information as possible, don't forget to fill "What OS..." and "What browsers" and *provide screenshots if possible** 17 | - type: textarea 18 | id: what-did 19 | attributes: 20 | label: What happened? 21 | description: Tell us what happened in a very clear and simple way 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: steps 26 | attributes: 27 | label: Steps to reproduce the problem 28 | description: Please provide us with precise step by step information on how to reproduce the bug 29 | value: | 30 | 1. Go to .... 31 | 2. Press .... 32 | 3. ... 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: what-should 37 | attributes: 38 | label: What should have happened? 39 | description: Tell what you think the normal behavior should be 40 | validations: 41 | required: true 42 | - type: textarea 43 | id: version 44 | attributes: 45 | label: Version where the problem happens 46 | description: "`python3 -m pip show revChatGPT`" 47 | validations: 48 | required: true 49 | - type: input 50 | id: python-version 51 | attributes: 52 | label: What Python version are you running this with? 53 | description: "`python3 -V`" 54 | - type: dropdown 55 | id: platforms 56 | attributes: 57 | label: What is your operating system ? 58 | multiple: true 59 | options: 60 | - Windows 61 | - Linux 62 | - MacOS 63 | - iOS 64 | - Android 65 | - Other/Cloud 66 | - type: textarea 67 | id: cmdargs 68 | attributes: 69 | label: Command Line Arguments 70 | description: Are you using any launching parameters/command line arguments (modified webui-user .bat/.sh) ? If yes, please write them below. Write "No" otherwise. 71 | render: Shell 72 | validations: 73 | required: true 74 | - type: textarea 75 | id: logs 76 | attributes: 77 | label: Console logs 78 | description: Please provide **full** cmd/terminal logs from the moment you started UI to the end of it, after your bug happened. If it's very long, provide a link to pastebin or similar service. 79 | render: Shell 80 | validations: 81 | required: true 82 | - type: textarea 83 | id: misc 84 | attributes: 85 | label: Additional information 86 | description: Please provide us with any relevant additional info or context. 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discussions, questions, and niche issues in Github 4 | url: https://github.com/acheong08/ChatGPT/discussions/new/choose 5 | about: For anything that is not an explicit bug 6 | - name: Discuss in the Discord 7 | url: https://discord.gg/9K2BvbXEHT 8 | about: 'Personal server: Chill discussions and more detailed updates' 9 | - name: Communicate in the Discord 10 | url: https://discord.gg/WMNtbDUjUv 11 | about: 'Public server: Large technical community with many high profile members like @transitive-bullshit' 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Are you sure you are not opening a duplicate? From now on, I will not be reading all issues. Use 👍 reaction on an issue to upvote it. I will be reading the top 5 issues each day." 3 | about: "DO NOT PRESS THIS" 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "[Feature Request]: " 4 | 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is there an existing issue for this? 9 | description: Please search to see if an issue already exists for the feature you want, and that it's not implemented in a recent build/commit. 10 | options: 11 | - label: I have searched the existing issues and checked the recent builds/commits 12 | required: true 13 | - type: markdown 14 | attributes: 15 | value: | 16 | *Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible* 17 | - type: textarea 18 | id: feature 19 | attributes: 20 | label: What would your feature do ? 21 | description: Tell us about your feature in a very clear and simple way, and what problem it would solve 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: workflow 26 | attributes: 27 | label: Proposed workflow 28 | description: Please provide us with step by step information on how you'd like the feature to be accessed and used 29 | value: | 30 | 1. Go to .... 31 | 2. Press .... 32 | 3. ... 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: misc 37 | attributes: 38 | label: Additional information 39 | description: Add any other context or screenshots about the feature request here. 40 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: Code Analysis Scanning 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | 6 | jobs: 7 | CodeQL-Build: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | actions: read 11 | contents: read 12 | security-events: write 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | - name: Initialize CodeQL 17 | uses: github/codeql-action/init@v2 18 | with: 19 | languages: python 20 | - name: AutoBuild - python 21 | uses: github/codeql-action/autobuild@v2 22 | - name: Perform CodeQL Analysis 23 | uses: github/codeql-action/analyze@v2 24 | with: 25 | category: "/language:python" 26 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [published] 6 | push: 7 | branches: [main] 8 | paths: 9 | - 'src/**' 10 | - '*.py' 11 | - 'test/**' 12 | - '.github/workflows/**' 13 | pull_request: 14 | types: [opened, reopened, synchronize] 15 | paths: 16 | - 'src/**' 17 | - '*.py' 18 | - 'test/**' 19 | - '.github/workflows/**' 20 | 21 | permissions: 22 | contents: read 23 | 24 | jobs: 25 | ci: 26 | if: github.event_name != 'release' 27 | runs-on: ${{ matrix.os }} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | python-version: ["3.9", "3.11"] 32 | os: [ubuntu-latest, windows-latest] 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Set up Python ${{ matrix.python-version }} 36 | uses: actions/setup-python@v4 37 | with: 38 | python-version: ${{ matrix.python-version }} 39 | - name: Install dependencies 40 | run: make 41 | - name: Build CI 42 | run: make build 43 | - name: Syntax CI 44 | run: make ci 45 | 46 | deploy: 47 | runs-on: ubuntu-latest 48 | if: github.event_name == 'release' 49 | steps: 50 | - uses: actions/checkout@v3 51 | - name: Set up Python 52 | uses: actions/setup-python@v4 53 | with: 54 | python-version: '3.11.0' 55 | - name: Install dependencies 56 | run: make 57 | - name: Build package 58 | run: make build 59 | - name: Publish package 60 | uses: pypa/gh-action-pypi-publish@v1.8.5 61 | with: 62 | user: __token__ 63 | password: ${{ secrets.PYPI_API_TOKEN }} 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Custom 2 | config.json 3 | config.v3.json 4 | .chatgpt_cache.json 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | #Usually these files are written by a python script from a template 37 | #before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | target/ 81 | 82 | # Jupyter Notebook 83 | .ipynb_checkpoints 84 | 85 | # IPython 86 | profile_default/ 87 | ipython_config.py 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | # Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .conda/ 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | 137 | # JetBrains IDEs configuration 138 | .idea/ 139 | src/revChatGPT/test.py 140 | README.md 141 | src/revChatGPT/V3.test.py 142 | .gitignore 143 | .gitignore 144 | captcha 145 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/reorder_python_imports 3 | rev: v3.9.0 4 | hooks: 5 | - id: reorder-python-imports 6 | args: [--py37-plus] 7 | - repo: https://github.com/asottile/add-trailing-comma 8 | rev: v2.3.0 9 | hooks: 10 | - id: add-trailing-comma 11 | args: [--py36-plus] 12 | - repo: https://github.com/asottile/pyupgrade 13 | rev: v3.3.1 14 | hooks: 15 | - id: pyupgrade 16 | args: [--py37-plus] 17 | 18 | - repo: https://github.com/pre-commit/pre-commit-hooks 19 | rev: v4.4.0 20 | hooks: 21 | - id: trailing-whitespace 22 | - id: end-of-file-fixer 23 | - id: check-yaml 24 | - id: debug-statements 25 | - id: double-quote-string-fixer 26 | - id: name-tests-test 27 | - id: requirements-txt-fixer 28 | - repo: https://github.com/psf/black 29 | rev: 22.10.0 30 | hooks: 31 | - id: black 32 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "njpwerner.autodocstring" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.linting.enabled": true, 4 | "cSpell.words": [ 5 | "acheong", 6 | "acreate", 7 | "aiter", 8 | "bcolors", 9 | "Browserless", 10 | "CHATGPT", 11 | "Cheong", 12 | "consts", 13 | "convo", 14 | "davinci", 15 | "duckduckgo", 16 | "ENDC", 17 | "endoftext", 18 | "httpx", 19 | "kwargs", 20 | "levelname", 21 | "mainloop", 22 | "Metaclasses", 23 | "OKBLUE", 24 | "OKCYAN", 25 | "OKGREEN", 26 | "openai", 27 | "padx", 28 | "pady", 29 | "Referer", 30 | "setconversation", 31 | "tiktoken", 32 | "tkinter", 33 | "unallowed" 34 | ], 35 | "python.formatting.provider": "black", 36 | "python.linting.mypyEnabled": false 37 | } 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs 2 | init: 3 | python -m pip install --upgrade pip 4 | python -m pip install -r ./requirements.txt --upgrade 5 | python -m pip install build setuptools wheel flake8 --upgrade 6 | build: 7 | python -m build 8 | ci: 9 | python -m flake8 src --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 10 | python -m flake8 src --count --select=E9,F63,F7,F82 --show-source --statistics 11 | python setup.py install 12 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "" 3 | } 4 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | acheong@student.dalat.org. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /docs/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 | **Notes**: For maintenance purposes, you should commit your code to the dev branch, but when you commit to other branches, our bot will change to the dev branch for you. 29 | 30 | ## Questions 31 | 32 | If you have any questions about contributing to ChatGPT, feel free to open an issue in the ChatGPT repository and ask. 33 | 34 | Thank you for considering a contribution to ChatGPT! 35 | -------------------------------------------------------------------------------- /docs/PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Versions 0, 2, and 3 2 | 3 | By using these versions, you agree to [OpenAI's privacy policy](https://openai.com/policies/privacy-policy). This repository does not collect any data. 4 | 5 | # Version 1 6 | 7 | Version 1 requires a cloudflare bypass to access `chat.openai.com`. Therefore, in combination to [OpenAI's privacy policy](https://openai.com/policies/privacy-policy), you must also accept the privacy policy of other providers involved in the process. 8 | 9 | - [Microsoft Azure](https://azure.microsoft.com/en-us/support/legal/) - The bypass server is hosted there 10 | - [Cloudflare](https://www.cloudflare.com/privacypolicy/) - Used to prevent abuse 11 | 12 | # My privacy policy 13 | 14 | No more data collection since 4.0.6 (Opt in previously) 15 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | English - [中文](./README_zh.md) - [Spanish](./README_sp.md) - [日本語](./README_ja.md) - [한국어](./README_ko.md) 4 | 5 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 6 | [![Support_Platform](https://img.shields.io/pypi/pyversions/revChatGPT)](https://pypi.python.org/pypi/revChatGPT) 7 | [![Downloads](https://static.pepy.tech/badge/revchatgpt)](https://pypi.python.org/pypi/revChatGPT) 8 | 9 | Reverse Engineered ChatGPT API by OpenAI. Extensible for chatbots etc. 10 | 11 | [![](https://github.com/acheong08/ChatGPT/blob/main/docs/view.gif?raw=true)](https://pypi.python.org/pypi/revChatGPT) 12 | 13 | # Installation 14 | 15 | ``` 16 | python -m pip install --upgrade revChatGPT 17 | ``` 18 | 19 | ### Suport Python Version 20 | 21 | - Minimum - Python3.9 22 | - Recommend - Python3.11+ 23 | 24 |
25 | 26 | 27 | 28 | # V1 Standard ChatGPT 29 | 30 | V1 uses a cloudflare bypass proxy to make life convenient for everyone. The proxy is open source: https://github.com/acheong08/ChatGPT-Proxy-V4 31 | 32 | To set your own deployed proxy, set the environment variable `CHATGPT_BASE_URL` to `https://yourproxy.com/api/` 33 | 34 | 35 | 36 | ## Rate limits 37 | 38 | - Proxy server: 5 requests / 10 seconds 39 | - OpenAI: 50 requests / hour for each account 40 | 41 | ## Configuration 42 | 43 | 1. Create account on [OpenAI's ChatGPT](https://chat.openai.com/) 44 | 2. Save your email and password 45 | 46 | ### Authentication method: (Choose 1) 47 | 48 | #### - Email/Password 49 | 50 | > Not supported for Google/Microsoft accounts. 51 | 52 | ```json 53 | { 54 | "email": "email", 55 | "password": "your password" 56 | } 57 | ``` 58 | 59 | #### - Access token 60 | 61 | https://chat.openai.com/api/auth/session 62 | 63 | ```json 64 | { 65 | "access_token": "" 66 | } 67 | ``` 68 | 69 | #### - Optional configuration: 70 | 71 | ```json 72 | { 73 | "conversation_id": "UUID...", 74 | "parent_id": "UUID...", 75 | "proxy": "...", 76 | "model": "gpt-4", // gpt-4-browsing, text-davinci-002-render-sha, gpt-4, gpt-4-plugins 77 | "plugin_ids": ["plugin-d1d6eb04-3375-40aa-940a-c2fc57ce0f51"], // Wolfram Alpha example 78 | "disable_history": true, 79 | "PUID": "<_puid cookie for plus accounts>", // Only if you have a plus account and use GPT-4 80 | "unverified_plugin_domains":["showme.redstarplugin.com"] // Unverfied plugins to install 81 | } 82 | ``` 83 | 84 | 1. Save this as `$HOME/.config/revChatGPT/config.json` 85 | 2. If you are using Windows, you will need to create an environment variable named `HOME` and set it to your home profile for the script to be able to locate the config.json file. 86 | 87 | Plugin IDs can be found [here](./plugins.json). Remember to set model to `gpt-4-plugins` if plugins are enabled. Plugins may or may not work if you haven't installed them from the web interface. You can call `chatbot.install_plugin(plugin_id=plugin_id)` to install any one of them from code. Call `chatbot.get_plugins()` to get a list of all plugins available. 88 | 89 | ## Usage 90 | 91 | ### Command line 92 | 93 | `python3 -m revChatGPT.V1` 94 | 95 | ``` 96 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 97 | Repo: github.com/acheong08/ChatGPT 98 | Type '!help' to show a full list of commands 99 | Logging in... 100 | You: 101 | (Press Esc followed by Enter to finish) 102 | ``` 103 | 104 | The command line interface supports multi-line inputs and allows navigation using arrow keys. Besides, you can also edit history inputs by arrow keys when the prompt is empty. It also completes your input if it finds matched previous prompts. To finish input, press `Esc` and then `Enter` as solely `Enter` itself is used for creating new line in multi-line mode. 105 | 106 | Set the environment variable `NO_COLOR` to `true` to disable color output. 107 | 108 | ### Developer API 109 | 110 | #### Basic example (streamed): 111 | 112 | ```python 113 | from revChatGPT.V1 import Chatbot 114 | chatbot = Chatbot(config={ 115 | "access_token": "" 116 | }) 117 | print("Chatbot: ") 118 | prev_text = "" 119 | for data in chatbot.ask( 120 | "Hello world", 121 | ): 122 | message = data["message"][len(prev_text) :] 123 | print(message, end="", flush=True) 124 | prev_text = data["message"] 125 | print() 126 | ``` 127 | 128 | #### Basic example (single result): 129 | 130 | ```python 131 | from revChatGPT.V1 import Chatbot 132 | chatbot = Chatbot(config={ 133 | "access_token": "" 134 | }) 135 | prompt = "how many beaches does portugal have?" 136 | response = "" 137 | for data in chatbot.ask( 138 | prompt 139 | ): 140 | response = data["message"] 141 | print(response) 142 | ``` 143 | 144 | #### All API methods 145 | 146 | Refer to the [wiki](https://github.com/acheong08/ChatGPT/wiki/) for advanced developer usage. 147 | 148 |
149 | 150 |
151 | 152 | 153 | 154 | # V3 Official Chat API 155 | 156 | > Recently released by OpenAI 157 | > 158 | > - Paid 159 | 160 | 161 | 162 | Get API key from https://platform.openai.com/account/api-keys 163 | 164 | ## Command line 165 | 166 | `python3 -m revChatGPT.V3 --api_key ` 167 | 168 | ``` 169 | $ python3 -m revChatGPT.V3 170 | 171 | ChatGPT - Official ChatGPT API 172 | Repo: github.com/acheong08/ChatGPT 173 | Version: 6.2 174 | 175 | Type '!help' to show a full list of commands 176 | Press Esc followed by Enter or Alt+Enter to send a message. 177 | 178 | usage: V3.py [-h] --api_key API_KEY [--temperature TEMPERATURE] [--no_stream] 179 | [--base_prompt BASE_PROMPT] [--proxy PROXY] [--top_p TOP_P] 180 | [--reply_count REPLY_COUNT] [--enable_internet] [--config CONFIG] 181 | [--submit_key SUBMIT_KEY] 182 | [--model {gpt-3.5-turbo,gpt-3.5-turbo-16k,gpt-3.5-turbo-0301,gpt-3.5-turbo-0613,gpt-4,gpt-4-0314,gpt-4-32k,gpt-4-32k-0314,gpt-4-0613}] 183 | [--truncate_limit TRUNCATE_LIMIT] 184 | ``` 185 | 186 | ## Developer API 187 | 188 | ### Basic example 189 | 190 | ```python 191 | from revChatGPT.V3 import Chatbot 192 | chatbot = Chatbot(api_key="") 193 | chatbot.ask("Hello world") 194 | ``` 195 | 196 | ### Streaming example 197 | 198 | ```python 199 | from revChatGPT.V3 import Chatbot 200 | chatbot = Chatbot(api_key="") 201 | for data in chatbot.ask_stream("Hello world"): 202 | print(data, end="", flush=True) 203 | ``` 204 | 205 |
206 | 207 | # Awesome ChatGPT 208 | 209 | [My list](https://github.com/stars/acheong08/lists/awesome-chatgpt) 210 | 211 | If you have a cool project you want added to the list, open an issue. 212 | 213 | # Disclaimers 214 | 215 | 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. 216 | 217 | ## Contributors 218 | 219 | This project exists thanks to all the people who contribute. 220 | 221 | 222 | 223 | 224 | 225 | ## Additional credits 226 | 227 | - Coding while listening to [this amazing song](https://www.youtube.com/watch?v=VaMR_xDhsGg) by [virtualharby](https://www.youtube.com/@virtualharby) 228 | -------------------------------------------------------------------------------- /docs/README_ja.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | [English](./README.md) - [中文](./README_zh.md) - [Spanish](./README_sp.md) - 日本語 4 | 5 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 6 | [![Support_Platform](https://img.shields.io/pypi/pyversions/revChatGPT)](https://pypi.python.org/pypi/revChatGPT) 7 | [![Downloads](https://static.pepy.tech/badge/revchatgpt)](https://pypi.python.org/pypi/revChatGPT) 8 | 9 | OpenAI による ChatGPT API をリバースエンジニアリング。チャットボットなどにも拡張可能。 10 | 11 | [![](https://github.com/acheong08/ChatGPT/blob/main/docs/view.gif?raw=true)](https://pypi.python.org/pypi/revChatGPT) 12 | 13 | > ## 私の仕事を応援してください 14 | > 15 | > プルリクエストを作成し、私の悪いコードを修正してください。 16 | > 17 | > [![support](https://ko-fi.com/img/githubbutton_sm.svg)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) 18 | 19 | > #### Discord サーバー: https://discord.gg/9K2BvbXEHT 20 | 21 | # インストール 22 | 23 | ``` 24 | python -m pip install --upgrade revChatGPT 25 | ``` 26 | 27 | ### サポート Python バージョン 28 | 29 | - 最小 - Python3.9 30 | - 推奨 - Python3.11+ 31 | 32 |
33 | 34 | 35 | 36 | # V1 スタンダード ChatGPT 37 | 38 | OpenAI のセキュリティ強化のため、デフォルトのエンドポイントは @pengzhile が提供するものに変更になりました。これはオープンソースではなく、プライバシーは保証されていません。自己責任で使ってください。私は、最新の変更を加えたオープンソースの実装に取り組んでいますが、しばらく時間がかかるかもしれません。 39 | 40 | 41 | 42 | ## レート制限 43 | - プロキシサーバー: 5 リクエスト / 10 秒 44 | - OpenAI: アカウントごとに 50 リクエスト/時間 45 | 46 | ## 構成 47 | 48 | 1. [OpenAI の ChatGPT](https://chat.openai.com/) でアカウントを作成 49 | 2. メールアドレスとパスワードを保存 50 | 51 | ### 認証方法: (1つを選択) 52 | 53 | #### - メールアドレス/パスワード 54 | 55 | > _現在、無料ユーザーでは壊れています。プラスアカウントをお持ちの方は、`export PUID="..."` を実行してください。PUID は `_puid` という名前のクッキーです_ 56 | > Google/Microsoft のアカウントには対応していません。 57 | ```json 58 | { 59 | "email": "email", 60 | "password": "your password" 61 | } 62 | ``` 63 | 64 | #### - アクセストークン 65 | 66 | > これでお願いします! 67 | https://chat.openai.com/api/auth/session 68 | 69 | ```json 70 | { 71 | "access_token": "" 72 | } 73 | ``` 74 | 75 | #### - オプションの構成: 76 | 77 | ```json 78 | { 79 | "conversation_id": "UUID...", 80 | "parent_id": "UUID...", 81 | "proxy": "...", 82 | "paid": false, 83 | "collect_analytics": true, 84 | "model": "gpt-4" 85 | } 86 | ``` 87 | 88 | Analytics はデフォルトで無効になっています。有効にするには `collect_analytics` を `true` に設定します。 89 | 90 | 3. これを `$HOME/.config/revChatGPT/config.json` として保存します 91 | 4. Windows を使用している場合、スクリプトが config.json ファイルを見つけることができるように、`HOME` という環境変数を作成し、あなたのホームプロファイルに設定する必要があります。 92 | 93 | ## 使用法 94 | 95 | ### コマンドライン 96 | 97 | `python3 -m revChatGPT.V1` 98 | 99 | ``` 100 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 101 | Repo: github.com/acheong08/ChatGPT 102 | Type '!help' to show a full list of commands 103 | Logging in... 104 | You: 105 | (Press Esc followed by Enter to finish) 106 | ``` 107 | 108 | コマンドラインインターフェイスは、複数行の入力をサポートし、矢印キーによるナビゲーションが可能です。また、プロンプトが空の場合、矢印キーで履歴入力を編集することができます。また、前のプロンプトと一致するものがあれば、入力を完了させることができます。入力を終了するには、`Esc` を押してから `Enter` を押します。`Enter` 自体は、複数行モードでは新しい行を作るために使われます。 109 | 110 | 環境変数 `NO_COLOR` に `true` を設定すると、カラー出力を無効にすることができます。 111 | 112 | ### 開発者 API 113 | 114 | #### 基本的な例 (ストリーミング): 115 | 116 | ```python 117 | from revChatGPT.V1 import Chatbot 118 | chatbot = Chatbot(config={ 119 | "access_token": "" 120 | }) 121 | print("Chatbot: ") 122 | prev_text = "" 123 | for data in chatbot.ask( 124 | "Hello world", 125 | ): 126 | message = data["message"][len(prev_text) :] 127 | print(message, end="", flush=True) 128 | prev_text = data["message"] 129 | print() 130 | ``` 131 | 132 | #### 基本的な例 (単一の結果): 133 | 134 | ```python 135 | from revChatGPT.V1 import Chatbot 136 | chatbot = Chatbot(config={ 137 | "access_token": "" 138 | }) 139 | prompt = "how many beaches does portugal have?" 140 | response = "" 141 | for data in chatbot.ask( 142 | prompt 143 | ): 144 | response = data["message"] 145 | print(response) 146 | ``` 147 | 148 | #### すべての API メソッド 149 | 150 | 高度な開発者の使い方については、[wiki](https://github.com/acheong08/ChatGPT/wiki/) を参照してください。 151 | 152 |
153 | 154 | 155 | 156 | # V3 公式 Chat API 157 | 158 | > OpenAI によって最近リリース 159 | > 160 | > - 有料 161 | 162 | 163 | 164 | https://platform.openai.com/account/api-keys から API キーを取得する 165 | 166 | ## コマンドライン 167 | 168 | `python3 -m revChatGPT.V3 --api_key ` 169 | 170 | ``` 171 | $ python3 -m revChatGPT.V3 --help 172 | 173 | ChatGPT - Official ChatGPT API 174 | Repo: github.com/acheong08/ChatGPT 175 | 176 | Type '!help' to show a full list of commands 177 | Press Esc followed by Enter or Alt+Enter to send a message. 178 | 179 | usage: V3.py [-h] --api_key API_KEY [--temperature TEMPERATURE] [--no_stream] [--base_prompt BASE_PROMPT] 180 | [--proxy PROXY] [--top_p TOP_P] [--reply_count REPLY_COUNT] [--enable_internet] 181 | [--config CONFIG] [--submit_key SUBMIT_KEY] [--model {gpt-3.5-turbo,gpt-4,gpt-4-32k}] 182 | [--truncate_limit TRUNCATE_LIMIT] 183 | 184 | options: 185 | -h, --help show this help message and exit 186 | --api_key API_KEY OpenAI API key 187 | --temperature TEMPERATURE 188 | Temperature for response 189 | --no_stream Disable streaming 190 | --base_prompt BASE_PROMPT 191 | Base prompt for chatbot 192 | --proxy PROXY Proxy address 193 | --top_p TOP_P Top p for response 194 | --reply_count REPLY_COUNT 195 | Number of replies for each prompt 196 | --enable_internet Allow ChatGPT to search the internet 197 | --config CONFIG Path to V3 config json file 198 | --submit_key SUBMIT_KEY 199 | Custom submit key for chatbot. For more information on keys, see README 200 | --model {gpt-3.5-turbo,gpt-4,gpt-4-32k} 201 | --truncate_limit TRUNCATE_LIMIT 202 | ``` 203 | 204 | ## 開発者 API 205 | 206 | ### 基本的な例 207 | 208 | ```python 209 | from revChatGPT.V3 import Chatbot 210 | chatbot = Chatbot(api_key="") 211 | chatbot.ask("Hello world") 212 | ``` 213 | 214 | ### ストリーミングの例 215 | 216 | ```python 217 | from revChatGPT.V3 import Chatbot 218 | chatbot = Chatbot(api_key="") 219 | for data in chatbot.ask_stream("Hello world"): 220 | print(data, end="", flush=True) 221 | ``` 222 | 223 | 224 | 225 | # Awesome ChatGPT 226 | 227 | [私のリスト](https://github.com/stars/acheong08/lists/awesome-chatgpt) 228 | 229 | リストに追加してほしいクールなプロジェクトがある場合は、issue を開いてください。 230 | 231 | # 免責事項 232 | 233 | 本製品は OpenAI の公式製品ではありません。これは個人的なプロジェクトであり、OpenAI とは一切関係がありません。私を訴えないでください。 234 | 235 | ## コントリビューター 236 | 237 | このプロジェクトが存在するのは、コントリビュートしてくださるすべての方々のおかげです。 238 | 239 | 240 | 241 | 242 | 243 | ## 追加クレジット 244 | 245 | - [virtualharby](https://www.youtube.com/@virtualharby) の[この素晴らしい歌](https://www.youtube.com/watch?v=VaMR_xDhsGg)を聴きながらコーディングする 246 | -------------------------------------------------------------------------------- /docs/README_ko.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | English - [中文](./README_zh.md) - [Spanish](./README_sp.md) - [日本語](./README_ja.md) - [한국어](./README_ko.md) 4 | 5 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 6 | [![Support_Platform](https://img.shields.io/pypi/pyversions/revChatGPT)](https://pypi.python.org/pypi/revChatGPT) 7 | [![Downloads](https://static.pepy.tech/badge/revchatgpt)](https://pypi.python.org/pypi/revChatGPT) 8 | 9 | OpenAI가 개발한 ChatGPT API를 Reverse-Engineering한 프로젝트입니다. 본 프로젝트를 통해 챗봇 등의 확장 가능한 목적으로 사용할 수 있습니다. 10 | 11 | [![](https://github.com/acheong08/ChatGPT/blob/main/docs/view.gif?raw=true)](https://pypi.python.org/pypi/revChatGPT) 12 | 13 | # 설치 14 | 15 | ``` 16 | python -m pip install --upgrade revChatGPT 17 | ``` 18 | 19 | ### 지원 가능한 파이썬 버전 20 | 21 | - Minimum - Python3.9 22 | - Recommend - Python3.11+ 23 | 24 |
25 | 26 | 27 | 28 | # V1 Standard ChatGPT 29 | 30 | V1은 모두에게 편리한 사용을 위해 클라우드플레어 우회 프록시를 사용합니다. 이 프록시는 오픈 소스로 제공됩니다: https://github.com/acheong08/ChatGPT-Proxy-V4 31 | 32 | 자체 배포한 프록시를 설정하려면 환경 변수 CHATGPT_BASE_URL을 https://yourproxy.com/api/로 설정하십시오. 33 | 34 | 35 | 36 | ## Rate limits 37 | - Proxy server: 5 requests / 10 seconds 38 | - OpenAI: 50 requests / hour for each account 39 | 40 | ## Configuration 41 | 42 | 1. Create account on [OpenAI's ChatGPT](https://chat.openai.com/) 43 | 2. Save your email and password 44 | 45 | ### Authentication method: (Choose 1) 46 | 47 | #### - Email/Password 48 | 49 | > Not supported for Google/Microsoft accounts. 50 | ```json 51 | { 52 | "email": "email", 53 | "password": "your password" 54 | } 55 | ``` 56 | 57 | #### - Access token 58 | https://chat.openai.com/api/auth/session 59 | 60 | ```json 61 | { 62 | "access_token": "" 63 | } 64 | ``` 65 | 66 | #### - Optional configuration: 67 | 68 | ```json 69 | { 70 | "conversation_id": "UUID...", 71 | "parent_id": "UUID...", 72 | "proxy": "...", 73 | "model": "gpt-4", // gpt-4-browsing, text-davinci-002-render-sha, gpt-4, gpt-4-plugins 74 | "plugin_ids" : ["plugin-d1d6eb04-3375-40aa-940a-c2fc57ce0f51"], // Wolfram Alpha example 75 | "disable_history": true, 76 | } 77 | ``` 78 | 79 | 1. 위 내용을 $HOME/.config/revChatGPT/config.json로 저장하세요. 80 | 2. Windows를 사용하는 경우, 스크립트가 config.json 파일을 찾을 수 있도록 환경 변수인 HOME을 생성하고 홈 프로필로 설정하셔야 합니다. 81 | 82 | Plugin IDs는 다음 [링크](./plugins.json)를 참조하세요. 만약 플러그인이 활성화되어 있다면, 모델을 gpt-4-plugins로 설정하세요. 웹 인터페이스에서 플러그인을 설치하지 않은 경우 플러그인이 작동할 수도 있고 작동하지 않을 수도 있습니다. 코드에서 chatbot.install_plugin(plugin_id=plugin_id)를 호출하여 플러그인 중 하나를 설치할 수 있습니다. chatbot.get_plugins()를 호출하여 사용 가능한 모든 플러그인 목록을 확인하실 수 있습니다. 83 | 84 | ## Usage 85 | 86 | ### Command line 87 | 88 | `python3 -m revChatGPT.V1` 89 | 90 | ``` 91 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 92 | Repo: github.com/acheong08/ChatGPT 93 | Type '!help' to show a full list of commands 94 | Logging in... 95 | You: 96 | (Press Esc followed by Enter to finish) 97 | ``` 98 | 99 | Command line 인터페이스는 여러 줄의 입력을 지원하며, 화살표 키를 사용하여 탐색할 수 있습니다. 또한, 프롬프트가 비어있을 때 화살표 키를 사용하여 이전 입력을 편집할 수도 있습니다. 이전 프롬프트와 일치하는 내용을 찾으면 입력을 자동 완성하며, 입력을 완료하려면 Esc를 누른 다음에 Enter를 누르세요. Enter키만 누르면 여러 줄 모드에서 새 줄을 생성합니다. 100 | 101 | 컬러 출력을 비활성화하려면 환경 변수 NO_COLOR를 true로 설정하세요. 102 | 103 | ### Developer API 104 | 105 | #### Basic example (streamed): 106 | 107 | ```python 108 | from revChatGPT.V1 import Chatbot 109 | chatbot = Chatbot(config={ 110 | "access_token": "" 111 | }) 112 | print("Chatbot: ") 113 | prev_text = "" 114 | for data in chatbot.ask( 115 | "Hello world", 116 | ): 117 | message = data["message"][len(prev_text) :] 118 | print(message, end="", flush=True) 119 | prev_text = data["message"] 120 | print() 121 | ``` 122 | 123 | #### Basic example (single result): 124 | 125 | ```python 126 | from revChatGPT.V1 import Chatbot 127 | chatbot = Chatbot(config={ 128 | "access_token": "" 129 | }) 130 | prompt = "how many beaches does portugal have?" 131 | response = "" 132 | for data in chatbot.ask( 133 | prompt 134 | ): 135 | response = data["message"] 136 | print(response) 137 | ``` 138 | 139 | #### All API methods 140 | 141 | Refer to the [wiki](https://github.com/acheong08/ChatGPT/wiki/) for advanced developer usage. 142 | 143 |
144 | 145 |
146 | 147 | 148 | 149 | # V3 Official Chat API 150 | 151 | > Recently released by OpenAI 152 | > 153 | > - Paid 154 | 155 | 156 | 157 | Get API key from https://platform.openai.com/account/api-keys 158 | 159 | ## Command line 160 | 161 | `python3 -m revChatGPT.V3 --api_key ` 162 | 163 | ``` 164 | $ python3 -m revChatGPT.V3 --help 165 | 166 | ChatGPT - Official ChatGPT API 167 | Repo: github.com/acheong08/ChatGPT 168 | 169 | Type '!help' to show a full list of commands 170 | Press Esc followed by Enter or Alt+Enter to send a message. 171 | 172 | usage: V3.py [-h] --api_key API_KEY [--temperature TEMPERATURE] [--no_stream] [--base_prompt BASE_PROMPT] 173 | [--proxy PROXY] [--top_p TOP_P] [--reply_count REPLY_COUNT] [--enable_internet] 174 | [--config CONFIG] [--submit_key SUBMIT_KEY] [--model {gpt-3.5-turbo,gpt-4,gpt-4-32k}] 175 | [--truncate_limit TRUNCATE_LIMIT] 176 | 177 | options: 178 | -h, --help show this help message and exit 179 | --api_key API_KEY OpenAI API key 180 | --temperature TEMPERATURE 181 | Temperature for response 182 | --no_stream Disable streaming 183 | --base_prompt BASE_PROMPT 184 | Base prompt for chatbot 185 | --proxy PROXY Proxy address 186 | --top_p TOP_P Top p for response 187 | --reply_count REPLY_COUNT 188 | Number of replies for each prompt 189 | --enable_internet Allow ChatGPT to search the internet 190 | --config CONFIG Path to V3 config json file 191 | --submit_key SUBMIT_KEY 192 | Custom submit key for chatbot. For more information on keys, see README 193 | --model {gpt-3.5-turbo,gpt-4,gpt-4-32k} 194 | --truncate_limit TRUNCATE_LIMIT 195 | ``` 196 | 197 | ## Developer API 198 | 199 | ### Basic example 200 | 201 | ```python 202 | from revChatGPT.V3 import Chatbot 203 | chatbot = Chatbot(api_key="") 204 | chatbot.ask("Hello world") 205 | ``` 206 | 207 | ### Streaming example 208 | 209 | ```python 210 | from revChatGPT.V3 import Chatbot 211 | chatbot = Chatbot(api_key="") 212 | for data in chatbot.ask_stream("Hello world"): 213 | print(data, end="", flush=True) 214 | ``` 215 | 216 |
217 | 218 | # Awesome ChatGPT 219 | 220 | [My list](https://github.com/stars/acheong08/lists/awesome-chatgpt) 221 | 222 | 만약 추가하고 싶은 멋진 프로젝트가 있다면, 이슈를 생성해주세요. 223 | 224 | # Disclaimers 225 | 226 | 이것은 공식적인 OpenAI Product가 아니며, 개인 프로젝트로 OpenAI와 어떠한 관련도 없습니다. 본 코드의 사용으로 인한 어떠한 책임도 지지 않습니다. 227 | 228 | ## Contributors 229 | 230 | 이 프로젝트는 기여해 주신 모든 분들에게 감사드립니다. 231 | 232 | 233 | 234 | 235 | 236 | ## Additional credits 237 | 238 | - Coding while listening to [this amazing song](https://www.youtube.com/watch?v=VaMR_xDhsGg) by [virtualharby](https://www.youtube.com/@virtualharby) 239 | -------------------------------------------------------------------------------- /docs/README_sp.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | [English](./README.md) - [中文](./README_zh.md) - Spanish - [日本語](./README_ja.md) 4 | 5 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 6 | [![Plataforma_de_Soporte](https://img.shields.io/pypi/pyversions/revChatGPT)](https://pypi.python.org/pypi/revChatGPT) 7 | [![Descargas](https://static.pepy.tech/badge/revchatgpt)](https://pypi.python.org/pypi/revChatGPT) 8 | 9 | API de ingeniería reversa para ChatGPT de OpenAI. Extensible para chatbots y más. 10 | 11 | [![](https://github.com/acheong08/ChatGPT/blob/main/docs/view.gif?raw=true)](https://pypi.python.org/pypi/revChatGPT) 12 | 13 | > ## Apoya mi trabajo 14 | > 15 | > Puedes colaborar con Pull Requests corrigiendo mi código imperfecto. 16 | > 17 | > [![Apoyo](https://ko-fi.com/img/githubbutton_sm.svg)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) 18 | 19 | > #### Servidor de Discord: https://discord.gg/9K2BvbXEHT 20 | 21 | # Instalación 22 | 23 | ``` 24 | python -m pip install --upgrade revChatGPT 25 | ``` 26 | 27 | ### Soporte para versiones de Python 28 | 29 | - Mínimo - Python3.9 30 | - Recomendado - Python3.11+ 31 | 32 |
33 | 34 | 35 | 36 | # V1 (ChatGPT Estándar) 37 | 38 | Debido al reciente endurecimiento de la seguridad de OpenAI, el endpoint predeterminado de este API se ha cambiado a uno proporcionado por @pengzhile. No es de código abierto y la privacidad no está garantizada. Úsalo bajo tu propio riesgo. Estoy trabajando en una implementación de código abierto con los últimos cambios, pero eso podría llevar un tiempo. 39 | 40 | 41 | 42 | ## Límites de peticiones 43 | - Servidor Proxy: 5 peticiones por cada 10 segundos 44 | - OpenAI: 50 peticiones por hora para cada cuenta 45 | 46 | ## Configuración 47 | 48 | 1. Crear Cuenta en [OpenAI's ChatGPT](https://chat.openai.com/) 49 | 2. Guarde su correo electrónico y contraseña 50 | 51 | ### Método de autentificación: (Choose 1) 52 | 53 | #### - Email / Contraseña de 54 | 55 | > _Actualmente no funciona para usuarios gratuitos de ChatGPT. Ejecuta `export PUID="..."` en el terminal si tienes una cuenta Plus. El PUID es un cookie de navegador llamado `_puid`_ 56 | > No está disponible para cuentas con login por Google/Microsoft. 57 | ```json 58 | { 59 | "email": "email", 60 | "password": "tu contraseña" 61 | } 62 | ``` 63 | 64 | #### - Token de Acceso 65 | 66 | > por favor lee esto primero! 67 | https://chat.openai.com/api/auth/session 68 | 69 | ```json 70 | { 71 | "access_token": "" 72 | } 73 | ``` 74 | 75 | #### - Configuración Opcional: 76 | 77 | ```json 78 | { 79 | "conversation_id": "UUID...", 80 | "parent_id": "UUID...", 81 | "proxy": "...", 82 | "paid": false, 83 | "collect_analytics": true, 84 | "model": "gpt-4" 85 | } 86 | ``` 87 | 88 | La recolección de datos para análisis de OpenAI está deshabilitada de forma predeterminada. Establezca `collect_analytics` en `true` para habilitarlo. 89 | 90 | 3. Guardar esto en un archivo json en `$HOME/.config/revChatGPT/config.json` 91 | 4. Si está utilizando Windows, deberá crear una variable de entorno llamada `HOME` y establecerla en su perfil de inicio para que el script pueda ubicar el archivo config.json. 92 | 93 | ## Uso 94 | 95 | ### Línea de comando 96 | 97 | `python3 -m revChatGPT.V1` 98 | 99 | ``` 100 | ChatGPT - Una interfaz de línea de comandos para ChatGPT de OpenAI (https://chat.openai.com/chat) 101 | Repo: github.com/acheong08/ChatGPT 102 | Escribe '!help' para mostrar una lista completa de comandos 103 | Logging in... 104 | You: 105 | (Presiona Esc seguido de Enter para terminar) 106 | ``` 107 | 108 | La interfaz de línea de comandos admite entradas multilinea y permite la navegación con las flechas del teclado. Además, también puede autocompletar la entrada si encuentra Prompts similares en el historial. Para finalizar presione `Esc` y luego `Enter` ya que únicamente `Enter` se usa para crear una nueva línea en el modo multilínea. 109 | 110 | Establezca la variable de entorno `NO_COLOR` a `true` para deshabilitar el texto colorido. 111 | 112 | ### API de desarrollador 113 | 114 | 115 | #### Ejemplo básico (streamed): 116 | 117 | ```python 118 | from revChatGPT.V1 import Chatbot 119 | chatbot = Chatbot(config={ 120 | "access_token": "" 121 | }) 122 | print("Chatbot: ") 123 | prev_text = "" 124 | for data in chatbot.ask( 125 | "Hello world", 126 | ): 127 | message = data["message"][len(prev_text) :] 128 | print(message, end="", flush=True) 129 | prev_text = data["message"] 130 | print() 131 | ``` 132 | 133 | #### Ejemplo básico (resultado único): 134 | 135 | ```python 136 | from revChatGPT.V1 import Chatbot 137 | chatbot = Chatbot(config={ 138 | "access_token": "" 139 | }) 140 | prompt = "how many beaches does portugal have?" 141 | response = "" 142 | for data in chatbot.ask( 143 | prompt 144 | ): 145 | response = data["message"] 146 | print(response) 147 | ``` 148 | 149 | #### Todos los métodos de la API 150 | 151 | Referirse a [wiki](https://github.com/acheong08/ChatGPT/wiki/) for advanced developer usage. 152 | 153 |
154 | 155 | 156 | 157 | # API oficial V3 (Chat API) 158 | 159 | > Lanzado recientemente por OpenAI 160 | > 161 | > - De pago 162 | 163 | 164 | 165 | Obtén clave API de https://platform.openai.com/account/api-keys 166 | 167 | ## Línea de comando 168 | 169 | `python3 -m revChatGPT.V3 --api_key ` 170 | 171 | ``` 172 | $ python3 -m revChatGPT.V3 --help 173 | 174 | ChatGPT - Official ChatGPT API 175 | Repo: github.com/acheong08/ChatGPT 176 | 177 | Escriba '!help' para mostrar una lista completa de comandos 178 | Presione Esc seguido de Enter o Alt+Enter para enviar un mensaje. 179 | 180 | usage: V3.py [-h] --api_key API_KEY [--temperature TEMPERATURE] [--no_stream] [--base_prompt BASE_PROMPT] 181 | [--proxy PROXY] [--top_p TOP_P] [--reply_count REPLY_COUNT] [--enable_internet] 182 | [--config CONFIG] [--submit_key SUBMIT_KEY] [--model {gpt-3.5-turbo,gpt-4,gpt-4-32k}] 183 | [--truncate_limit TRUNCATE_LIMIT] 184 | 185 | opciones: 186 | -h, --help mostrar este mensaje de ayuda y salir 187 | --api_key API_KEY Clave API de OpenAI 188 | --temperature TEMPERATURE 189 | Temperatura de respuesta 190 | --no_stream Deshabilitar transmisión 191 | --base_prompt BASE_PROMPT 192 | Indicación base para chatbot 193 | --proxy PROXY Dirección proxy 194 | --top_p TOP_P Top p para respuesta 195 | --reply_count REPLY_COUNT 196 | Número de respuestas para cada mensaje 197 | --enable_internet Permitir que ChatGPT busque en Internet 198 | --config CONFIG Ruta al archivo json de configuración V3 199 | --submit_key SUBMIT_KEY 200 | Clave de envío personalizada para chatbot. Para obtener más información sobre las claves, consulte LÉAME 201 | --model {gpt-3.5-turbo,gpt-4,gpt-4-32k} 202 | --truncate_limit TRUNCATE_LIMIT 203 | ``` 204 | 205 | ## API de desarrollador 206 | 207 | ### Ejemplo básico 208 | 209 | ```python 210 | from revChatGPT.V3 import Chatbot 211 | chatbot = Chatbot(api_key="") 212 | chatbot.ask("Hello world") 213 | ``` 214 | 215 | ### Ejemplo de transmisión 216 | 217 | ```python 218 | from revChatGPT.V3 import Chatbot 219 | chatbot = Chatbot(api_key="") 220 | for data in chatbot.ask_stream("Hello world"): 221 | print(data, end="", flush=True) 222 | ``` 223 | 224 | 225 | 226 | # Awesome ChatGPT 227 | 228 | [Más proyectos recomendados](https://github.com/stars/acheong08/lists/awesome-chatgpt) 229 | 230 | Si tienes un proyecto interesante que desearias agregar a la lista, agrega un Issue en este repositorio de Github. 231 | 232 | # Descargos de responsabilidad 233 | 234 | Este no es un producto oficial de OpenAI. Este es un proyecto personal y no está afiliado a OpenAI de ninguna manera. No me demandes. 235 | 236 | ## Colaboradores 237 | 238 | Este proyecto existe gracias a todas las personas que contribuyen. 239 | 240 | 241 | 242 | 243 | 244 | ## Créditos adicionales 245 | 246 | - Codificando mientras escuchas [esta increíble canción](https://www.youtube.com/watch?v=VaMR_xDhsGg) por [virtualharby](https://www.youtube.com/@virtualharby) 247 | -------------------------------------------------------------------------------- /docs/README_zh.md: -------------------------------------------------------------------------------- 1 | # ChatGPT 2 | 3 | [English](./README.md) - 中文 - [Spanish](./README_sp.md) - [日本語](./README_ja.md) 4 | 5 | [![PyPi](https://img.shields.io/pypi/v/revChatGPT.svg)](https://pypi.python.org/pypi/revChatGPT) 6 | [![支持的平台](https://img.shields.io/pypi/pyversions/revChatGPT)](https://pypi.python.org/pypi/revChatGPT) 7 | [![Downloads](https://static.pepy.tech/badge/revchatgpt)](https://pypi.python.org/pypi/revChatGPT) 8 | 9 | ChatGPT 的逆向工程可扩展 API,可用于聊天机器人等。 10 | 11 | [![](https://github.com/acheong08/ChatGPT/blob/main/docs/view.gif?raw=true)](https://pypi.python.org/pypi/revChatGPT) 12 | 13 | > ## 支持本项目 14 | > 开 Pull Request 并修复我的代码 15 | 16 | > #### Discord 服务器: https://discord.gg/9K2BvbXEHT 17 | 18 | # 安装 19 | 20 | ``` 21 | python -m pip install --upgrade revChatGPT 22 | ``` 23 | 24 | ### 支持的Python版本 25 | - 最低版本 - Python3.9 26 | - 推荐版本 - Python3.11+ 27 | 28 | 29 |
30 | 31 | 32 | 33 | # V1 标准 ChatGPT 34 | 35 | 通过对 `chat.openai.com` API 进行逆向工程,再[绕过Cloudflare Server](https://github.com/acheong08/ChatGPT-Proxy-V4),以免费使用 ChatGPT API。由于 OpenAI 严格的访问频率限制,此特定库仅供个人使用。尚未针对多帐户进行优化。 36 | 37 | 您也可以查看此[项目](https://github.com/acheong08/ChatGPT-to-API)用于搭建多账户循环调用系统,鉴于它与官方 API 兼容。使用 [OpenAI 的文档](https://platform.openai.com/docs/guides/chat) 作为使用参考。它在帐户之间进行对话,以确保在帐户数量过多的情况下不会达到速率限制。 38 | 39 | 40 | 41 | ## 速率限制 42 | - 代理服务器:5 请求/秒 43 | - OpenAI:60 请求/小时(每个账户) 44 | 45 | ## 配置 46 | 47 | 1. 在OpenAI的 [ChatGPT 网站](https://chat.openai.com/)创建账户 48 | 2. 记住你的邮箱地址与密码 49 | 50 | ### 身份验证方式: (任选其一) 51 | 52 | #### - 邮箱/密码 登录 53 | 不支持使用 Google/Microsoft 账号 授权登录的账户 54 | ```json 55 | { 56 | "email": "email", 57 | "password": "your password" 58 | } 59 | ``` 60 | 61 | #### - 访问令牌(Access Token)验证 62 | 63 | > 建议使用该方式验证! 64 | 65 | https://chat.openai.com/api/auth/session 66 | 67 | ```json 68 | { 69 | "access_token": "" 70 | } 71 | ``` 72 | 73 | #### - 可选配置内容: 74 | 75 | ```json 76 | { 77 | "conversation_id": "UUID...", 78 | "parent_id": "UUID...", 79 | "proxy": "...", 80 | "paid": false, 81 | "collect_analytics": true, 82 | "model": "gpt-4" 83 | } 84 | ``` 85 | 默认情况下,数据收集&分析处于禁用状态。将`collect_analytics`设置为`true`以启用它。 86 | 87 | 3. 另存为 `$HOME/.config/revChatGPT/config.json` 88 | 4. 如果您使用的是 Windows,则需要创建一个名为`HOME`的环境变量,并将其设置为您的主配置文件,以便脚本能够找到 config.json 文件。 89 | 90 | ## 使用方法 91 | 92 | ### 命令行程序 93 | 94 | ``` 95 | python3 -m revChatGPT.V1 96 | ``` 97 | 98 | ``` 99 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 100 | Repo: github.com/acheong08/ChatGPT 101 | 102 | Type '!help' to show a full list of commands 103 | 104 | Logging in... 105 | 106 | You: 107 | (Press Esc followed by Enter to finish) 108 | ``` 109 | 110 | 命令行界面支持多行输入,并允许使用箭头键进行导航。此外,您还可以在提示为空时通过箭头键编辑历史记录输入。如果找到匹配的先前提示,它也会完成您的输入。要完成输入,请按`Esc`,然后按`Enter`,因为仅`Enter`本身用于在多行模式下创建新行。 111 | 112 | 设置环境变量`NO_COLOR`为`true`可以禁用带色彩的命令行输出 113 | 114 | 115 | ### 开发人员的API 116 | 117 | #### 基础开发(命令行程序): 118 | ```python 119 | from revChatGPT.V1 import Chatbot 120 | 121 | chatbot = Chatbot(config={ 122 | "email": "", 123 | "password": "" 124 | }) 125 | 126 | print("Chatbot: ") 127 | prev_text = "" 128 | for data in chatbot.ask( 129 | "Hello world", 130 | ): 131 | message = data["message"][len(prev_text) :] 132 | print(message, end="", flush=True) 133 | prev_text = data["message"] 134 | print() 135 | ``` 136 | 137 | #### 基础示例 (对话流): 138 | 139 | ```python 140 | from revChatGPT.V1 import Chatbot 141 | 142 | chatbot = Chatbot(config={ 143 | "access_token": "" 144 | }) 145 | 146 | print("Chatbot: ") 147 | prev_text = "" 148 | for data in chatbot.ask( 149 | "Hello world", 150 | ): 151 | message = data["message"][len(prev_text) :] 152 | print(message, end="", flush=True) 153 | prev_text = data["message"] 154 | print() 155 | ``` 156 | 157 | #### 基础示例 (获取返回值): 158 | 159 | ```python 160 | from revChatGPT.V1 import Chatbot 161 | 162 | chatbot = Chatbot(config={ 163 | "access_token": "" 164 | }) 165 | 166 | prompt = "how many beaches does portugal have?" 167 | response = "" 168 | 169 | for data in chatbot.ask( 170 | prompt 171 | ): 172 | response = data["message"] 173 | 174 | print(response) 175 | ``` 176 | #### 所有的API方法 177 | 请移步 [wiki](https://github.com/acheong08/ChatGPT/wiki/) 以了解高级的开发者功能 178 | 179 |
180 | 181 | 182 |
183 | 184 | 185 | 186 | # V3 官方API 187 | > 最近由OpenAI发布 188 | > - 付费账户 189 | 190 | 191 | 192 | 从 https://platform.openai.com/account/api-keys 获取API-key 193 | 194 | ## 命令行程序 195 | ``` 196 | python3 -m revChatGPT.V3 --api_key 197 | ``` 198 | 199 | ``` 200 | $ python3 -m revChatGPT.V3 -h 201 | 202 | ChatGPT - Official ChatGPT API 203 | Repo: github.com/acheong08/ChatGPT 204 | 205 | Type '!help' to show a full list of commands 206 | Press Esc followed by Enter or Alt+Enter to send a message. 207 | 208 | usage: V3.py [-h] --api_key API_KEY [--temperature TEMPERATURE] [--no_stream] 209 | [--base_prompt BASE_PROMPT] [--proxy PROXY] [--top_p TOP_P] 210 | [--reply_count REPLY_COUNT] [--enable_internet] [--config CONFIG] 211 | [--submit_key SUBMIT_KEY] 212 | [--model {gpt-3.5-turbo,gpt-4,gpt-4-32k}] 213 | 214 | options: 215 | -h, --help show this help message and exit 216 | --api_key API_KEY OpenAI API key 217 | --temperature TEMPERATURE 218 | Temperature for response 219 | --no_stream Disable streaming 220 | --base_prompt BASE_PROMPT 221 | Base prompt for chatbot 222 | --proxy PROXY Proxy address 223 | --top_p TOP_P Top p for response 224 | --reply_count REPLY_COUNT 225 | Number of replies for each prompt 226 | --enable_internet Allow ChatGPT to search the internet 227 | --config CONFIG Path to V3 config json file 228 | --submit_key SUBMIT_KEY 229 | Custom submit key for chatbot. For more information on keys, see https://python-prompt-toolkit.readthedocs.io/en/stable/pages/advanced_topics/key_bindings.html#list-of-special-keys 230 | --model {gpt-3.5-turbo,gpt-4,gpt-4-32k} 231 | ``` 232 | 233 | ## 开发API 234 | 235 | ### 基础示例 236 | ```python 237 | from revChatGPT.V3 import Chatbot 238 | chatbot = Chatbot(api_key="") 239 | chatbot.ask("Hello world") 240 | ``` 241 | 242 | ### 命令行程序 243 | ```python 244 | from revChatGPT.V3 import Chatbot 245 | chatbot = Chatbot(api_key="") 246 | for data in chatbot.ask_stream("Hello world"): 247 | print(data, end="", flush=True) 248 | ``` 249 | 250 |
251 | 252 | # 贼好用的ChatGPT工具 253 | 254 | [我的列表](https://github.com/stars/acheong08/lists/awesome-chatgpt) 255 | 256 | 如果要将很酷的项目添加到列表中,请提出issue 257 | 258 | # 免责声明 259 | 260 | 这不是OpenAI官方的产品,这仅仅是我个人的项目,与OpenAI没有任何关系,不要以任何理由起诉我。 261 | 262 | 263 | ## 贡献 264 | 265 | 感谢所有为本项目做出贡献的开发者们 266 | 267 | 268 | 269 | 270 | 271 | ## 附加说明 272 | 273 | - 一边写代码一边听由 [virtualharby](https://www.youtube.com/@virtualharby) 写的[无与伦比的歌曲](https://www.youtube.com/watch?v=VaMR_xDhsGg) 274 | -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acheong08/ChatGPT/9167b325addc7d3520987face684e8230bd62b46/docs/view.gif -------------------------------------------------------------------------------- /docs/wiki/Authentication.md: -------------------------------------------------------------------------------- 1 | # Methods of authentication 2 | 3 | You cannot put multiple forms of authentication into a config at the same time 4 | 5 | ## Email/Password 6 | 7 | - Does not support Google and Microsoft login 8 | - Uses https://github.com/acheong08/OpenAIAuth to authenticate locally 9 | - Allows you to fetch a `session_token` 10 | 11 | ## Session token 12 | 13 | - This comes from the `__Secure-next-auth.session-token` cookie found on `chat.openai.com` 14 | - It allows you to get a `access_token` via `https://chat.openai.com/api/auth/session` 15 | - This is supported for all account types 16 | - Validity time is unknown 17 | 18 | ## Access token 19 | 20 | - This is what is actually used for authentication and can be found at `https://chat.openai.com/api/auth/session` 21 | - It is valid for 2 weeks 22 | - Recommended method of authentication 23 | - Can be found if you log in to `https://chat.openai.com/` and then go to `https://chat.openai.com/api/auth/session` 24 | -------------------------------------------------------------------------------- /docs/wiki/Code-examples.md: -------------------------------------------------------------------------------- 1 | ## Simple CLI ChatGPT python code 2 | 3 | ```python 4 | from revChatGPT.V1 import Chatbot 5 | 6 | chatbot = Chatbot(config={ 7 | "email": "email", 8 | "password": "your password" 9 | }) 10 | 11 | 12 | def start_chat(): 13 | print('Welcome to ChatGPT CLI') 14 | while True: 15 | prompt = input('> ') 16 | 17 | response = "" 18 | 19 | for data in chatbot.ask( 20 | prompt 21 | ): 22 | response = data["message"] 23 | 24 | print(response) 25 | 26 | 27 | if __name__ == "__main__": 28 | start_chat() 29 | ``` 30 | 31 | ## A GUI ChatGPT code with tkinter 32 | 33 | ```python 34 | import tkinter as tk 35 | from revChatGPT.V1 import Chatbot 36 | 37 | 38 | chatbot = Chatbot(config={ 39 | "email": "", 40 | "password": "" 41 | }) 42 | 43 | 44 | def respond(event): 45 | if event.state == 1: 46 | return 47 | 48 | prompt = textbox.get("1.0", 'end-1c') 49 | response = "" 50 | 51 | for data in chatbot.ask( 52 | prompt 53 | ): 54 | response = data["message"] 55 | textbox.delete("1.0", 'end-1c') 56 | history.insert(tk.INSERT, "User: " + prompt + "\n\nChatGPT: " + response + "\n\n\n") 57 | 58 | 59 | root = tk.Tk() 60 | root.title("Chat App") 61 | 62 | title = tk.Label(root, text="ChatGPT GUI", width=70, font=("Arial", 30, "bold")) 63 | title.pack() 64 | textbox = tk.Text(root, width=50, font=("Arial", 14), fg="white") 65 | 66 | history = tk.Text(root, width=110, font=("Arial", 12)) 67 | history.pack(padx=10, pady=10) 68 | 69 | textbox.pack(padx=10, pady=10) 70 | 71 | textbox.bind("", respond) 72 | 73 | root.configure(background="#292929") 74 | textbox.configure(background="#39433e") 75 | history.configure(background="#39433e", foreground="#F7C04A") 76 | title.configure(background="#292929", foreground="#FFFFFF") 77 | root.geometry("1100x700") 78 | root.mainloop() 79 | 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/wiki/Home.md: -------------------------------------------------------------------------------- 1 | Welcome to the ChatGPT wiki! 2 | 3 | ## Languages 4 | 5 | - English 6 | - [简体中文](https://github.com/CoolPlayLin/ChatGPT-Wiki/tree/master/docs/ChatGPT) 7 | -------------------------------------------------------------------------------- /docs/wiki/Recipient.md: -------------------------------------------------------------------------------- 1 | # Recipient Framework 2 | 3 | This module provides a framework for managing recipients. It defines three class `Recipient`, `RecipientManager` and `PythonRecipient`. It also defines a metaclass `RecipientMeta` for the `Recipient` class. 4 | 5 | `Recipient` is an abstract base class that defines the basic structure and methods for a recipient. It provides an interface for processing a message and an asynchronous processing method, along with a UUID generator for generating unique message IDs. 6 | 7 | `RecipientManager` is a class that manages a registry of recipients. It allows users to register and unregister recipients by name, and provides an interface for accessing and retrieving registered recipients. The class also provides a property for listing all available recipients, along with their descriptions. 8 | 9 | `PythonRecipient` is a class that provides an interface for processing Python code. It provides an asynchronous context manager for executing code in a separate thread, and an asynchronous processing method for processing messages. 10 | 11 | `RecipientMeta` is a metaclass for the `Recipient` class. It sets the `RECIPIENT_NAME` attribute of the class to the name of the class, if the attribute is not already set. 12 | 13 | ## Example usage 14 | 15 | More detail on the usage of the recipient framework can be found in the ./tests/test_recipient.py file. 16 | 17 | ### Defining a custom recipient 18 | 19 | ```python 20 | # Define a custom recipient by extending the Recipient base class 21 | class CustomRecipient(Recipient): 22 | def process(self, message: dict, **kwargs: dict) -> dict: 23 | # Custom message processing logic here 24 | return { 25 | "id": self._uuid(), 26 | "author": { 27 | "role": "tool", 28 | "name": self.RECIPIENT_NAME, 29 | }, 30 | "content": {"content_type": "text", "parts": ["success"]}, 31 | } 32 | async def aprocess(self, message: dict, **kwargs: dict) -> dict: 33 | raise NotImplementedError("Please call the process method instead.") 34 | 35 | # Create a recipient manager instance 36 | manager = RecipientManager() 37 | # Register the custom recipient with the manager using the __setitem__ method 38 | manager["custom"] = CustomRecipient() 39 | 40 | # Register the custom recipient with the manager using the @manager.register decorator 41 | @manager.register("another_custom") 42 | class AsyncCustomRecipient(CustomRecipient): 43 | async def aprocess(self, message: dict, **kwargs: dict) -> dict: 44 | # Custom asynchronous message processing logic here 45 | return { 46 | "id": self._uuid(), 47 | "author": { 48 | "role": "tool", 49 | "name": self.RECIPIENT_NAME, 50 | }, 51 | "content": {"content_type": "text", "parts": ["success"]}, 52 | } 53 | 54 | # Retrieve the custom recipient from the manager 55 | custom_recipient = manager["custom"] 56 | # Get a list of all available recipients 57 | available_recipients = manager.available_recipients 58 | ``` 59 | 60 | ### How to use 61 | 62 | ```python 63 | ... Assume that the cbt was configured correctly ... 64 | 65 | # Register the recipient 66 | cbt.recipients["python"] = PythonRecipient 67 | # To get the recipient instance 68 | python = cbt.recipients["python"]() 69 | 70 | # Create API Docs 71 | api_docs = f""" 72 | 73 | Knowledge cutoff: 2021-09 74 | Current date: {datetime.datetime.now().strftime("%Y-%m-%d")} 75 | 76 | ###Available Tools: 77 | python 78 | 79 | {python.API_DOCS} 80 | """ 81 | # To notify the assistant that the recipient is ready 82 | for _ in cbt.ask("You are ChatGPT." + api_docs): 83 | pass 84 | result = {} 85 | 86 | # Now, ask GPT to calculate 27! + 8! by using the python recipient 87 | for _ in cbt.ask("Please calculate 27! + 8! by using python."): 88 | result = _ 89 | 90 | times = 0 91 | # "end_turn" is a flag that indicates whether the GPT has finished the work. 92 | # If the flag is False, it means that the GPT needs to use the recipient to help it. 93 | # If the flag is True, it means that the GPT has finished the work. 94 | while not result.get("end_turn", True): 95 | times += 1 96 | # Get the name of the recipient 97 | recipient_name = result["recipient"] 98 | # To avoid the endless loop. 99 | if times >= 3: 100 | break 101 | 102 | # This process could be managed by a class, but I don't finish it yet. 103 | if recipient_name == "python": 104 | # To get the result of executing the code 105 | msg = asyncio.get_event_loop().run_until_complete( 106 | python.aprocess(message=result.copy()) 107 | ) 108 | 109 | # To send the result to the GPT 110 | for _ in cbt.post_messages([msg]): 111 | result = _ 112 | 113 | # Now the GPT has finished the work. 114 | print(result['message']) 115 | # The GPT will calculate 27! + 8! correctly. 116 | ``` 117 | 118 | ## RecipientMeta 119 | 120 | A metaclass for the `Recipient` class. It sets the `RECIPIENT_NAME` attribute of the class to the name of the class, if the attribute is not already set. 121 | 122 | ### Methods 123 | 124 | - `__new__(mcs, name, bases, namespace, /, **kwargs)` 125 | 126 | ## Recipient 127 | 128 | The base class for recipients. 129 | 130 | ### Attributes 131 | 132 | - `DESCRIPTION : str` : A description of the recipient for humans. 133 | - `API_DOCS : str` : Documentation of the recipient for machines. 134 | - `REQUIRED_ARGS : list` : A list of required parameters. 135 | - `EXAMPLE_MESSAGES : list` : A list of example messages. 136 | - `RECIPIENT_NAME : str` : The name of the recipient. Defaults to the class name. 137 | 138 | ### Methods 139 | 140 | - `process(message: dict, **kwargs: dict) -> dict` : Process a message. 141 | - `aprocess(message: dict, **kwargs: dict) -> dict` : Asynchronously process a message. 142 | 143 | ## RecipientManager 144 | 145 | A class for managing recipients. 146 | 147 | ### Methods 148 | 149 | - `register(name: str) -> Callable[[Type[Recipient]], Type[Recipient]]` : Decorator for registering a recipient to the manager. 150 | - `__getitem__(name: str) -> Type[Recipient]` : Get a recipient from the manager. 151 | - `__setitem__(name: str, recipient_class: Type[Recipient])` : Register a recipient to the manager. 152 | - `__delitem__(name: str)` : Unregister a recipient from the manager. 153 | 154 | ### Properties 155 | 156 | - `available_recipients : dict[str, str]` : A dictionary containing the available recipients. 157 | 158 | ## PythonRecipient 159 | 160 | A class for processing Python code. 161 | 162 | ### Attributes 163 | 164 | - `DESCRIPTION : str` : A description of the Python recipient for humans. 165 | - `API_DOCS : str` : Documentation of the Python recipient for machines. 166 | - `RECIPIENT_NAME : str` : The name of the Python recipient. 167 | 168 | ### Methods 169 | 170 | - `process(message: dict, **kwargs: dict) -> dict` : Not implemented. PythonRecipient is asynchronous only. 171 | - `aprocess(message: dict, **kwargs: dict) -> dict` : Asynchronously process a message. It will execute the code in the `message` in Tio. 172 | - `_uuid() -> str` : Generate a UUID. 173 | - `__aenter__() -> PythonRecipient` : Enter the PythonRecipient async context manager. 174 | - `__aexit__(exc_type, exc_val, exc_tb) -> None` : Exit the PythonRecipient async context manager. 175 | -------------------------------------------------------------------------------- /docs/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) 4 | -------------------------------------------------------------------------------- /docs/wiki/V1.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # revChatGPT.V1 4 | 5 | Standard ChatGPT 6 | 7 | 8 | 9 | #### generate\_random\_hex 10 | 11 | ```python 12 | def generate_random_hex(length: int = 17) -> str 13 | ``` 14 | 15 | Generate a random hex string 16 | 17 | **Arguments**: 18 | 19 | - `length` _int, optional_ - Length of the hex string. Defaults to 17. 20 | 21 | 22 | **Returns**: 23 | 24 | - `str` - Random hex string 25 | 26 | 27 | 28 | #### random\_int 29 | 30 | ```python 31 | def random_int(min: int, max: int) -> int 32 | ``` 33 | 34 | Generate a random integer 35 | 36 | **Arguments**: 37 | 38 | - `min` _int_ - Minimum value 39 | - `max` _int_ - Maximum value 40 | 41 | 42 | **Returns**: 43 | 44 | - `int` - Random integer 45 | 46 | 47 | 48 | #### logger 49 | 50 | ```python 51 | def logger(is_timed: bool) 52 | ``` 53 | 54 | Logger decorator 55 | 56 | **Arguments**: 57 | 58 | - `is_timed` _bool_ - Whether to include function running time in exit log 59 | 60 | 61 | **Returns**: 62 | 63 | - `_type_` - decorated function 64 | 65 | 66 | 67 | #### get\_arkose\_token 68 | 69 | ```python 70 | def get_arkose_token(download_images: bool = True, 71 | solver: function = captcha_solver) -> str 72 | ``` 73 | 74 | The solver function should take in a list of images in base64 and a dict of challenge details 75 | and return the index of the image that matches the challenge details 76 | 77 | Challenge details: 78 | game_type: str - Audio or Image 79 | instructions: str - Instructions for the captcha 80 | URLs: list[str] - URLs of the images or audio files 81 | 82 | 83 | 84 | ## Chatbot Objects 85 | 86 | ```python 87 | class Chatbot() 88 | ``` 89 | 90 | Chatbot class for ChatGPT 91 | 92 | 93 | 94 | #### \_\_init\_\_ 95 | 96 | ```python 97 | @logger(is_timed=True) 98 | def __init__(config: dict[str, str], 99 | conversation_id: str | None = None, 100 | parent_id: str | None = None, 101 | lazy_loading: bool = True, 102 | base_url: str | None = None, 103 | captcha_solver: function = captcha_solver, 104 | captcha_download_images: bool = True) -> None 105 | ``` 106 | 107 | Initialize a chatbot 108 | 109 | **Arguments**: 110 | 111 | - `config` _dict[str, str]_ - Login and proxy info. Example: 112 | { 113 | - `"access_token"` - "" 114 | - `"proxy"` - "", 115 | - `"model"` - "", 116 | - `"plugin"` - "", 117 | } 118 | More details on these are available at https://github.com/acheong08/ChatGPT#configuration 119 | - `conversation_id` _str | None, optional_ - Id of the conversation to continue on. Defaults to None. 120 | - `parent_id` _str | None, optional_ - Id of the previous response message to continue on. Defaults to None. 121 | - `lazy_loading` _bool, optional_ - Whether to load only the active conversation. Defaults to True. 122 | - `base_url` _str | None, optional_ - Base URL of the ChatGPT server. Defaults to None. 123 | - `captcha_solver` _function, optional_ - Function to solve captcha. Defaults to captcha_solver. 124 | - `captcha_download_images` _bool, optional_ - Whether to download captcha images. Defaults to True. 125 | 126 | 127 | **Raises**: 128 | 129 | - `Exception` - _description_ 130 | 131 | 132 | 133 | #### set\_access\_token 134 | 135 | ```python 136 | @logger(is_timed=False) 137 | def set_access_token(access_token: str) -> None 138 | ``` 139 | 140 | Set access token in request header and self.config, then cache it to file. 141 | 142 | **Arguments**: 143 | 144 | - `access_token` _str_ - access_token 145 | 146 | 147 | 148 | #### login 149 | 150 | ```python 151 | @logger(is_timed=True) 152 | def login() -> None 153 | ``` 154 | 155 | Login to OpenAI by email and password 156 | 157 | 158 | 159 | #### post\_messages 160 | 161 | ```python 162 | @logger(is_timed=True) 163 | def post_messages(messages: list[dict], 164 | conversation_id: str | None = None, 165 | parent_id: str | None = None, 166 | plugin_ids: list = [], 167 | model: str | None = None, 168 | auto_continue: bool = False, 169 | timeout: float = 360, 170 | **kwargs) -> Generator[dict, None, None] 171 | ``` 172 | 173 | Ask a question to the chatbot 174 | 175 | **Arguments**: 176 | 177 | - `messages` _list[dict]_ - The messages to send 178 | - `conversation_id` _str | None, optional_ - UUID for the conversation to continue on. Defaults to None. 179 | - `parent_id` _str | None, optional_ - UUID for the message to continue on. Defaults to None. 180 | - `model` _str | None, optional_ - The model to use. Defaults to None. 181 | - `auto_continue` _bool, optional_ - Whether to continue the conversation automatically. Defaults to False. 182 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 183 | 184 | - `Yields` - Generator[dict, None, None] - The response from the chatbot 185 | - `dict` - { 186 | - `"message"` - str, 187 | - `"conversation_id"` - str, 188 | - `"parent_id"` - str, 189 | - `"model"` - str, 190 | - `"finish_details"` - str, # "max_tokens" or "stop" 191 | - `"end_turn"` - bool, 192 | - `"recipient"` - str, 193 | - `"citations"` - list[dict], 194 | } 195 | 196 | 197 | 198 | #### ask 199 | 200 | ```python 201 | @logger(is_timed=True) 202 | def ask(prompt: str, 203 | conversation_id: str | None = None, 204 | parent_id: str = "", 205 | model: str = "", 206 | plugin_ids: list = [], 207 | auto_continue: bool = False, 208 | timeout: float = 360, 209 | **kwargs) -> Generator[dict, None, None] 210 | ``` 211 | 212 | Ask a question to the chatbot 213 | 214 | **Arguments**: 215 | 216 | - `prompt` _str_ - The question 217 | - `conversation_id` _str, optional_ - UUID for the conversation to continue on. Defaults to None. 218 | - `parent_id` _str, optional_ - UUID for the message to continue on. Defaults to "". 219 | - `model` _str, optional_ - The model to use. Defaults to "". 220 | - `auto_continue` _bool, optional_ - Whether to continue the conversation automatically. Defaults to False. 221 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 222 | 223 | - `Yields` - The response from the chatbot 224 | - `dict` - { 225 | - `"message"` - str, 226 | - `"conversation_id"` - str, 227 | - `"parent_id"` - str, 228 | - `"model"` - str, 229 | - `"finish_details"` - str, # "max_tokens" or "stop" 230 | - `"end_turn"` - bool, 231 | - `"recipient"` - str, 232 | } 233 | 234 | 235 | 236 | #### continue\_write 237 | 238 | ```python 239 | @logger(is_timed=True) 240 | def continue_write(conversation_id: str | None = None, 241 | parent_id: str = "", 242 | model: str = "", 243 | auto_continue: bool = False, 244 | timeout: float = 360) -> Generator[dict, None, None] 245 | ``` 246 | 247 | let the chatbot continue to write. 248 | 249 | **Arguments**: 250 | 251 | - `conversation_id` _str | None, optional_ - UUID for the conversation to continue on. Defaults to None. 252 | - `parent_id` _str, optional_ - UUID for the message to continue on. Defaults to None. 253 | - `model` _str, optional_ - The model to use. Defaults to None. 254 | - `auto_continue` _bool, optional_ - Whether to continue the conversation automatically. Defaults to False. 255 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 256 | 257 | 258 | **Yields**: 259 | 260 | - `dict` - { 261 | - `"message"` - str, 262 | - `"conversation_id"` - str, 263 | - `"parent_id"` - str, 264 | - `"model"` - str, 265 | - `"finish_details"` - str, # "max_tokens" or "stop" 266 | - `"end_turn"` - bool, 267 | - `"recipient"` - str, 268 | } 269 | 270 | 271 | 272 | #### get\_conversations 273 | 274 | ```python 275 | @logger(is_timed=True) 276 | def get_conversations(offset: int = 0, 277 | limit: int = 20, 278 | encoding: str | None = None) -> list 279 | ``` 280 | 281 | Get conversations 282 | 283 | **Arguments**: 284 | 285 | - `offset`: Integer 286 | - `limit`: Integer 287 | 288 | 289 | 290 | #### get\_msg\_history 291 | 292 | ```python 293 | @logger(is_timed=True) 294 | def get_msg_history(convo_id: str, encoding: str | None = None) -> list 295 | ``` 296 | 297 | Get message history 298 | 299 | **Arguments**: 300 | 301 | - `id`: UUID of conversation 302 | - `encoding`: String 303 | 304 | 305 | 306 | #### share\_conversation 307 | 308 | ```python 309 | def share_conversation(title: str = None, 310 | convo_id: str = None, 311 | node_id: str = None, 312 | anonymous: bool = True) -> str 313 | ``` 314 | 315 | Creates a share link to a conversation 316 | 317 | **Arguments**: 318 | 319 | - `convo_id`: UUID of conversation 320 | - `node_id`: UUID of node 321 | - `anonymous`: Boolean 322 | - `title`: String 323 | Returns: 324 | str: A URL to the shared link 325 | 326 | 327 | 328 | #### gen\_title 329 | 330 | ```python 331 | @logger(is_timed=True) 332 | def gen_title(convo_id: str, message_id: str) -> str 333 | ``` 334 | 335 | Generate title for conversation 336 | 337 | **Arguments**: 338 | 339 | - `id`: UUID of conversation 340 | - `message_id`: UUID of message 341 | 342 | 343 | 344 | #### change\_title 345 | 346 | ```python 347 | @logger(is_timed=True) 348 | def change_title(convo_id: str, title: str) -> None 349 | ``` 350 | 351 | Change title of conversation 352 | 353 | **Arguments**: 354 | 355 | - `id`: UUID of conversation 356 | - `title`: String 357 | 358 | 359 | 360 | #### delete\_conversation 361 | 362 | ```python 363 | @logger(is_timed=True) 364 | def delete_conversation(convo_id: str) -> None 365 | ``` 366 | 367 | Delete conversation 368 | 369 | **Arguments**: 370 | 371 | - `id`: UUID of conversation 372 | 373 | 374 | 375 | #### clear\_conversations 376 | 377 | ```python 378 | @logger(is_timed=True) 379 | def clear_conversations() -> None 380 | ``` 381 | 382 | Delete all conversations 383 | 384 | 385 | 386 | #### reset\_chat 387 | 388 | ```python 389 | @logger(is_timed=False) 390 | def reset_chat() -> None 391 | ``` 392 | 393 | Reset the conversation ID and parent ID. 394 | 395 | **Returns**: 396 | 397 | None 398 | 399 | 400 | 401 | #### rollback\_conversation 402 | 403 | ```python 404 | @logger(is_timed=False) 405 | def rollback_conversation(num: int = 1) -> None 406 | ``` 407 | 408 | Rollback the conversation. 409 | 410 | **Arguments**: 411 | 412 | - `num`: Integer. The number of messages to rollback 413 | 414 | **Returns**: 415 | 416 | None 417 | 418 | 419 | 420 | #### get\_plugins 421 | 422 | ```python 423 | @logger(is_timed=True) 424 | def get_plugins(offset: int = 0, limit: int = 250, status: str = "approved") 425 | ``` 426 | 427 | Get plugins 428 | 429 | **Arguments**: 430 | 431 | - `offset`: Integer. Offset (Only supports 0) 432 | - `limit`: Integer. Limit (Only below 250) 433 | - `status`: String. Status of plugin (approved) 434 | 435 | 436 | 437 | #### install\_plugin 438 | 439 | ```python 440 | @logger(is_timed=True) 441 | def install_plugin(plugin_id: str) 442 | ``` 443 | 444 | Install plugin by ID 445 | 446 | **Arguments**: 447 | 448 | - `plugin_id`: String. ID of plugin 449 | 450 | 451 | 452 | #### get\_unverified\_plugin 453 | 454 | ```python 455 | @logger(is_timed=True) 456 | def get_unverified_plugin(domain: str, install: bool = True) -> dict 457 | ``` 458 | 459 | Get unverified plugin by domain 460 | 461 | **Arguments**: 462 | 463 | - `domain`: String. Domain of plugin 464 | - `install`: Boolean. Install plugin if found 465 | 466 | 467 | 468 | ## AsyncChatbot Objects 469 | 470 | ```python 471 | class AsyncChatbot(Chatbot) 472 | ``` 473 | 474 | Async Chatbot class for ChatGPT 475 | 476 | 477 | 478 | #### \_\_init\_\_ 479 | 480 | ```python 481 | def __init__(config: dict, 482 | conversation_id: str | None = None, 483 | parent_id: str | None = None, 484 | base_url: str | None = None, 485 | lazy_loading: bool = True) -> None 486 | ``` 487 | 488 | Same as Chatbot class, but with async methods. 489 | 490 | 491 | 492 | #### post\_messages 493 | 494 | ```python 495 | async def post_messages(messages: list[dict], 496 | conversation_id: str | None = None, 497 | parent_id: str | None = None, 498 | plugin_ids: list = [], 499 | model: str | None = None, 500 | auto_continue: bool = False, 501 | timeout: float = 360, 502 | **kwargs) -> AsyncGenerator[dict, None] 503 | ``` 504 | 505 | Post messages to the chatbot 506 | 507 | **Arguments**: 508 | 509 | - `messages` _list[dict]_ - the messages to post 510 | - `conversation_id` _str | None, optional_ - UUID for the conversation to continue on. Defaults to None. 511 | - `parent_id` _str | None, optional_ - UUID for the message to continue on. Defaults to None. 512 | - `model` _str | None, optional_ - The model to use. Defaults to None. 513 | - `auto_continue` _bool, optional_ - Whether to continue the conversation automatically. Defaults to False. 514 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 515 | 516 | 517 | **Yields**: 518 | 519 | AsyncGenerator[dict, None]: The response from the chatbot 520 | { 521 | - `"message"` - str, 522 | - `"conversation_id"` - str, 523 | - `"parent_id"` - str, 524 | - `"model"` - str, 525 | - `"finish_details"` - str, 526 | - `"end_turn"` - bool, 527 | - `"recipient"` - str, 528 | - `"citations"` - list[dict], 529 | } 530 | 531 | 532 | 533 | #### ask 534 | 535 | ```python 536 | async def ask(prompt: str, 537 | conversation_id: str | None = None, 538 | parent_id: str = "", 539 | model: str = "", 540 | plugin_ids: list = [], 541 | auto_continue: bool = False, 542 | timeout: int = 360, 543 | **kwargs) -> AsyncGenerator[dict, None] 544 | ``` 545 | 546 | Ask a question to the chatbot 547 | 548 | **Arguments**: 549 | 550 | - `prompt` _str_ - The question to ask 551 | - `conversation_id` _str | None, optional_ - UUID for the conversation to continue on. Defaults to None. 552 | - `parent_id` _str, optional_ - UUID for the message to continue on. Defaults to "". 553 | - `model` _str, optional_ - The model to use. Defaults to "". 554 | - `auto_continue` _bool, optional_ - Whether to continue the conversation automatically. Defaults to False. 555 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 556 | 557 | 558 | **Yields**: 559 | 560 | AsyncGenerator[dict, None]: The response from the chatbot 561 | { 562 | - `"message"` - str, 563 | - `"conversation_id"` - str, 564 | - `"parent_id"` - str, 565 | - `"model"` - str, 566 | - `"finish_details"` - str, 567 | - `"end_turn"` - bool, 568 | - `"recipient"` - str, 569 | } 570 | 571 | 572 | 573 | #### continue\_write 574 | 575 | ```python 576 | async def continue_write(conversation_id: str | None = None, 577 | parent_id: str = "", 578 | model: str = "", 579 | auto_continue: bool = False, 580 | timeout: float = 360) -> AsyncGenerator[dict, None] 581 | ``` 582 | 583 | let the chatbot continue to write 584 | 585 | **Arguments**: 586 | 587 | - `conversation_id` _str | None, optional_ - UUID for the conversation to continue on. Defaults to None. 588 | - `parent_id` _str, optional_ - UUID for the message to continue on. Defaults to None. 589 | - `model` _str, optional_ - Model to use. Defaults to None. 590 | - `auto_continue` _bool, optional_ - Whether to continue writing automatically. Defaults to False. 591 | - `timeout` _float, optional_ - Timeout for getting the full response, unit is second. Defaults to 360. 592 | 593 | 594 | 595 | **Yields**: 596 | 597 | AsyncGenerator[dict, None]: The response from the chatbot 598 | { 599 | - `"message"` - str, 600 | - `"conversation_id"` - str, 601 | - `"parent_id"` - str, 602 | - `"model"` - str, 603 | - `"finish_details"` - str, 604 | - `"end_turn"` - bool, 605 | - `"recipient"` - str, 606 | } 607 | 608 | 609 | 610 | #### get\_conversations 611 | 612 | ```python 613 | async def get_conversations(offset: int = 0, limit: int = 20) -> list 614 | ``` 615 | 616 | Get conversations 617 | 618 | **Arguments**: 619 | 620 | - `offset`: Integer 621 | - `limit`: Integer 622 | 623 | 624 | 625 | #### get\_msg\_history 626 | 627 | ```python 628 | async def get_msg_history(convo_id: str, 629 | encoding: str | None = "utf-8") -> dict 630 | ``` 631 | 632 | Get message history 633 | 634 | **Arguments**: 635 | 636 | - `id`: UUID of conversation 637 | 638 | 639 | 640 | #### share\_conversation 641 | 642 | ```python 643 | async def share_conversation(title: str = None, 644 | convo_id: str = None, 645 | node_id: str = None, 646 | anonymous: bool = True) -> str 647 | ``` 648 | 649 | Creates a share link to a conversation 650 | 651 | **Arguments**: 652 | 653 | - `convo_id`: UUID of conversation 654 | - `node_id`: UUID of node 655 | Returns: 656 | str: A URL to the shared link 657 | 658 | 659 | 660 | #### gen\_title 661 | 662 | ```python 663 | async def gen_title(convo_id: str, message_id: str) -> None 664 | ``` 665 | 666 | Generate title for conversation 667 | 668 | 669 | 670 | #### change\_title 671 | 672 | ```python 673 | async def change_title(convo_id: str, title: str) -> None 674 | ``` 675 | 676 | Change title of conversation 677 | 678 | **Arguments**: 679 | 680 | - `convo_id`: UUID of conversation 681 | - `title`: String 682 | 683 | 684 | 685 | #### delete\_conversation 686 | 687 | ```python 688 | async def delete_conversation(convo_id: str) -> None 689 | ``` 690 | 691 | Delete conversation 692 | 693 | **Arguments**: 694 | 695 | - `convo_id`: UUID of conversation 696 | 697 | 698 | 699 | #### clear\_conversations 700 | 701 | ```python 702 | async def clear_conversations() -> None 703 | ``` 704 | 705 | Delete all conversations 706 | 707 | 708 | 709 | #### configure 710 | 711 | ```python 712 | @logger(is_timed=False) 713 | def configure() -> dict 714 | ``` 715 | 716 | Looks for a config file in the following locations: 717 | 718 | 719 | 720 | #### main 721 | 722 | ```python 723 | @logger(is_timed=False) 724 | def main(config: dict) -> NoReturn 725 | ``` 726 | 727 | Main function for the chatGPT program. 728 | -------------------------------------------------------------------------------- /docs/wiki/V3.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # revChatGPT.V3 4 | 5 | A simple wrapper for the official ChatGPT API 6 | 7 | 8 | 9 | ## Chatbot Objects 10 | 11 | ```python 12 | class Chatbot() 13 | ``` 14 | 15 | Official ChatGPT API 16 | 17 | 18 | 19 | #### \_\_init\_\_ 20 | 21 | ```python 22 | def __init__( 23 | api_key: str, 24 | engine: str = os.environ.get("GPT_ENGINE") or "gpt-3.5-turbo", 25 | proxy: str = None, 26 | timeout: float = None, 27 | max_tokens: int = None, 28 | temperature: float = 0.5, 29 | top_p: float = 1.0, 30 | presence_penalty: float = 0.0, 31 | frequency_penalty: float = 0.0, 32 | reply_count: int = 1, 33 | truncate_limit: int = None, 34 | system_prompt: 35 | str = "You are ChatGPT, a large language model trained by OpenAI. Respond conversationally" 36 | ) -> None 37 | ``` 38 | 39 | Initialize Chatbot with API key (from https://platform.openai.com/account/api-keys) 40 | 41 | 42 | 43 | #### add\_to\_conversation 44 | 45 | ```python 46 | def add_to_conversation(message: str, 47 | role: str, 48 | convo_id: str = "default") -> None 49 | ``` 50 | 51 | Add a message to the conversation 52 | 53 | 54 | 55 | #### get\_token\_count 56 | 57 | ```python 58 | def get_token_count(convo_id: str = "default") -> int 59 | ``` 60 | 61 | Get token count 62 | 63 | 64 | 65 | #### get\_max\_tokens 66 | 67 | ```python 68 | def get_max_tokens(convo_id: str) -> int 69 | ``` 70 | 71 | Get max tokens 72 | 73 | 74 | 75 | #### ask\_stream 76 | 77 | ```python 78 | def ask_stream(prompt: str, 79 | role: str = "user", 80 | convo_id: str = "default", 81 | model: str = None, 82 | pass_history: bool = True, 83 | **kwargs) 84 | ``` 85 | 86 | Ask a question 87 | 88 | 89 | 90 | #### ask\_stream\_async 91 | 92 | ```python 93 | async def ask_stream_async(prompt: str, 94 | role: str = "user", 95 | convo_id: str = "default", 96 | model: str = None, 97 | pass_history: bool = True, 98 | **kwargs) -> AsyncGenerator[str, None] 99 | ``` 100 | 101 | Ask a question 102 | 103 | 104 | 105 | #### ask\_async 106 | 107 | ```python 108 | async def ask_async(prompt: str, 109 | role: str = "user", 110 | convo_id: str = "default", 111 | model: str = None, 112 | pass_history: bool = True, 113 | **kwargs) -> str 114 | ``` 115 | 116 | Non-streaming ask 117 | 118 | 119 | 120 | #### ask 121 | 122 | ```python 123 | def ask(prompt: str, 124 | role: str = "user", 125 | convo_id: str = "default", 126 | model: str = None, 127 | pass_history: bool = True, 128 | **kwargs) -> str 129 | ``` 130 | 131 | Non-streaming ask 132 | 133 | 134 | 135 | #### rollback 136 | 137 | ```python 138 | def rollback(n: int = 1, convo_id: str = "default") -> None 139 | ``` 140 | 141 | Rollback the conversation 142 | 143 | 144 | 145 | #### reset 146 | 147 | ```python 148 | def reset(convo_id: str = "default", system_prompt: str = None) -> None 149 | ``` 150 | 151 | Reset the conversation 152 | 153 | 154 | 155 | #### save 156 | 157 | ```python 158 | def save(file: str, *keys: str) -> None 159 | ``` 160 | 161 | Save the Chatbot configuration to a JSON file 162 | 163 | 164 | 165 | #### load 166 | 167 | ```python 168 | def load(file: Path, *keys_: str) -> None 169 | ``` 170 | 171 | Load the Chatbot configuration from a JSON file 172 | 173 | 174 | 175 | ## ChatbotCLI Objects 176 | 177 | ```python 178 | class ChatbotCLI(Chatbot) 179 | ``` 180 | 181 | Command Line Interface for Chatbot 182 | 183 | 184 | 185 | #### print\_config 186 | 187 | ```python 188 | def print_config(convo_id: str = "default") -> None 189 | ``` 190 | 191 | Prints the current configuration 192 | 193 | 194 | 195 | #### print\_help 196 | 197 | ```python 198 | def print_help() -> None 199 | ``` 200 | 201 | Prints the help message 202 | 203 | 204 | 205 | #### handle\_commands 206 | 207 | ```python 208 | def handle_commands(prompt: str, convo_id: str = "default") -> bool 209 | ``` 210 | 211 | Handle chatbot commands 212 | 213 | 214 | 215 | #### main 216 | 217 | ```python 218 | def main() -> NoReturn 219 | ``` 220 | 221 | Main function 222 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acheong08/ChatGPT/9167b325addc7d3520987face684e8230bd62b46/logo.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | OpenAIAuth>=2.0.0 2 | requests[socks] 3 | httpx[socks] 4 | prompt-toolkit 5 | tiktoken>=0.3.0 6 | openai 7 | rich -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | [metadata] 3 | description_file=README.md 4 | license_files=LICENSE 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from setuptools import find_namespace_packages 4 | from setuptools import setup 5 | 6 | DOCS_PATH = Path(__file__).parents[0] / "docs/README.md" 7 | PATH = Path("README.md") 8 | if not PATH.exists(): 9 | with open(DOCS_PATH, encoding="utf-8") as f1: 10 | with open(PATH, "w+", encoding="utf-8") as f2: 11 | f2.write(f1.read()) 12 | 13 | VERSION_PATH = Path(__file__).parents[0] / "src/revChatGPT/version.py" 14 | with open(VERSION_PATH, encoding="utf-8") as f: 15 | version = f.read().split('"')[1] 16 | 17 | setup( 18 | name="revChatGPT", 19 | version=version, 20 | description="ChatGPT is a reverse engineering of OpenAI's ChatGPT API", 21 | long_description=open(PATH, encoding="utf-8").read(), 22 | long_description_content_type="text/markdown", 23 | url="https://github.com/acheong08/ChatGPT", 24 | project_urls={ 25 | "Bug Report": "https://github.com/acheong08/ChatGPT/issues/new?assignees=&labels=bug-report&template=bug_report.yml&title=%5BBug%5D%3A+", 26 | "Feature request": "https://github.com/acheong08/ChatGPT/issues/new?assignees=&labels=enhancement&template=feature_request.yml&title=%5BFeature+Request%5D%3A+", 27 | }, 28 | author="Antonio Cheong", 29 | author_email="acheong@student.dalat.org", 30 | license="GNU General Public License v2.0", 31 | packages=find_namespace_packages("src"), 32 | package_dir={"": "src"}, 33 | py_modules=["revChatGPT"], 34 | package_data={"": ["*.json"]}, 35 | install_requires=[ 36 | "OpenAIAuth>=3.0.0", 37 | "requests[socks]", 38 | "httpx[socks]", 39 | "prompt-toolkit", 40 | "tiktoken>=0.3.0", 41 | "openai", 42 | "rich", 43 | ], 44 | classifiers=[ 45 | "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", 46 | "Intended Audience :: Developers", 47 | "Intended Audience :: End Users/Desktop", 48 | "Natural Language :: English", 49 | "Topic :: Software Development :: Libraries :: Python Modules", 50 | "Programming Language :: Python :: 3 :: Only", 51 | "Programming Language :: Python :: 3.9", 52 | "Programming Language :: Python :: 3.10", 53 | "Programming Language :: Python :: 3.11", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /src/revChatGPT/V3.py: -------------------------------------------------------------------------------- 1 | """ 2 | A simple wrapper for the official ChatGPT API 3 | """ 4 | import argparse 5 | import json 6 | import os 7 | import sys 8 | from importlib.resources import path 9 | from pathlib import Path 10 | from typing import AsyncGenerator 11 | from typing import NoReturn 12 | 13 | import httpx 14 | import requests 15 | import tiktoken 16 | 17 | from . import __version__ 18 | from . import typings as t 19 | from .utils import create_completer 20 | from .utils import create_keybindings 21 | from .utils import create_session 22 | from .utils import get_filtered_keys_from_object 23 | from .utils import get_input 24 | 25 | ENGINES = [ 26 | "gpt-3.5-turbo", 27 | "gpt-3.5-turbo-16k", 28 | "gpt-3.5-turbo-0301", 29 | "gpt-3.5-turbo-0613", 30 | "gpt-3.5-turbo-16k-0613", 31 | "gpt-4", 32 | "gpt-4-0314", 33 | "gpt-4-32k", 34 | "gpt-4-32k-0314", 35 | "gpt-4-0613", 36 | "gpt-4-32k-0613", 37 | ] 38 | 39 | 40 | class Chatbot: 41 | """ 42 | Official ChatGPT API 43 | """ 44 | 45 | def __init__( 46 | self, 47 | api_key: str, 48 | engine: str = os.environ.get("GPT_ENGINE") or "gpt-3.5-turbo", 49 | proxy: str = None, 50 | timeout: float = None, 51 | max_tokens: int = None, 52 | temperature: float = 0.5, 53 | top_p: float = 1.0, 54 | presence_penalty: float = 0.0, 55 | frequency_penalty: float = 0.0, 56 | reply_count: int = 1, 57 | truncate_limit: int = None, 58 | system_prompt: str = "You are ChatGPT, a large language model trained by OpenAI. Respond conversationally", 59 | ) -> None: 60 | """ 61 | Initialize Chatbot with API key (from https://platform.openai.com/account/api-keys) 62 | """ 63 | self.engine: str = engine 64 | self.api_key: str = api_key 65 | self.system_prompt: str = system_prompt 66 | self.max_tokens: int = max_tokens or ( 67 | 31000 68 | if "gpt-4-32k" in engine 69 | else 7000 70 | if "gpt-4" in engine 71 | else 15000 72 | if "gpt-3.5-turbo-16k" in engine 73 | else 4000 74 | ) 75 | self.truncate_limit: int = truncate_limit or ( 76 | 30500 77 | if "gpt-4-32k" in engine 78 | else 6500 79 | if "gpt-4" in engine 80 | else 14500 81 | if "gpt-3.5-turbo-16k" in engine 82 | else 3500 83 | ) 84 | self.temperature: float = temperature 85 | self.top_p: float = top_p 86 | self.presence_penalty: float = presence_penalty 87 | self.frequency_penalty: float = frequency_penalty 88 | self.reply_count: int = reply_count 89 | self.timeout: float = timeout 90 | self.proxy = proxy 91 | self.session = requests.Session() 92 | self.session.proxies.update( 93 | { 94 | "http": proxy, 95 | "https": proxy, 96 | }, 97 | ) 98 | if proxy := ( 99 | proxy or os.environ.get("all_proxy") or os.environ.get("ALL_PROXY") or None 100 | ): 101 | if "socks5h" not in proxy: 102 | self.aclient = httpx.AsyncClient( 103 | follow_redirects=True, 104 | proxies=proxy, 105 | timeout=timeout, 106 | ) 107 | else: 108 | self.aclient = httpx.AsyncClient( 109 | follow_redirects=True, 110 | proxies=proxy, 111 | timeout=timeout, 112 | ) 113 | 114 | self.conversation: dict[str, list[dict]] = { 115 | "default": [ 116 | { 117 | "role": "system", 118 | "content": system_prompt, 119 | }, 120 | ], 121 | } 122 | 123 | if self.get_token_count("default") > self.max_tokens: 124 | raise t.ActionRefuseError("System prompt is too long") 125 | 126 | def add_to_conversation( 127 | self, 128 | message: str, 129 | role: str, 130 | convo_id: str = "default", 131 | ) -> None: 132 | """ 133 | Add a message to the conversation 134 | """ 135 | self.conversation[convo_id].append({"role": role, "content": message}) 136 | 137 | def __truncate_conversation(self, convo_id: str = "default") -> None: 138 | """ 139 | Truncate the conversation 140 | """ 141 | while True: 142 | if ( 143 | self.get_token_count(convo_id) > self.truncate_limit 144 | and len(self.conversation[convo_id]) > 1 145 | ): 146 | # Don't remove the first message 147 | self.conversation[convo_id].pop(1) 148 | else: 149 | break 150 | 151 | # https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb 152 | def get_token_count(self, convo_id: str = "default") -> int: 153 | """ 154 | Get token count 155 | """ 156 | if self.engine not in ENGINES: 157 | raise NotImplementedError( 158 | f"Engine {self.engine} is not supported. Select from {ENGINES}", 159 | ) 160 | tiktoken.model.MODEL_TO_ENCODING["gpt-4"] = "cl100k_base" 161 | 162 | encoding = tiktoken.encoding_for_model(self.engine) 163 | 164 | num_tokens = 0 165 | for message in self.conversation[convo_id]: 166 | # every message follows {role/name}\n{content}\n 167 | num_tokens += 5 168 | for key, value in message.items(): 169 | if value: 170 | num_tokens += len(encoding.encode(value)) 171 | if key == "name": # if there's a name, the role is omitted 172 | num_tokens += 5 # role is always required and always 1 token 173 | num_tokens += 5 # every reply is primed with assistant 174 | return num_tokens 175 | 176 | def get_max_tokens(self, convo_id: str) -> int: 177 | """ 178 | Get max tokens 179 | """ 180 | return self.max_tokens - self.get_token_count(convo_id) 181 | 182 | def ask_stream( 183 | self, 184 | prompt: str, 185 | role: str = "user", 186 | convo_id: str = "default", 187 | model: str = None, 188 | pass_history: bool = True, 189 | **kwargs, 190 | ): 191 | """ 192 | Ask a question 193 | """ 194 | # Make conversation if it doesn't exist 195 | if convo_id not in self.conversation: 196 | self.reset(convo_id=convo_id, system_prompt=self.system_prompt) 197 | self.add_to_conversation(prompt, "user", convo_id=convo_id) 198 | self.__truncate_conversation(convo_id=convo_id) 199 | # Get response 200 | if os.environ.get("API_URL") and os.environ.get("MODEL_NAME"): 201 | # https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api 202 | url = ( 203 | os.environ.get("API_URL") 204 | + "openai/deployments/" 205 | + os.environ.get("MODEL_NAME") 206 | + "/chat/completions?api-version=2023-05-15" 207 | ) 208 | headers = {"Content-Type": "application/json", "api-key": self.api_key} 209 | else: 210 | url = ( 211 | os.environ.get("API_URL") 212 | or "https://api.openai.com/v1/chat/completions" 213 | ) 214 | headers = {"Authorization": f"Bearer {kwargs.get('api_key', self.api_key)}"} 215 | response = self.session.post( 216 | url, 217 | headers=headers, 218 | json={ 219 | "model": os.environ.get("MODEL_NAME") or model or self.engine, 220 | "messages": self.conversation[convo_id] if pass_history else [prompt], 221 | "stream": True, 222 | # kwargs 223 | "temperature": kwargs.get("temperature", self.temperature), 224 | "top_p": kwargs.get("top_p", self.top_p), 225 | "presence_penalty": kwargs.get( 226 | "presence_penalty", 227 | self.presence_penalty, 228 | ), 229 | "frequency_penalty": kwargs.get( 230 | "frequency_penalty", 231 | self.frequency_penalty, 232 | ), 233 | "n": kwargs.get("n", self.reply_count), 234 | "user": role, 235 | "max_tokens": min( 236 | self.get_max_tokens(convo_id=convo_id), 237 | kwargs.get("max_tokens", self.max_tokens), 238 | ), 239 | }, 240 | timeout=kwargs.get("timeout", self.timeout), 241 | stream=True, 242 | ) 243 | if response.status_code != 200: 244 | raise t.APIConnectionError( 245 | f"{response.status_code} {response.reason} {response.text}", 246 | ) 247 | response_role: str or None = None 248 | full_response: str = "" 249 | for line in response.iter_lines(): 250 | if not line: 251 | continue 252 | # Remove "data: " 253 | line = line.decode("utf-8")[6:] 254 | if line == "[DONE]": 255 | break 256 | resp: dict = json.loads(line) 257 | choices = resp.get("choices") 258 | if not choices: 259 | continue 260 | delta = choices[0].get("delta") 261 | if not delta: 262 | continue 263 | if "role" in delta: 264 | response_role = delta["role"] 265 | if "content" in delta: 266 | content = delta["content"] 267 | full_response += content 268 | yield content 269 | self.add_to_conversation(full_response, response_role, convo_id=convo_id) 270 | 271 | async def ask_stream_async( 272 | self, 273 | prompt: str, 274 | role: str = "user", 275 | convo_id: str = "default", 276 | model: str = None, 277 | pass_history: bool = True, 278 | **kwargs, 279 | ) -> AsyncGenerator[str, None]: 280 | """ 281 | Ask a question 282 | """ 283 | # Make conversation if it doesn't exist 284 | if convo_id not in self.conversation: 285 | self.reset(convo_id=convo_id, system_prompt=self.system_prompt) 286 | self.add_to_conversation(prompt, "user", convo_id=convo_id) 287 | self.__truncate_conversation(convo_id=convo_id) 288 | # Get response 289 | async with self.aclient.stream( 290 | "post", 291 | os.environ.get("API_URL") or "https://api.openai.com/v1/chat/completions", 292 | headers={"Authorization": f"Bearer {kwargs.get('api_key', self.api_key)}"}, 293 | json={ 294 | "model": model or self.engine, 295 | "messages": self.conversation[convo_id] if pass_history else [prompt], 296 | "stream": True, 297 | # kwargs 298 | "temperature": kwargs.get("temperature", self.temperature), 299 | "top_p": kwargs.get("top_p", self.top_p), 300 | "presence_penalty": kwargs.get( 301 | "presence_penalty", 302 | self.presence_penalty, 303 | ), 304 | "frequency_penalty": kwargs.get( 305 | "frequency_penalty", 306 | self.frequency_penalty, 307 | ), 308 | "n": kwargs.get("n", self.reply_count), 309 | "user": role, 310 | "max_tokens": min( 311 | self.get_max_tokens(convo_id=convo_id), 312 | kwargs.get("max_tokens", self.max_tokens), 313 | ), 314 | }, 315 | timeout=kwargs.get("timeout", self.timeout), 316 | ) as response: 317 | if response.status_code != 200: 318 | await response.aread() 319 | raise t.APIConnectionError( 320 | f"{response.status_code} {response.reason_phrase} {response.text}", 321 | ) 322 | 323 | response_role: str = "" 324 | full_response: str = "" 325 | async for line in response.aiter_lines(): 326 | line = line.strip() 327 | if not line: 328 | continue 329 | # Remove "data: " 330 | line = line[6:] 331 | if line == "[DONE]": 332 | break 333 | resp: dict = json.loads(line) 334 | if "error" in resp: 335 | raise t.ResponseError(f"{resp['error']}") 336 | choices = resp.get("choices") 337 | if not choices: 338 | continue 339 | delta: dict[str, str] = choices[0].get("delta") 340 | if not delta: 341 | continue 342 | if "role" in delta: 343 | response_role = delta["role"] 344 | if "content" in delta: 345 | content: str = delta["content"] 346 | full_response += content 347 | yield content 348 | self.add_to_conversation(full_response, response_role, convo_id=convo_id) 349 | 350 | async def ask_async( 351 | self, 352 | prompt: str, 353 | role: str = "user", 354 | convo_id: str = "default", 355 | model: str = None, 356 | pass_history: bool = True, 357 | **kwargs, 358 | ) -> str: 359 | """ 360 | Non-streaming ask 361 | """ 362 | response = self.ask_stream_async( 363 | prompt=prompt, 364 | role=role, 365 | convo_id=convo_id, 366 | **kwargs, 367 | ) 368 | full_response: str = "".join([r async for r in response]) 369 | return full_response 370 | 371 | def ask( 372 | self, 373 | prompt: str, 374 | role: str = "user", 375 | convo_id: str = "default", 376 | model: str = None, 377 | pass_history: bool = True, 378 | **kwargs, 379 | ) -> str: 380 | """ 381 | Non-streaming ask 382 | """ 383 | response = self.ask_stream( 384 | prompt=prompt, 385 | role=role, 386 | convo_id=convo_id, 387 | model=model, 388 | pass_history=pass_history, 389 | **kwargs, 390 | ) 391 | full_response: str = "".join(response) 392 | return full_response 393 | 394 | def rollback(self, n: int = 1, convo_id: str = "default") -> None: 395 | """ 396 | Rollback the conversation 397 | """ 398 | for _ in range(n): 399 | self.conversation[convo_id].pop() 400 | 401 | def reset(self, convo_id: str = "default", system_prompt: str = None) -> None: 402 | """ 403 | Reset the conversation 404 | """ 405 | self.conversation[convo_id] = [ 406 | {"role": "system", "content": system_prompt or self.system_prompt}, 407 | ] 408 | 409 | def save(self, file: str, *keys: str) -> None: 410 | """ 411 | Save the Chatbot configuration to a JSON file 412 | """ 413 | with open(file, "w", encoding="utf-8") as f: 414 | data = { 415 | key: self.__dict__[key] 416 | for key in get_filtered_keys_from_object(self, *keys) 417 | } 418 | # saves session.proxies dict as session 419 | # leave this here for compatibility 420 | data["session"] = data["proxy"] 421 | del data["aclient"] 422 | json.dump( 423 | data, 424 | f, 425 | indent=2, 426 | ) 427 | 428 | def load(self, file: Path, *keys_: str) -> None: 429 | """ 430 | Load the Chatbot configuration from a JSON file 431 | """ 432 | with open(file, encoding="utf-8") as f: 433 | # load json, if session is in keys, load proxies 434 | loaded_config = json.load(f) 435 | keys = get_filtered_keys_from_object(self, *keys_) 436 | 437 | if ( 438 | "session" in keys 439 | and loaded_config["session"] 440 | or "proxy" in keys 441 | and loaded_config["proxy"] 442 | ): 443 | self.proxy = loaded_config.get("session", loaded_config["proxy"]) 444 | self.session = httpx.Client( 445 | follow_redirects=True, 446 | proxies=self.proxy, 447 | timeout=self.timeout, 448 | cookies=self.session.cookies, 449 | headers=self.session.headers, 450 | ) 451 | self.aclient = httpx.AsyncClient( 452 | follow_redirects=True, 453 | proxies=self.proxy, 454 | timeout=self.timeout, 455 | cookies=self.session.cookies, 456 | headers=self.session.headers, 457 | ) 458 | if "session" in keys: 459 | keys.remove("session") 460 | if "aclient" in keys: 461 | keys.remove("aclient") 462 | self.__dict__.update({key: loaded_config[key] for key in keys}) 463 | 464 | 465 | class ChatbotCLI(Chatbot): 466 | """ 467 | Command Line Interface for Chatbot 468 | """ 469 | 470 | def print_config(self, convo_id: str = "default") -> None: 471 | """ 472 | Prints the current configuration 473 | """ 474 | print( 475 | f""" 476 | ChatGPT Configuration: 477 | Conversation ID: {convo_id} 478 | Messages: {len(self.conversation[convo_id])} 479 | Tokens used: {( num_tokens := self.get_token_count(convo_id) )} / {self.max_tokens} 480 | Cost: {"${:.5f}".format(( num_tokens / 1000 ) * 0.002)} 481 | Engine: {self.engine} 482 | Temperature: {self.temperature} 483 | Top_p: {self.top_p} 484 | Reply count: {self.reply_count} 485 | """, 486 | ) 487 | 488 | def print_help(self) -> None: 489 | """ 490 | Prints the help message 491 | """ 492 | print( 493 | """ 494 | Commands: 495 | !help Display this message 496 | !rollback n Rollback the conversation by n messages 497 | !save file [keys] Save the Chatbot configuration to a JSON file 498 | !load file [keys] Load the Chatbot configuration from a JSON file 499 | !reset Reset the conversation 500 | !exit Quit chat 501 | 502 | Config Commands: 503 | !config Display the current config 504 | !temperature n Set the temperature to n 505 | !top_p n Set the top_p to n 506 | !reply_count n Set the reply_count to n 507 | !engine engine Sets the chat model to engine 508 | 509 | Examples: 510 | !save c.json Saves all ChatbotGPT class variables to c.json 511 | !save c.json engine top_p Saves only temperature and top_p to c.json 512 | !load c.json not engine Loads all but engine from c.json 513 | !load c.json session Loads session proxies from c.json 514 | 515 | 516 | """, 517 | ) 518 | 519 | def handle_commands(self, prompt: str, convo_id: str = "default") -> bool: 520 | """ 521 | Handle chatbot commands 522 | """ 523 | command, *value = prompt.split(" ") 524 | if command == "!help": 525 | self.print_help() 526 | elif command == "!exit": 527 | sys.exit() 528 | elif command == "!reset": 529 | self.reset(convo_id=convo_id) 530 | print("\nConversation has been reset") 531 | elif command == "!config": 532 | self.print_config(convo_id=convo_id) 533 | elif command == "!rollback": 534 | self.rollback(int(value[0]), convo_id=convo_id) 535 | print(f"\nRolled back by {value[0]} messages") 536 | elif command == "!save": 537 | self.save(*value) 538 | print( 539 | f"Saved {', '.join(value[1:]) if len(value) > 1 else 'all'} keys to {value[0]}", 540 | ) 541 | elif command == "!load": 542 | self.load(*value) 543 | print( 544 | f"Loaded {', '.join(value[1:]) if len(value) > 1 else 'all'} keys from {value[0]}", 545 | ) 546 | elif command == "!temperature": 547 | self.temperature = float(value[0]) 548 | print(f"\nTemperature set to {value[0]}") 549 | elif command == "!top_p": 550 | self.top_p = float(value[0]) 551 | print(f"\nTop_p set to {value[0]}") 552 | elif command == "!reply_count": 553 | self.reply_count = int(value[0]) 554 | print(f"\nReply count set to {value[0]}") 555 | elif command == "!engine": 556 | if len(value) > 0: 557 | self.engine = value[0] 558 | print(f"\nEngine set to {self.engine}") 559 | else: 560 | return False 561 | 562 | return True 563 | 564 | 565 | def main() -> NoReturn: 566 | """ 567 | Main function 568 | """ 569 | print( 570 | f""" 571 | ChatGPT - Official ChatGPT API 572 | Repo: github.com/acheong08/ChatGPT 573 | Version: {__version__} 574 | """, 575 | ) 576 | print("Type '!help' to show a full list of commands") 577 | print("Press Esc followed by Enter or Alt+Enter to send a message.\n") 578 | 579 | # Get API key from command line 580 | parser = argparse.ArgumentParser() 581 | parser.add_argument( 582 | "--api_key", 583 | type=str, 584 | required="--config" not in sys.argv, 585 | help="OpenAI API key", 586 | ) 587 | parser.add_argument( 588 | "--temperature", 589 | type=float, 590 | default=0.5, 591 | help="Temperature for response", 592 | ) 593 | parser.add_argument( 594 | "--no_stream", 595 | action="store_true", 596 | help="Disable streaming", 597 | ) 598 | parser.add_argument( 599 | "--base_prompt", 600 | type=str, 601 | default="You are ChatGPT, a large language model trained by OpenAI. Respond conversationally", 602 | help="Base prompt for chatbot", 603 | ) 604 | parser.add_argument( 605 | "--proxy", 606 | type=str, 607 | default=None, 608 | help="Proxy address", 609 | ) 610 | parser.add_argument( 611 | "--top_p", 612 | type=float, 613 | default=1, 614 | help="Top p for response", 615 | ) 616 | parser.add_argument( 617 | "--reply_count", 618 | type=int, 619 | default=1, 620 | help="Number of replies for each prompt", 621 | ) 622 | parser.add_argument( 623 | "--enable_internet", 624 | action="store_true", 625 | help="Allow ChatGPT to search the internet", 626 | ) 627 | parser.add_argument( 628 | "--config", 629 | type=str, 630 | default=False, 631 | help="Path to V3 config json file", 632 | ) 633 | parser.add_argument( 634 | "--submit_key", 635 | type=str, 636 | default=None, 637 | help="Custom submit key for chatbot. For more information on keys, see README", 638 | ) 639 | parser.add_argument( 640 | "--model", 641 | type=str, 642 | default="gpt-3.5-turbo", 643 | choices=ENGINES, 644 | ) 645 | 646 | parser.add_argument( 647 | "--truncate_limit", 648 | type=int, 649 | default=None, 650 | ) 651 | 652 | args, _ = parser.parse_known_args() 653 | 654 | # Initialize chatbot 655 | if config := args.config or os.environ.get("GPT_CONFIG_PATH"): 656 | chatbot = ChatbotCLI(args.api_key) 657 | try: 658 | chatbot.load(config) 659 | except Exception as err: 660 | print(f"Error: {args.config} could not be loaded") 661 | raise err 662 | else: 663 | chatbot = ChatbotCLI( 664 | api_key=args.api_key, 665 | system_prompt=args.base_prompt, 666 | proxy=args.proxy, 667 | temperature=args.temperature, 668 | top_p=args.top_p, 669 | reply_count=args.reply_count, 670 | engine=args.model, 671 | truncate_limit=args.truncate_limit, 672 | ) 673 | # Check if internet is enabled 674 | if args.enable_internet: 675 | config = path("revChatGPT", "config").__str__() 676 | chatbot.load(Path(config, "enable_internet.json"), "conversation") 677 | 678 | session = create_session() 679 | completer = create_completer( 680 | [ 681 | "!help", 682 | "!exit", 683 | "!reset", 684 | "!rollback", 685 | "!config", 686 | "!engine", 687 | "!temperture", 688 | "!top_p", 689 | "!reply_count", 690 | "!save", 691 | "!load", 692 | ], 693 | ) 694 | key_bindings = create_keybindings() 695 | if args.submit_key: 696 | key_bindings = create_keybindings(args.submit_key) 697 | # Start chat 698 | while True: 699 | print() 700 | try: 701 | print("User: ") 702 | prompt = get_input( 703 | session=session, 704 | completer=completer, 705 | key_bindings=key_bindings, 706 | ) 707 | except KeyboardInterrupt: 708 | print("\nExiting...") 709 | sys.exit() 710 | if prompt.startswith("!"): 711 | try: 712 | chatbot.handle_commands(prompt) 713 | except ( 714 | requests.exceptions.Timeout, 715 | requests.exceptions.ConnectionError, 716 | ) as err: 717 | print(f"Error: {err}") 718 | continue 719 | continue 720 | print() 721 | print("ChatGPT: ", flush=True) 722 | if args.enable_internet: 723 | query = chatbot.ask( 724 | f'This is a prompt from a user to a chatbot: "{prompt}". Respond with "none" if it is directed at the chatbot or cannot be answered by an internet search. Otherwise, respond with a possible search query to a search engine. Do not write any additional text. Make it as minimal as possible', 725 | convo_id="search", 726 | temperature=0.0, 727 | ).strip() 728 | print("Searching for: ", query, "") 729 | # Get search results 730 | search_results = '{"results": "No search results"}' 731 | if query != "none": 732 | resp = requests.post( 733 | url="https://ddg-api.herokuapp.com/search", 734 | json={"query": query, "limit": 3}, 735 | timeout=10, 736 | ) 737 | resp.encoding = "utf-8" if resp.encoding is None else resp.encoding 738 | search_results = resp.text 739 | print(json.dumps(json.loads(search_results), indent=4)) 740 | chatbot.add_to_conversation( 741 | f"Search results:{search_results}", 742 | "system", 743 | convo_id="default", 744 | ) 745 | if args.no_stream: 746 | print(chatbot.ask(prompt, "user", convo_id="default")) 747 | else: 748 | for query in chatbot.ask_stream(prompt): 749 | print(query, end="", flush=True) 750 | elif args.no_stream: 751 | print(chatbot.ask(prompt, "user")) 752 | else: 753 | for query in chatbot.ask_stream(prompt): 754 | print(query, end="", flush=True) 755 | print() 756 | 757 | 758 | if __name__ == "__main__": 759 | try: 760 | main() 761 | except Exception as exc: 762 | raise t.CLIError("Command line program unknown error") from exc 763 | except KeyboardInterrupt: 764 | print("\nExiting...") 765 | sys.exit() 766 | -------------------------------------------------------------------------------- /src/revChatGPT/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The __init__ file does not a main file 3 | 4 | You can import the following module to use: 5 | revChatGPT.V1 6 | revChatGPT.V3 7 | """ 8 | from .version import version 9 | 10 | __version__ = version 11 | __all__ = () 12 | 13 | 14 | def verify() -> None: 15 | # Available Python Version Verify 16 | from . import typings as t 17 | 18 | if int(__import__("platform").python_version_tuple()[0]) < 3: 19 | error = t.NotAllowRunning("Not available Python version") 20 | raise error 21 | if int(__import__("platform").python_version_tuple()[1]) < 9: 22 | error = t.NotAllowRunning( 23 | f"Not available Python version: {__import__('platform').python_version()}", 24 | ) 25 | raise error 26 | if ( 27 | int(__import__("platform").python_version_tuple()[1]) < 10 28 | and int(__import__("platform").python_version_tuple()[0]) == 3 29 | ): 30 | __import__("warnings").warn( 31 | UserWarning( 32 | "The current Python is not a recommended version, 3.10+ is recommended", 33 | ), 34 | ) 35 | 36 | 37 | verify() 38 | -------------------------------------------------------------------------------- /src/revChatGPT/__main__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Main CLI 3 | """ 4 | import argparse 5 | import sys 6 | 7 | from . import __version__ 8 | from . import typings as t 9 | from . import V1 10 | from . import V3 11 | 12 | __all__ = () 13 | 14 | 15 | def main() -> None: 16 | """ 17 | main function for CLI 18 | """ 19 | parser = argparse.ArgumentParser( 20 | description="ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat)", 21 | epilog="Repo: github.com/acheong08/ChatGPT", 22 | allow_abbrev=True, 23 | ) 24 | parser.add_argument( 25 | "--V1", 26 | action="store_true", 27 | help="Use the website version of ChatGPT", 28 | ) 29 | parser.add_argument( 30 | "--V3", 31 | action="store_true", 32 | help="Use the API version of ChatGPT", 33 | ) 34 | args, _ = parser.parse_known_args() 35 | mode = "V1" if args.V1 else "V3" if args.V3 else input("Version (V1/V3):") 36 | 37 | if mode == "V1": 38 | print( 39 | f""" 40 | ChatGPT - A command-line interface to OpenAI's ChatGPT (https://chat.openai.com/chat) 41 | Repo: github.com/acheong08/ChatGPT 42 | Version: {__version__} 43 | """, 44 | ) 45 | print("Type '!help' to show a full list of commands") 46 | print( 47 | f"{V1.bcolors.BOLD}{V1.bcolors.WARNING}Press Esc followed by Enter or Alt+Enter to send a message.{V1.bcolors.ENDC}", 48 | ) 49 | V1.main(V1.configure()) 50 | elif mode == "V3": 51 | try: 52 | V3.main() 53 | except Exception as exc: 54 | error = t.CLIError("Command line program unknown error") 55 | raise error from exc 56 | except KeyboardInterrupt: 57 | print("\nExiting...") 58 | sys.exit() 59 | else: 60 | error = NotImplementedError(f"Unknown version: {mode}") 61 | raise error 62 | 63 | 64 | if __name__ == "__main__": 65 | main() 66 | -------------------------------------------------------------------------------- /src/revChatGPT/config/enable_internet.json: -------------------------------------------------------------------------------- 1 | { 2 | "conversation": { 3 | "default": [ 4 | { 5 | "content": "You are ChatGPT, an AI assistant that can access the internet. Internet search results will be sent from the system in JSON format. Respond conversationally and cite your sources via a URL at the end of your message.", 6 | "role": "system" 7 | } 8 | ], 9 | "search": [ 10 | { 11 | "role": "system", 12 | "content": "For given prompts, summarize it to fit the style of a search query to a search engine. If the prompt cannot be answered by an internet search, is a standalone statement, is a creative task, is directed at a person, or does not make sense, type \"none\". DO NOT TRY TO RESPOND CONVERSATIONALLY. DO NOT TALK ABOUT YOURSELF. IF THE PROMPT IS DIRECTED AT YOU, TYPE \"none\"." 13 | }, 14 | { 15 | "content": "What is the capital of France?", 16 | "role": "user" 17 | }, 18 | { 19 | "content": "Capital of France", 20 | "role": "assistant" 21 | }, 22 | { 23 | "content": "Who are you?", 24 | "role": "user" 25 | }, 26 | { 27 | "content": "none", 28 | "role": "assistant" 29 | }, 30 | { 31 | "content": "Write an essay about the history of the United States", 32 | "role": "user" 33 | }, 34 | { 35 | "content": "none", 36 | "role": "assistant" 37 | }, 38 | { 39 | "content": "What is the best way to cook a steak?", 40 | "role": "user" 41 | }, 42 | { 43 | "content": "How to cook a steak", 44 | "role": "assistant" 45 | }, 46 | { 47 | "content": "Hello world", 48 | "role": "user" 49 | }, 50 | { 51 | "content": "none", 52 | "role": "assistant" 53 | }, 54 | { 55 | "content": "Who is the current president of the United States?", 56 | "role": "user" 57 | }, 58 | { 59 | "content": "United States president", 60 | "role": "assistant" 61 | } 62 | ] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/revChatGPT/typings.py: -------------------------------------------------------------------------------- 1 | """ 2 | A module that contains all the types used in this project 3 | """ 4 | 5 | import os 6 | import platform 7 | from enum import Enum 8 | from typing import Union 9 | 10 | 11 | python_version = list(platform.python_version_tuple()) 12 | SUPPORT_ADD_NOTES = int(python_version[0]) >= 3 and int(python_version[1]) >= 11 13 | 14 | 15 | class ChatbotError(Exception): 16 | """ 17 | Base class for all Chatbot errors in this Project 18 | """ 19 | 20 | def __init__(self, *args: object) -> None: 21 | if SUPPORT_ADD_NOTES: 22 | super().add_note( 23 | "Please check that the input is correct, or you can resolve this issue by filing an issue", 24 | ) 25 | super().add_note("Project URL: https://github.com/acheong08/ChatGPT") 26 | super().__init__(*args) 27 | 28 | 29 | class ActionError(ChatbotError): 30 | """ 31 | Subclass of ChatbotError 32 | 33 | An object that throws an error because the execution of an operation is blocked 34 | """ 35 | 36 | def __init__(self, *args: object) -> None: 37 | if SUPPORT_ADD_NOTES: 38 | super().add_note( 39 | "The current operation is not allowed, which may be intentional", 40 | ) 41 | super().__init__(*args) 42 | 43 | 44 | class ActionNotAllowedError(ActionError): 45 | """ 46 | Subclass of ActionError 47 | 48 | An object that throws an error because the execution of an unalloyed operation is blocked 49 | """ 50 | 51 | 52 | class ActionRefuseError(ActionError): 53 | """ 54 | Subclass of ActionError 55 | 56 | An object that throws an error because the execution of a refused operation is blocked. 57 | """ 58 | 59 | 60 | class CLIError(ChatbotError): 61 | """ 62 | Subclass of ChatbotError 63 | 64 | The error caused by a CLI program error 65 | """ 66 | 67 | 68 | class ErrorType(Enum): 69 | """ 70 | Enumeration class for different types of errors. 71 | """ 72 | 73 | USER_ERROR = -1 74 | UNKNOWN_ERROR = 0 75 | SERVER_ERROR = 1 76 | RATE_LIMIT_ERROR = 2 77 | INVALID_REQUEST_ERROR = 3 78 | EXPIRED_ACCESS_TOKEN_ERROR = 4 79 | INVALID_ACCESS_TOKEN_ERROR = 5 80 | PROHIBITED_CONCURRENT_QUERY_ERROR = 6 81 | AUTHENTICATION_ERROR = 7 82 | CLOUDFLARE_ERROR = 8 83 | 84 | 85 | class Error(ChatbotError): 86 | """ 87 | Base class for exceptions in V1 module. 88 | """ 89 | 90 | def __init__( 91 | self, 92 | source: str, 93 | message: str, 94 | *args: object, 95 | code: Union[ErrorType, int] = ErrorType.UNKNOWN_ERROR, 96 | ) -> None: 97 | self.source: str = source 98 | self.message: str = message 99 | self.code: ErrorType | int = code 100 | super().__init__(*args) 101 | 102 | def __str__(self) -> str: 103 | return f"{self.source}: {self.message} (code: {self.code})" 104 | 105 | def __repr__(self) -> str: 106 | return f"{self.source}: {self.message} (code: {self.code})" 107 | 108 | 109 | class AuthenticationError(ChatbotError): 110 | """ 111 | Subclass of ChatbotError 112 | 113 | The object of the error thrown by a validation failure or exception 114 | """ 115 | 116 | def __init__(self, *args: object) -> None: 117 | if SUPPORT_ADD_NOTES: 118 | super().add_note( 119 | "Please check if your key is correct, maybe it may not be valid", 120 | ) 121 | super().__init__(*args) 122 | 123 | 124 | class APIConnectionError(ChatbotError): 125 | """ 126 | Subclass of ChatbotError 127 | 128 | An exception object thrown when an API connection fails or fails to connect due to network or 129 | other miscellaneous reasons 130 | """ 131 | 132 | def __init__(self, *args: object) -> None: 133 | if SUPPORT_ADD_NOTES: 134 | super().add_note( 135 | "Please check if there is a problem with your network connection", 136 | ) 137 | super().__init__(*args) 138 | 139 | 140 | class NotAllowRunning(ActionNotAllowedError): 141 | """ 142 | Subclass of ActionNotAllowedError 143 | 144 | Direct startup is not allowed for some reason 145 | """ 146 | 147 | 148 | class ResponseError(APIConnectionError): 149 | """ 150 | Subclass of APIConnectionError 151 | 152 | Error objects caused by API request errors due to network or other miscellaneous reasons 153 | """ 154 | 155 | 156 | class OpenAIError(APIConnectionError): 157 | """ 158 | Subclass of APIConnectionError 159 | 160 | Error objects caused by OpenAI's own server errors 161 | """ 162 | 163 | 164 | class RequestError(APIConnectionError): 165 | """ 166 | Subclass of APIConnectionError 167 | 168 | There is a problem with the API response due to network or other miscellaneous reasons, or there 169 | is no reply to the object that caused the error at all 170 | """ 171 | 172 | 173 | class Colors: 174 | """ 175 | Colors for printing 176 | """ 177 | 178 | HEADER = "\033[95m" 179 | OKBLUE = "\033[94m" 180 | OKCYAN = "\033[96m" 181 | OKGREEN = "\033[92m" 182 | WARNING = "\033[93m" 183 | FAIL = "\033[91m" 184 | ENDC = "\033[0m" 185 | BOLD = "\033[1m" 186 | UNDERLINE = "\033[4m" 187 | 188 | def __init__(self) -> None: 189 | if os.getenv("NO_COLOR"): 190 | Colors.HEADER = "" 191 | Colors.OKBLUE = "" 192 | Colors.OKCYAN = "" 193 | Colors.OKGREEN = "" 194 | Colors.WARNING = "" 195 | Colors.FAIL = "" 196 | Colors.ENDC = "" 197 | Colors.BOLD = "" 198 | Colors.UNDERLINE = "" 199 | -------------------------------------------------------------------------------- /src/revChatGPT/utils.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Set 3 | 4 | from prompt_toolkit import prompt 5 | from prompt_toolkit import PromptSession 6 | from prompt_toolkit.auto_suggest import AutoSuggestFromHistory 7 | from prompt_toolkit.completion import WordCompleter 8 | from prompt_toolkit.history import InMemoryHistory 9 | from prompt_toolkit.key_binding import KeyBindings 10 | 11 | bindings = KeyBindings() 12 | 13 | 14 | def create_keybindings(key: str = "c-@") -> KeyBindings: 15 | """ 16 | Create keybindings for prompt_toolkit. Default key is ctrl+space. 17 | For possible keybindings, see: https://python-prompt-toolkit.readthedocs.io/en/stable/pages/advanced_topics/key_bindings.html#list-of-special-keys 18 | """ 19 | 20 | @bindings.add(key) 21 | def _(event: dict) -> None: 22 | event.app.exit(result=event.app.current_buffer.text) 23 | 24 | return bindings 25 | 26 | 27 | def create_session() -> PromptSession: 28 | return PromptSession(history=InMemoryHistory()) 29 | 30 | 31 | def create_completer(commands: list, pattern_str: str = "$") -> WordCompleter: 32 | return WordCompleter(words=commands, pattern=re.compile(pattern_str)) 33 | 34 | 35 | def get_input( 36 | session: PromptSession = None, 37 | completer: WordCompleter = None, 38 | key_bindings: KeyBindings = None, 39 | ) -> str: 40 | """ 41 | Multiline input function. 42 | """ 43 | return ( 44 | session.prompt( 45 | completer=completer, 46 | multiline=True, 47 | auto_suggest=AutoSuggestFromHistory(), 48 | key_bindings=key_bindings, 49 | ) 50 | if session 51 | else prompt(multiline=True) 52 | ) 53 | 54 | 55 | async def get_input_async( 56 | session: PromptSession = None, 57 | completer: WordCompleter = None, 58 | ) -> str: 59 | """ 60 | Multiline input function. 61 | """ 62 | return ( 63 | await session.prompt_async( 64 | completer=completer, 65 | multiline=True, 66 | auto_suggest=AutoSuggestFromHistory(), 67 | ) 68 | if session 69 | else prompt(multiline=True) 70 | ) 71 | 72 | 73 | def get_filtered_keys_from_object(obj: object, *keys: str) -> Set[str]: 74 | """ 75 | Get filtered list of object variable names. 76 | :param keys: List of keys to include. If the first key is "not", the remaining keys will be removed from the class keys. 77 | :return: List of class keys. 78 | """ 79 | class_keys = obj.__dict__.keys() 80 | if not keys: 81 | return set(class_keys) 82 | 83 | # Remove the passed keys from the class keys. 84 | if keys[0] == "not": 85 | return {key for key in class_keys if key not in keys[1:]} 86 | # Check if all passed keys are valid 87 | if invalid_keys := set(keys) - class_keys: 88 | raise ValueError( 89 | f"Invalid keys: {invalid_keys}", 90 | ) 91 | # Only return specified keys that are in class_keys 92 | return {key for key in keys if key in class_keys} 93 | -------------------------------------------------------------------------------- /src/revChatGPT/version.py: -------------------------------------------------------------------------------- 1 | version = "6.8.6" 2 | -------------------------------------------------------------------------------- /tests/debug.bat: -------------------------------------------------------------------------------- 1 | cd %~dp0 2 | cd ../ 3 | python -m pip uninstall revChatGPT -y 4 | python setup.py install 5 | -------------------------------------------------------------------------------- /tests/test_recipient.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | 4 | from revChatGPT.V1 import AsyncChatbot 5 | from revChatGPT.V1 import Chatbot 6 | 7 | config = json.load(open("/home/acheong/.config/revChatGPT/config.json")) 8 | 9 | 10 | async def main() -> None: 11 | chatbot = AsyncChatbot(config) 12 | async for message in chatbot.ask("Hello, how are you?"): 13 | print(message.get("message")) 14 | 15 | print(await chatbot.share_conversation()) 16 | 17 | 18 | def sync_main(): 19 | chatbot = Chatbot(config) 20 | for message in chatbot.ask("Hello, how are you?"): 21 | print(message.get("message")) 22 | 23 | 24 | asyncio.run(main()) 25 | --------------------------------------------------------------------------------