├── .gitattributes ├── .github └── workflows │ ├── docker-build-push.yml │ └── sync-hugging.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── babel.cfg ├── client ├── css │ ├── button.css │ ├── buttons.css │ ├── checkbox.css │ ├── conversation.css │ ├── dropdown.css │ ├── field.css │ ├── global.css │ ├── hljs.css │ ├── label.css │ ├── main.css │ ├── message-input.css │ ├── message.css │ ├── options.css │ ├── select.css │ ├── settings.css │ ├── sidebar.css │ ├── stop-generating.css │ ├── style.css │ └── typing.css ├── html │ └── index.html ├── img │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── gpt.png │ ├── site.webmanifest │ └── user.png └── js │ ├── change-language.js │ ├── chat.js │ ├── highlight.min.js │ ├── highlightjs-copy.min.js │ ├── icons.js │ ├── sidebar-toggler.js │ └── theme-toggler.js ├── config.json ├── docker-compose.yml ├── g4f ├── Provider │ ├── Provider.py │ ├── Providers │ │ ├── AiService.py │ │ ├── Aichat.py │ │ ├── Ails.py │ │ ├── Bard.py │ │ ├── Better.py │ │ ├── Bing.py │ │ ├── ChatFree.py │ │ ├── ChatgptAi.py │ │ ├── ChatgptLogin.py │ │ ├── DeepAi.py │ │ ├── Easychat.py │ │ ├── Ezcht.py │ │ ├── Fakeopen.py │ │ ├── Forefront.py │ │ ├── GetGpt.py │ │ ├── Gravityengine.py │ │ ├── H2o.py │ │ ├── Liaobots.py │ │ ├── Lockchat.py │ │ ├── Mishalsgpt.py │ │ ├── Phind.py │ │ ├── Theb.py │ │ ├── Vercel.py │ │ ├── Weuseing.py │ │ ├── Wewordle.py │ │ ├── Xiaor.py │ │ ├── You.py │ │ ├── Yqcloud.py │ │ ├── Zeabur.py │ │ ├── helpers │ │ │ ├── gpt4love.py │ │ │ ├── phind.py │ │ │ ├── theb.py │ │ │ └── you.py │ │ └── hteyun.py │ └── __init__.py ├── README.md ├── __init__.py ├── active_providers.py ├── models.py ├── typing.py └── utils.py ├── get_working_providers.py ├── requirements.txt ├── run.py ├── server ├── babel.py ├── backend.py ├── bp.py ├── config.py └── website.py └── translations ├── README.md ├── ar_SA └── LC_MESSAGES │ └── messages.po ├── cs_CZ └── LC_MESSAGES │ └── messages.po ├── da_DK └── LC_MESSAGES │ └── messages.po ├── de_DE └── LC_MESSAGES │ └── messages.po ├── el_GR └── LC_MESSAGES │ └── messages.po ├── en_US └── LC_MESSAGES │ └── messages.po ├── es_ES └── LC_MESSAGES │ └── messages.po ├── es_MX └── LC_MESSAGES │ └── messages.po ├── fi_FI └── LC_MESSAGES │ └── messages.po ├── fr_FR └── LC_MESSAGES │ └── messages.po ├── he_IL └── LC_MESSAGES │ └── messages.po ├── hi_IN └── LC_MESSAGES │ └── messages.po ├── hu_HU └── LC_MESSAGES │ └── messages.po ├── id_ID └── LC_MESSAGES │ └── messages.po ├── it_IT └── LC_MESSAGES │ └── messages.po ├── ja_JP └── LC_MESSAGES │ └── messages.po ├── ko_KR └── LC_MESSAGES │ └── messages.po ├── nb_NO └── LC_MESSAGES │ └── messages.po ├── nl_NL └── LC_MESSAGES │ └── messages.po ├── pl_PL └── LC_MESSAGES │ └── messages.po ├── pt_BR └── LC_MESSAGES │ └── messages.po ├── ro_RO └── LC_MESSAGES │ └── messages.po ├── ru_RU └── LC_MESSAGES │ └── messages.po ├── sk_SK └── LC_MESSAGES │ └── messages.po ├── sv_SE └── LC_MESSAGES │ └── messages.po ├── th_TH └── LC_MESSAGES │ └── messages.po ├── tr_TR └── LC_MESSAGES │ └── messages.po ├── uk_UA └── LC_MESSAGES │ └── messages.po ├── vi_VN └── LC_MESSAGES │ └── messages.po ├── zh_Hans_CN └── LC_MESSAGES │ └── messages.po └── zh_Hant_TW └── LC_MESSAGES └── messages.po /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/docker-build-push.yml: -------------------------------------------------------------------------------- 1 | name: Docker Build and Push 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | build-and-push: 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - name: Checkout code 12 | uses: actions/checkout@v2 13 | 14 | - name: Set up QEMU - Support for more platforms 15 | uses: docker/setup-qemu-action@v2 16 | 17 | - name: Set up Docker Buildx 18 | uses: docker/setup-buildx-action@v2 19 | 20 | - name: Login to Docker Hub 21 | uses: docker/login-action@v1 22 | with: 23 | username: ${{ secrets.DOCKER_USERNAME }} 24 | password: ${{ secrets.DOCKER_PASSWORD }} 25 | 26 | - name: Build and push Docker image 27 | uses: docker/build-push-action@v2 28 | with: 29 | context: . 30 | file: Dockerfile 31 | platforms: linux/amd64,linux/arm64 32 | push: true 33 | tags: ${{ secrets.DOCKER_USERNAME }}/freegpt-webui:latest 34 | -------------------------------------------------------------------------------- /.github/workflows/sync-hugging.yml: -------------------------------------------------------------------------------- 1 | name: Sync with Hugging Face Hub 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Sync with Hugging Face 13 | uses: ramonvc/huggingface-sync-action@v0.0.1 14 | with: 15 | github_repo_id: ramonvc/freegpt-webui 16 | huggingface_repo_id: monra/freegpt-webui 17 | repo_type: space 18 | space_sdk: docker 19 | hf_token: ${{ secrets.HF_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | 147 | # others 148 | .config/ 149 | .upm/ 150 | .vscode/ 151 | 152 | # PyCharm 153 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 154 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 155 | # and can be added to the global gitignore or merged into this file. For a more nuclear 156 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 157 | #.idea/ 158 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt requirements.txt 6 | 7 | RUN python -m venv venv 8 | ENV PATH="/app/venv/bin:$PATH" 9 | 10 | RUN apt-get update && \ 11 | apt-get install -y --no-install-recommends build-essential libffi-dev cmake libcurl4-openssl-dev && \ 12 | pip3 install --no-cache-dir -r requirements.txt 13 | 14 | COPY . . 15 | 16 | RUN chmod -R 777 translations 17 | 18 | CMD ["python3", "./run.py"] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreeGPT WebUI 2 | ## GPT 3.5/4 3 | 4 | This project features a WebUI utilizing the [G4F API](https://github.com/xtekky/gpt4free).
5 | Experience the power of ChatGPT with a user-friendly interface, enhanced jailbreaks, and completely free. 6 | 7 | ## 8 | > [!WARNING] 9 | > It's with a heavy heart that I announce the archiving of this repository. Due to various commitments, I no longer have the time to maintain and keep it updated. 10 | > I want to express my sincere thanks to everyone who contributed to and used this project; your involvement was invaluable. 11 | > Even though this repository is being archived, it will remain available as a guide and reference for those who wish to integrate G4F with web interfaces. 12 | > I appreciate everyone's understanding and wish you all success in your future projects! 13 | 14 | ## Project Hosting and Demonstration 🌐🚀 15 | The project is hosted on multiple platforms to be tested and modified. 16 | |Platform|Status|API Key|Free|Repo|Demo| 17 | |--|--|--|--|--|--| 18 | |[replit](https://replit.com/)|![Active](https://img.shields.io/badge/Active-brightgreen)|◼️|☑️|[FreeGPT WebUI](https://replit.com/@ramonvc/freegpt-webui)|[Chat](https://freegpt-webui.ramonvc.repl.co/chat/) 19 | |[hugging face](https://huggingface.co)|![Active](https://img.shields.io/badge/Active-brightgreen)|◼️|☑️|[FreeGPT WebUI](https://huggingface.co/spaces/monra/freegpt-webui/tree/main)|[Chat](https://huggingface.co/spaces/monra/freegpt-webui) 20 | |[replit](https://replit.com/)|![Active](https://img.shields.io/badge/Active-brightgreen)|☑️|☑️|[FreeGPT WebUI - Naga Version](https://replit.com/@ramonvc/freegpt-webui-chimera)|[Chat](https://freegpt-webui-chimera.ramonvc.repl.co/chat/) 21 | |[hugging face](https://huggingface.co)|![Active](https://img.shields.io/badge/Active-brightgreen)|☑️|☑️|[FreeGPT WebUI - Naga Version](https://huggingface.co/spaces/monra/freegpt-webui-chimera/tree/main)|[Chat](https://huggingface.co/spaces/monra/freegpt-webui-chimera) 22 | 23 | ## Table of Contents 24 | - [To-Do List](#to-do-list-%EF%B8%8F) 25 | - [Getting Started](#getting-started-white_check_mark) 26 | - [Cloning the Repository](#cloning-the-repository-inbox_tray) 27 | - [Install Dependencies](#install-dependencies-wrench) 28 | - [Running the Application](#running-the-application-rocket) 29 | - [Docker](#docker-) 30 | - [Prerequisites](#prerequisites) 31 | - [Running the Docker](#running-the-docker) 32 | - [Incorporated Projects](#incorporated-projects-busts_in_silhouette) 33 | - [WebUI](#webui) 34 | - [API FreeGPT](#api-g4f) 35 | - [Star History](#star-history) 36 | - [Legal Notice](#legal-notice) 37 | 38 | ## Getting Started :white_check_mark: 39 | To get started with this project, you'll need to clone the repository and have [Python](https://www.python.org/downloads/) installed on your system. 40 | 41 | ### Cloning the Repository :inbox_tray: 42 | Run the following command to clone the repository: 43 | 44 | ``` 45 | git clone https://github.com/ramonvc/freegpt-webui.git 46 | ``` 47 | 48 | ### Install Dependencies :wrench: 49 | Navigate to the project directory: 50 | ``` 51 | cd freegpt-webui 52 | ``` 53 | 54 | Install the dependencies: 55 | ``` 56 | pip install -r requirements.txt 57 | ``` 58 | ## Running the Application :rocket: 59 | To run the application, run the following command: 60 | ``` 61 | python run.py 62 | ``` 63 | 64 | Access the application in your browser using the URL: 65 | ``` 66 | http://127.0.0.1:1338 67 | ``` 68 | or 69 | ``` 70 | http://localhost:1338 71 | ``` 72 | 73 | 74 | ## Docker 🐳 75 | ### Prerequisites 76 | Before you start, make sure you have installed [Docker](https://www.docker.com/get-started) on your machine. 77 | 78 | ### Running the Docker 79 | Pull the Docker image from Docker Hub: 80 | ``` 81 | docker pull ramonvc/freegpt-webui 82 | ``` 83 | 84 | Run the application using Docker: 85 | ``` 86 | docker run -p 1338:1338 ramonvc/freegpt-webui 87 | ``` 88 | 89 | Access the application in your browser using the URL: 90 | ``` 91 | http://127.0.0.1:1338 92 | ``` 93 | or 94 | ``` 95 | http://localhost:1338 96 | ``` 97 | 98 | When you're done using the application, stop the Docker containers using the following command: 99 | ``` 100 | docker stop 101 | ``` 102 | 103 | ## Incorporated Projects :busts_in_silhouette: 104 | I highly recommend visiting and supporting both projects. 105 | 106 | ### WebUI 107 | The application interface was incorporated from the [chatgpt-clone](https://github.com/xtekky/chatgpt-clone) repository. 108 | 109 | ### API G4F 110 | The free GPT-4 API was incorporated from the [GPT4Free](https://github.com/xtekky/gpt4free) repository. 111 | 112 |
113 | 114 | ## Star History 115 | [![Star History Chart](https://api.star-history.com/svg?repos=ramonvc/freegpt-webui&type=Timeline)](https://star-history.com/#ramonvc/freegpt-webui&Timeline) 116 | 117 |
118 | 119 | ## Legal Notice 120 | This repository is _not_ associated with or endorsed by providers of the APIs contained in this GitHub repository. This 121 | project is intended **for educational purposes only**. This is just a little personal project. Sites may contact me to 122 | improve their security or request the removal of their site from this repository. 123 | 124 | Please note the following: 125 | 126 | 1. **Disclaimer**: The APIs, services, and trademarks mentioned in this repository belong to their respective owners. 127 | This project is _not_ claiming any right over them nor is it affiliated with or endorsed by any of the providers 128 | mentioned. 129 | 130 | 2. **Responsibility**: The author of this repository is _not_ responsible for any consequences, damages, or losses 131 | arising from the use or misuse of this repository or the content provided by the third-party APIs. Users are solely 132 | responsible for their actions and any repercussions that may follow. We strongly recommend the users to follow the 133 | TOS of the each Website. 134 | 135 | 3. **Educational Purposes Only**: This repository and its content are provided strictly for educational purposes. By 136 | using the information and code provided, users acknowledge that they are using the APIs and models at their own risk 137 | and agree to comply with any applicable laws and regulations. 138 | 139 | 4. **Copyright**: All content in this repository, including but not limited to code, images, and documentation, is the 140 | intellectual property of the repository author, unless otherwise stated. Unauthorized copying, distribution, or use 141 | of any content in this repository is strictly prohibited without the express written consent of the repository 142 | author. 143 | 144 | 5. **Indemnification**: Users agree to indemnify, defend, and hold harmless the author of this repository from and 145 | against any and all claims, liabilities, damages, losses, or expenses, including legal fees and costs, arising out of 146 | or in any way connected with their use or misuse of this repository, its content, or related third-party APIs. 147 | 148 | 6. **Updates and Changes**: The author reserves the right to modify, update, or remove any content, information, or 149 | features in this repository at any time without prior notice. Users are responsible for regularly reviewing the 150 | content and any changes made to this repository. 151 | 152 | By using this repository or any code related to it, you agree to these terms. The author is not responsible for any 153 | copies, forks, or reuploads made by other users. This is the author's only account and repository. To prevent 154 | impersonation or irresponsible actions, you may comply with the GNU GPL license this Repository uses. 155 | -------------------------------------------------------------------------------- /babel.cfg: -------------------------------------------------------------------------------- 1 | [python: **/server/.py] 2 | [jinja2: **/client/html/**.html] 3 | -------------------------------------------------------------------------------- /client/css/button.css: -------------------------------------------------------------------------------- 1 | .button { 2 | display: flex; 3 | padding: 8px 12px; 4 | align-items: center; 5 | justify-content: center; 6 | border: 1px solid var(--conversations); 7 | border-radius: var(--border-radius-1); 8 | width: 100%; 9 | background: transparent; 10 | cursor: pointer; 11 | } 12 | 13 | .button span { 14 | color: var(--colour-3); 15 | font-size: 0.875rem; 16 | } 17 | 18 | .button i::before { 19 | margin-right: 8px; 20 | } 21 | 22 | @media screen and (max-width: 990px) { 23 | .button span { 24 | font-size: 0.75rem; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/css/buttons.css: -------------------------------------------------------------------------------- 1 | .buttons { 2 | display: flex; 3 | justify-content: left; 4 | } 5 | -------------------------------------------------------------------------------- /client/css/checkbox.css: -------------------------------------------------------------------------------- 1 | .checkbox input { 2 | height: 0; 3 | width: 0; 4 | display: none; 5 | } 6 | 7 | .checkbox span { 8 | font-size: 0.875rem; 9 | color: var(--colour-2); 10 | margin-left: 4px; 11 | } 12 | 13 | .checkbox label:after { 14 | content: ""; 15 | position: absolute; 16 | top: 50%; 17 | transform: translateY(-50%); 18 | left: 5px; 19 | width: 20px; 20 | height: 20px; 21 | background: var(--blur-border); 22 | border-radius: 90px; 23 | transition: 0.33s; 24 | } 25 | 26 | .checkbox input + label:after, 27 | .checkbox input:checked + label { 28 | background: var(--colour-3); 29 | } 30 | 31 | .checkbox input + label, 32 | .checkbox input:checked + label:after { 33 | background: var(--blur-border); 34 | } 35 | 36 | .checkbox input:checked + label:after { 37 | left: calc(100% - 5px - 20px); 38 | } 39 | 40 | @media screen and (max-width: 990px) { 41 | .checkbox label { 42 | width: 25px; 43 | height: 15px; 44 | } 45 | 46 | .checkbox label:after { 47 | left: 2px; 48 | width: 10px; 49 | height: 10px; 50 | } 51 | 52 | .checkbox input:checked + label:after { 53 | left: calc(100% - 2px - 10px); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /client/css/conversation.css: -------------------------------------------------------------------------------- 1 | .conversation { 2 | width: 60%; 3 | margin: 0px 16px; 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | .conversation #messages { 9 | width: 100%; 10 | display: flex; 11 | flex-direction: column; 12 | overflow: auto; 13 | overflow-wrap: break-word; 14 | padding-bottom: 8px; 15 | } 16 | 17 | .conversation .user-input { 18 | max-height: 180px; 19 | margin: 16px 0px; 20 | } 21 | 22 | .conversation .user-input input { 23 | font-size: 1rem; 24 | background: none; 25 | border: none; 26 | outline: none; 27 | color: var(--colour-3); 28 | } 29 | 30 | .conversation .user-input input::placeholder { 31 | color: var(--user-input); 32 | } 33 | 34 | .conversation-title { 35 | color: var(--colour-3); 36 | font-size: 14px; 37 | } 38 | 39 | .conversation .user-input textarea { 40 | font-size: 1rem; 41 | width: 100%; 42 | height: 100%; 43 | padding: 12px; 44 | background: none; 45 | border: none; 46 | outline: none; 47 | color: var(--colour-3); 48 | resize: vertical; 49 | max-height: 150px; 50 | min-height: 80px; 51 | } 52 | 53 | .box { 54 | backdrop-filter: blur(20px); 55 | -webkit-backdrop-filter: blur(20px); 56 | background-color: var(--blur-bg); 57 | height: 100%; 58 | width: 100%; 59 | border-radius: var(--border-radius-1); 60 | border: 1px solid var(--blur-border); 61 | } 62 | 63 | .box.input-box { 64 | position: relative; 65 | align-items: center; 66 | padding: 8px; 67 | cursor: pointer; 68 | } 69 | 70 | #send-button { 71 | position: absolute; 72 | bottom: 25%; 73 | right: 10px; 74 | z-index: 1; 75 | padding: 16px; 76 | } 77 | 78 | #cursor { 79 | line-height: 17px; 80 | margin-left: 3px; 81 | -webkit-animation: blink 0.8s infinite; 82 | animation: blink 0.8s infinite; 83 | width: 7px; 84 | height: 15px; 85 | } 86 | 87 | @keyframes blink { 88 | 0% { 89 | background: #ffffff00; 90 | } 91 | 92 | 50% { 93 | background: white; 94 | } 95 | 96 | 100% { 97 | background: #ffffff00; 98 | } 99 | } 100 | 101 | @-webkit-keyframes blink { 102 | 0% { 103 | background: #ffffff00; 104 | } 105 | 106 | 50% { 107 | background: white; 108 | } 109 | 110 | 100% { 111 | background: #ffffff00; 112 | } 113 | } 114 | 115 | /* scrollbar */ 116 | .conversation #messages::-webkit-scrollbar { 117 | width: 4px; 118 | padding: 8px 0px; 119 | } 120 | 121 | .conversation #messages::-webkit-scrollbar-track { 122 | background-color: #ffffff00; 123 | } 124 | 125 | .conversation #messages::-webkit-scrollbar-thumb { 126 | background-color: #555555; 127 | border-radius: 10px; 128 | } 129 | 130 | @media screen and (max-width: 990px) { 131 | .conversation { 132 | width: 100%; 133 | height: 90%; 134 | } 135 | } 136 | 137 | @media screen and (max-height: 720px) { 138 | .conversation.box { 139 | height: 70%; 140 | } 141 | 142 | .conversation .user-input textarea { 143 | font-size: 0.875rem; 144 | } 145 | } 146 | 147 | @media screen and (max-width: 360px) { 148 | .box { 149 | border-radius: 0; 150 | } 151 | .conversation { 152 | margin: 0; 153 | margin-top: 48px; 154 | } 155 | .conversation .user-input { 156 | margin: 2px 0 8px 0; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /client/css/dropdown.css: -------------------------------------------------------------------------------- 1 | .dropdown { 2 | border: 1px solid var(--conversations); 3 | } 4 | 5 | @media screen and (max-width: 990px) { 6 | .dropdown { 7 | padding: 4px 8px; 8 | font-size: 0.75rem; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/css/field.css: -------------------------------------------------------------------------------- 1 | .field { 2 | display: flex; 3 | align-items: center; 4 | padding: 4px; 5 | } 6 | 7 | @media screen and (max-width: 990px) { 8 | .field { 9 | flex-wrap: nowrap; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/css/global.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"); 2 | * { 3 | --font-1: "Inter", sans-serif; 4 | --section-gap: 24px; 5 | --border-radius-1: 8px; 6 | margin: 0; 7 | padding: 0; 8 | box-sizing: border-box; 9 | position: relative; 10 | font-family: var(--font-1); 11 | } 12 | 13 | .theme-light { 14 | --colour-1: #f5f5f5; 15 | --colour-2: #000000; 16 | --colour-3: #474747; 17 | --colour-4: #949494; 18 | --colour-5: #ebebeb; 19 | --colour-6: #dadada; 20 | 21 | --accent: #3a3a3a; 22 | --blur-bg: #ffffff; 23 | --blur-border: #dbdbdb; 24 | --user-input: #282828; 25 | --conversations: #666666; 26 | } 27 | 28 | .theme-dark { 29 | --colour-1: #181818; 30 | --colour-2: #ccc; 31 | --colour-3: #dadada; 32 | --colour-4: #f0f0f0; 33 | --colour-5: #181818; 34 | --colour-6: #242424; 35 | 36 | --accent: #151718; 37 | --blur-bg: #242627; 38 | --blur-border: #242627; 39 | --user-input: #f5f5f5; 40 | --conversations: #555555; 41 | } 42 | 43 | html, 44 | body { 45 | background: var(--colour-1); 46 | color: var(--colour-3); 47 | } 48 | 49 | ol, 50 | ul { 51 | padding-left: 20px; 52 | } 53 | 54 | .shown { 55 | display: flex !important; 56 | } 57 | 58 | a:-webkit-any-link { 59 | color: var(--accent); 60 | } 61 | 62 | pre { 63 | white-space: pre-wrap; 64 | } 65 | 66 | @media screen and (max-height: 720px) { 67 | :root { 68 | --section-gap: 16px; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /client/css/hljs.css: -------------------------------------------------------------------------------- 1 | .hljs { 2 | color: #e9e9f4; 3 | background: #28293629; 4 | border-radius: var(--border-radius-1); 5 | border: 1px solid var(--blur-border); 6 | font-size: 15px; 7 | word-wrap: break-word; 8 | white-space: pre-wrap; 9 | } 10 | 11 | /* style for hljs copy */ 12 | .hljs-copy-wrapper { 13 | position: relative; 14 | overflow: hidden; 15 | } 16 | 17 | .hljs-copy-wrapper:hover .hljs-copy-button, 18 | .hljs-copy-button:focus { 19 | transform: translateX(0); 20 | } 21 | 22 | .hljs-copy-button { 23 | position: absolute; 24 | transform: translateX(calc(100% + 1.125em)); 25 | top: 1em; 26 | right: 1em; 27 | width: 2rem; 28 | height: 2rem; 29 | text-indent: -9999px; 30 | color: #fff; 31 | border-radius: 0.25rem; 32 | border: 1px solid #ffffff22; 33 | background-color: #2d2b57; 34 | background-image: url('data:image/svg+xml;utf-8,'); 35 | background-repeat: no-repeat; 36 | background-position: center; 37 | transition: background-color 200ms ease, transform 200ms ease-out; 38 | } 39 | 40 | .hljs-copy-button:hover { 41 | border-color: #ffffff44; 42 | } 43 | 44 | .hljs-copy-button:active { 45 | border-color: #ffffff66; 46 | } 47 | 48 | .hljs-copy-button[data-copied="true"] { 49 | text-indent: 0; 50 | width: auto; 51 | background-image: none; 52 | } 53 | 54 | .hljs-copy-alert { 55 | clip: rect(0 0 0 0); 56 | clip-path: inset(50%); 57 | height: 1px; 58 | overflow: hidden; 59 | position: absolute; 60 | white-space: nowrap; 61 | width: 1px; 62 | } 63 | 64 | @media (prefers-reduced-motion) { 65 | .hljs-copy-button { 66 | transition: none; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /client/css/label.css: -------------------------------------------------------------------------------- 1 | label { 2 | cursor: pointer; 3 | text-indent: -9999px; 4 | width: 50px; 5 | height: 30px; 6 | backdrop-filter: blur(20px); 7 | -webkit-backdrop-filter: blur(20px); 8 | background-color: var(--blur-bg); 9 | border-radius: var(--border-radius-1); 10 | border: 1px solid var(--blur-border); 11 | display: block; 12 | border-radius: 100px; 13 | position: relative; 14 | overflow: hidden; 15 | transition: 0.33s; 16 | } 17 | -------------------------------------------------------------------------------- /client/css/main.css: -------------------------------------------------------------------------------- 1 | .main-container { 2 | display: flex; 3 | padding: var(--section-gap); 4 | height: 100vh; 5 | justify-content: center; 6 | box-sizing: border-box; 7 | } 8 | 9 | @media screen and (max-width: 360px) { 10 | .main-container { 11 | padding: 0px; 12 | height: 90vh; 13 | } 14 | } -------------------------------------------------------------------------------- /client/css/message-input.css: -------------------------------------------------------------------------------- 1 | #message-input { 2 | margin-right: 30px; 3 | height: 64px; 4 | } 5 | 6 | #message-input::-webkit-scrollbar { 7 | width: 5px; 8 | } 9 | 10 | #message-input::-webkit-scrollbar-track { 11 | background: #f1f1f1; 12 | } 13 | 14 | #message-input::-webkit-scrollbar-thumb { 15 | background: #c7a2ff; 16 | } 17 | 18 | #message-input::-webkit-scrollbar-thumb:hover { 19 | background: #8b3dff; 20 | } 21 | 22 | @media screen and (max-width: 360px) { 23 | #message-input { 24 | margin: 0; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /client/css/message.css: -------------------------------------------------------------------------------- 1 | .message { 2 | width: 100%; 3 | overflow-wrap: break-word; 4 | display: flex; 5 | gap: var(--section-gap); 6 | padding: var(--section-gap); 7 | padding-bottom: 0; 8 | } 9 | 10 | .message:last-child { 11 | animation: 0.6s show_message; 12 | } 13 | 14 | @keyframes show_message { 15 | from { 16 | transform: translateY(10px); 17 | opacity: 0; 18 | } 19 | } 20 | 21 | .message .avatar-container img { 22 | max-width: 48px; 23 | max-height: 48px; 24 | box-shadow: 0.4px 0.5px 0.7px -2px rgba(0, 0, 0, 0.08), 1.1px 1.3px 2px -2px rgba(0, 0, 0, 0.041), 25 | 2.7px 3px 4.8px -2px rgba(0, 0, 0, 0.029), 9px 10px 16px -2px rgba(0, 0, 0, 0.022); 26 | } 27 | 28 | .message .content { 29 | display: flex; 30 | flex-direction: column; 31 | width: 90%; 32 | gap: 18px; 33 | } 34 | 35 | .message .content p, 36 | .message .content li, 37 | .message .content code { 38 | font-size: 1rem; 39 | line-height: 1.3; 40 | } 41 | 42 | @media screen and (max-height: 720px) { 43 | .message { 44 | padding: 12px; 45 | gap: 0; 46 | } 47 | 48 | .message .content { 49 | margin-left: 8px; 50 | width: 80%; 51 | } 52 | 53 | .message .avatar-container img { 54 | max-width: 32px; 55 | max-height: 32px; 56 | } 57 | 58 | .message .content, 59 | .message .content p, 60 | .message .content li, 61 | .message .content code { 62 | font-size: 0.875rem; 63 | line-height: 1.3; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /client/css/options.css: -------------------------------------------------------------------------------- 1 | .options-container { 2 | display: flex; 3 | flex-wrap: wrap; 4 | } 5 | 6 | @media screen and (max-width: 990px) { 7 | .options-container { 8 | justify-content: space-between; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/css/select.css: -------------------------------------------------------------------------------- 1 | select { 2 | -webkit-border-radius: 8px; 3 | -moz-border-radius: 8px; 4 | border-radius: 8px; 5 | 6 | -webkit-backdrop-filter: blur(20px); 7 | backdrop-filter: blur(20px); 8 | 9 | cursor: pointer; 10 | background-color: var(--blur-bg); 11 | border: 1px solid var(--blur-border); 12 | color: var(--colour-3); 13 | display: block; 14 | position: relative; 15 | overflow: hidden; 16 | outline: none; 17 | padding: 8px 16px; 18 | 19 | appearance: none; 20 | } 21 | 22 | /* scrollbar */ 23 | select.dropdown::-webkit-scrollbar { 24 | width: 4px; 25 | padding: 8px 0px; 26 | } 27 | 28 | select.dropdown::-webkit-scrollbar-track { 29 | background-color: #ffffff00; 30 | } 31 | 32 | select.dropdown::-webkit-scrollbar-thumb { 33 | background-color: #555555; 34 | border-radius: 10px; 35 | } 36 | -------------------------------------------------------------------------------- /client/css/settings.css: -------------------------------------------------------------------------------- 1 | .settings-container { 2 | color: var(--colour-2); 3 | margin: 24px 0px 8px 0px; 4 | justify-content: center; 5 | } 6 | 7 | .settings-container span { 8 | font-size: 0.875rem; 9 | margin: 0; 10 | } 11 | 12 | .settings-container label { 13 | width: 24px; 14 | height: 16px; 15 | } 16 | 17 | .settings-container .field { 18 | justify-content: space-between; 19 | } 20 | 21 | .settings-container .checkbox input + label, 22 | .settings-container .checkbox input:checked + label:after { 23 | background: var(--colour-1); 24 | } 25 | 26 | .settings-container .checkbox input + label:after, 27 | .settings-container .checkbox input:checked + label { 28 | background: var(--colour-3); 29 | } 30 | 31 | .settings-container .checkbox label:after { 32 | left: 2px; 33 | width: 10px; 34 | height: 10px; 35 | } 36 | 37 | .settings-container .checkbox input:checked + label:after { 38 | left: calc(100% - 2px - 10px); 39 | } 40 | 41 | .settings-container .dropdown { 42 | padding: 4px 8px; 43 | font-size: 0.75rem; 44 | } 45 | -------------------------------------------------------------------------------- /client/css/sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | max-width: 260px; 3 | padding: var(--section-gap); 4 | flex-shrink: 0; 5 | display: flex; 6 | flex-direction: column; 7 | justify-content: space-between; 8 | } 9 | 10 | .sidebar .title { 11 | font-size: 14px; 12 | font-weight: 500; 13 | } 14 | 15 | .sidebar .conversation-sidebar { 16 | padding: 8px 12px; 17 | display: flex; 18 | gap: 18px; 19 | align-items: center; 20 | user-select: none; 21 | justify-content: space-between; 22 | } 23 | 24 | .sidebar .conversation-sidebar .left { 25 | cursor: pointer; 26 | display: flex; 27 | align-items: center; 28 | gap: 10px; 29 | } 30 | 31 | .sidebar i { 32 | color: var(--conversations); 33 | cursor: pointer; 34 | } 35 | 36 | .sidebar .top { 37 | display: flex; 38 | flex-direction: column; 39 | overflow: hidden; 40 | gap: 16px; 41 | padding-right: 8px; 42 | } 43 | 44 | .sidebar .top:hover { 45 | overflow: auto; 46 | } 47 | 48 | .sidebar .info { 49 | padding: 8px 12px 0px 12px; 50 | display: flex; 51 | align-items: center; 52 | justify-content: center; 53 | user-select: none; 54 | background: transparent; 55 | width: 100%; 56 | border: none; 57 | text-decoration: none; 58 | } 59 | 60 | .sidebar .info span { 61 | color: var(--conversations); 62 | line-height: 1.5; 63 | font-size: 0.75rem; 64 | } 65 | 66 | .sidebar .info i::before { 67 | margin-right: 8px; 68 | } 69 | 70 | .sidebar-footer { 71 | width: 100%; 72 | margin-top: 16px; 73 | display: flex; 74 | flex-direction: column; 75 | } 76 | 77 | .sidebar-footer button { 78 | cursor: pointer; 79 | user-select: none; 80 | background: transparent; 81 | } 82 | 83 | .sidebar.shown { 84 | position: fixed; 85 | top: 0; 86 | left: 0; 87 | width: 100%; 88 | height: 100%; 89 | z-index: 1000; 90 | } 91 | 92 | .sidebar.shown .box { 93 | background-color: #16171a; 94 | width: 80%; 95 | height: 100%; 96 | overflow-y: auto; 97 | } 98 | 99 | @keyframes spinner { 100 | to { 101 | transform: rotate(360deg); 102 | } 103 | } 104 | 105 | /* scrollbar */ 106 | .sidebar .top::-webkit-scrollbar { 107 | width: 4px; 108 | padding: 8px 0px; 109 | } 110 | 111 | .sidebar .top::-webkit-scrollbar-track { 112 | background-color: #ffffff00; 113 | } 114 | 115 | .sidebar .top::-webkit-scrollbar-thumb { 116 | background-color: #555555; 117 | border-radius: 10px; 118 | } 119 | 120 | .spinner:before { 121 | content: ""; 122 | box-sizing: border-box; 123 | position: absolute; 124 | top: 50%; 125 | left: 45%; 126 | width: 20px; 127 | height: 20px; 128 | border-radius: 50%; 129 | border: 1px solid var(--conversations); 130 | border-top-color: white; 131 | animation: spinner 0.6s linear infinite; 132 | } 133 | 134 | .menu-button { 135 | display: none !important; 136 | position: absolute; 137 | z-index: 100000; 138 | top: 0; 139 | left: 0; 140 | margin: 10px; 141 | font-size: 1rem; 142 | cursor: pointer; 143 | width: 30px; 144 | height: 30px; 145 | justify-content: center; 146 | align-items: center; 147 | transition: 0.33s; 148 | } 149 | 150 | .menu-button i { 151 | transition: 0.33s; 152 | } 153 | 154 | .rotated { 155 | transform: rotate(360deg); 156 | } 157 | 158 | .menu-button.rotated { 159 | position: fixed; 160 | top: 10px; 161 | left: 10px; 162 | z-index: 1001; 163 | } 164 | 165 | @media screen and (max-width: 990px) { 166 | .sidebar { 167 | display: none; 168 | width: 100%; 169 | max-width: none; 170 | } 171 | 172 | .menu-button { 173 | display: flex !important; 174 | } 175 | } 176 | 177 | @media (max-width: 990px) { 178 | .sidebar .top { 179 | padding-top: 48px; 180 | } 181 | } 182 | 183 | @media (min-width: 768px) { 184 | .sidebar.shown { 185 | position: static; 186 | width: auto; 187 | height: auto; 188 | background-color: transparent; 189 | } 190 | 191 | .sidebar.shown .box { 192 | background-color: #16171a; 193 | width: auto; 194 | height: auto; 195 | overflow-y: auto; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /client/css/stop-generating.css: -------------------------------------------------------------------------------- 1 | .stop-generating { 2 | position: absolute; 3 | bottom: 128px; 4 | left: 50%; 5 | transform: translateX(-50%); 6 | z-index: 1000000; 7 | } 8 | 9 | .stop-generating button { 10 | backdrop-filter: blur(20px); 11 | -webkit-backdrop-filter: blur(20px); 12 | background-color: var(--blur-bg); 13 | color: var(--colour-3); 14 | cursor: pointer; 15 | animation: show_popup 0.4s; 16 | } 17 | 18 | @keyframes show_popup { 19 | from { 20 | opacity: 0; 21 | transform: translateY(10px); 22 | } 23 | } 24 | 25 | @keyframes hide_popup { 26 | to { 27 | opacity: 0; 28 | transform: translateY(10px); 29 | } 30 | } 31 | 32 | .stop-generating-hiding button { 33 | animation: hide_popup 0.4s; 34 | } 35 | 36 | .stop-generating-hidden button { 37 | display: none; 38 | } 39 | -------------------------------------------------------------------------------- /client/css/style.css: -------------------------------------------------------------------------------- 1 | @import "./global.css"; 2 | @import "./hljs.css"; 3 | @import "./main.css"; 4 | @import "./sidebar.css"; 5 | @import "./conversation.css"; 6 | @import "./message.css"; 7 | @import "./stop-generating.css"; 8 | @import "./typing.css"; 9 | @import "./checkbox.css"; 10 | @import "./label.css"; 11 | @import "./button.css"; 12 | @import "./buttons.css"; 13 | @import "./dropdown.css"; 14 | @import "./field.css"; 15 | @import "./select.css"; 16 | @import "./options.css"; 17 | @import "./settings.css"; 18 | @import "./message-input.css"; 19 | -------------------------------------------------------------------------------- /client/css/typing.css: -------------------------------------------------------------------------------- 1 | .typing { 2 | position: absolute; 3 | top: -25px; 4 | left: 0; 5 | font-size: 14px; 6 | animation: show_popup 0.4s; 7 | } 8 | 9 | .typing-hiding { 10 | animation: hide_popup 0.4s; 11 | } 12 | 13 | .typing-hidden { 14 | display: none; 15 | } 16 | -------------------------------------------------------------------------------- /client/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 19 | 24 | 29 | 30 | 33 | FreeGPT 34 | 35 | 36 | 37 |
38 | 71 |
72 |
73 | 76 |
77 |
78 |
79 |
80 | 86 |
87 | 88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | 100 |
101 |
102 | 107 |
108 |
109 |
110 | 111 | 112 | {{_('Web Access')}} 113 |
114 |
115 |
116 |
117 |
118 | 121 | 122 | 123 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /client/img/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/android-chrome-192x192.png -------------------------------------------------------------------------------- /client/img/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/android-chrome-512x512.png -------------------------------------------------------------------------------- /client/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/apple-touch-icon.png -------------------------------------------------------------------------------- /client/img/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/favicon-16x16.png -------------------------------------------------------------------------------- /client/img/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/favicon-32x32.png -------------------------------------------------------------------------------- /client/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/favicon.ico -------------------------------------------------------------------------------- /client/img/gpt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/gpt.png -------------------------------------------------------------------------------- /client/img/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/assets/img/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/assets/img/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } -------------------------------------------------------------------------------- /client/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramon-victor/freegpt-webui/098db3dfeb41555c2ca9269df0f13e10ec1c35dc/client/img/user.png -------------------------------------------------------------------------------- /client/js/change-language.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', fetchLanguages); 2 | 3 | async function fetchLanguages() { 4 | try { 5 | const [languagesResponse, currentLanguageResponse] = await Promise.all([ 6 | fetch(`${url_prefix}/get-languages`), 7 | fetch(`${url_prefix}/get-locale`) 8 | ]); 9 | 10 | const languages = await languagesResponse.json(); 11 | const currentLanguage = await currentLanguageResponse.text(); 12 | 13 | const languageSelect = document.getElementById('language'); 14 | languages.forEach(lang => { 15 | const option = document.createElement('option'); 16 | option.value = lang; 17 | option.textContent = lang; 18 | languageSelect.appendChild(option); 19 | }); 20 | 21 | const savedLanguage = localStorage.getItem("language") || currentLanguage; 22 | setLanguageOnPageLoad(savedLanguage); 23 | } catch (error) { 24 | console.error("Failed to fetch languages or current language"); 25 | } 26 | } 27 | 28 | function setLanguageOnPageLoad(language) { 29 | document.getElementById("language").value = language; 30 | } 31 | 32 | function changeLanguage(lang) { 33 | fetch(`${url_prefix}/change-language`, { 34 | method: "POST", 35 | headers: { 36 | "Content-Type": "application/json", 37 | }, 38 | body: JSON.stringify({ language: lang }), 39 | }).then((response) => { 40 | if (response.ok) { 41 | localStorage.setItem("language", lang); 42 | location.reload(); 43 | } else { 44 | console.error("Failed to change language"); 45 | } 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /client/js/highlightjs-copy.min.js: -------------------------------------------------------------------------------- 1 | class CopyButtonPlugin{constructor(options={}){self.hook=options.hook;self.callback=options.callback}"after:highlightElement"({el,text}){let button=Object.assign(document.createElement("button"),{innerHTML:"Copy",className:"hljs-copy-button"});button.dataset.copied=false;el.parentElement.classList.add("hljs-copy-wrapper");el.parentElement.appendChild(button);el.parentElement.style.setProperty("--hljs-theme-background",window.getComputedStyle(el).backgroundColor);button.onclick=function(){if(!navigator.clipboard)return;let newText=text;if(hook&&typeof hook==="function"){newText=hook(text,el)||text}navigator.clipboard.writeText(newText).then(function(){button.innerHTML="Copied!";button.dataset.copied=true;let alert=Object.assign(document.createElement("div"),{role:"status",className:"hljs-copy-alert",innerHTML:"Copied to clipboard"});el.parentElement.appendChild(alert);setTimeout(()=>{button.innerHTML="Copy";button.dataset.copied=false;el.parentElement.removeChild(alert);alert=null},2e3)}).then(function(){if(typeof callback==="function")return callback(newText,el)})}}} -------------------------------------------------------------------------------- /client/js/icons.js: -------------------------------------------------------------------------------- 1 | window.FontAwesomeKitConfig={asyncLoading:{enabled:!1},autoA11y:{enabled:!0},baseUrl:"https://ka-f.fontawesome.com",baseUrlKit:"https://kit-pro.fontawesome.com",detectConflictsUntil:null,iconUploads:{},id:96462084,license:"pro",method:"css",minify:{enabled:!0},token:"d0514f1901",v4FontFaceShim:{enabled:!0},v4shim:{enabled:!0},v5FontFaceShim:{enabled:!0},version:"6.1.1"},function(t){"function"==typeof define&&define.amd?define("kit-loader",t):t()}(function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function n(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,o)}return n}function o(t){for(var o=1;ot.length)&&(e=t.length);for(var n=0,o=new Array(e);n2&&void 0!==arguments[2]?arguments[2]:function(){},r=e.document||r,i=a.bind(a,r,["fa","fab","fas","far","fal","fad","fak"]),u=Object.keys(t.iconUploads||{}).length>0;t.autoA11y.enabled&&n(i);var f=[{id:"fa-main",addOn:void 0}];t.v4shim&&t.v4shim.enabled&&f.push({id:"fa-v4-shims",addOn:"-v4-shims"}),t.v5FontFaceShim&&t.v5FontFaceShim.enabled&&f.push({id:"fa-v5-font-face",addOn:"-v5-font-face"}),t.v4FontFaceShim&&t.v4FontFaceShim.enabled&&f.push({id:"fa-v4-font-face",addOn:"-v4-font-face"}),u&&f.push({id:"fa-kit-upload",customCss:!0});var s=f.map(function(n){return new F(function(r,i){E(n.customCss?function(t){return t.baseUrlKit+"/"+t.token+"/"+t.id+"/kit-upload.css"}(t):c(t,{addOn:n.addOn,minify:t.minify.enabled}),e).then(function(i){r(function(t,e){var n=e.contentFilter||function(t,e){return t},o=document.createElement("style"),r=document.createTextNode(n(t,e));return o.appendChild(r),o.media="all",e.id&&o.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&o.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),o}(i,o(o({},e),{},{baseUrl:t.baseUrl,version:t.version,id:n.id,contentFilter:function(t,e){return _(t,e.baseUrl,e.version)}})))}).catch(i)})});return F.all(s)}function P(t,e){var n=document.createElement("SCRIPT"),o=document.createTextNode(t);return n.appendChild(o),n.referrerPolicy="strict-origin",e.id&&n.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n}function U(t){var e,n=[],o=document,r=(o.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(o.readyState);r||o.addEventListener("DOMContentLoaded",e=function(){for(o.removeEventListener("DOMContentLoaded",e),r=1;e=n.shift();)e()}),r?setTimeout(t,0):n.push(t)}try{if(window.FontAwesomeKitConfig){var k=window.FontAwesomeKitConfig,L={detectingConflicts:k.detectConflictsUntil&&new Date<=new Date(k.detectConflictsUntil),detectionIgnoreAttr:"data-fa-detection-ignore",fetch:window.fetch,token:k.token,XMLHttpRequest:window.XMLHttpRequest,document:document},I=document.currentScript,T=I?I.parentElement:document.head;(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return"js"===t.method?function(t,e){e.autoA11y=t.autoA11y.enabled,"pro"===t.license&&(e.autoFetchSvg=!0,e.fetchSvgFrom=t.baseUrl+"/releases/"+("latest"===t.version?"latest":"v".concat(t.version))+"/svgs",e.fetchUploadedSvgFrom=t.uploadsUrl);var n=[];return t.v4shim.enabled&&n.push(new F(function(n,r){E(c(t,{addOn:"-v4-shims",minify:t.minify.enabled}),e).then(function(t){n(P(t,o(o({},e),{},{id:"fa-v4-shims"})))}).catch(r)})),n.push(new F(function(n,r){E(c(t,{minify:t.minify.enabled}),e).then(function(t){var r=P(t,o(o({},e),{},{id:"fa-main"}));n(function(t,e){var n=e&&void 0!==e.autoFetchSvg?e.autoFetchSvg:void 0,o=e&&void 0!==e.autoA11y?e.autoA11y:void 0;return void 0!==o&&t.setAttribute("data-auto-a11y",o?"true":"false"),n&&(t.setAttributeNode(document.createAttribute("data-auto-fetch-svg")),t.setAttribute("data-fetch-svg-from",e.fetchSvgFrom),t.setAttribute("data-fetch-uploaded-svg-from",e.fetchUploadedSvgFrom)),t}(r,e))}).catch(r)})),F.all(n)}(t,e):"css"===t.method?C(t,e,function(t){U(t),function(t){"undefined"!=typeof MutationObserver&&new MutationObserver(t).observe(document,{childList:!0,subtree:!0})}(t)}):void 0})(k,L).then(function(t){t.map(function(t){try{T.insertBefore(t,I?I.nextSibling:null)}catch(e){T.appendChild(t)}}),L.detectingConflicts&&I&&U(function(){I.setAttributeNode(document.createAttribute(L.detectionIgnoreAttr));var t=function(t,e){var n=document.createElement("script");return e&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n.src=c(t,{baseFilename:"conflict-detection",fileSuffix:"js",subdir:"js",minify:t.minify.enabled}),n}(k,L);document.body.appendChild(t)})}).catch(function(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))})}}catch(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))}}); -------------------------------------------------------------------------------- /client/js/sidebar-toggler.js: -------------------------------------------------------------------------------- 1 | const sidebar = document.querySelector(".sidebar"); 2 | const menuButton = document.querySelector(".menu-button"); 3 | 4 | function toggleSidebar(event) { 5 | if (sidebar.classList.contains("shown")) { 6 | hideSidebar(event.target); 7 | } else { 8 | showSidebar(event.target); 9 | } 10 | window.scrollTo(0, 0); 11 | } 12 | 13 | function showSidebar(target) { 14 | sidebar.classList.add("shown"); 15 | target.classList.add("rotated"); 16 | document.body.style.overflow = "hidden"; 17 | } 18 | 19 | function hideSidebar(target) { 20 | sidebar.classList.remove("shown"); 21 | target.classList.remove("rotated"); 22 | document.body.style.overflow = "auto"; 23 | } 24 | 25 | menuButton.addEventListener("click", toggleSidebar); 26 | 27 | document.body.addEventListener('click', function(event) { 28 | if (event.target.matches('.conversation-title')) { 29 | const menuButtonStyle = window.getComputedStyle(menuButton); 30 | if (menuButtonStyle.display !== 'none') { 31 | hideSidebar(menuButton); 32 | } 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /client/js/theme-toggler.js: -------------------------------------------------------------------------------- 1 | var switch_theme_toggler = document.getElementById("theme-toggler"); 2 | 3 | switch_theme_toggler.addEventListener("change", toggleTheme); 4 | 5 | function setTheme(themeName) { 6 | localStorage.setItem("theme", themeName); 7 | document.documentElement.className = themeName; 8 | } 9 | 10 | function toggleTheme() { 11 | var currentTheme = localStorage.getItem("theme"); 12 | var newTheme = currentTheme === "theme-dark" ? "theme-light" : "theme-dark"; 13 | 14 | setTheme(newTheme); 15 | switch_theme_toggler.checked = newTheme === "theme-dark"; 16 | } 17 | 18 | (function () { 19 | var currentTheme = localStorage.getItem("theme") || "theme-dark"; 20 | setTheme(currentTheme); 21 | switch_theme_toggler.checked = currentTheme === "theme-dark"; 22 | })(); 23 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "site_config": { 3 | "host": "0.0.0.0", 4 | "port": 1338, 5 | "debug": false 6 | }, 7 | "url_prefix": "" 8 | } 9 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | services: 4 | freegpt-webui: 5 | image: freegpt-webui 6 | container_name: freegpt-webui 7 | build: 8 | context: . 9 | dockerfile: Dockerfile 10 | ports: 11 | - "1338:1338" 12 | -------------------------------------------------------------------------------- /g4f/Provider/Provider.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ..typing import sha256, Dict, get_type_hints 3 | 4 | url = None 5 | model = None 6 | supports_stream = False 7 | needs_auth = False 8 | 9 | 10 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 11 | return 12 | 13 | 14 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 15 | '(%s)' % ', '.join( 16 | [f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) 17 | -------------------------------------------------------------------------------- /g4f/Provider/Providers/AiService.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from ...typing import get_type_hints 4 | 5 | url = "https://aiservice.vercel.app/api/chat/answer" 6 | model = ['gpt-3.5-turbo'] 7 | supports_stream = False 8 | needs_auth = False 9 | 10 | 11 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 12 | base = '' 13 | for message in messages: 14 | base += '%s: %s\n' % (message['role'], message['content']) 15 | base += 'assistant:' 16 | 17 | headers = { 18 | "accept": "*/*", 19 | "content-type": "text/plain;charset=UTF-8", 20 | "sec-fetch-dest": "empty", 21 | "sec-fetch-mode": "cors", 22 | "sec-fetch-site": "same-origin", 23 | "Referer": "https://aiservice.vercel.app/chat", 24 | } 25 | data = { 26 | "input": base 27 | } 28 | response = requests.post(url, headers=headers, json=data) 29 | if response.status_code == 200: 30 | _json = response.json() 31 | yield _json['data'] 32 | else: 33 | print(f"Error Occurred::{response.status_code}") 34 | return None 35 | 36 | 37 | 38 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 39 | '(%s)' % ', '.join( 40 | [f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) -------------------------------------------------------------------------------- /g4f/Provider/Providers/Aichat.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | import json 4 | from ...typing import sha256, Dict, get_type_hints 5 | 6 | url = 'https://hteyun.com' 7 | model = ['gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-16k-0613', 'gpt-3.5-turbo-0613'] 8 | supports_stream = True 9 | needs_auth = False 10 | 11 | def _create_completion(model: str, messages: list, stream: bool, temperature: float = 0.7, **kwargs): 12 | headers = { 13 | 'Content-Type': 'application/json', 14 | } 15 | data = { 16 | 'model': model, 17 | 'temperature': 0.7, 18 | 'presence_penalty': 0, 19 | 'messages': messages, 20 | } 21 | response = requests.post(url + '/api/chat-stream', 22 | json=data, stream=True) 23 | 24 | if stream: 25 | for chunk in response.iter_content(chunk_size=None): 26 | chunk = chunk.decode('utf-8') 27 | if chunk.strip(): 28 | message = json.loads(chunk)['choices'][0]['message']['content'] 29 | yield message 30 | else: 31 | message = response.json()['choices'][0]['message']['content'] 32 | yield message 33 | 34 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 35 | '(%s)' % ', '.join([f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) -------------------------------------------------------------------------------- /g4f/Provider/Providers/Ails.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import json 4 | import uuid 5 | import hashlib 6 | import requests 7 | 8 | from ...typing import sha256, Dict, get_type_hints 9 | from datetime import datetime 10 | 11 | url: str = 'https://ai.ls' 12 | model: str = 'gpt-3.5-turbo' 13 | supports_stream = True 14 | needs_auth = False 15 | working = True 16 | 17 | 18 | class Utils: 19 | def hash(json_data: Dict[str, str]) -> sha256: 20 | 21 | base_string: str = '%s:%s:%s:%s' % ( 22 | json_data['t'], 23 | json_data['m'], 24 | 'WI,2rU#_r:r~aF4aJ36[.Z(/8Rv93Rf', 25 | len(json_data['m']) 26 | ) 27 | 28 | return hashlib.sha256(base_string.encode()).hexdigest() 29 | 30 | def format_timestamp(timestamp: int) -> str: 31 | 32 | e = timestamp 33 | n = e % 10 34 | r = n + 1 if n % 2 == 0 else n 35 | return str(e - n + r) 36 | 37 | 38 | def _create_completion(model: str, messages: list, temperature: float = 0.6, stream: bool = False, **kwargs): 39 | 40 | headers = { 41 | 'authority': 'api.caipacity.com', 42 | 'accept': '*/*', 43 | 'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3', 44 | 'authorization': 'Bearer free', 45 | 'client-id': str(uuid.uuid4()), 46 | 'client-v': '0.1.249', 47 | 'content-type': 'application/json', 48 | 'origin': 'https://ai.ls', 49 | 'referer': 'https://ai.ls/', 50 | 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', 51 | 'sec-ch-ua-mobile': '?0', 52 | 'sec-ch-ua-platform': '"Windows"', 53 | 'sec-fetch-dest': 'empty', 54 | 'sec-fetch-mode': 'cors', 55 | 'sec-fetch-site': 'cross-site', 56 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 57 | } 58 | 59 | timestamp = Utils.format_timestamp(int(time.time() * 1000)) 60 | 61 | sig = { 62 | 'd': datetime.now().strftime('%Y-%m-%d'), 63 | 't': timestamp, 64 | 's': Utils.hash({ 65 | 't': timestamp, 66 | 'm': messages[-1]['content']})} 67 | 68 | json_data = json.dumps(separators=(',', ':'), obj={ 69 | 'model': 'gpt-3.5-turbo', 70 | 'temperature': 0.6, 71 | 'stream': True, 72 | 'messages': messages} | sig) 73 | 74 | response = requests.post('https://api.caipacity.com/v1/chat/completions', 75 | headers=headers, data=json_data, stream=True) 76 | 77 | for token in response.iter_lines(): 78 | if b'content' in token: 79 | completion_chunk = json.loads(token.decode().replace('data: ', '')) 80 | token = completion_chunk['choices'][0]['delta'].get('content') 81 | if token != None: 82 | yield token 83 | 84 | 85 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 86 | '(%s)' % ', '.join( 87 | [f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) 88 | -------------------------------------------------------------------------------- /g4f/Provider/Providers/Bard.py: -------------------------------------------------------------------------------- 1 | import os, requests, json, browser_cookie3, re, random 2 | from ...typing import sha256, Dict, get_type_hints 3 | 4 | url = 'https://bard.google.com' 5 | model = ['Palm2'] 6 | supports_stream = False 7 | needs_auth = True 8 | 9 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 10 | psid = {cookie.name: cookie.value for cookie in browser_cookie3.chrome( 11 | domain_name='.google.com')}['__Secure-1PSID'] 12 | 13 | formatted = '\n'.join([ 14 | '%s: %s' % (message['role'], message['content']) for message in messages 15 | ]) 16 | prompt = f'{formatted}\nAssistant:' 17 | 18 | proxy = kwargs.get('proxy', False) 19 | if proxy == False: 20 | print('warning!, you did not give a proxy, a lot of countries are banned from Google Bard, so it may not work') 21 | 22 | snlm0e = None 23 | conversation_id = None 24 | response_id = None 25 | choice_id = None 26 | 27 | client = requests.Session() 28 | client.proxies = { 29 | 'http': f'http://{proxy}', 30 | 'https': f'http://{proxy}'} if proxy else None 31 | 32 | client.headers = { 33 | 'authority': 'bard.google.com', 34 | 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8', 35 | 'origin': 'https://bard.google.com', 36 | 'referer': 'https://bard.google.com/', 37 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', 38 | 'x-same-domain': '1', 39 | 'cookie': f'__Secure-1PSID={psid}' 40 | } 41 | 42 | snlm0e = re.search(r'SNlM0e\":\"(.*?)\"', 43 | client.get('https://bard.google.com/').text).group(1) if not snlm0e else snlm0e 44 | 45 | params = { 46 | 'bl': 'boq_assistant-bard-web-server_20230326.21_p0', 47 | '_reqid': random.randint(1111, 9999), 48 | 'rt': 'c' 49 | } 50 | 51 | data = { 52 | 'at': snlm0e, 53 | 'f.req': json.dumps([None, json.dumps([[prompt], None, [conversation_id, response_id, choice_id]])])} 54 | 55 | intents = '.'.join([ 56 | 'assistant', 57 | 'lamda', 58 | 'BardFrontendService' 59 | ]) 60 | 61 | response = client.post(f'https://bard.google.com/_/BardChatUi/data/{intents}/StreamGenerate', 62 | data=data, params=params) 63 | 64 | chat_data = json.loads(response.content.splitlines()[3])[0][2] 65 | if chat_data: 66 | json_chat_data = json.loads(chat_data) 67 | 68 | yield json_chat_data[0][0] 69 | 70 | else: 71 | yield 'error' 72 | 73 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 74 | '(%s)' % ', '.join([f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) -------------------------------------------------------------------------------- /g4f/Provider/Providers/Better.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import requests 4 | from typing import Dict, get_type_hints 5 | 6 | url = 'https://openai-proxy-api.vercel.app/v1/' 7 | model = [ 8 | 'gpt-3.5-turbo', 9 | 'gpt-3.5-turbo-0613', 10 | 'gpt-3.5-turbo-16k', 11 | 'gpt-3.5-turbo-16k-0613', 12 | 'gpt-4', 13 | ] 14 | 15 | supports_stream = True 16 | needs_auth = False 17 | 18 | 19 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 20 | headers = { 21 | 'Content-Type': 'application/json', 22 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58', 23 | 'Referer': 'https://chat.ylokh.xyz/', 24 | 'Origin': 'https://chat.ylokh.xyz', 25 | 'Connection': 'keep-alive', 26 | } 27 | 28 | json_data = { 29 | 'messages': messages, 30 | 'temperature': 1.0, 31 | 'model': model, 32 | 'stream': stream, 33 | } 34 | 35 | response = requests.post( 36 | 'https://openai-proxy-api.vercel.app/v1/chat/completions', headers=headers, json=json_data, stream=True 37 | ) 38 | 39 | for token in response.iter_lines(): 40 | decoded = token.decode('utf-8') 41 | if decoded.startswith('data: '): 42 | data_str = decoded.replace('data: ', '') 43 | data = json.loads(data_str) 44 | if 'choices' in data and 'delta' in data['choices'][0]: 45 | delta = data['choices'][0]['delta'] 46 | content = delta.get('content', '') 47 | finish_reason = delta.get('finish_reason', '') 48 | 49 | if finish_reason == 'stop': 50 | break 51 | if content: 52 | yield content 53 | 54 | 55 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + '(%s)' % ', '.join( 56 | [f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) 57 | -------------------------------------------------------------------------------- /g4f/Provider/Providers/ChatFree.py: -------------------------------------------------------------------------------- 1 | import os, requests 2 | from ...typing import sha256, Dict, get_type_hints 3 | import json 4 | 5 | url = "https://v.chatfree.cc" 6 | model = ['gpt-3.5-turbo', 'gpt-3.5-turbo-16k'] 7 | supports_stream = False 8 | needs_auth = False 9 | 10 | 11 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 12 | headers = { 13 | 'authority': 'chat.dfehub.com', 14 | 'accept': '*/*', 15 | 'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3', 16 | 'content-type': 'application/json', 17 | 'origin': 'https://v.chatfree.cc', 18 | 'referer': 'https://v.chatfree.cc/', 19 | 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', 20 | 'sec-ch-ua-mobile': '?0', 21 | 'sec-ch-ua-platform': '"macOS"', 22 | 'sec-fetch-dest': 'empty', 23 | 'sec-fetch-mode': 'cors', 24 | 'sec-fetch-site': 'same-origin', 25 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 26 | 'x-requested-with': 'XMLHttpRequest', 27 | } 28 | 29 | json_data = { 30 | 'messages': messages, 31 | 'stream': True, 32 | 'model': model, 33 | 'temperature': 0.5, 34 | 'presence_penalty': 0, 35 | 'frequency_penalty': 0, 36 | 'top_p': 1, 37 | } 38 | 39 | response = requests.post('https://v.chatfree.cc/api/openai/v1/chat/completions', 40 | headers=headers, json=json_data) 41 | 42 | for chunk in response.iter_lines(): 43 | if b'content' in chunk: 44 | data = json.loads(chunk.decode().split('data: ')[1]) 45 | yield (data['choices'][0]['delta']['content']) 46 | 47 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 48 | '(%s)' % ', '.join([f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) -------------------------------------------------------------------------------- /g4f/Provider/Providers/ChatgptAi.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests, re 3 | from ...typing import sha256, Dict, get_type_hints 4 | 5 | url = 'https://chatgpt.ai/gpt-4/' 6 | model = ['gpt-4'] 7 | supports_stream = True 8 | needs_auth = False 9 | 10 | 11 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 12 | chat = '' 13 | for message in messages: 14 | chat += '%s: %s\n' % (message['role'], message['content']) 15 | chat += 'assistant: ' 16 | 17 | response = requests.get('https://chatgpt.ai/') 18 | nonce, post_id, _, bot_id = re.findall(r'data-nonce="(.*)"\n data-post-id="(.*)"\n data-url="(.*)"\n data-bot-id="(.*)"\n data-width', response.text)[0] 19 | 20 | headers = { 21 | 'authority': 'chatgpt.ai', 22 | 'accept': '*/*', 23 | 'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3', 24 | 'cache-control': 'no-cache', 25 | 'origin': 'https://chatgpt.ai', 26 | 'pragma': 'no-cache', 27 | 'referer': 'https://chatgpt.ai/gpt-4/', 28 | 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', 29 | 'sec-ch-ua-mobile': '?0', 30 | 'sec-ch-ua-platform': '"Windows"', 31 | 'sec-fetch-dest': 'empty', 32 | 'sec-fetch-mode': 'cors', 33 | 'sec-fetch-site': 'same-origin', 34 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 35 | } 36 | data = { 37 | '_wpnonce': nonce, 38 | 'post_id': post_id, 39 | 'url': 'https://chatgpt.ai/gpt-4', 40 | 'action': 'wpaicg_chat_shortcode_message', 41 | 'message': chat, 42 | 'bot_id': bot_id 43 | } 44 | 45 | response = requests.post('https://chatgpt.ai/wp-admin/admin-ajax.php', 46 | headers=headers, data=data) 47 | 48 | yield (response.json()['data']) 49 | 50 | params = f'g4f.Providers.{os.path.basename(__file__)[:-3]} supports: ' + \ 51 | '(%s)' % ', '.join([f"{name}: {get_type_hints(_create_completion)[name].__name__}" for name in _create_completion.__code__.co_varnames[:_create_completion.__code__.co_argcount]]) -------------------------------------------------------------------------------- /g4f/Provider/Providers/ChatgptLogin.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ...typing import sha256, Dict, get_type_hints 3 | import requests 4 | import re 5 | import base64 6 | 7 | url = 'https://chatgptlogin.ac' 8 | model = ['gpt-3.5-turbo'] 9 | supports_stream = False 10 | needs_auth = False 11 | 12 | 13 | def _create_completion(model: str, messages: list, stream: bool, **kwargs): 14 | def get_nonce(): 15 | res = requests.get('https://chatgptlogin.ac/use-chatgpt-free/', headers={ 16 | "Referer": "https://chatgptlogin.ac/use-chatgpt-free/", 17 | "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' 18 | }) 19 | 20 | src = re.search(r'class="mwai-chat mwai-chatgpt">.*Send