├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ └── ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── bard_api.gif ├── bard_img.png ├── bard_links.png ├── bardapi_run_code.png ├── bardimg.png ├── sponsor_ad.png └── translate.png ├── bardapi ├── __init__.py ├── chat.py ├── constants.py ├── core.py ├── core_async.py ├── core_cookies.py ├── models │ ├── __init__.py │ ├── citation.py │ ├── draft.py │ ├── image.py │ ├── result.py │ ├── tools │ │ ├── __init__.py │ │ ├── code.py │ │ ├── flight.py │ │ ├── gdocs.py │ │ ├── gworkspace.py │ │ ├── hotel.py │ │ ├── json.py │ │ ├── link.py │ │ ├── map.py │ │ ├── tool.py │ │ ├── tool_declaimer.py │ │ └── youtube.py │ └── user_content.py └── utils.py ├── docs ├── Makefile ├── bardapi.rst ├── conf.py ├── index.rst ├── installation.rst ├── make.bat ├── officialgithub.rst └── source │ ├── Makefile │ ├── bardapi.models.rst │ ├── bardapi.models.tools.rst │ ├── bardapi.rst │ ├── conf.py │ ├── index.rst │ └── make.bat ├── documents ├── README_DEV.md └── README_FAQ.md ├── func_test.ipynb ├── main.py ├── requirements.txt ├── scripts ├── google_api.ipynb ├── google_official_api.ipynb ├── microsoft_api.ipynb └── openai_api.ipynb ├── setup.py ├── tests ├── data.py ├── google.test.js └── test_bard_result.py └── translate_to_other_programming_language ├── asyncio_core.py ├── bardapi.KT ├── bardapi.TS ├── bardapi.cs ├── bardapi.go ├── bardapi.java ├── bardapi.js ├── bardapi.php ├── bardapi.rs ├── bardapi.swift └── core_async.py /.gitattributes: -------------------------------------------------------------------------------- 1 | assets/bardapi.gif filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dsdanielpark 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # minwoopark 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: dsdanielpark 7 | 8 | --- 9 | 10 | 💚💜 Thank you for interest. ❤️💛 11 | **Please** make sure to check for more efficient package management. 12 | 13 | **To Reproduce** 14 | - [ ] I have read [README.md](https://github.com/dsdanielpark/Bard-API). Please read me. 15 | - [ ] I have searched for existing issues and [FAQ](https://github.com/dsdanielpark/Bard-API/blob/main/documents/README_FAQ.md) *(Most of the issues are duplicates.)* 16 | - [ ] I installed the appropriate version and confirmed that the previous version was properly removed upon reinstallation. 17 | - [ ] I also checked the environment (not only on a single local machine but also on Google Colab, different Google accounts, and tried resetting cookies, etc. Please make sure to attempt these steps if necessary, and test the functionality in a new virtual environment if needed.) 18 | 19 | Example 20 | ``` 21 | pip uninstall bardapi # and restart kernel 22 | pip install bardapi==0.1.29 # check proper version 23 | pip install -u bardapi==0.1.29 # upgrade version 24 | ``` 25 | 26 | ```python 27 | import bardapi 28 | bardapi.__version__ 29 | ``` 30 | 31 | ----------Please delete the content above this line, including this line.------------- 32 | 33 | 34 | **Describe the bug** 35 | A clear and concise description of what the bug is. 36 | 37 | **Version** 38 | OS: 39 | Python: 40 | Bard API: 41 | Using proxy: 42 | Legion: 43 | 44 | **Code** 45 | ```python 46 | code line 47 | ``` 48 | 49 | **Error** 50 | ``` 51 | error message 52 | ``` 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 💚💜 Thank you for interest. ❤️💛 11 | Please make sure to check for more efficient package management. *Please prioritize checking existing issues first. I will repay with higher-quality code.* 12 | 13 | **To Reproduce** 14 | - [ ] I have read [README.md](https://github.com/dsdanielpark/Bard-API). Please read me. 15 | - [ ] I have searched for existing issues. *(Most of the issues are duplicates.)* 16 | - [ ] I installed the appropriate version and confirmed that the previous version was properly removed upon reinstallation. 17 | - [ ] I also checked the environment (not only on a single local machine but also on Google Colab, different Google accounts, and tried resetting cookies, etc. Please make sure to attempt these steps if necessary, and test the functionality in a new virtual environment if needed.) 18 | 19 | Example 20 | ``` 21 | pip uninstall bardapi # and restart kernel 22 | pip install bardapi==0.1.29 # check proper version 23 | pip install -u bardapi==0.1.29 # upgrade version 24 | ``` 25 | 26 | ```python 27 | import bardapi 28 | bardapi.__version__ 29 | ``` 30 | ----------Please delete the content above this line, including this line.------------- 31 | 32 | 33 | Free form 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 💚💜 Thank you for interest. ❤️💛 11 | Please make sure to check for more efficient package management. *Please prioritize checking existing issues first. I will repay with higher-quality code.* 12 | 13 | **To Reproduce** 14 | - [ ] I have read [README.md](https://github.com/dsdanielpark/Bard-API). Please read me. 15 | - [ ] I have searched for existing issues. *(Most of the issues are duplicates.)* 16 | 17 | ----------Please delete the content above this line, including this line.------------- 18 | 19 | 20 | **Solution you'd like** 21 | A clear and concise description of what you want to happen. 22 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | I welcome the overall code refactoring and new features. However, please make sure to conduct QA. Before making a PR, please check the entire functionality by adding it to https://github.com/dsdanielpark/Bard-API/blob/main/func_test.ipynb. Due to various reasons, I couldn't implement test mocking code. I also welcome anyone who can provide test mocking and refactoring. But please keep the existing method names and examples. While I aim to accept PRs as quickly as possible, they may be rejected if QA is not correct. 2 | 3 | 4 | # BARD-API Pull Request Template 5 | Please provide the necessary information as succinctly as possible. I appreciate it if you write it in an easy-to-read format as I don't have much time to dedicate to maintaining this package. 6 | 7 | ## Description 8 | 9 | 10 | ## Related Issue 11 | 12 | 13 | 14 | 15 | 16 | ## Motivation and Context 17 | 18 | 19 | 20 | ## How Has This Been Tested? 21 | 22 | 23 | 24 | 25 | ## Screenshots (if appropriate): 26 | 27 | 28 | Thank you once again to all the contributors. Your efforts are greatly appreciated! 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.event.number || github.run_id }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | testing: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: install python 3.9 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.9' 23 | cache: 'pip' # caching pip dependencies 24 | - name: Check formatting (black) 25 | run: | 26 | pip install black 27 | black . --check 28 | - name: Check install 29 | run: | 30 | pip install . 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | notebook 2 | 3 | .gitattributes 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | share/python-wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | MANIFEST 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .nox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | *.py,cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | cover/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 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 | # For a library or package, you might want to ignore these files since the code is 91 | # intended to run in multiple environments; otherwise, check them in: 92 | # .python-version 93 | 94 | # pipenv 95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 98 | # install all needed dependencies. 99 | #Pipfile.lock 100 | 101 | # poetry 102 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 103 | # This is especially recommended for binary packages to ensure reproducibility, and is more 104 | # commonly ignored for libraries. 105 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 106 | #poetry.lock 107 | 108 | # pdm 109 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 110 | #pdm.lock 111 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 112 | # in version control. 113 | # https://pdm.fming.dev/#use-with-ide 114 | .pdm.toml 115 | 116 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 117 | __pypackages__/ 118 | 119 | # Celery stuff 120 | celerybeat-schedule 121 | celerybeat.pid 122 | 123 | # SageMath parsed files 124 | *.sage.py 125 | 126 | # Environments 127 | .env 128 | .venv 129 | env/ 130 | venv/ 131 | ENV/ 132 | env.bak/ 133 | venv.bak/ 134 | 135 | # Spyder project settings 136 | .spyderproject 137 | .spyproject 138 | 139 | # Rope project settings 140 | .ropeproject 141 | 142 | # mkdocs documentation 143 | /site 144 | 145 | .idea 146 | 147 | # mypy 148 | .mypy_cache/ 149 | .dmypy.json 150 | dmypy.json 151 | 152 | # Pyre type checker 153 | .pyre/ 154 | 155 | # pytype static type analyzer 156 | .pytype/ 157 | 158 | # Cython debug symbols 159 | cython_debug/ 160 | 161 | # PyCharm 162 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 163 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 164 | # and can be added to the global gitignore or merged into this file. For a more nuclear 165 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 166 | #.idea/ 167 | 168 | test.ipynb 169 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 MinWoo(Daniel) Park 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/bard_api.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/bard_api.gif -------------------------------------------------------------------------------- /assets/bard_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/bard_img.png -------------------------------------------------------------------------------- /assets/bard_links.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/bard_links.png -------------------------------------------------------------------------------- /assets/bardapi_run_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/bardapi_run_code.png -------------------------------------------------------------------------------- /assets/bardimg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/bardimg.png -------------------------------------------------------------------------------- /assets/sponsor_ad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/sponsor_ad.png -------------------------------------------------------------------------------- /assets/translate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/assets/translate.png -------------------------------------------------------------------------------- /bardapi/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Daniel Park, MIT License 2 | 3 | from os import environ 4 | from bardapi.core import Bard 5 | from bardapi.chat import ChatBard 6 | from bardapi.core_async import BardAsync 7 | from bardapi.core_cookies import BardCookies, BardAsyncCookies 8 | from bardapi.constants import ( 9 | SESSION_HEADERS, 10 | ALLOWED_LANGUAGES, 11 | DEFAULT_LANGUAGE, 12 | SEPARATOR_LINE, 13 | USER_PROMPT, 14 | IMG_UPLOAD_HEADERS, 15 | Tool, 16 | ) 17 | from bardapi.utils import ( 18 | extract_links, 19 | upload_image, 20 | extract_bard_cookie, 21 | max_token, 22 | max_sentence, 23 | ) 24 | 25 | # Get the API key from the environment variable 26 | bard_api_key = environ.get("_BARD_API_KEY") 27 | 28 | __all__ = [ 29 | "Bard", 30 | "ChatBard", 31 | "BardAsync", 32 | "BardCookies", 33 | "BardAsyncCookies", 34 | "SESSION_HEADERS", 35 | "ALLOWED_LANGUAGES", 36 | "DEFAULT_LANGUAGE", 37 | "IMG_UPLOAD_HEADERS", 38 | "SEPARATOR_LINE", 39 | "USER_PROMPT", 40 | "extract_links", 41 | "upload_image", 42 | "extract_bard_cookie", 43 | "max_token", 44 | "max_sentence", 45 | "Tool", 46 | ] 47 | __version__ = "1.0.0" 48 | __author__ = "daniel park " 49 | -------------------------------------------------------------------------------- /bardapi/chat.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from typing import Optional 4 | from colorama import Fore, Back, Style 5 | from bardapi.core import Bard 6 | from bardapi.constants import SEPARATOR_LINE, SESSION_HEADERS 7 | from bardapi.utils import extract_bard_cookie 8 | 9 | 10 | class ChatBard(Bard): 11 | """ 12 | A class representing a chatbot powered by the Bard API. 13 | 14 | Usage: 15 | chat = ChatBard() 16 | chat.start() 17 | 18 | Example: 19 | from bardapi import ChatBard 20 | 21 | chat = ChatBard() 22 | chat.start() 23 | """ 24 | 25 | USER_PROMPT = ">>> " 26 | 27 | def __init__( 28 | self, 29 | token: Optional[str] = None, 30 | timeout: int = 20, 31 | proxies: Optional[dict] = None, 32 | session: Optional[requests.Session] = None, 33 | google_translator_api_key: Optional[str] = None, 34 | language: Optional[str] = None, 35 | token_from_browser: bool = False, 36 | multi_cookies_bool: bool = False, 37 | cookie_dict: dict = None, 38 | ): 39 | """ 40 | Initialize the Chat Bard. 41 | 42 | Args: 43 | token (str, optional): Bard API token. 44 | timeout (int, optional, default = 20): Request timeout in seconds. 45 | proxies (dict, optional): Proxy configuration for requests. 46 | session (requests.Session, optional): Requests session object. 47 | google_translator_api_key (str, optional): Google cloud translation API key. 48 | language (str, optional): Chat Bard language. 49 | token_from_browser (bool, optional, default = False): Gets a token from the browser 50 | """ 51 | self.cookie_dict = cookie_dict 52 | self.multi_cookies_bool = multi_cookies_bool 53 | self.session = session or self._get_session(token, proxies) 54 | self.language = language or os.getenv("_BARD_API_LANG", "english") 55 | self.timeout = int(timeout or os.getenv("_BARD_API_TIMEOUT", 30)) 56 | self.token = self._get_token(token, token_from_browser) 57 | self.token_from_browser = token_from_browser 58 | self.proxies = proxies 59 | self.google_translator_api_key = google_translator_api_key 60 | 61 | super().__init__( 62 | token=self.token, 63 | session=self.session, 64 | google_translator_api_key=self.google_translator_api_key, 65 | timeout=self.timeout, 66 | language=self.language, 67 | proxies=self.proxies, 68 | token_from_browser=self.token_from_browser, 69 | cookie_dict=self.cookie_dict, 70 | multi_cookies_bool=self.multi_cookies_bool, 71 | ) 72 | 73 | # Chat history list 74 | self.chat_history = [] 75 | 76 | def _get_session( 77 | self, token: Optional[str], proxies: Optional[dict] 78 | ) -> requests.Session: 79 | """ 80 | Get the requests Session object. 81 | 82 | Args: 83 | token (str, optional): Bard API token. 84 | proxies (dict, optional): Proxy configuration for requests. 85 | 86 | Returns: 87 | requests.Session: The Session object. 88 | """ 89 | new_session = requests.Session() 90 | new_session.headers = SESSION_HEADERS 91 | new_session.cookies.set("__Secure-1PSID", self.token) 92 | new_session.proxies = proxies 93 | 94 | if self.cookie_dict is not None: 95 | for k, v in self.cookie_dict.items(): 96 | new_session.cookies.set(k, v) 97 | 98 | return new_session 99 | 100 | def _get_token(self, token: str, token_from_browser: bool) -> str: 101 | """ 102 | Get the Bard API token either from the provided token or from the browser cookie. 103 | 104 | Args: 105 | token (str, optional): Bard API token. 106 | token_from_browser (bool): Whether to extract the token from the browser cookie. 107 | 108 | Returns: 109 | str: The Bard API token. 110 | Raises: 111 | Exception: If the token is not provided and can't be extracted from the browser. 112 | """ 113 | if token: 114 | return token 115 | 116 | env_token = os.getenv("_BARD_API_KEY") 117 | if env_token: 118 | return env_token 119 | 120 | if token_from_browser: 121 | extracted_cookie_dict = extract_bard_cookie(cookies=self.multi_cookies_bool) 122 | if self.multi_cookies_bool: 123 | self.cookie_dict = extracted_cookie_dict 124 | required_cookies = [ 125 | "__Secure-1PSID", 126 | "__Secure-1PSIDTS", 127 | "__Secure-1PSIDCC", 128 | ] 129 | if len(extracted_cookie_dict) < len(required_cookies) or not all( 130 | key in extracted_cookie_dict for key in required_cookies 131 | ): 132 | print( 133 | "Essential cookies (__Secure-1PSID, __Secure-1PSIDTS, __Secure-1PSIDCC) are missing." 134 | ) 135 | return extracted_cookie_dict.get("__Secure-1PSID", "") 136 | if extracted_cookie_dict: 137 | return extracted_cookie_dict.get("__Secure-1PSID", "") 138 | 139 | raise Exception( 140 | "Bard API Key must be provided as the 'token' argument or extracted from the browser." 141 | ) 142 | 143 | def start(self, prompt: Optional[str] = None) -> None: 144 | """ 145 | Starts the chatbot interaction. 146 | 147 | Takes user input and retrieves responses from the Bard API until the user enters "quit", "q", or "stop". 148 | Prints the chatbot's response, including image links if available. 149 | 150 | Parameters: 151 | prompt (str, optional): Custom prompt message for user input. If not provided, defaults to the class constant USER_PROMPT. 152 | 153 | Returns: 154 | None 155 | """ 156 | 157 | prompt = prompt or self.USER_PROMPT 158 | print( 159 | f"{SEPARATOR_LINE}\n{Back.BLUE} Welcome to Chatbot {Back.RESET}\n{SEPARATOR_LINE}" 160 | ) 161 | print("If you enter quit, q, or stop, the chat will end.") 162 | 163 | # Start chat 164 | while True: 165 | user_input = input(prompt).lower() 166 | if user_input in ["quit", "q", "stop"]: 167 | break 168 | 169 | # Validate user input 170 | if not self._is_valid_input(user_input): 171 | print(f"{Fore.RED}Invalid input! Please try again.{Fore.RESET}") 172 | continue 173 | 174 | # Get response from Bard API 175 | try: 176 | response = self.bard.get_answer(user_input) 177 | if response.get("error"): 178 | print(f"{Fore.RED}Error: {response['error']}{Fore.RESET}") 179 | else: 180 | self._display_response(response) 181 | # Add user input and chatbot response to chat history 182 | self._add_to_chat_history(user_input, response["content"]) 183 | except requests.exceptions.RequestException as e: 184 | print(f"{Fore.RED}Error occurred: {str(e)}{Fore.RESET}") 185 | 186 | print( 187 | f"{SEPARATOR_LINE}\n{Fore.RED}Chat Ended.{Fore.RESET}\n\nDanielPark's Chat Template\n{SEPARATOR_LINE}" 188 | ) 189 | 190 | def display_chat_history(self) -> None: 191 | """ 192 | Displays the chat history. 193 | 194 | Prints the user input and chatbot responses from the chat history. 195 | 196 | Returns: 197 | None 198 | """ 199 | print( 200 | f"{SEPARATOR_LINE}\n{Back.YELLOW} Chat History {Back.RESET}\n{SEPARATOR_LINE}" 201 | ) 202 | 203 | for entry in self.chat_history: 204 | print(f"{Fore.GREEN}User: {entry['User']}{Fore.RESET}") 205 | print(f"{Fore.BLUE}Chatbot: {entry['Chatbot']}{Fore.RESET}") 206 | 207 | print(SEPARATOR_LINE) 208 | 209 | def get_chat_history(self) -> list: 210 | """ 211 | Retrieve the chat history. 212 | 213 | Usage: 214 | chat = ChatBard() 215 | chat.start() 216 | history_list = chat.get_chat_history() 217 | 218 | Returns: 219 | list: A list of dictionaries containing chat history entries. 220 | Each entry has two keys: 'User' and 'Chatbot'. 221 | 'User' contains the user input, and 'Chatbot' contains the chatbot's response. 222 | 223 | Example: 224 | chat = ChatBard() 225 | chat.start() 226 | history_list = chat.get_chat_history() 227 | 228 | # Access individual chat history entries 229 | for entry in history_list: 230 | user_input = entry['User'] 231 | chatbot_response = entry['Chatbot'] 232 | print(f"User: {user_input}") 233 | print(f"Chatbot: {chatbot_response}") 234 | 235 | :return: List of chat history entries. 236 | :rtype: list 237 | """ 238 | return self.chat_history 239 | 240 | @staticmethod 241 | def _is_valid_input(user_input: str) -> bool: 242 | """ 243 | Checks if the user input is valid. 244 | 245 | Validates the user input by checking if it is empty or exceeds a certain length. 246 | 247 | Parameters: 248 | user_input (str): The user input. 249 | 250 | Returns: 251 | bool: True if the user input is valid, False otherwise. 252 | """ 253 | if not user_input: 254 | return False 255 | if len(user_input) > 1000: 256 | return False 257 | return True 258 | 259 | @staticmethod 260 | def _display_response(response: dict) -> None: 261 | """ 262 | Displays the chatbot's response. 263 | 264 | Prints the chatbot's response, including image links if available. 265 | 266 | Parameters: 267 | response (dict): The response from the Bard API. 268 | 269 | Returns: 270 | None 271 | """ 272 | if response.get("images"): 273 | print( 274 | f"{Fore.BLUE}{Style.BRIGHT}Chatbot: {response['content']} \n\n Image links: {response['images']}{Fore.RESET}{Style.RESET_ALL}" 275 | ) 276 | else: 277 | print( 278 | f"{Fore.BLUE}{Style.BRIGHT}Chatbot: {response['content']} {Fore.RESET}{Style.RESET_ALL}" 279 | ) 280 | 281 | def _add_to_chat_history(self, user_input: str, chatbot_response: str) -> None: 282 | """ 283 | Adds the user input and chatbot response to the chat history. 284 | 285 | Parameters: 286 | user_input (str): The user input. 287 | chatbot_response (str): The chatbot's response. 288 | 289 | Returns: 290 | None 291 | """ 292 | self.chat_history.append({"User": user_input, "Chatbot": chatbot_response}) 293 | -------------------------------------------------------------------------------- /bardapi/constants.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from colorama import Fore 3 | 4 | # https://support.google.com/bard/answer/13575153?hl=en 5 | ALLOWED_LANGUAGES = { 6 | "korean", 7 | "english", 8 | "japanese", 9 | "arabic", 10 | "bengali", 11 | "bulgarian", 12 | "chinese (simplified)", 13 | "chinese (traditional)", 14 | "croatian", 15 | "czech", 16 | "danish", 17 | "dutch", 18 | "english", 19 | "estonian", 20 | "farsi", 21 | "finnish", 22 | "french", 23 | "german", 24 | "greek", 25 | "gujarati", 26 | "hebrew", 27 | "hindi", 28 | "hungarian", 29 | "indonesian", 30 | "italian", 31 | "japanese", 32 | "kannada", 33 | "korean", 34 | "latvian", 35 | "lithuanian", 36 | "malayalam", 37 | "marathi", 38 | "norwegian", 39 | "polish", 40 | "portuguese", 41 | "romanian", 42 | "russian", 43 | "serbian", 44 | "slovak", 45 | "slovenian", 46 | "spanish", 47 | "swahili", 48 | "swedish", 49 | "tamil", 50 | "telugu", 51 | "thai", 52 | "turkish", 53 | "ukrainian", 54 | "urdu", 55 | "vietnamese", 56 | "ko", 57 | "en", 58 | "ja", 59 | "ar", 60 | "bn", 61 | "bg", 62 | "zh-cn", 63 | "zh-tw", 64 | "hr", 65 | "cs", 66 | "da", 67 | "nl", 68 | "en", 69 | "et", 70 | "fa", 71 | "fi", 72 | "fr", 73 | "de", 74 | "el", 75 | "gu", 76 | "he", 77 | "hi", 78 | "hu", 79 | "id", 80 | "it", 81 | "kn", 82 | "lv", 83 | "lt", 84 | "ml", 85 | "mr", 86 | "no", 87 | "pl", 88 | "pt", 89 | "ro", 90 | "ru", 91 | "sr", 92 | "sk", 93 | "sl", 94 | "es", 95 | "sw", 96 | "sv", 97 | "ta", 98 | "te", 99 | "th", 100 | "tr", 101 | "uk", 102 | "ur", 103 | "vi", 104 | } 105 | 106 | DEFAULT_LANGUAGE = "en" 107 | SEPARATOR_LINE = "=" * 36 108 | USER_PROMPT = Fore.BLUE + "You: " + Fore.RESET 109 | TEXT_GENERATION_WEB_SERVER_PARAM = "boq_assistant-bard-web-server_20230912.07_p1" 110 | POST_ENDPOINT = "https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate" 111 | 112 | 113 | SESSION_HEADERS = { 114 | "Host": "gemini.google.com", 115 | "X-Same-Domain": "1", 116 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 117 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", 118 | "Origin": "https://gemini.google.com", 119 | "Referer": "https://gemini.google.com/app", 120 | } 121 | 122 | IMG_UPLOAD_HEADERS = { 123 | "authority": "content-push.googleapis.com", 124 | "accept": "*/*", 125 | "accept-language": "en-US,en;q=0.7", 126 | "authorization": "Basic c2F2ZXM6cyNMdGhlNmxzd2F2b0RsN3J1d1U=", # Constant Authorization Key 127 | "content-type": "application/x-www-form-urlencoded;charset=UTF-8", 128 | "origin": "https://gemini.google.com", 129 | "push-id": "feeds/mcudyrk2a4khkz", # Constant 130 | "referer": "https://gemini.google.com/app", 131 | "x-goog-upload-command": "start", 132 | "x-goog-upload-header-content-length": "", 133 | "x-goog-upload-protocol": "resumable", 134 | "x-tenant-id": "bard-storage", 135 | } 136 | 137 | REPLIT_SUPPORT_PROGRAM_LANGUAGES = { 138 | "python": "main.py", 139 | "javascript": "index.js", 140 | "go": "main.go", 141 | "java": "Main.java", 142 | "kotlin": "Main.kt", 143 | "php": "index.php", 144 | "c#": "main.cs", 145 | "swift": "main.swift", 146 | "r": "main.r", 147 | "ruby": "main.rb", 148 | "c": "main.c", 149 | "c++": "main.cpp", 150 | "matlab": "main.m", 151 | "typescript": "main.ts", 152 | "scala": "main.scala", 153 | "sql": "main.sql", 154 | "html": "index.html", 155 | "css": "style.css", 156 | "nosql": "main.nosql", 157 | "rust": "main.rs", 158 | "perl": "main.pl", 159 | } 160 | 161 | 162 | class Tool(Enum): 163 | GMAIL = ["workspace_tool", "Gmail"] 164 | GOOGLE_DOCS = ["workspace_tool", "Google Docs"] 165 | GOOGLE_DRIVE = ["workspace_tool", "Google Drive"] 166 | GOOGLE_FLIGHTS = ["google_flights_tool"] 167 | GOOGLE_HOTELS = ["google_hotels_tool"] 168 | GOOGLE_MAPS = ["google_map_tool"] 169 | YOUTUBE = ["youtube_tool"] 170 | -------------------------------------------------------------------------------- /bardapi/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/bardapi/models/__init__.py -------------------------------------------------------------------------------- /bardapi/models/citation.py: -------------------------------------------------------------------------------- 1 | class DraftCitation: 2 | """Github source 3 | [[909, 1095, ['', 'edelahoz/Introduction-to-Python ', '', '', '', None, None, '', False, '', '', '', '', '', '', ''], 1, 100, None, [1]], 4 | [940, 1139, ['', 'Engr-Asad-Hussain/oop ', '', '', '', None, None, '', False, '', '', '', '', '', '', ''], 1, 100, None, [1]], 5 | [953, 1166, ['', 'TeknikhogskolanGothenburg/PGBPYH21_Programmering', '', '', '', None, None, '', False, '', '', '', '', '', '', ''], 1, 100, None, [1]]] 6 | 7 | Wiki source 8 | [[284, 425, ['http://en.wikipedia.org/wiki/Jill_Biden', ' ', '', None, '', None, None, '', False, '', '', '', '', '', '', ''], 1, 1 , None, [1, 'normal_citation_datasets']], 9 | [196, 411, ['https://en.wikipedia.org/wiki/Jill_Biden#:~:text=Jill%20Tracy%20Jacobs%20was%20born,II%20who%20used%20the%20G.I.', '', '', '', '', None, None, '', False, '', '', '', '', '', '', ''], 2, 2, None, [1, 'normal_citation_datasets']]]] 10 | 11 | [None, None, ['https://en.wikipedia.org/wiki/Te%27omim_Cave'], 3] 12 | """ 13 | 14 | def __init__(self, input_list: list, text: str): 15 | self._input_list = input_list 16 | self.span: tuple[int, int] = (self._input_list[0], self._input_list[1]) 17 | if self.span[0] is None or self.span[1] is None: 18 | self.text = "" 19 | else: 20 | self.text: str = text[self.span[0] : self.span[1]] 21 | 22 | @property 23 | def source_path(self) -> str: 24 | return self._input_list[2][1] if len(self._input_list[2]) > 1 else "" 25 | 26 | @property 27 | def source_full(self) -> str: 28 | return self._input_list[2][0] 29 | 30 | @property 31 | def source_dataset(self) -> list: 32 | if len(self._input_list) < 5: 33 | return [] 34 | return self._input_list[6] 35 | 36 | def __str__(self) -> str: 37 | return self.source_full if self.source_full else self.source_path 38 | -------------------------------------------------------------------------------- /bardapi/models/draft.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Union, Dict, Tuple 2 | 3 | from bardapi.models.citation import DraftCitation 4 | from bardapi.models.tools.code import CodeContent 5 | from bardapi.models.tools.flight import BardFlightContent 6 | from bardapi.models.tools.gworkspace import GoogleWorkspaceContent 7 | from bardapi.models.image import BardImageContent 8 | from bardapi.models.tools.hotel import BardHotelContent 9 | from bardapi.models.tools.json import JsonContent 10 | from bardapi.models.tools.link import BardLink 11 | from bardapi.models.tools.map import BardMapContent 12 | from bardapi.models.tools.tool_declaimer import BardToolDeclaimer 13 | from bardapi.models.user_content import UserContent 14 | from bardapi.models.tools.youtube import BardYoutubeContent 15 | 16 | 17 | class BardDraft: 18 | def __init__(self, input_list: list): 19 | self._input_list = input_list 20 | self.id = self._input_list[0] 21 | 22 | @property 23 | def text(self) -> str: 24 | return self._input_list[1][0] 25 | 26 | @property 27 | def text_with_user_content(self) -> str: 28 | text = self.text 29 | for uc in self.user_content.values(): 30 | key = uc.key 31 | mk = uc.markdown_text 32 | text = text.replace(key, "\n" + mk) 33 | return text 34 | 35 | @property 36 | def citations(self) -> list[DraftCitation]: 37 | text = self.text 38 | return ( 39 | [DraftCitation(c, text) for c in self._input_list[2][0]] 40 | if self._input_list[2] 41 | else [] 42 | ) 43 | 44 | @property 45 | def images(self) -> list[BardImageContent]: 46 | # also in self._attachments[1] 47 | return ( 48 | [BardImageContent(img) for img in self._input_list[4]] 49 | if self._input_list[4] 50 | else [] 51 | ) 52 | 53 | @property 54 | def language(self) -> str: 55 | # en 56 | return self._input_list[9] 57 | 58 | @property 59 | def _attachments(self) -> Optional[list]: 60 | return self._input_list[12] 61 | 62 | @property 63 | def map_content(self) -> list[BardMapContent]: 64 | if not self._attachments: 65 | return [] 66 | return ( 67 | [BardMapContent(a) for a in self._attachments[3]] 68 | if self._attachments[3] 69 | else [] 70 | ) 71 | 72 | @property 73 | def json_content(self) -> list[JsonContent]: 74 | if not self._attachments: 75 | return [] 76 | return ( 77 | [JsonContent(a) for a in self._attachments[10]] 78 | if self._attachments[10] 79 | else [] 80 | ) 81 | 82 | @property 83 | def gworkspace(self) -> list[GoogleWorkspaceContent]: 84 | if not self._attachments or len(self._attachments) < 13: 85 | return [] 86 | return ( 87 | [GoogleWorkspaceContent(a) for a in self._attachments[12][0][2]] 88 | if self._attachments[12] 89 | else [] 90 | ) 91 | 92 | @property 93 | def youtube(self) -> list[BardYoutubeContent]: 94 | if not self._attachments: 95 | return [] 96 | return ( 97 | [BardYoutubeContent(a) for a in self._attachments[4]] 98 | if self._attachments[4] 99 | else [] 100 | ) 101 | 102 | @property 103 | def python_code(self) -> list[CodeContent]: 104 | # Google has a dedicated Python model that can also run code. 105 | # The text model uses the output of the Python model to generate answers, 106 | # including answers in other languages. 107 | # 108 | # The code snippet is the same for all drafts! 109 | if not self._attachments: 110 | return [] 111 | return ( 112 | [CodeContent(a) for a in self._attachments[5]] 113 | if self._attachments[5] and self._attachments[5][0][3] 114 | else [] 115 | ) 116 | 117 | @property 118 | def links(self) -> list[BardLink]: 119 | if not self._attachments: 120 | return [] 121 | return ( 122 | [BardLink(a) for a in self._attachments[8]] if self._attachments[8] else [] 123 | ) 124 | 125 | @property 126 | def flights(self) -> list[BardFlightContent]: 127 | if not self._attachments or len(self._attachments) < 17: 128 | return [] 129 | return ( 130 | [BardFlightContent(a) for a in self._attachments[16]] 131 | if self._attachments[16] 132 | else [] 133 | ) 134 | 135 | @property 136 | def hotels(self) -> list[BardHotelContent]: 137 | if not self._attachments or len(self._attachments) < 19: 138 | return [] 139 | return ( 140 | [BardHotelContent(a) for a in self._attachments[17]] 141 | if self._attachments[17] 142 | else [] 143 | ) 144 | 145 | @property 146 | def tool_disclaimers(self) -> list[BardToolDeclaimer]: 147 | if not self._attachments or len(self._attachments) < 23: 148 | return [] 149 | 150 | return ( 151 | [BardToolDeclaimer(a) for a in self._attachments[22]] 152 | if self._attachments[22] 153 | else [] 154 | ) 155 | 156 | @property 157 | def user_content(self) -> Dict[str, UserContent]: 158 | d = {v.key: v for v in self.youtube} 159 | d.update({v.key: v for v in self.map_content}) 160 | d.update({v.key: v for v in self.flights}) 161 | d.update({v.key: v for v in self.links}) 162 | d.update({v.key: v for v in self.tool_disclaimers}) 163 | d.update({v.key: v for v in self.json_content}) 164 | d.update({v.key: v for v in self.hotels}) 165 | return d 166 | 167 | def __str__(self) -> str: 168 | return self.text 169 | -------------------------------------------------------------------------------- /bardapi/models/image.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | class BardImage: 5 | def __init__(self, input_list: list): 6 | self._input_list = input_list 7 | self.urls = input_list[0] 8 | self.width = input_list[2] 9 | self.height = input_list[3] 10 | self.alt: Optional[str] = input_list[4] if len(input_list) > 4 else None 11 | 12 | def __str__(self) -> str: 13 | return f"{self.urls[0]} ({self.width}x{self.height})" 14 | 15 | 16 | class BardImageContent: 17 | def __init__(self, input_list: list): 18 | self._input_list = input_list 19 | 20 | @property 21 | def original(self) -> BardImage: 22 | return BardImage(self._input_list[0]) 23 | 24 | @property 25 | def source(self) -> dict: 26 | v = self._input_list[1] 27 | return {"pages": v[0], "domain": v[1], "fav_icon": v[3]} 28 | 29 | @property 30 | def key(self) -> str: 31 | """use this to replace the image in the markdown, several images can have the same key""" 32 | return self._input_list[2] 33 | 34 | @property 35 | def thumbnail(self) -> BardImage: 36 | return BardImage(self._input_list[3]) 37 | 38 | @property 39 | def markdown(self) -> list: 40 | return self._input_list[7] 41 | 42 | @property 43 | def alt(self) -> str: 44 | return self.markdown[2] 45 | 46 | def __str__(self) -> str: 47 | return f"[{self.alt}]({self.original.urls[0]})" 48 | -------------------------------------------------------------------------------- /bardapi/models/result.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Union, Dict, Tuple 2 | 3 | from bardapi.models.draft import BardDraft 4 | from bardapi.models.tools.tool import BardTool 5 | 6 | 7 | class BardUserLocation: 8 | def __init__(self, input_list: list): 9 | self._input_list = input_list 10 | 11 | @property 12 | def location_str(self) -> str: 13 | return self._input_list[0] 14 | 15 | @property 16 | def description(self) -> str: 17 | return self._input_list[1] 18 | 19 | @property 20 | def geo_position(self) -> list: 21 | return self._input_list[3][0][0][3] 22 | 23 | @property 24 | def image_url(self) -> str: 25 | return "https:" + self._input_list[4] 26 | 27 | def __str__(self) -> str: 28 | return self.location_str 29 | 30 | 31 | class BardResult: 32 | def __init__(self, input_list: list): 33 | self._input_list = input_list 34 | self.conversation_id = self._input_list[1][0] 35 | self.response_id = self._input_list[1][1] 36 | 37 | @property 38 | def search_queries(self) -> list[str, int]: 39 | return self._input_list[2] 40 | 41 | @property 42 | def factuality_queries(self) -> Optional[list]: 43 | return self._input_list[3] 44 | 45 | @property 46 | def drafts(self) -> list[BardDraft]: 47 | return ( 48 | [BardDraft(c) for c in self._input_list[4]] if self._input_list[4] else [] 49 | ) 50 | 51 | @property 52 | def location(self) -> BardUserLocation: 53 | return BardUserLocation(self._input_list[5]) 54 | 55 | @property 56 | def progress_tool(self) -> BardTool: 57 | return BardTool(self._input_list[6]) if self._input_list[6] else None 58 | 59 | @property 60 | def country(self) -> str: 61 | return self._input_list[8] 62 | 63 | @property 64 | def topic(self) -> Optional[str]: 65 | if len(self._input_list) < 11 or not self._input_list[10]: 66 | return None 67 | return self._input_list[10][0] 68 | 69 | @property 70 | def tools_applied(self) -> list[BardTool]: 71 | if len(self._input_list) < 12: 72 | return [] 73 | return ( 74 | [BardTool(tool) for tool in self._input_list[11]] 75 | if self._input_list[11] 76 | else [] 77 | ) 78 | -------------------------------------------------------------------------------- /bardapi/models/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/bardapi/models/tools/__init__.py -------------------------------------------------------------------------------- /bardapi/models/tools/code.py: -------------------------------------------------------------------------------- 1 | class CodeContent: 2 | # 32 items 3 | def __init__(self, input_list: list): 4 | self._input_list = input_list 5 | 6 | @property 7 | def request(self) -> str: 8 | return self._input_list[3] 9 | 10 | @property 11 | def output(self) -> str: 12 | return self._input_list[1] 13 | 14 | @property 15 | def output_image(self) -> str: 16 | # Don't know how to extract this, but it's 17 | # [['[image-tag: code_execution_image_1_1695640907.0254648.png]']] 18 | return self._input_list[27] 19 | 20 | @property 21 | def code(self) -> str: 22 | return self._input_list[8] 23 | 24 | def __str__(self) -> str: 25 | return self.code 26 | -------------------------------------------------------------------------------- /bardapi/models/tools/flight.py: -------------------------------------------------------------------------------- 1 | from bardapi.models.user_content import UserContent 2 | from typing import List 3 | 4 | 5 | class BardFlight: 6 | def __init__(self, input_list: List): 7 | self._input_list = input_list 8 | 9 | @property 10 | def url(self) -> str: 11 | if len(self._input_list) > 2: 12 | return self._input_list[2] 13 | else: 14 | return "" 15 | 16 | @property 17 | def price(self) -> str: 18 | if len(self._input_list) > 3: 19 | return self._input_list[3] 20 | else: 21 | return "" 22 | 23 | @property 24 | def airlines(self) -> List[str]: 25 | if len(self._input_list) > 0 and isinstance(self._input_list[0], list): 26 | return self._input_list[0] 27 | else: 28 | return [] 29 | 30 | @property 31 | def airline_logo(self) -> str: 32 | return self._input_list[0][1] 33 | 34 | @property 35 | def departure_airport(self) -> str: 36 | return self._input_list[0][2] 37 | 38 | @property 39 | def arrival_airport(self) -> str: 40 | return self._input_list[0][3] 41 | 42 | @property 43 | def departure_time(self) -> str: 44 | return self._input_list[0][7] 45 | 46 | @property 47 | def arrival_time(self) -> str: 48 | return self._input_list[0][8] 49 | 50 | @property 51 | def duration(self) -> str: 52 | return self._input_list[0][9] 53 | 54 | @property 55 | def stops(self) -> str: 56 | return self._input_list[0][6] 57 | 58 | def __str__(self) -> str: 59 | return f'{",".join(self.airlines)} - {self.departure_airport} to {self.arrival_airport} - {self.departure_time} to {self.arrival_time} - {self.price}' 60 | 61 | 62 | class BardFlightContent(UserContent): 63 | """http://googleusercontent.com/flight_content/""" 64 | 65 | def __init__(self, input_list: list): 66 | self._input_list = input_list 67 | 68 | @property 69 | def key(self) -> str: 70 | return self._input_list[3][0] 71 | 72 | @property 73 | def title(self) -> str: 74 | return self._input_list[3][2] 75 | 76 | @property 77 | def search_url(self) -> str: 78 | return self._input_list[2] 79 | 80 | @property 81 | def flights(self) -> List[BardFlight]: 82 | return ( 83 | [BardFlight(flight) for flight in self._input_list[1]] 84 | if self._input_list[1] 85 | else [] 86 | ) 87 | 88 | @property 89 | def from_airport(self) -> str: 90 | # 'OSL' 91 | return self._input_list[4] 92 | 93 | @property 94 | def to_airport(self) -> str: 95 | # 'MAD' 96 | return self._input_list[5] 97 | 98 | @property 99 | def from_date(self) -> str: 100 | # Jan 22 101 | return self._input_list[6] 102 | 103 | @property 104 | def to_date(self) -> str: 105 | # Jan 28 106 | return self._input_list[7] 107 | 108 | @property 109 | def who(self) -> str: 110 | # '1 adult' 111 | return self._input_list[8] 112 | 113 | def __getitem__(self, item) -> BardFlight: 114 | return self.flights[item] 115 | 116 | def __len__(self): 117 | return len(self.flights) 118 | 119 | def __str__(self) -> str: 120 | return self.title 121 | 122 | @property 123 | def markdown_text(self) -> str: 124 | return f"#### {self.title}\n\n" + "\n".join( 125 | [" * " + str(flight) for flight in self.flights] 126 | ) 127 | -------------------------------------------------------------------------------- /bardapi/models/tools/gdocs.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsdanielpark/Bard-API/d5398b93027c11cb7eb6a4ec2c51db15ba800afd/bardapi/models/tools/gdocs.py -------------------------------------------------------------------------------- /bardapi/models/tools/gworkspace.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class GoogleWorkspaceContentKind(Enum): 5 | UNKNOWN = 0 6 | EMAIL = 1 7 | FILE = 2 8 | DOCUMENT = 3 9 | PDF = 4 10 | SPREADSHEET = 5 11 | 12 | 13 | class GoogleWorkspaceContent: 14 | # [[1], 'https://mail.google.com/mail/u/0/#all/18ad29e935cf6dc3', 15 | # 'Start your journey to becoming an AI expert today!', ['18ad29e935cf6dc3'], 16 | # 'Tuesday, 26 September 2023 19:52 CEST', 'Stanford University', [1695750721]] 17 | 18 | # [[3], 'https://docs.google.com/document/d/1pS5RTC2PSVn02lGOOAtaEg5U9M4_Ss_eoqkb2msO-Yo', 19 | # 'CV (Andrew Matuk)', ['1pS5RTC2PSVn02lGOOAtaEg5U9M4_Ss_eoqkb2msO-Yo', 147325], 20 | # 'Friday, 28 July 2023 11:29 CEST', 'Andrew Me', [1690536542, 363000000]] 21 | def __init__(self, input_list: list): 22 | self._input_list = input_list 23 | 24 | @property 25 | def kind(self) -> GoogleWorkspaceContentKind: 26 | return ( 27 | GoogleWorkspaceContentKind(self._input_list[0][0]) 28 | if self._input_list[0] < 5 29 | else GoogleWorkspaceContentKind.UNKNOWN 30 | ) 31 | 32 | def icon(self) -> str: 33 | di = { 34 | GoogleWorkspaceContentKind.UNKNOWN: "https://drive-thirdparty.googleusercontent.com/64/type/application/vnd.google-apps.unknown", 35 | GoogleWorkspaceContentKind.EMAIL: "https://www.gstatic.com/lamda/images/default_email_avatar_7fc85bbd3d2f35d5bd091.svg", 36 | GoogleWorkspaceContentKind.FILE: "https://drive-thirdparty.googleusercontent.com/64/type/application/vnd.google-apps.file", 37 | GoogleWorkspaceContentKind.DOCUMENT: "https://drive-thirdparty.googleusercontent.com/64/type/application/vnd.google-apps.document", 38 | GoogleWorkspaceContentKind.PDF: "https://drive-thirdparty.googleusercontent.com/64/type/application/pdf", 39 | GoogleWorkspaceContentKind.SPREADSHEET: "https://drive-thirdparty.googleusercontent.com/64/type/application/vnd.google-apps.spreadsheet", 40 | } 41 | return di[self.kind] 42 | 43 | @property 44 | def url(self) -> str: 45 | return self._input_list[1] 46 | 47 | @property 48 | def title(self) -> str: 49 | return self._input_list[2] 50 | 51 | @property 52 | def id(self) -> str: 53 | return self._input_list[3][0] 54 | 55 | @property 56 | def date(self) -> str: 57 | return self._input_list[4] 58 | 59 | @property 60 | def author(self) -> str: 61 | return self._input_list[5] 62 | 63 | @property 64 | def timestamp_seconds(self) -> [int]: 65 | return self._input_list[6] 66 | 67 | def __str__(self) -> str: 68 | return self.title 69 | -------------------------------------------------------------------------------- /bardapi/models/tools/hotel.py: -------------------------------------------------------------------------------- 1 | from bardapi.models.user_content import UserContent 2 | from typing import List 3 | 4 | 5 | class BardHotel: 6 | def __init__(self, input_list: list): 7 | self._input_list = input_list 8 | 9 | @property 10 | def name(self) -> str: 11 | return self._input_list[0] 12 | 13 | @property 14 | def images(self) -> List[str]: 15 | return self._input_list[1] 16 | 17 | @property 18 | def stars(self) -> int: 19 | return self._input_list[2] 20 | 21 | @property 22 | def rating_count(self) -> int: 23 | return self._input_list[3] 24 | 25 | @property 26 | def stars_text(self) -> int: 27 | return self._input_list[4] 28 | 29 | @property 30 | def description(self) -> int: 31 | return self._input_list[5] 32 | 33 | @property 34 | def url(self) -> int: 35 | return self._input_list[7] 36 | 37 | @property 38 | def price(self) -> int: 39 | return self._input_list[8] 40 | 41 | def __str__(self): 42 | return f"{self.name} {self.stars}★({self.rating_count})\n{self.description} {self.price}" 43 | 44 | def markdown_text(self): 45 | return ( 46 | f"**{self.name}** {self.stars}★({self.rating_count}) - {self.price}\n - ![]({self.images[0]})" 47 | f"\n - {self.description}" 48 | ) 49 | 50 | 51 | class BardHotelContent(UserContent): 52 | def __init__(self, input_list: list): 53 | self._input_list = input_list 54 | 55 | @property 56 | def hotels(self) -> List[BardHotel]: 57 | return ( 58 | [BardHotel(h) for h in self._input_list[0]] if self._input_list[0] else [] 59 | ) 60 | 61 | @property 62 | def key(self) -> str: 63 | return self._input_list[2][0] 64 | 65 | @property 66 | def full_title(self) -> str: 67 | return self._input_list[2][2] 68 | 69 | @property 70 | def tool_name(self): 71 | return self._input_list[2][6][1] 72 | 73 | @property 74 | def title(self) -> str: 75 | return self._input_list[3] 76 | 77 | @property 78 | def from_date(self) -> str: 79 | return self._input_list[4] 80 | 81 | @property 82 | def to_date(self) -> str: 83 | return self._input_list[5] 84 | 85 | @property 86 | def who(self) -> str: 87 | return self._input_list[8] 88 | 89 | def __str__(self): 90 | return self.full_title 91 | 92 | @property 93 | def markdown_text(self) -> str: 94 | return f"#### {self.full_title}\n\n" + "\n".join( 95 | ["1. " + flight.markdown_text() for flight in self.hotels] 96 | ) 97 | -------------------------------------------------------------------------------- /bardapi/models/tools/json.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from bardapi.models.user_content import UserContent 4 | 5 | 6 | class JsonContent(UserContent): 7 | def __init__(self, input_list: list): 8 | self._input_list = input_list 9 | 10 | @property 11 | def object(self) -> str: 12 | return json.loads(self.json_text) 13 | 14 | @property 15 | def json_text(self) -> str: 16 | return self._input_list[1] 17 | 18 | @property 19 | def key(self) -> str: 20 | return self._input_list[0] 21 | 22 | @property 23 | def markdown_text(self) -> str: 24 | return "{json}" 25 | 26 | def __str__(self) -> str: 27 | return self.json_text[:20] 28 | -------------------------------------------------------------------------------- /bardapi/models/tools/link.py: -------------------------------------------------------------------------------- 1 | from bardapi.models.user_content import UserContent 2 | 3 | 4 | class BardLink(UserContent): 5 | def __init__(self, input_list: list): 6 | self._input_list = input_list 7 | 8 | @property 9 | def key(self) -> str: 10 | return self._input_list[0][0] 11 | 12 | @property 13 | def url(self) -> str: 14 | return self._input_list[1] 15 | 16 | def __str__(self) -> str: 17 | return self.url 18 | 19 | @property 20 | def markdown_text(self) -> str: 21 | return f"[{self.url}]({self.url})" 22 | -------------------------------------------------------------------------------- /bardapi/models/tools/map.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import List, Optional, Union, Dict, Tuple 3 | 4 | from bardapi.models.user_content import UserContent 5 | 6 | 7 | class BardMapsPoint: 8 | def __init__(self, input_list: list): 9 | self._input_list = input_list 10 | 11 | self.geo_position = self._input_list[11] 12 | self.lat: float = self.geo_position[0] 13 | self.lng: float = self.geo_position[1] 14 | 15 | @property 16 | def id(self) -> str: 17 | return self._input_list[1] 18 | 19 | @property 20 | def address(self) -> str: 21 | # '12170 Dornans Rd, Moose, WY 83012, USA' 22 | return self._input_list[8] 23 | 24 | @property 25 | def address_short(self) -> str: 26 | # 'Dornans, 12170 Dornans Rd, Moose' 27 | return self._input_list[50] 28 | 29 | @property 30 | def geo_position_rect(self) -> list: 31 | return self._input_list[12] 32 | 33 | @property 34 | def rating(self) -> float: 35 | return self._input_list[13] 36 | 37 | @property 38 | def rating_count(self) -> int: 39 | return self._input_list[27] 40 | 41 | @property 42 | def gmaps_url(self) -> str: 43 | return self._input_list[14] 44 | 45 | @property 46 | def website_url(self) -> str: 47 | return self._input_list[15] 48 | 49 | @property 50 | def schedule(self) -> dict: 51 | v = self._input_list[20] 52 | return { 53 | "open": v[0], 54 | "value": v[1], 55 | "human": v[2], 56 | } 57 | 58 | @property 59 | def title(self) -> Tuple[str, str]: 60 | # Albertsons, "en" 61 | return self._input_list[30] 62 | 63 | @property 64 | def place_type_and_lang(self) -> Optional[Tuple[str, str]]: 65 | # ['Grocery store', 'en'] 66 | return self._input_list[31] 67 | 68 | @property 69 | def place_type(self) -> str: 70 | # grocery_store 71 | return self._input_list[49] # same [31], "en" 72 | 73 | def description(self) -> Optional[Tuple[str, str]]: 74 | # ['Gourmet groceries, cheeses & baked goods are available at this casual deli in a resort setting.', 'en'] 75 | return self._input_list[51] 76 | 77 | @property 78 | def images(self) -> list: 79 | return ( 80 | [{"url": img[0], "author": img[3]} for img in self._input_list[53]] 81 | if self._input_list[53] 82 | else [] 83 | ) 84 | 85 | def __str__(self) -> str: 86 | place_type = self.place_type_and_lang 87 | if place_type: 88 | place_type = " - " + place_type[0] 89 | else: 90 | place_type = "" 91 | return f"{self.title[0]}{place_type}" 92 | 93 | def markdown(self) -> str: 94 | description = self.description() 95 | if description: 96 | description = "\n" + description[0] 97 | else: 98 | description = "" 99 | 100 | place_type = self.place_type_and_lang 101 | if place_type: 102 | place_type = place_type[0] 103 | else: 104 | place_type = "" 105 | return f"{self.title[0]}\n{place_type} {self.rating}★({self.rating_count}){description}" 106 | 107 | 108 | class TravelMode(Enum): 109 | DRIVING = 0 110 | WALKING = 1 111 | TRANSIT = 2 112 | BICYCLING = 3 113 | UNKNOWN = 4 114 | 115 | 116 | class BardMapsRoadSection: 117 | def __init__(self, input_list: list): 118 | self._input_list = input_list 119 | 120 | @property 121 | def instructions(self) -> list: 122 | return self._input_list[0] 123 | 124 | @property 125 | def duration(self) -> [int, str]: 126 | # [16873, '4 hours 41 mins'] 127 | return self._input_list[1] 128 | 129 | @property 130 | def distance(self) -> [int, str]: 131 | # [313054, '313 km'] 132 | return self._input_list[2] 133 | 134 | @property 135 | def start_point(self) -> [float, float]: 136 | return self._input_list[5] 137 | 138 | @property 139 | def end_point(self) -> [float, float]: 140 | return self._input_list[6] 141 | 142 | @property 143 | def start_location(self) -> str: 144 | return self._input_list[7] 145 | 146 | @property 147 | def end_location(self) -> str: 148 | return self._input_list[8] 149 | 150 | def __str__(self): 151 | return f"{self.start_location} to {self.end_location} - {self.duration[1]}({self.distance[1]})" 152 | 153 | 154 | class BardMapsDirections: 155 | def __init__(self, input_list: list): 156 | self._input_list = input_list 157 | 158 | @property 159 | def _map(self) -> list: 160 | return self._input_list[0][1][0] 161 | 162 | @property 163 | def url(self) -> str: 164 | return self._input_list[1] 165 | 166 | @property 167 | def road_name(self) -> str: 168 | return self._map[0] 169 | 170 | @property 171 | def sections(self) -> List[BardMapsRoadSection]: 172 | return [BardMapsRoadSection(s) for s in self._map[1]] 173 | 174 | @property 175 | def geo_position(self) -> [[float, float], [float, float]]: 176 | return self._map[6] 177 | 178 | def __str__(self): 179 | return "via " + self.road_name 180 | 181 | 182 | class BardMapContent(UserContent): 183 | """http://googleusercontent.com/map_content/""" 184 | 185 | def __init__(self, input_list: list): 186 | self._input_list = input_list 187 | 188 | @property 189 | def key(self) -> str: 190 | return self._input_list[2][0] 191 | 192 | @property 193 | def title(self) -> str: 194 | # Places 195 | return self._input_list[2][2] 196 | 197 | @property 198 | def tool_human_name(self) -> str: 199 | # Google Maps 200 | return self._input_list[2][6][0] 201 | 202 | @property 203 | def points(self) -> List[BardMapsPoint]: 204 | return ( 205 | [BardMapsPoint(point) for point in self._input_list[0][1]] 206 | if self._input_list[0] 207 | else [] 208 | ) 209 | 210 | @property 211 | def directions(self) -> Optional[BardMapsDirections]: 212 | return BardMapsDirections(self._input_list[1]) if self._input_list[1] else None 213 | 214 | def __str__(self) -> str: 215 | return self.title 216 | 217 | @property 218 | def markdown_text(self) -> str: 219 | res = f"# {self.title}\n\n" 220 | if self.directions: 221 | res += f"## {self.directions}\n\n" 222 | 223 | if self.points: 224 | res += "\n\n".join([f"## {p.markdown()}" for p in self.points]) 225 | 226 | return res 227 | -------------------------------------------------------------------------------- /bardapi/models/tools/tool.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | class BardTool: 5 | def __init__(self, input_list: list): 6 | self._input_list = input_list 7 | 8 | @property 9 | def step(self) -> Optional[str]: 10 | # Finding your documents 11 | return self._input_list[0] 12 | 13 | @property 14 | def name(self) -> str: 15 | # google_map_tool 16 | return self._input_list[1][0] 17 | 18 | @property 19 | def human_name(self) -> str: 20 | # Google Maps 21 | return self._input_list[1][1][2] 22 | 23 | @property 24 | def logo(self) -> str: 25 | return self._input_list[1][1][3] 26 | 27 | def __str__(self) -> str: 28 | return f'{self.human_name} - {self.step or ""}' 29 | -------------------------------------------------------------------------------- /bardapi/models/tools/tool_declaimer.py: -------------------------------------------------------------------------------- 1 | from bardapi.models.user_content import UserContent 2 | 3 | 4 | class BardToolDeclaimer(UserContent): 5 | """http://googleusercontent.com/tool_disclaimer_content/""" 6 | 7 | def __init__(self, input_list: list): 8 | self._input_list = input_list 9 | self.text = self._input_list[1] 10 | 11 | @property 12 | def key(self) -> str: 13 | return self._input_list[0][0] 14 | 15 | @property 16 | def markdown_text(self) -> str: 17 | return "\n".join(["> " + line for line in self.text.split("\n")]) 18 | 19 | def __str__(self) -> str: 20 | return self.text[:20] 21 | -------------------------------------------------------------------------------- /bardapi/models/tools/youtube.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Union, Dict, Tuple 2 | 3 | from bardapi.models.user_content import UserContent 4 | 5 | 6 | class BardYoutubeVideo: 7 | def __init__(self, input_list: list): 8 | self._input_list = input_list 9 | 10 | @property 11 | def id(self) -> str: 12 | return self._input_list[1] 13 | 14 | @property 15 | def title(self) -> str: 16 | return self._input_list[0] 17 | 18 | @property 19 | def url(self) -> str: 20 | return self._input_list[2] 21 | 22 | @property 23 | def author(self) -> str: 24 | return self._input_list[3] 25 | 26 | @property 27 | def channel_logo(self) -> str: 28 | return self._input_list[4] 29 | 30 | @property 31 | def text(self) -> str: 32 | return self._input_list[5][0] if self._input_list[5] else "" 33 | 34 | def __str__(self) -> str: 35 | return self.title 36 | 37 | 38 | class BardYoutubeContent(UserContent): 39 | """http://googleusercontent.com/youtube_content/""" 40 | 41 | def __init__(self, input_list: list): 42 | self._input_list = input_list 43 | 44 | @property 45 | def key(self) -> str: 46 | return self._input_list[0][0] 47 | 48 | @property 49 | def search_query(self) -> str: 50 | return self._input_list[0][2] 51 | 52 | @property 53 | def search_url(self) -> str: 54 | return self._input_list[7] 55 | 56 | def __getitem__(self, item): 57 | return self.videos[item] 58 | 59 | def __len__(self): 60 | return len(self._input_list[4][0]) 61 | 62 | @property 63 | def videos(self) -> list[BardYoutubeVideo]: 64 | return ( 65 | [BardYoutubeVideo(video) for video in self._input_list[4][0]] 66 | if self._input_list[4] 67 | else [] 68 | ) 69 | 70 | def __str__(self) -> str: 71 | return self.search_query 72 | 73 | @property 74 | def markdown_text(self) -> str: 75 | videos = [ 76 | ( 77 | f"1. [{video.title}]({video.url}) by {video.author}\n\n - {video.text}" 78 | if video.text 79 | else f"1. [{video.title}]({video.url}) by {video.author}" 80 | ) 81 | for video in self.videos 82 | ] 83 | 84 | return ( 85 | f"#### {self.search_query}\n\n" 86 | + "\n".join(videos) 87 | + f"\n\n _View related videos on_ [YouTube]({self.search_url})" 88 | ) 89 | -------------------------------------------------------------------------------- /bardapi/models/user_content.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod, abstractproperty 2 | 3 | 4 | class UserContent(ABC): 5 | @property 6 | @abstractmethod 7 | def key(self) -> str: 8 | pass 9 | 10 | # markdown representation as a long string 11 | @property 12 | @abstractmethod 13 | def markdown_text(self) -> str: 14 | pass 15 | -------------------------------------------------------------------------------- /bardapi/utils.py: -------------------------------------------------------------------------------- 1 | # Util Functions for Async and Sync Core Cookie Modes 2 | import json 3 | import requests 4 | from typing import Optional 5 | from bardapi.constants import IMG_UPLOAD_HEADERS 6 | 7 | 8 | def extract_links(data: list) -> list: 9 | """ 10 | Extract links from the given data. 11 | 12 | Args: 13 | data: Data to extract links from. 14 | 15 | Returns: 16 | list: Extracted links. 17 | """ 18 | links = [] 19 | if isinstance(data, list): 20 | for item in data: 21 | if isinstance(item, list): 22 | # recursive 23 | links.extend(extract_links(item)) 24 | elif ( 25 | isinstance(item, str) 26 | and item.startswith("http") 27 | and "favicon" not in item 28 | ): 29 | links.append(item) 30 | return links 31 | 32 | 33 | def upload_image(image: bytes, filename: str = "Photo.jpg"): 34 | """ 35 | Upload image into bard bucket on Google API, do not need session. 36 | 37 | Returns: 38 | str: relative URL of image. 39 | """ 40 | resp = requests.options("https://content-push.googleapis.com/upload/") 41 | resp.raise_for_status() 42 | size = len(image) 43 | 44 | headers = IMG_UPLOAD_HEADERS 45 | headers["size"] = str(size) 46 | headers["x-goog-upload-command"] = "start" 47 | 48 | data = f"File name: {filename}" 49 | resp = requests.post( 50 | "https://content-push.googleapis.com/upload/", headers=headers, data=data 51 | ) 52 | resp.raise_for_status() 53 | upload_url = resp.headers["X-Goog-Upload-Url"] 54 | resp = requests.options(upload_url, headers=headers) 55 | resp.raise_for_status() 56 | headers["x-goog-upload-command"] = "upload, finalize" 57 | 58 | # It can be that we need to check returned offset 59 | headers["X-Goog-Upload-Offset"] = "0" 60 | resp = requests.post(upload_url, headers=headers, data=image) 61 | resp.raise_for_status() 62 | return resp.text 63 | 64 | 65 | def extract_bard_cookie(cookies: bool = False) -> dict: 66 | """ 67 | Extracts the specified Bard cookie(s) from the browser's cookies. 68 | 69 | This function searches for the specified Bard cookies in various web browsers 70 | installed on the system. It supports modern web browsers and operating systems. 71 | 72 | Args: 73 | cookies (bool, optional): If False, extracts only '__Secure-1PSID' cookie. 74 | If True, extracts '__Secure-1PSID', '__Secure-1PSIDTS', and '__Secure-1PSIDCC' cookies. 75 | Defaults to False. 76 | 77 | Returns: 78 | dict: A dictionary containing the extracted Bard cookies. 79 | 80 | Raises: 81 | Exception: If no supported browser is found or if there's an issue with cookie extraction. 82 | """ 83 | import browser_cookie3 84 | 85 | supported_browsers = [ 86 | browser_cookie3.chrome, 87 | browser_cookie3.chromium, 88 | browser_cookie3.opera, 89 | browser_cookie3.opera_gx, 90 | browser_cookie3.brave, 91 | browser_cookie3.edge, 92 | browser_cookie3.vivaldi, 93 | browser_cookie3.firefox, 94 | browser_cookie3.librewolf, 95 | browser_cookie3.safari, 96 | ] 97 | 98 | cookie_dict = {} 99 | 100 | for browser_fn in supported_browsers: 101 | try: 102 | cj = browser_fn(domain_name=".google.com") 103 | 104 | for cookie in cj: 105 | print(cookie.name) 106 | if cookie.name == "__Secure-1PSID" and cookie.value.endswith("."): 107 | cookie_dict["__Secure-1PSID"] = cookie.value 108 | if cookies: 109 | if cookie.name == "__Secure-1PSIDTS": 110 | print(cookie.value) 111 | cookie_dict["__Secure-1PSIDTS"] = cookie.value 112 | elif cookie.name == "__Secure-1PSIDCC": 113 | print(cookie.value) 114 | cookie_dict["__Secure-1PSIDCC"] = cookie.value 115 | if len(cookie_dict) == 3: 116 | return cookie_dict 117 | except Exception as e: 118 | # Ignore exceptions and try the next browser function 119 | continue 120 | 121 | if not cookie_dict: 122 | raise Exception("No supported browser found or issue with cookie extraction") 123 | 124 | print(cookie_dict) 125 | return cookie_dict 126 | 127 | 128 | def max_token(text: str, n: int) -> str: 129 | """ 130 | Return the first 'n' tokens (words) of the given text. 131 | 132 | Args: 133 | text (str): The input text to be processed. 134 | n (int): The number of tokens (words) to be included in the result. 135 | 136 | Returns: 137 | str: The first 'n' tokens from the input text. 138 | """ 139 | if not isinstance(text, str): 140 | raise ValueError("Input 'text' must be a valid string.") 141 | 142 | tokens = text.split() # Split the text into tokens (words) 143 | if n <= len(tokens): 144 | return " ".join(tokens[:n]) # Return the first 'n' tokens as a string 145 | else: 146 | return text 147 | 148 | 149 | def max_sentence(text: str, n: int): 150 | """ 151 | Print the first 'n' sentences of the given text. 152 | 153 | Args: 154 | text (str): The input text to be processed. 155 | n (int): The number of sentences to be printed from the beginning. 156 | 157 | Returns: 158 | None 159 | """ 160 | punctuations = set("?!.") 161 | 162 | sentences = [] 163 | sentence_count = 0 164 | for char in text: 165 | sentences.append(char) 166 | if char in punctuations: 167 | sentence_count += 1 168 | if sentence_count == n: 169 | result = "".join(sentences).strip() 170 | return result 171 | 172 | 173 | def build_input_text_struct( 174 | input_text: str, 175 | conversation_id: Optional[str], 176 | response_id: Optional[str], 177 | choice_id: Optional[str], 178 | image_url: str = None, 179 | image_name: str = None, 180 | tools: list[list[str]] = None, 181 | ) -> list: 182 | image_arr = [] 183 | if image_url is not None: 184 | image_arr = [[[image_url, 1], image_name]] 185 | 186 | if tools is None: 187 | tools = [] 188 | 189 | return [ 190 | [input_text, 0, None, image_arr, None, None, 0], 191 | ["en"], 192 | [conversation_id, response_id, choice_id, None, None, []], 193 | None, # Unknown random string value (1000 characters +) - If needed, can replace with a random string generator 194 | None, # Random uuidv4 (32 characters) 195 | None, 196 | [1], 197 | 0, 198 | [], 199 | tools, 200 | 1, 201 | 0, 202 | ] 203 | 204 | 205 | def build_input_replit_data_struct(instructions: str, code: str, filename: str) -> list: 206 | """ 207 | Creates and returns the input_image_data_struct based on provided parameters. 208 | 209 | :param instructions: The instruction text. 210 | :param code: The code. 211 | :param filename: The filename. 212 | 213 | :return: The input_image_data_struct. 214 | """ 215 | return [ 216 | [ 217 | [ 218 | "qACoKe", 219 | json.dumps([instructions, 5, code, [[filename, code]]]), 220 | None, 221 | "generic", 222 | ] 223 | ] 224 | ] 225 | 226 | 227 | def build_bard_answer( 228 | parsed_answer: list, 229 | images: list[str], 230 | program_lang: str, 231 | code: str, 232 | status_code: int, 233 | ) -> dict: 234 | return { 235 | "content": parsed_answer[4][0][1][0], 236 | "conversation_id": parsed_answer[1][0], 237 | "response_id": parsed_answer[1][1], 238 | "factuality_queries": parsed_answer[3], 239 | "text_query": parsed_answer[2][0] if parsed_answer[2] else "", 240 | "choices": [{"id": x[0], "content": x[1]} for x in parsed_answer[4]], 241 | "links": extract_links(parsed_answer[4]), 242 | "images": images, 243 | "program_lang": program_lang, 244 | "code": code, 245 | "status_code": status_code, 246 | } 247 | 248 | 249 | def build_export_data_structure( 250 | conv_id: int, resp_id: int, choice_id: int, title: str 251 | ) -> list: 252 | return [ 253 | [ 254 | [ 255 | "fuVx7", 256 | json.dumps( 257 | [ 258 | [ 259 | None, 260 | [ 261 | [ 262 | [conv_id, resp_id], 263 | None, 264 | None, 265 | [[], [], [], choice_id, []], 266 | ] 267 | ], 268 | [0, title], 269 | ] 270 | ] 271 | ), 272 | None, 273 | "generic", 274 | ] 275 | ] 276 | ] 277 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/bardapi.rst: -------------------------------------------------------------------------------- 1 | bardapi package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | bardapi.models 11 | 12 | Submodules 13 | ---------- 14 | 15 | bardapi.chat module 16 | ------------------- 17 | 18 | .. automodule:: bardapi.chat 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bardapi.constants module 24 | ------------------------ 25 | 26 | .. automodule:: bardapi.constants 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bardapi.core module 32 | ------------------- 33 | 34 | .. automodule:: bardapi.core 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bardapi.core\_async module 40 | -------------------------- 41 | 42 | .. automodule:: bardapi.core_async 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bardapi.utils module 48 | -------------------- 49 | 50 | .. automodule:: bardapi.utils 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | Module contents 56 | --------------- 57 | 58 | .. automodule:: bardapi 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # This will include the necessary source files folders in the PATH to be able to generate the documentation from. 22 | # devdir=r'C:\Users\parkm\Desktop\git\ExceptionNotifier' 23 | # try: 24 | # if os.environ['DEVDIR']: 25 | # devdir = os.environ['DEVDIR'] 26 | # except KeyError: 27 | # print('Unable to obtain $DEVDIR from the environment.') 28 | # pass 29 | 30 | sys.path.insert(0, os.path.abspath("../..")) 31 | sys.setrecursionlimit(1500) 32 | 33 | 34 | # Ensure that the __init__ method gets documented. 35 | def skip(app, what, name, obj, skip, options): 36 | if name == "__init__": 37 | return False 38 | return skip 39 | 40 | 41 | # -- Project information ----------------------------------------------------- 42 | 43 | project = "bardapi" 44 | copyright = "2024, minwoo park" 45 | author = "minwoo park" 46 | 47 | # The full version, including alpha/beta/rc tags 48 | release = "0.1.39" 49 | 50 | 51 | # -- General configuration --------------------------------------------------- 52 | 53 | # Add any Sphinx extension module names here, as strings. They can be 54 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 55 | # ones. 56 | extensions = ["sphinx.ext.autodoc", "sphinx.ext.todo"] 57 | 58 | # ,'sphinx.ext.napoleon' 59 | 60 | # Add any paths that contain templates here, relative to this directory. 61 | templates_path = ["_templates"] 62 | todo_include_todos = True 63 | # List of patterns, relative to source directory, that match files and 64 | # directories to ignore when looking for source files. 65 | # This pattern also affects html_static_path and html_extra_path. 66 | exclude_patterns = [] 67 | 68 | 69 | # -- Options for HTML output ------------------------------------------------- 70 | 71 | # The theme to use for HTML and HTML Help pages. See the documentation for 72 | # a list of builtin themes. 73 | # 74 | html_theme = "sphinx_rtd_theme" 75 | 76 | # Add any paths that contain custom static files (such as style sheets) here, 77 | # relative to this directory. They are copied after the builtin static files, 78 | # so a file named "default.css" will overwrite the builtin "default.css". 79 | html_static_path = ["_static"] 80 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. bardapi documentation master file, created by 2 | sphinx-quickstart on Wed Jan 24 02:50:19 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to BardAPI's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 4 11 | :caption: Contents: 12 | 13 | installation 14 | officialgithub 15 | bardapi 16 | 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | =============================================================================================== 3 | 4 | Install `The Python Package:BardAPI` with `pip`: 5 | 6 | ``$ pip install BardAPI`` 7 | 8 | or 9 | 10 | ``$ pip install bardapi`` 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/officialgithub.rst: -------------------------------------------------------------------------------- 1 | Official Github 2 | ===================================================================== 3 | 4 | `BardAPI` Official Github: 5 | - https://github.com/dsdanielpark/Bard-API 6 | 7 | Check the latest information through the official github. Active debugging and development are in progress until the beta release, so updates to GitHub will be a little faster than official documentation. Sincerely grateful for any reports on new features or bugs. Your valuable feedback on the code is highly appreciated. 8 | -------------------------------------------------------------------------------- /docs/source/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/source/bardapi.models.rst: -------------------------------------------------------------------------------- 1 | bardapi.models package 2 | ====================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | bardapi.models.tools 11 | 12 | Submodules 13 | ---------- 14 | 15 | bardapi.models.citation module 16 | ------------------------------ 17 | 18 | .. automodule:: bardapi.models.citation 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bardapi.models.draft module 24 | --------------------------- 25 | 26 | .. automodule:: bardapi.models.draft 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bardapi.models.image module 32 | --------------------------- 33 | 34 | .. automodule:: bardapi.models.image 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bardapi.models.result module 40 | ---------------------------- 41 | 42 | .. automodule:: bardapi.models.result 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bardapi.models.user\_content module 48 | ----------------------------------- 49 | 50 | .. automodule:: bardapi.models.user_content 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | Module contents 56 | --------------- 57 | 58 | .. automodule:: bardapi.models 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | -------------------------------------------------------------------------------- /docs/source/bardapi.models.tools.rst: -------------------------------------------------------------------------------- 1 | bardapi.models.tools package 2 | ============================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | bardapi.models.tools.code module 8 | -------------------------------- 9 | 10 | .. automodule:: bardapi.models.tools.code 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | bardapi.models.tools.flight module 16 | ---------------------------------- 17 | 18 | .. automodule:: bardapi.models.tools.flight 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bardapi.models.tools.gdocs module 24 | --------------------------------- 25 | 26 | .. automodule:: bardapi.models.tools.gdocs 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bardapi.models.tools.gworkspace module 32 | -------------------------------------- 33 | 34 | .. automodule:: bardapi.models.tools.gworkspace 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bardapi.models.tools.hotel module 40 | --------------------------------- 41 | 42 | .. automodule:: bardapi.models.tools.hotel 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bardapi.models.tools.json module 48 | -------------------------------- 49 | 50 | .. automodule:: bardapi.models.tools.json 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | bardapi.models.tools.link module 56 | -------------------------------- 57 | 58 | .. automodule:: bardapi.models.tools.link 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | bardapi.models.tools.map module 64 | ------------------------------- 65 | 66 | .. automodule:: bardapi.models.tools.map 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | bardapi.models.tools.tool module 72 | -------------------------------- 73 | 74 | .. automodule:: bardapi.models.tools.tool 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | bardapi.models.tools.tool\_declaimer module 80 | ------------------------------------------- 81 | 82 | .. automodule:: bardapi.models.tools.tool_declaimer 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | bardapi.models.tools.youtube module 88 | ----------------------------------- 89 | 90 | .. automodule:: bardapi.models.tools.youtube 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | 95 | Module contents 96 | --------------- 97 | 98 | .. automodule:: bardapi.models.tools 99 | :members: 100 | :undoc-members: 101 | :show-inheritance: 102 | -------------------------------------------------------------------------------- /docs/source/bardapi.rst: -------------------------------------------------------------------------------- 1 | Bard API Package 2 | ================ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | bardapi.models 11 | 12 | Submodules 13 | ---------- 14 | 15 | bardapi.chat module 16 | ------------------- 17 | 18 | .. automodule:: bardapi.chat 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bardapi.constants module 24 | ------------------------ 25 | 26 | .. automodule:: bardapi.constants 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bardapi.core module 32 | ------------------- 33 | 34 | .. automodule:: bardapi.core 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bardapi.core\_async module 40 | -------------------------- 41 | 42 | .. automodule:: bardapi.core_async 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bardapi.utils module 48 | -------------------- 49 | 50 | .. automodule:: bardapi.utils 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | Module contents 56 | --------------- 57 | 58 | .. automodule:: bardapi 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, 'C:\\Users\\parkm\\Desktop\\git_ram\\BARD_API\\bardapi') 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = "bardapi" 21 | copyright = "2024, Author" 22 | author = "Author" 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = [ 31 | "sphinx.ext.autodoc", 32 | "sphinx.ext.viewcode", 33 | "sphinx.ext.todo", 34 | ] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ["_templates"] 38 | 39 | # The language for content autogenerated by Sphinx. Refer to documentation 40 | # for a list of supported languages. 41 | # 42 | # This is also used if you do content translation via gettext catalogs. 43 | # Usually you set "language" from the command line for these cases. 44 | language = "en" 45 | 46 | # List of patterns, relative to source directory, that match files and 47 | # directories to ignore when looking for source files. 48 | # This pattern also affects html_static_path and html_extra_path. 49 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 50 | 51 | 52 | # -- Options for HTML output ------------------------------------------------- 53 | 54 | # The theme to use for HTML and HTML Help pages. See the documentation for 55 | # a list of builtin themes. 56 | # 57 | html_theme = "alabaster" 58 | 59 | # Add any paths that contain custom static files (such as style sheets) here, 60 | # relative to this directory. They are copied after the builtin static files, 61 | # so a file named "default.css" will overwrite the builtin "default.css". 62 | html_static_path = ["_static"] 63 | 64 | 65 | # -- Extension configuration ------------------------------------------------- 66 | 67 | # -- Options for todo extension ---------------------------------------------- 68 | 69 | # If true, `todo` and `todoList` produce output, else they produce nothing. 70 | todo_include_todos = True 71 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. bardapi documentation master file, created by 2 | sphinx-quickstart on Wed Jan 24 02:51:28 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to bardapi's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 4 11 | :caption: Contents: 12 | 13 | installation 14 | officialgithub 15 | bardapi 16 | 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | -------------------------------------------------------------------------------- /docs/source/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /documents/README_DEV.md: -------------------------------------------------------------------------------- 1 | Development Status :: 5 - Production/Stable 2 | 3 | 4 | # GitHub installation required for the following features. 5 | Starting from version `0.1.18`, the GitHub version of BardAPI will be synchronized with the PyPI version and released simultaneously. 6 | ``` 7 | pip install git+https://github.com/dsdanielpark/Bard-API.git 8 | ``` 9 | 10 | 11 | # Contents 12 | - [GitHub installation required for the following features.](#github-installation-required-for-the-following-features) 13 | - [Contents](#contents) 14 | - [Structure of `core.py - Bard` class](#structure-of-corepy---bard-class) 15 | - [Auto Cookie Bard](#auto-cookie-bard) 16 | - [Text To Speech(TTS)](#text-to-speechtts) 17 | - [Multi-language Bard](#multi-language-bard) 18 | - [Bard `ask_about_image` method](#bard-ask_about_image-method) 19 | - [Get image links](#get-image-links) 20 | - [ChatBard](#chatbard) 21 | - [Export Conversation](#export-conversation) 22 | - [Export Code to Repl.it](#export-code-to-replit) 23 | - [Executing Python code received as a response from Bard](#executing-python-code-received-as-a-response-from-bard) 24 | - [Using Bard asynchronously](#using-bard-asynchronously) 25 | - [Multi-cookie Bard](#multi-cookie-bard) 26 | - [Fix Conversation ID (Fix Context)](#fix-conversation-id-fix-context) 27 | - [Translation to Another Programming Language](#translation-to-another-programming-language) 28 | - [max\_token, max\_sentence](#max_token-max_sentence) 29 | - [ChatBard with more features](#chatbard-with-more-features) 30 | - [Usage](#usage) 31 | - [Features](#features) 32 | - [Handle API Errors](#handle-api-errors) 33 | - [Input Validation](#input-validation) 34 | - [Chat History](#chat-history) 35 | - [Multilingual Support](#multilingual-support) 36 | - [Improved User Experience](#improved-user-experience) 37 | - [Integration with Other APIs](#integration-with-other-apis) 38 | 39 | 40 | 41 |
42 | 43 | 44 | ### Structure of `core.py - Bard` class 45 | 46 |
47 | See class structure... 48 | 49 | ```python 50 | class Bard: 51 | """ 52 | Bard class for interacting with the Bard API. 53 | """ 54 | 55 | def __init__( 56 | self, 57 | token: Optional[str] = None, 58 | timeout: int = 20, 59 | proxies: Optional[dict] = None, 60 | session: Optional[requests.Session] = None, 61 | conversation_id: Optional[str] = None, 62 | google_translator_api_key: Optional[str] = None, 63 | language: Optional[str] = None, 64 | run_code: bool = False, 65 | token_from_browser: bool = False, 66 | ): 67 | """ 68 | Initialize the Bard instance. 69 | ... 70 | """ 71 | 72 | def get_answer(self, input_text: str) -> dict: 73 | """ 74 | Get an answer from the Bard API for the given input text. 75 | ... 76 | """ 77 | 78 | def speech(self, input_text: str, lang: str = "en-US") -> dict: 79 | """ 80 | Get speech audio from Bard API for the given input text. 81 | ... 82 | """ 83 | 84 | def export_conversation(self, bard_answer, title: str = "") -> dict: 85 | """ 86 | Get Share URL for specific answer from Bard. 87 | ... 88 | """ 89 | 90 | def ask_about_image(self, input_text: str, image: bytes, lang: Optional[str] = None) -> dict: 91 | """ 92 | Send Bard image along with question and get an answer. 93 | ... 94 | """ 95 | 96 | def export_replit( 97 | self, code: str, langcode: Optional[str] = None, filename: Optional[str] = None, **kwargs 98 | ) -> dict: 99 | """ 100 | Get Export URL to repl.it from code. 101 | ... 102 | """ 103 | 104 | def _get_snim0e(self) -> str: 105 | """ 106 | Get the SNlM0e value from the Bard API response. 107 | ... 108 | """ 109 | 110 | def _get_session(self, session: Optional[requests.Session]) -> requests.Session: 111 | """ 112 | Get the requests Session object. 113 | """ 114 | 115 | def _get_token(self, token: str, token_from_browser: bool) -> str: 116 | """ 117 | Get the Bard API token either from the provided token or from the browser cookie. 118 | """ 119 | ``` 120 |
121 | 122 |
123 | 124 | ### Auto Cookie Bard 125 | Using [browser_cookie3](https://github.com/borisbabic/browser_cookie3) we extract the `__Secure-1PSID`` cookie from all browsers, and then we can use the API without passing the token. However, there are still incomplete dependency packages and various variables, so please seek assistance in the following [GitHub Issues](https://github.com/borisbabic/browser_cookie3/issues) or adjust your browser's version. 126 | 127 | ```python 128 | from bardapi import Bard 129 | 130 | bard = Bard(token_from_browser=True) 131 | bard_answer = bard.get_answer("Do you like cookies?")['content'] 132 | print(bard_answer) 133 | ``` 134 | 135 |
136 | 137 | ### Text To Speech(TTS) 138 | ```python 139 | from bardapi import Bard 140 | 141 | bard = Bard(token= xxxxxxxxx ) 142 | audio = bard.speech("Hello, I am bard! How can I assist you?", lang='en-US') # Get bytes audio object. 143 | 144 | # Save audio object. 145 | with open('bard_response.mp3', 'wb') as f: 146 | f.write(audio['audio']) 147 | ``` 148 | 149 |
150 | 151 | ### Multi-language Bard 152 | For commercial use cases, please refrain from using the unofficial Google Translate package included in bardapi for non-commercial purposes. Instead, kindly visit the official Google Cloud Translation website. Please use it responsibly, taking full responsibility for your actions, as bardapi package does not assume any implicit or explicit liability. 153 | > Official Google Translation API 154 | - Support Languages: https://cloud.google.com/translate/docs/languages?hl=ko 155 | > Unofficial Google Trnaslator for non-profit purposes (such as feature testing) 156 | - Support Languages: https://github.com/nidhaloff/deep-translator/blob/master/deep_translator/constants.py 157 | ```python 158 | from bardapi import Bard 159 | 160 | bard = Bard(token=token, language='chinese (simplified)') 161 | res = bard.get_answer("今天首尔的天气怎么样?") 162 | print(res['content']) 163 | ``` 164 | or 165 | ```python 166 | from bardapi import Bard 167 | import os 168 | os.environ["_BARD_API_LANG"] = 'chinese (simplified)' 169 | os.environ["_BARD_API_KEY"] = 'xxxxxxxxx' 170 | 171 | res = Bard().get_answer("今天首尔的天气怎么样?") 172 | print(res['content']) 173 | ``` 174 | 175 |
176 | 177 | ### Bard `ask_about_image` method 178 | *It may not work as it is only available for certain accounts, regions, and other restrictions.* 179 | As an experimental feature, it is possible to ask questions with an image. However, this functionality is only available for accounts with image upload capability in Bard's web UI. 180 | 181 | ```python 182 | from bardapi import Bard 183 | 184 | bard = Bard(token='xxxxxxxx') 185 | image = open('image.jpg', 'rb').read() # (jpeg, png, webp) are supported. 186 | bard_answer = bard.ask_about_image('What is in the image?', image) 187 | print(bard_answer['content']) 188 | ``` 189 | 190 |
191 | 192 | ### Get image links 193 | ```python 194 | from bardapi import Bard 195 | bard = Bard(token='xxxxxxxx') 196 | res = bard.get_answer("Find me an image of the main entrance of Stanford University.") 197 | res['links'] # Get image links (list) 198 | res['images'] # Get images (list) 199 | ``` 200 | 201 |
202 | 203 | ### ChatBard 204 | Some errors in ChatBard have been fixed. However, it is recommended not to pass the value of the token through input. See detials in [ChatBard with more features](https://github.com/dsdanielpark/Bard-API/blob/main/README_DEV.md#chatbard-with-more-features). 205 | 206 | ```python 207 | from bardapi import ChatBard 208 | 209 | chat = ChatBard(token="xxxxxxxx", language='en') 210 | chat.start() 211 | ``` 212 | or 213 | ```python 214 | from bardapi import ChatBard 215 | import os 216 | os.environ["_BARD_API_KEY"]='xxxxxxxx' # Requird 217 | os.environ["_BARD_API_LANG"]="Arabic" # Optional, Default to English 218 | os.environ["_BARD_API_TIMEOUT"]=30 # Optional, Session Timeout 219 | 220 | chat = ChatBard() 221 | chat.start() 222 | ``` 223 | or 224 | ```python 225 | from bardapi import Bard, SESSION_HEADERS 226 | import requests 227 | 228 | token='xxxxxxxx' 229 | session = requests.Session() 230 | session.headers = SESSION_HEADERS 231 | session.cookies.set("__Secure-1PSID", token) 232 | proxies = { 233 | 'http': 'http://proxy.example.com:8080', 234 | 'https': 'https://proxy.example.com:8080' 235 | } 236 | 237 | ChatBard(token=token, session=session, proxies=proxies, timeout=40, language="chinese (simplified)").start() 238 | ``` 239 | 240 |
241 | 242 | ### Export Conversation 243 | *It may not work as it is only available for certain accounts, regions, and other restrictions.* 244 | Bard UI offers a convenient way to share a specific answer from Bard by generating a URL. This feature enables users to easily create and share URLs for individual answers. 245 | 246 | ```python 247 | from bardapi import Bard 248 | bard = Bard(token='xxxxxxxx') 249 | bard_answer = bard.get_answer('How are you?') 250 | url = bard.export_conversation(bard_answer, title='Example Shared conversation') 251 | print(url['url']) 252 | 253 | ``` 254 | 255 |
256 | 257 | ### Export Code to [Repl.it](https://replit.com/) 258 | ```python 259 | from bardapi import Bard 260 | 261 | bard = Bard(token='xxxxxxxx') 262 | 263 | bard_answer = bard.get_answer("code python to print hello world") 264 | # {'code': 'print("Hello World")', 'program_lang': 'python'} 265 | url = bard.export_replit( 266 | code=bard_answer['code'], 267 | program_lang=bard_answer['program_lang'], 268 | ) 269 | print(url['url']) # https://replit.com/external/v1/claims/xxx/claim 270 | ``` 271 | 272 |
273 | 274 | ### Executing Python code received as a response from Bard 275 | ```python 276 | from bardapi import Bard 277 | 278 | bard = Bard(token="xxxxxxxx", run_code=True) 279 | bard.get_answer("code a pie chart in python for this data={'blue':25, 'red':30, 'green':30, 'purple':15}") 280 | ``` 281 | ![](assets/bardapi_run_code.png) 282 | 283 |
284 | 285 | ### Using Bard asynchronously 286 | Using asynchronous implementation will be efficient when implementing ChatBots or something alone those lines. 287 | BardAsync is not using requests library instead it is using httpx library and http2 protocol. 288 | 289 | ```python 290 | from httpx import AsyncClient 291 | from bardapi import BardAsync 292 | # Uncomment and set your API key as needed 293 | # import os 294 | # os.environ['_BARD_API_KEY'] = 'xxxxxxx' 295 | token = 'xxxxxxx' # Replace with your actual token 296 | 297 | SESSION_HEADERS = { 298 | "Host": "bard.google.com", 299 | "X-Same-Domain": "1", 300 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 301 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", 302 | "Origin": "https://bard.google.com", 303 | "Referer": "https://bard.google.com/", 304 | } 305 | timeout = 30 # Example timeout 306 | proxies = {} # Replace with your proxies if needed 307 | 308 | client = AsyncClient( 309 | http2=True, 310 | headers=SESSION_HEADERS, 311 | cookies={"__Secure-1PSID": token}, 312 | timeout=timeout, 313 | proxies=proxies, 314 | ) 315 | 316 | bard_async = BardAsync(token=token, client=client) 317 | 318 | # Asynchronous function to get the answer 319 | async def get_bard_answer(question): 320 | await bard_async.async_setup() # Ensure async setup is done 321 | return await bard_async.get_answer(question) 322 | 323 | response = await get_bard_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘") 324 | print(response['content']) 325 | ``` 326 | 327 |
328 | 329 | 330 | ### Multi-cookie Bard 331 | Depending on the country, region, and status of your Google account, you may need to use multiple cookies. If so, please provide the cookies in the form of a dictionary. 332 | ```python 333 | from bardapi import BardCookies 334 | 335 | cookie_dict = { 336 | "__Secure-1PSID": "xxxxxxxx", 337 | "__Secure-1PSIDTS": "xxxxxxxx", 338 | "__Secure-1PSIDCC", "xxxxxxxx", 339 | # Any cookie values you want to pass session object. 340 | } 341 | 342 | bard = BardCookies(cookie_dict=cookie_dict) 343 | print(bard.get_answer("こんにちは")['content']) 344 | ``` 345 | 346 | Bard with reusable session which contain mutiple cookie value 347 | ```python 348 | import requests 349 | from bardapi import Bard, SESSION_HEADERS 350 | 351 | session = requests.Session() 352 | session.cookies.set("__Secure-1PSID", "bard __Secure-1PSID token") 353 | session.cookies.set( "__Secure-1PSIDCC", "bard __Secure-1PSIDCC token") 354 | session.cookies.set("__Secure-1PSIDTS", "bard __Secure-1PSIDTS token") 355 | session.headers = SESSION_HEADERS 356 | 357 | bard = Bard(session=session) 358 | bard.get_answer("How is the weather today in seoul?") 359 | ``` 360 | 361 | 362 | Multi-cookie Bard with auto cookies from browser 363 | ```python 364 | from bardapi import Bard 365 | 366 | bard = BardCookies(token_from_browser=True) 367 | bard.get_answer("How is the weather today in seoul?") 368 | ``` 369 | 370 |
371 | 372 | ### Fix Conversation ID (Fix Context) 373 | BART returns multiple responses as candidate answers. Each of these responses is assigned a conversation_id. While using a reusable session, you can observe that your prompt is stored. However, if you desire consistent answers, you can provide the desired conversation_id as an argument among the returned candidate answers. 374 | 375 | - Passing only the `session`: Retains your prompt. 376 | - Passing both `session` and `conversation_id`: Retains your prompt and allows you to receive answers with consistent parameters. 377 | 378 | ```python 379 | from bardapi import Bard, SESSION_HEADERS 380 | import requests 381 | 382 | # Set token 383 | token= 'xxxxxxxx' 384 | 385 | # Set session 386 | session = requests.Session() 387 | session.headers = SESSION_HEADERS 388 | session.cookies.set("__Secure-1PSID", token) 389 | 390 | # Give session and conversation id. (check manually) 391 | bard = Bard(token=token, session=session, conversation_id="c_1f04f704a788e6e4", timeout=30) 392 | bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘")['content'] 393 | ``` 394 | 395 |
396 | 397 | ### Translation to Another Programming Language 398 | Please check the translation results in [this folder](https://github.com/dsdanielpark/Bard-API/tree/main/translate_to). 399 | - Copy the code of [Core.py](https://github.com/dsdanielpark/Bard-API/blob/17d5e948d4afc535317de3964232ab82fe223521/bardapi/core.py). 400 | - Ask ChatGPT to translate like "Translate to Swift." 401 | - Ask ChatGPT to optimize the code or provide any desired instructions until you're satisfied.
402 | 403 | ![](./assets/translate.png) 404 | 405 | 406 |
407 | 408 | ### max_token, max_sentence 409 | Bard does not support temperature or hyperparameter adjustments, but it is possible to achieve the appearance of limiting the number of output tokens or the number of output sentences using simple algorithms, as follows: 410 | ```python 411 | from bardapi import Bard, max_token, max_sentence 412 | 413 | token = 'xxxxxxx' 414 | bard = Bard(token=token) 415 | 416 | # max_token==30 417 | max_token(bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘")['content'], 30) 418 | # max_sentence==2 419 | max_sentence(bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘")['content'], 2) 420 | ``` 421 | 422 |
423 | 424 | 425 | ### ChatBard with more features 426 | ChatBard is a chatbot class powered by the Bard API. It allows users to have interactive conversations with the chatbot and retrieve responses from the Bard API. 427 | 428 | #### Usage 429 | 430 | ```python 431 | from bardapi import ChatBard 432 | 433 | chat = ChatBard() 434 | chat.start() 435 | ``` 436 | 437 | #### Features 438 | Customize User Prompt 439 | Users can customize the prompt displayed to the user before input by providing a custom prompt message to the start() method. 440 | ```python 441 | chat.start(prompt="Enter your message: ") 442 | ``` 443 | 444 | #### Handle API Errors 445 | Error handling has been implemented for API requests. If an error occurs while communicating with the Bard API, an appropriate error message will be displayed to the user. 446 | 447 | #### Input Validation 448 | User input is validated before sending it to the API. The input is checked for emptiness and length validation. If the input is invalid, the user is prompted to provide valid input. 449 | 450 | #### Chat History 451 | Chat history is stored during the conversation, including the user input and the corresponding chatbot responses. The display_chat_history() method can be called to print the chat history. 452 | ```python 453 | chat.display_chat_history() 454 | ``` 455 | 456 | #### Multilingual Support 457 | Users can select different languages for the chatbot interaction by specifying the language parameter when initializing the ChatBard object. The default language is English. 458 | ```python 459 | chat = ChatBard(language="spanish") 460 | ``` 461 | 462 | #### Improved User Experience 463 | Chatbot responses are displayed using colors and formatting to enhance the user experience. User input is displayed in green, and chatbot responses are displayed in blue. 464 | 465 | #### Integration with Other APIs 466 | The ChatBard class focuses on the interaction with the Bard API. If you want to integrate additional APIs, you can extend the functionality by adding appropriate methods and making the necessary API calls within the ChatBard class. 467 | 468 | 469 | -------------------------------------------------------------------------------- /documents/README_FAQ.md: -------------------------------------------------------------------------------- 1 | Development Status :: 5 - Production/Stable 2 | 3 | # FAQ 4 | Cookie values may only be valid for a limited time (approximately 15-20 minutes and may be subject to rate limiting even sooner). Again, it's challenging to implement this in official services. Also, this is not an official Google package, and its availability for future use is uncertain. 5 | 6 | ## Before using the Bard API 7 | - Google Bard can return different responses based on various factors such as account, country, region, IP, etc., following Google's policies. This means that even well-functioning methods, especially the `ask_about_image` method, can encounter Response Errors, which are caused by various reasons related to Google's policies, not package errors. It cannot be resolved at the package level. (e.g., [CAPTCHA](https://en.wikipedia.org/wiki/CAPTCHA) or [HTTP 429 error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429)) 8 | - The API token(__Secure-1PSID cookie value) for this service is unofficial. Additionally, exposing it can allow others to easily use the Bard service with your Google ID, so never expose it. 9 | - This service has very limited and variable call limits per unit of time, and exceeding rate limiting temporarily prevents obtaining normal response results. 10 | - Sending the same question multiple times in requests can also temporarily prevent obtaining normal response results. 11 | - Some regions may require additional cookie values besides __Secure-1PSID; refer to the issue page. 12 | - The __Secure-1PSID cookie value may change frequently. Logout, restart your web browser, and enter the new __Secure-1PSID cookie value. 13 | - Using this package for real-world applications is highly inappropriate. Due to rate limiting and variable API policies, it will only function temporarily. 14 | - If the time interval between requests is very short, the Google API process may interpret it as performing a large number of requests and may not return normal responses. 15 | - All these policies are subject to change, and the interface is also variable. 16 | - The reason this Bard API's method names do not follow the typical inference format of general LLMs is to prevent confusion with the official API. This Python package merely serves as an unofficial API to fetch responses from Bard's website, so please do not be mistaken. 17 | - The official API format for Bard will likely be as follows. 18 |
19 | Click to view the text generative AI model API code template 20 | 21 | ```python 22 | bard.configure(api_key='YOUR_API_KEY') 23 | 24 | models = [m for m in palm.list_models() if 'generateText' in m.supported_generation_methods] 25 | model = models[0].name 26 | print(model) 27 | 28 | prompt = "Who are you?" 29 | 30 | completion = bard.generate_text( 31 | model=model, 32 | prompt=prompt, 33 | temperature=0, 34 | # The maximum length of the response 35 | max_output_tokens=800, 36 | ) 37 | ``` 38 |
39 | 40 | 41 | 42 |

43 | 44 | *** 45 | 46 | ### Q: Why is the package structure so messy and unorganized like this? 47 | 48 | ### A: While rapidly adapting to Google's interface changes, various unexpected features were added, causing the structure to become messy. This package is not intended for providing stable services, and it may become unusable at any time based on Google's decisions, so it hasn't been heavily optimized. It would be advisable to use it temporarily for testing purposes only. 49 | 50 | [#263](https://github.com/dsdanielpark/Bard-API/discussions/267) 51 | 52 | Originally, Bard had very simple functionality as it was meant for experimental purposes. It used to fetch only a single response through a single cookie even in the 'get_answer' function. However, various additional features were added to Bard over time, such as uploading images, fetching image links, or executing code, among others. The Bard API package was developed quickly in Python to implement these features and perform lightweight testing. 53 | 54 | In other words, the package initially lacked these diverse functionalities, and as unexpected features were added, the focus was solely on getting the functionality to work. This resulted in a messy package structure and less-than-clean code. 55 | 56 | Additionally, implementing asynchronous functionality did not provide significant benefits, but it was added upon the requests of some developers to quickly implement the features. It was discovered that some users needed more than one cookie, so the goal was to implement these functionalities within the existing structure in the shortest possible time. 57 | 58 | Overall, it was difficult to predict the interface or structure, and this package was created primarily for temporary and lightweight prototyping, as it was not meant for providing a stable service. 59 | 60 | Therefore, it is very messy and not optimized, and this continues to be a major concern. The package's functionality may stop working at any time due to changes in Google's interface decisions. 61 | 62 | Furthermore, adapting to new features or removing them is not straightforward. I feel a great responsibility for providing developers with unoptimized code that has caused inefficiencies, but developing a new package to address this issue has been challenging given the uncertainty of when the functionality might come to an end. 63 | 64 | Nevertheless, I am making efforts to revise the package structure whenever possible. Your understanding is appreciated. 65 | 66 | *** 67 | 68 | ### #01. Response Error 69 | ```python 70 | Response Error: b')]}\\'\\n\\n38\\n[[\"wrb.fr\",null,null,null,null,[8]]]\\n54\\n[[\"di\",59], 71 | [\"af.httprm\",59,\"4239016509367430469\",0]]\\n25\\n[[\"e\",4,null,null,129]]\\n'. 72 | Temporarily unavailable due to traffic or an error in cookie values. Please double-check the cookie values and verify your network environment. 73 | ``` 74 | 75 | The error you're experiencing isn't originating from the package itself; it's related to your Google account and may be due to various factors like your country or region settings, which can prevent you from receiving accurate results from Bard. Therefore, it's beyond the scope of the package to resolve, but please consider checking the following: 76 | 77 | 1. First, thoroughly read the readme and see if it pertains to cases of temporary abnormal responses from the package. Try again after some time or a few hours: [Before using Bard API](https://github.com/dsdanielpark/Bard-API/blob/main/README.md#before-using-the-bard-api) 78 | 2. Bypass proxies: [Behind a proxy](https://github.com/dsdanielpark/Bard-API#behind-a-proxy) 79 | 3. Try using an account from a different region or change the language settings of your Google account. 80 | 4. Restart your browser to refresh the cookie values and use the new __Secure-1PSID. 81 | 5. Try passing three or more cookies using [Multi-cookie Bard](https://github.com/dsdanielpark/Bard-API/blob/main/documents/README_DEV.md#multi-cookie-bard). If that doesn't work, consider passing almost all cookie values. 82 | 83 | Please let me know if you need further assistance. 84 | 85 | *** 86 | 87 | ### #02. Response Status is 429 88 | 89 | ``` 90 | Traceback (most recent call last): 91 | File "/Users/arielolin/IAPP-server/server.py", line 20, in 92 | bard = Bard(token=BARD_TOKEN, session=bard_session) 93 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 94 | File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/bardapi/core.py", line 78, in __init__ 95 | self.SNlM0e = self._get_snim0e() 96 | ^^^^^^^^^^^^^^^^^^ 97 | File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/bardapi/core.py", line 149, in _get_snim0e 98 | raise Exception( 99 | Exception: Response status code is not 200. Response Status is 429 100 | ``` 101 | 102 | Both are not package-related issues and are unsolvable problems. It is recommended to work around them as much as possible. This is a problem at the level of Google's API, and while it would take a long time to develop software to work around it, even assuming that it could be developed, it is not worth developing because it is easily blocked. There are no plans to update it further. There is no package-level solution to prevent captcha or HTTP 429 errors other than efforts such as bypassing readme and proxy, and creating a time interval between requests to avoid rate limiting. 103 | - `CAPTCHA`: a program or system intended to distinguish human from machine input, typically as a way of [thwarting](https://www.google.com/search?sca_esv=573532060&sxsrf=AM9HkKmd5Faz1q0x4sLsgIG3VgVR9V18iA:1697335053753&q=thwarting&si=ALGXSlbSiMNWMsv5Y0U_0sBS8EWzwSlNZdPczeDdDqrhgxYO86hMDzIqBVTJp6ZKxKdXeVsCSihVIJAH_MROqwPM7RtQB0OoEA%3D%3D&expnd=1) spam and automated extraction of data from websites. 104 | - `The HTTP 429`: Too Many Requests response status code indicates the user has sent too many requests in a given amount of time ("rate limiting") 105 | 106 | *** 107 | 108 | ### #03. Exception: SNlM0e value not found. Double-check __Secure-1PSID value or pass it as token='xxxxx'. #155, #99 109 | - https://github.com/dsdanielpark/Bard-API/issues/155 110 | - https://github.com/dsdanielpark/Bard-API/issues/99 111 | 112 | *** 113 | 114 | ### #04. Response Error: b')]}\\'\\n\\n38\\n[[\"wrb.fr\",null,null,null,null,[8]]]\\n54\\n[[\"di\",59],[\"af.httprm\",59,\"4239016509367430469\",0]]\\n25\\n[[\"e\",4,null,null,129]]\\n'. \nTemporarily unavailable due to traffic or an error in cookie values. Please double-check the cookie values and verify your network environment. #128 115 | - https://github.com/dsdanielpark/Bard-API/issues/128 116 | 117 | *** 118 | 119 | ### #05. Using Proxy 120 | If you cannot receive a normal response in your area, try making the request through [Crawlbase](https://crawlbase.com/)'s anonymous [smart proxy service.](https://crawlbase.com/docs/smart-proxy/get/) (Still, be mindful of Google's rate limiting, so adjust the time between requests and avoid requesting duplicate responses.) 121 | 122 | ``` 123 | $ pip install bardapi 124 | ``` 125 | 126 | ```python 127 | from bardapi import Bard 128 | import requests 129 | 130 | # Get your proxy url at crawlbase https://crawlbase.com/docs/smart-proxy/get/ 131 | proxy_url = "http://xxxxxxxxxxxxxx:@smartproxy.crawlbase.com:8012" 132 | proxies = {"http": proxy_url, "https": proxy_url} 133 | 134 | bard = Bard(token='xxxxxxx', proxies=proxies, timeout=30) 135 | bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘")['content'] 136 | ``` 137 | 138 | *** 139 | 140 | ### #06. How to output results sequentially without delay like ChatGPT? 141 | 142 | - Short answer: Bard is currently not supported. 143 | 144 | OpenAI provides immediate asynchronous returns of some generated text results (tokens) at the inference stage of the model. However, Bard does not yet support this feature. Bard returns the results to the user once the model has completed generating all text (tokens). There may be various reasons for this, but ultimately, the speed difference between the two is dependent on resources and may be challenging for users to address. In conclusion, consider exploring other ways to reduce perceived delays for users. 145 | 146 | Note that for Hugging Face's Open LLM models, you can implement this using TextStreamer as follows. 147 | 148 | 149 | ```python 150 | from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer 151 | 152 | model_name = "meta-llama/Llama-2-70b-chat-hf" 153 | tokenizer = AutoTokenizer.from_pretrained(model_name) 154 | model = AutoModelForCausalLM.from_pretrained(model_name) 155 | streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) 156 | 157 | output = model.generate(**inputs, streamer=streamer, use_cache=True) 158 | ``` 159 | 160 | Furthermore, since this package is an unofficial Python package that intercepts values returned by the web UI of Google Bard's official website, there is nothing more we can support at this package level. 161 | 162 | *** 163 | 164 | ### #07. The conversation keeps starting anew. Can this be resolved? 165 | 166 | - Short answer: It seems unlikely. It might be possible, but it requires experimentation. If you find a solution, anyone can contribute through a pull request. 167 | You can attempt to fix the session by referring to the contents of a reusable session or try to lock the returned values with a context ID. However, fundamentally, users need an option to fix the seed value, as seen in OpenAI's ChatGPT, to address this issue. Currently, Bard offers limited options to users, even temperature and basic settings, so it may take some time. To make the conversation memorable, you can 1) code to summarize and store the conversation in a database, ensuring the queue changes approximately every 3-5 turns, and 2) transmit the summarized conversation and response to Bard along with a new question. Other models like ChatGPT also remember conversations through similar methods (with more diverse solutions). 168 | 169 | In conclusion, users cannot adjust the seed option in model inference, and some additional coding work is needed to remember the conversation. However, using a reusable session allowed retrieving previous responses, showing some effectiveness. To maintain full context like GPT, a large database and resources would be needed, and even models like OpenAI's GPT or Meta's LLaMA-2 struggle to consistently answer. (Refer to LLaMA-2's ghost attention and some appendix examples; it's important to know that making a model operate as a single persona is difficult and costly. Thus, we should remember that general models like Bard or GPT can't be expected to function like specific counselors.) 170 | 171 | If anyone has made progress on this, they are welcome to contribute. 172 | 173 | Thank you. We always welcome your contributions. 174 | -------------------------------------------------------------------------------- /func_test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from bardapi import Bard" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "token = 'xxxxxxx'" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "bard = Bard(token=token)\n", 28 | "bard.get_answer(\"나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘\")['content']" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from bardapi import Bard\n", 38 | "\n", 39 | "bard = Bard(token=token, language='chinese (simplified)')\n", 40 | "res = bard.get_answer(\"今天首尔的天气怎么样?\")\n", 41 | "print(res['content'])" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "from bardapi import Bard\n", 51 | "bard = Bard(token=token)\n", 52 | "res = bard.get_answer(\"Find me an image of the main entrance of Stanford University.\")\n", 53 | "res['links'] # Get image links (list)\n", 54 | "res['images'] # Get images (list)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "from bardapi import Bard\n", 64 | "bard = Bard(token=token)\n", 65 | "res = bard.get_answer(\"Find me an image of the main entrance of Stanford University.\")\n", 66 | "res['links'] # Get image links (list)\n", 67 | "res['images'] # Get images (list)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 2, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "XQhVqoq8lHTI8oZ09DAdXKBTLGrMiT9xv61UNWs51CE6UmY16Qbs-jPWnMm7ciAXtJPopA.\n", 80 | "\n", 81 | "====================================\n", 82 | "\u001b[44m Welcome to Chatbot \u001b[49m\n", 83 | "====================================\n", 84 | "If you enter quit, q, or stop, the chat will end.\n", 85 | "USER: q\n", 86 | "====================================\n", 87 | "\u001b[31mChat Ended.\u001b[39m\n", 88 | "\n", 89 | "DanielPark's Chat Template\n", 90 | "====================================\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "from bardapi import ChatBard\n", 96 | " \n", 97 | "chat = ChatBard(token='xxxxxxx')\n", 98 | "chat.start()" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "from bardapi import Bard\n", 108 | " \n", 109 | "bard = Bard(token=token, run_code=True)\n", 110 | "bard.get_answer(\"code a pie chart in python for this data={'blue':25, 'red':30, 'green':30, 'purple':15}\")" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "from bardapi import BardAsync \n", 120 | " \n", 121 | "bard = BardAsync(token=token)\n", 122 | "res = await bard.get_answer(\"What is Metaverse?\")\n", 123 | "print(res['content'])" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "from bardapi import Bard, SESSION_HEADERS\n", 133 | "import os\n", 134 | "import requests\n", 135 | "\n", 136 | "# Set token\n", 137 | "token= token\n", 138 | "\n", 139 | "# Set session\n", 140 | "session = requests.Session()\n", 141 | "session.headers = SESSION_HEADERS\n", 142 | "session.cookies.set(\"__Secure-1PSID\", token) \n", 143 | "\n", 144 | "# Give session and conversation id\n", 145 | "bard = Bard(token=token, session=session, conversation_id=\"c_1f04f704a788e6e4\", timeout=30)\n", 146 | "bard.get_answer(\"나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘\")['content']" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 7, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "name": "stdout", 156 | "output_type": "stream", 157 | "text": [ 158 | "\n", 159 | "authuser=0&pid=658\n", 160 | "og_pid: 658\n", 161 | "Values array: [3, 0, 1, 0, 3701177, 0]\n", 162 | "rot: 3\n", 163 | "exp_id: 3701177\n", 164 | "\n", 165 | "['-7546079642772715825']\n", 166 | "New cookies: {'__Secure-1PSIDTS': 'sidts-CjEBNiGH7ldEz633gURuY8PfjdJ4UNDlxnz-8Ii6G_j16helunBkZzzTHkTcyRXfvJvsEAA', 'Domain': '.google.com', 'Expires': 'Thu, 28-Nov-2024 02:01:26 GMT', 'Path': '/', 'Priority': 'HIGH', 'SameParty, __Secure-3PSIDTS': 'sidts-CjEBNiGH7ldEz633gURuY8PfjdJ4UNDlxnz-8Ii6G_j16helunBkZzzTHkTcyRXfvJvsEAA', 'expires': 'Thu, 28-Nov-2024 02:01:26 GMT', 'path': '/', 'domain': '.google.com', 'priority': 'high', 'SameSite': 'none'}\n", 167 | "sidts-CjEBNiGH7ldEz633gURuY8PfjdJ4UNDlxnz-8Ii6G_j16helunBkZzzTHkTcyRXfvJvsEAA\n", 168 | "None\n", 169 | "None\n" 170 | ] 171 | } 172 | ], 173 | "source": [ 174 | "from bardapi import Bard, SESSION_HEADERS\n", 175 | "import requests\n", 176 | "session = requests.Session()\n", 177 | "token = '-'\n", 178 | "session.cookies.set(\"__Secure-1PSID\", token)\n", 179 | "session.cookies.set( \"__Secure-1PSIDCC\", \"-\")\n", 180 | "session.cookies.set(\"__Secure-1PSIDTS\", \"-\")\n", 181 | "session.headers = SESSION_HEADERS\n", 182 | "bard = Bard(token=token, session=session, timeout=30)\n", 183 | "\n", 184 | "new_cookies = bard.update_1PSIDTS()\n", 185 | "print('New cookies:', new_cookies)\n", 186 | "print(new_cookies.get(\"__Secure-1PSIDTS\"))\n", 187 | "print(new_cookies.get(\"__Secure-1PSIDCC\"))\n", 188 | "print(new_cookies.get(\"__Secure-3PSIDTS\"))\n" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [] 197 | } 198 | ], 199 | "metadata": { 200 | "kernelspec": { 201 | "display_name": "cc", 202 | "language": "python", 203 | "name": "cc" 204 | }, 205 | "language_info": { 206 | "codemirror_mode": { 207 | "name": "ipython", 208 | "version": 3 209 | }, 210 | "file_extension": ".py", 211 | "mimetype": "text/x-python", 212 | "name": "python", 213 | "nbconvert_exporter": "python", 214 | "pygments_lexer": "ipython3", 215 | "version": "3.9.12" 216 | }, 217 | "orig_nbformat": 4 218 | }, 219 | "nbformat": 4, 220 | "nbformat_minor": 2 221 | } 222 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from bardapi import ChatBard 2 | 3 | 4 | if __name__ == "__main__": 5 | chat = ChatBard() 6 | chat.start() 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Automatically generated using PDM. Do not edit manually. 2 | requests 3 | colorama 4 | httpx[http2]>=0.20.0 5 | langdetect 6 | deep_translator 7 | google-cloud-translate 8 | browser_cookie3 9 | python-gemini-api > 2.3.0 -------------------------------------------------------------------------------- /scripts/google_api.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# There is no Official BARD API\n", 9 | "Currently, there is no official API available from Google. However, if an official API is released in the future, I will ensure to prominently announce it at the top of the repository's readme. If an Official Bard API is released, please inform me, and I will make sure to include an announcement at the top of the readme file.\n", 10 | "- There is no official API from Google. https://www.googlecloudcommunity.com/gc/AI-ML/Google-Bard-API/m-p/538517" 11 | ] 12 | }, 13 | { 14 | "attachments": {}, 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "# Python Package(Unofficial) Bard API\n", 19 | "This package is not official Bard API. " 20 | ] 21 | }, 22 | { 23 | "attachments": {}, 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "In the official version, due to the lack of methods and official documentation for returning Bard's images or links, as well as plot images, for over two months, this project serves as a testing project to prepare for future additions of official features." 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "!pip install bardapi" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 10, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "import bardapi\n", 46 | "import os\n", 47 | "\n", 48 | "# set your __Secure-1PSID value to key\n", 49 | "os.environ['_BARD_API_KEY']=\"xxxxxxxxxx.\"\n", 50 | "\n", 51 | "# set your input text\n", 52 | "input_text = \"What is Google Bard?\"\n", 53 | "\n", 54 | "# Send an API request and get a response.\n", 55 | "response = bardapi.core.Bard().get_answer(input_text)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 13, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "data": { 65 | "text/plain": [ 66 | "'Google Bard is a large language model, also known as a conversational AI or chatbot trained to be informative and comprehensive. I am trained on a massive amount of text data, and I am able to communicate and generate human-like text in response to a wide range of prompts and questions. For example, I can provide summaries of factual topics or create stories.\\r\\n\\r\\nGoogle Bard is still under development, but I have learned to perform many kinds of tasks, including\\r\\n* I will try my best to follow your instructions and complete your requests thoughtfully.\\r\\n* I will use my knowledge to answer your questions in a comprehensive and informative way, even if they are open ended, challenging, or strange.\\r\\n* I will generate different creative text formats of text content, like poems, code, scripts, musical pieces, email, letters, etc. I will try my best to fulfill all your requirements.\\r\\n\\r\\nI am excited to see what I can do in the future, and I hope that I can be a helpful and informative tool for you.'" 67 | ] 68 | }, 69 | "execution_count": 13, 70 | "metadata": {}, 71 | "output_type": "execute_result" 72 | } 73 | ], 74 | "source": [ 75 | "response['content']" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 15, 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "data": { 85 | "text/plain": [ 86 | "'Google Bard is a large language model, also known as a conversational AI or chatbot trained to be informative and comprehensive. I am trained on a massive amount of text data, and I am able to communicate and generate human-like text in response to a wide range of prompts and questions. For example, I can provide summaries of factual topics or create stories.\\r\\n\\r\\nBard is still under development, but I have learned to perform many kinds of tasks, including\\r\\n\\r\\n* I will try my best to follow your instructions and complete your requests thoughtfully.\\r\\n* I will use my knowledge to answer your questions in a comprehensive and informative way, even if they are open ended, challenging, or strange.\\r\\n* I will generate different creative text formats, like poems, code, scripts, musical pieces, email, letters, etc. I will try my best to fulfill all your requirements.\\r\\n\\r\\nI am excited to see what people will use me for. I believe that I have the potential to be a powerful tool for creativity, learning, and communication.'" 87 | ] 88 | }, 89 | "execution_count": 15, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "from bardapi import Bard\n", 96 | "import os\n", 97 | "\n", 98 | "os.environ['_BARD_API_KEY']=\"xxxxxxxxxx.\"\n", 99 | "\n", 100 | "Bard().get_answer(\"What is Google BARD????\")['content']" 101 | ] 102 | } 103 | ], 104 | "metadata": { 105 | "kernelspec": { 106 | "display_name": "mxnet", 107 | "language": "python", 108 | "name": "mxnet" 109 | }, 110 | "language_info": { 111 | "codemirror_mode": { 112 | "name": "ipython", 113 | "version": 3 114 | }, 115 | "file_extension": ".py", 116 | "mimetype": "text/x-python", 117 | "name": "python", 118 | "nbconvert_exporter": "python", 119 | "pygments_lexer": "ipython3", 120 | "version": "3.9.12" 121 | }, 122 | "orig_nbformat": 4 123 | }, 124 | "nbformat": 4, 125 | "nbformat_minor": 2 126 | } 127 | -------------------------------------------------------------------------------- /scripts/google_official_api.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Google Gemini API\n", 8 | "\n", 9 | "**Gemini API Quick Start** - You can start using the Gemini API by following the instructions in this [link](https://ai.google.dev/tutorials/python_quickstart).\n", 10 | "\n", 11 | "To set up authentication, please refer to the [ADC (Application Default Credentials) documentation](https://cloud.google.com/docs/authentication/application-default-credentials).\n", 12 | "\n", 13 | "To obtain an API key, visit [AI Studio](https://makersuite.google.com/app/apikey).\n", 14 | "\n", 15 | "Alternatively, you can also use [Colab](https://colab.research.google.com/github/google/generative-ai-docs/blob/main/site/en/tutorials/python_quickstart.ipynb) for this purpose." 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "!pip install -q -U google-generativeai" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import pathlib\n", 34 | "import textwrap\n", 35 | "\n", 36 | "import google.generativeai as genai" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# import os\n", 46 | "# os.environ['GOOGLE_API_KEY'] = \"xxxxxxx\"\n", 47 | "\n", 48 | "GOOGLE_API_KEY = \"xxxxx\"\n", 49 | "genai.configure(api_key=GOOGLE_API_KEY)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "for m in genai.list_models():\n", 59 | " if 'generateContent' in m.supported_generation_methods:\n", 60 | " print(m.name)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "model = genai.GenerativeModel('gemini-pro')" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "response = model.generate_content(\"What is the meaning of life?\")" 79 | ] 80 | } 81 | ], 82 | "metadata": { 83 | "kernelspec": { 84 | "display_name": "cc", 85 | "language": "python", 86 | "name": "cc" 87 | }, 88 | "language_info": { 89 | "codemirror_mode": { 90 | "name": "ipython", 91 | "version": 3 92 | }, 93 | "file_extension": ".py", 94 | "mimetype": "text/x-python", 95 | "name": "python", 96 | "nbconvert_exporter": "python", 97 | "pygments_lexer": "ipython3", 98 | "version": "3.9.12" 99 | }, 100 | "orig_nbformat": 4 101 | }, 102 | "nbformat": 4, 103 | "nbformat_minor": 2 104 | } 105 | -------------------------------------------------------------------------------- /scripts/microsoft_api.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "To get a subscription key for Bing Search APIs, you need to follow these steps:\n", 9 | "\n", 10 | " https://www.microsoft.com/en-us/bing/apis/bing-search-apis-portal\n", 11 | "Sign in with your Microsoft account.\n", 12 | "Click on the \"Get started\" button.\n", 13 | "Select the API you want to use.\n", 14 | "Follow the instructions to create a new resource and get your subscription key.\n", 15 | "Here's an example Python code snippet that shows how to use the Bing Search API with a subscription key:" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import requests\n", 25 | "\n", 26 | "# Specify the endpoint URLs for Bing Spell Check and AutoSuggest APIs\n", 27 | "spell_check_url = \"https://api.bing.microsoft.com/v7.0/spellcheck\"\n", 28 | "auto_suggest_url = \"https://api.bing.microsoft.com/v7.0/Suggestions\"\n", 29 | "\n", 30 | "# Set your Bing API subscription key\n", 31 | "subscription_key = \"YOUR_BING_API_SUBSCRIPTION_KEY\"\n", 32 | "\n", 33 | "# Set your query text\n", 34 | "query = \"Hello, how are yuo?\"\n", 35 | "\n", 36 | "# Spell Check API request\n", 37 | "spell_check_params = {\n", 38 | " \"text\": query,\n", 39 | " \"mode\": \"proof\",\n", 40 | "}\n", 41 | "\n", 42 | "spell_check_headers = {\n", 43 | " \"Content-Type\": \"application/x-www-form-urlencoded\",\n", 44 | " \"Ocp-Apim-Subscription-Key\": subscription_key,\n", 45 | "}\n", 46 | "\n", 47 | "spell_check_response = requests.post(spell_check_url, params=spell_check_params, headers=spell_check_headers)\n", 48 | "spell_check_data = spell_check_response.json()\n", 49 | "\n", 50 | "# Get the corrected query from the Spell Check API response\n", 51 | "corrected_query = spell_check_data[\"flaggedTokens\"][0][\"suggestions\"][0][\"suggestion\"]\n", 52 | "\n", 53 | "# AutoSuggest API request\n", 54 | "auto_suggest_params = {\n", 55 | " \"q\": corrected_query,\n", 56 | " \"mkt\": \"en-US\",\n", 57 | "}\n", 58 | "\n", 59 | "auto_suggest_headers = {\n", 60 | " \"Ocp-Apim-Subscription-Key\": subscription_key,\n", 61 | "}\n", 62 | "\n", 63 | "auto_suggest_response = requests.get(auto_suggest_url, params=auto_suggest_params, headers=auto_suggest_headers)\n", 64 | "auto_suggest_data = auto_suggest_response.json()\n", 65 | "\n", 66 | "# Get the suggested queries from the AutoSuggest API response\n", 67 | "suggested_queries = [suggestion[\"displayText\"] for suggestion in auto_suggest_data[\"suggestionGroups\"][0][\"searchSuggestions\"]]\n", 68 | "\n", 69 | "# Print the results\n", 70 | "print(\"Corrected Query: \", corrected_query)\n", 71 | "print(\"Suggested Queries: \", suggested_queries)" 72 | ] 73 | } 74 | ], 75 | "metadata": { 76 | "language_info": { 77 | "name": "python" 78 | }, 79 | "orig_nbformat": 4 80 | }, 81 | "nbformat": 4, 82 | "nbformat_minor": 2 83 | } 84 | -------------------------------------------------------------------------------- /scripts/openai_api.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "The OpenAI API site can be found at the following URL:\n", 9 | "\n", 10 | "https://platform.openai.com" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "import openai\n", 20 | "\n", 21 | "# list models\n", 22 | "models = openai.Model.list()\n", 23 | "\n", 24 | "# api key\n", 25 | "openai.api_key = \"sk-xxxxx\"\n", 26 | "\n", 27 | "# Then, you can call the \"gpt-3.5-turbo\" model\n", 28 | "model_engine = \"gpt-3.5-turbo\"\n", 29 | "\n", 30 | "# set your input text\n", 31 | "input_text = \"What is chatGPT??????????\"\n", 32 | "\n", 33 | "# Send an API request and get a response, note that the interface and parameters have changed compared to the old model\n", 34 | "response = openai.ChatCompletion.create(\n", 35 | " model=model_engine,\n", 36 | " messages=[{\"role\": \"user\", \"content\": input_text }]\n", 37 | ")" 38 | ] 39 | } 40 | ], 41 | "metadata": { 42 | "language_info": { 43 | "name": "python" 44 | }, 45 | "orig_nbformat": 4 46 | }, 47 | "nbformat": 4, 48 | "nbformat_minor": 2 49 | } 50 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Daniel Park, MIT License 2 | 3 | import re 4 | from setuptools import find_packages 5 | from setuptools import setup 6 | 7 | 8 | def get_version(): 9 | filename = "bardapi/__init__.py" 10 | with open(filename) as f: 11 | match = re.search(r"""^__version__ = ['"]([^'"]*)['"]""", f.read(), re.M) 12 | if not match: 13 | raise RuntimeError("{} doesn't contain __version__".format(filename)) 14 | version = match.groups()[0] 15 | return version 16 | 17 | 18 | def get_long_description(): 19 | with open("README.md", encoding="UTF-8") as f: 20 | long_description = f.read() 21 | return long_description 22 | 23 | 24 | version = get_version() 25 | 26 | setup( 27 | name="bardapi", 28 | version="1.0.0", 29 | author="daniel park", 30 | author_email="parkminwoo1991@gmail.com", 31 | description="The python package that returns Response of Google Bard through API.", 32 | long_description=get_long_description(), 33 | long_description_content_type="text/markdown", 34 | url="https://github.com/dsdanielpark/Bard-API", 35 | packages=find_packages(exclude=[]), 36 | python_requires=">=3.6", 37 | install_requires=[ 38 | "httpx[http2]>=0.20.0", 39 | "requests", 40 | "colorama", 41 | "python-gemini-api", 42 | ], 43 | extras_require={ 44 | "translate": [ 45 | "browser_cookie3", 46 | "deep_translator", 47 | "google-cloud-translate", 48 | "langdetect", 49 | ] 50 | }, 51 | keywords="Python, API, Bard, Google Bard, Large Language Model, Chatbot API, Google API, Chatbot", 52 | classifiers=[ 53 | "Development Status :: 5 - Production/Stable", 54 | "Intended Audience :: Science/Research", 55 | "Natural Language :: English", 56 | "Programming Language :: Python", 57 | "Programming Language :: Python :: 3.7", 58 | "Programming Language :: Python :: 3.8", 59 | "Programming Language :: Python :: 3.9", 60 | "Programming Language :: Python :: 3.10", 61 | "Programming Language :: Python :: 3.11", 62 | "License :: OSI Approved :: MIT License", 63 | "Topic :: Scientific/Engineering :: Artificial Intelligence", 64 | ], 65 | entry_points={"console_scripts": ["bard_api=bard_api.cli:main"]}, 66 | ) 67 | -------------------------------------------------------------------------------- /tests/test_bard_result.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from bardapi.models.result import BardResult 4 | from data import t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 5 | 6 | 7 | class TestBardResult(unittest.TestCase): 8 | def test_5images(self): 9 | img0 = BardResult(t1[0]) 10 | self.assertEqual(len(img0.drafts[0].images), 5) 11 | 12 | def test_topic(self): 13 | img1 = BardResult(t1[1]) 14 | self.assertEqual(img1.topic, "Orcas in the wild") 15 | 16 | def test_2images(self): 17 | img2 = BardResult(t2) 18 | self.assertEqual( 19 | img2.search_queries, 20 | [ 21 | ["2 pictures of orcas", 1], 22 | ["Why is orca called Killer?", 4], 23 | ["What do orcas look like?", 4], 24 | ], 25 | ) 26 | 27 | # images can be separated by key 28 | self.assertEqual( 29 | "[Image of Two orcas breaching the water]", img2.drafts[0].images[0].key 30 | ) 31 | self.assertEqual( 32 | "[Image of Two orcas swimming together]", img2.drafts[0].images[1].key 33 | ) 34 | # or merged on an album 35 | self.assertEqual("[2 Images of orcas]", img2.drafts[1].images[0].key) 36 | self.assertEqual("[2 Images of orcas]", img2.drafts[1].images[1].key) 37 | 38 | def test_map_content(self): 39 | maps4 = BardResult(t3[4]) 40 | self.assertEqual( 41 | "http://googleusercontent.com/map_content/0", 42 | maps4.drafts[0].map_content[0].key, 43 | ) 44 | self.assertEqual(10, len(maps4.drafts[0].map_content[0].points[4].images)) 45 | 46 | maps9 = BardResult(t9) 47 | self.assertEqual("Rv52", maps9.drafts[0].map_content[1].directions.road_name) 48 | self.assertTrue( 49 | maps9.drafts[0] 50 | .map_content[1] 51 | .directions.url.startswith("https://www.google.com/maps/dir/") 52 | ) 53 | self.assertEqual(2, len(maps9.drafts[0].map_content[1].directions.sections)) 54 | self.assertFalse(maps9.drafts[0].python_code) 55 | 56 | self.assertFalse( 57 | "http://googleusercontent.com/" in maps4.drafts[0].text_with_user_content 58 | ) 59 | self.assertFalse( 60 | "http://googleusercontent.com/" in maps9.drafts[0].text_with_user_content 61 | ) 62 | 63 | def test_google_workspace(self): 64 | drive4 = BardResult(t4[4]) 65 | self.assertEqual(len(drive4.drafts[0].gworkspace), 3) 66 | 67 | def test_youtube(self): 68 | video4 = BardResult(t5[4]) 69 | self.assertEqual(len(video4.drafts[0].youtube[0]), 5) 70 | self.assertFalse( 71 | "http://googleusercontent.com/" in video4.drafts[0].text_with_user_content 72 | ) 73 | 74 | def test_flights(self): 75 | flights4 = BardResult(t6[4]) 76 | self.assertEqual(len(flights4.drafts[0].flights[0].flights), 5) 77 | self.assertIsNotNone(flights4.drafts[0].flights[0].markdown_text) 78 | 79 | def test_flights_and_hotel(self): 80 | res = BardResult(t11) 81 | self.assertEqual(5, len(res.drafts[0].flights[0].flights)) 82 | self.assertEqual(5, len(res.drafts[0].hotels[0].hotels)) 83 | 84 | def test_python(self): 85 | python = BardResult(t7[0]) 86 | self.assertEqual(len(python.drafts[1].citations), 3) 87 | self.assertEqual("A\nA str\n", python.drafts[0].python_code[0].output) 88 | 89 | def test_citations(self): 90 | citations = BardResult(t8[0]) 91 | self.assertEqual(len(citations.drafts[0].citations), 2) 92 | self.assertFalse( 93 | "http://googleusercontent.com/" 94 | in citations.drafts[0].text_with_user_content 95 | ) 96 | 97 | def test_summary(self): 98 | summary = BardResult(t10) 99 | self.assertEqual(len(summary.drafts[0].citations), 1) 100 | json_o = summary.drafts[0].json_content[0].object 101 | self.assertIsNotNone(json_o) 102 | self.assertEqual(len(summary.drafts[0].json_content), 1) 103 | 104 | 105 | if __name__ == "__main__": 106 | unittest.main() 107 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/asyncio_core.py: -------------------------------------------------------------------------------- 1 | import os 2 | import string 3 | import random 4 | import json 5 | import re 6 | import aiohttp 7 | import asyncio 8 | from deep_translator import GoogleTranslator 9 | from bardapi.constants import ALLOWED_LANGUAGES, SESSION_HEADERS 10 | 11 | 12 | class Bard: 13 | """ 14 | Bard class for interacting with the Bard API. 15 | """ 16 | 17 | def __init__( 18 | self, 19 | token: str = None, 20 | timeout: int = 20, 21 | proxies: dict = None, 22 | session: aiohttp.ClientSession = None, 23 | language: str = None, 24 | ): 25 | """ 26 | Initialize the Bard instance. 27 | 28 | Args: 29 | token (str): Bard API token. 30 | timeout (int): Request timeout in seconds. 31 | proxies (dict): Proxy configuration for requests. 32 | session (aiohttp.ClientSession): aiohttp session object. 33 | language (str): Language code for translation (e.g., "en", "ko", "ja"). 34 | """ 35 | self.token = token or os.getenv("_BARD_API_KEY") 36 | self.proxies = proxies 37 | self.timeout = timeout 38 | self._reqid = int("".join(random.choices(string.digits, k=4))) 39 | self.conversation_id = "" 40 | self.response_id = "" 41 | self.choice_id = "" 42 | if session is None: 43 | self.session = aiohttp.ClientSession( 44 | headers=SESSION_HEADERS, cookies={"__Secure-1PSID": self.token} 45 | ) 46 | else: 47 | self.session = session 48 | self.SNlM0e = self._get_snim0e() 49 | self.language = language or os.getenv("_BARD_API_LANG") 50 | 51 | async def _get_snim0e(self) -> str: 52 | """ 53 | Get the SNlM0e value from the Bard API response. 54 | 55 | Returns: 56 | str: SNlM0e value. 57 | Raises: 58 | Exception: If the __Secure-1PSID value is invalid or SNlM0e value is not found in the response. 59 | """ 60 | if not self.token or self.token[-1] != ".": 61 | raise Exception( 62 | "__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value." 63 | ) 64 | resp = await self.session.get( 65 | "https://bard.google.com/", timeout=self.timeout, proxies=self.proxies 66 | ) 67 | if resp.status != 200: 68 | raise Exception(f"Response code not 200. Response Status is {resp.status}") 69 | resp_text = await resp.text() 70 | snim0e = re.search(r"SNlM0e\":\"(.*?)\"", resp_text) 71 | if not snim0e: 72 | raise Exception( 73 | "SNlM0e value not found in response. Check __Secure-1PSID value." 74 | ) 75 | return snim0e.group(1) 76 | 77 | def _extract_links(self, data: list) -> list: 78 | """ 79 | Extract links from the given data. 80 | 81 | Args: 82 | data: Data to extract links from. 83 | 84 | Returns: 85 | list: Extracted links. 86 | """ 87 | links = [] 88 | if isinstance(data, list): 89 | for item in data: 90 | if isinstance(item, list): 91 | links.extend(self._extract_links(item)) 92 | elif ( 93 | isinstance(item, str) 94 | and item.startswith("http") 95 | and "favicon" not in item 96 | ): 97 | links.append(item) 98 | return links 99 | 100 | async def get_answer(self, input_text: str) -> dict: 101 | """ 102 | Get an answer from the Bard API for the given input text. 103 | 104 | Example: 105 | >>> token = 'xxxxxxxxxx' 106 | >>> bard = Bard(token=token) 107 | >>> response = await bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘") 108 | >>> print(response['content']) 109 | 110 | Args: 111 | input_text (str): Input text for the query. 112 | 113 | Returns: 114 | dict: Answer from the Bard API in the following format: 115 | { 116 | "content": str, 117 | "conversation_id": str, 118 | "response_id": str, 119 | "factualityQueries": list, 120 | "textQuery": str, 121 | "choices": list, 122 | "links": list 123 | "imgaes": set 124 | } 125 | """ 126 | params = { 127 | "bl": "boq_assistant-bard-web-server_20230419.00_p1", 128 | "_reqid": str(self._reqid), 129 | "rt": "c", 130 | } 131 | if self.language is not None and self.language not in ALLOWED_LANGUAGES: 132 | translator_to_eng = GoogleTranslator(source="auto", target="en") 133 | input_text = await translator_to_eng.translate(input_text) 134 | input_text_struct = [ 135 | [input_text], 136 | None, 137 | [self.conversation_id, self.response_id, self.choice_id], 138 | ] 139 | data = { 140 | "f.req": json.dumps([None, json.dumps(input_text_struct)]), 141 | "at": self.SNlM0e, 142 | } 143 | resp = await self.session.post( 144 | "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate", 145 | params=params, 146 | data=data, 147 | timeout=self.timeout, 148 | proxies=self.proxies, 149 | ) 150 | resp_text = await resp.text() 151 | resp_dict = json.loads(resp_text.splitlines()[3])[0][2] 152 | 153 | if not resp_dict: 154 | return {"content": f"Response Error: {resp_text}."} 155 | resp_json = json.loads(resp_dict) 156 | images = list() 157 | if len(resp_json) >= 3: 158 | if len(resp_json[4][0]) >= 4 and resp_json[4][0][4] is not None: 159 | for img in resp_json[4][0][4]: 160 | images.append(img[0][0][0]) 161 | parsed_answer = json.loads(resp_dict) 162 | if self.language is not None and self.language not in ALLOWED_LANGUAGES: 163 | translator_to_lang = GoogleTranslator(source="auto", target=self.language) 164 | parsed_answer[0][0] = await translator_to_lang.translate( 165 | parsed_answer[0][0] 166 | ) 167 | parsed_answer[4] = [ 168 | (x[0], await translator_to_lang.translate(x[1][0])) 169 | for x in parsed_answer[4] 170 | ] 171 | bard_answer = { 172 | "content": parsed_answer[0][0], 173 | "conversation_id": parsed_answer[1][0], 174 | "response_id": parsed_answer[1][1], 175 | "factualityQueries": parsed_answer[3], 176 | "textQuery": parsed_answer[2][0] if parsed_answer[2] else "", 177 | "choices": [{"id": x[0], "content": x[1]} for x in parsed_answer[4]], 178 | "links": self._extract_links(parsed_answer[4]), 179 | "images": images, 180 | } 181 | self.conversation_id, self.response_id, self.choice_id = ( 182 | bard_answer["conversation_id"], 183 | bard_answer["response_id"], 184 | bard_answer["choices"][0]["id"], 185 | ) 186 | self._reqid += 100000 187 | 188 | return bard_answer 189 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.KT: -------------------------------------------------------------------------------- 1 | import okhttp3.* 2 | import org.json.JSONArray 3 | import org.json.JSONObject 4 | import kotlin.random.Random 5 | 6 | class Bard( 7 | private val token: String? = null, 8 | private val timeout: Int = 20, 9 | private val proxies: Map? = null, 10 | private val client: OkHttpClient = OkHttpClient.Builder().build() 11 | ) { 12 | companion object { 13 | private const val BARD_URL = "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate" 14 | private val HEADERS = mapOf( 15 | "Host" to "bard.google.com", 16 | "X-Same-Domain" to "1", 17 | "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 18 | "Content-Type" to "application/x-www-form-urlencoded;charset=UTF-8", 19 | "Origin" to "https://bard.google.com", 20 | "Referer" to "https://bard.google.com/" 21 | ) 22 | } 23 | 24 | private var reqId: Int = Random.nextInt(10000) 25 | private var conversationId: String = "" 26 | private var responseId: String = "" 27 | private var choiceId: String = "" 28 | private val snim0e: String 29 | 30 | init { 31 | require(token != null && token.endsWith(".")) 32 | snim0e = getSNlM0e() 33 | } 34 | 35 | private fun getSNlM0e(): String { 36 | val request = Request.Builder() 37 | .url("https://bard.google.com/") 38 | .headers(Headers.of(HEADERS)) 39 | .build() 40 | 41 | client.newCall(request).execute().use { response -> 42 | require(response.isSuccessful) { "Response code not 200. Response Status is ${response.code()}" } 43 | 44 | val responseBody = response.body()?.string() ?: throw RuntimeException("Response body is null") 45 | val pattern = "SNlM0e\":\"(.*?)\"".toRegex() 46 | val matchResult = pattern.find(responseBody) 47 | ?: throw RuntimeException("SNlM0e value not found in response. Check __Secure-1PSID value.") 48 | 49 | return matchResult.groupValues[1] 50 | } 51 | } 52 | 53 | fun getAnswer(inputText: String): Map { 54 | val inputTextStruct = "[[\"$inputText\"],null,[\"$conversationId\",\"$responseId\",\"$choiceId\"]]" 55 | val data = mapOf("f.req" to listOf(null, inputTextStruct), "at" to snim0e) 56 | 57 | val requestBody = FormBody.Builder() 58 | .add("f.req", "[null,\"$inputTextStruct\"]") 59 | .add("at", snim0e) 60 | .build() 61 | 62 | val request = Request.Builder() 63 | .url(BARD_URL) 64 | .headers(Headers.of(HEADERS)) 65 | .post(requestBody) 66 | .build() 67 | 68 | client.newCall(request).execute().use { response -> 69 | require(response.isSuccessful) { "Response code not 200. Response Status is ${response.code()}" } 70 | 71 | val responseBody = response.body()?.string() ?: throw RuntimeException("Response body is null") 72 | val parsedAnswer = JSONArray(JSONArray(responseBody).getJSONArray(0).getString(2)) 73 | 74 | require(parsedAnswer.isNotEmpty()) { "Response Error: $responseBody" } 75 | 76 | val bardAnswer = mutableMapOf() 77 | bardAnswer["content"] = parsedAnswer.getJSONArray(0).getString(0) 78 | bardAnswer["conversation_id"] = parsedAnswer.getJSONArray(1).getString(0) 79 | bardAnswer["response_id"] = parsedAnswer.getJSONArray(1).getString(1) 80 | bardAnswer["factualityQueries"] = parsedAnswer.getJSONArray(3) 81 | 82 | val textQuery = parsedAnswer.getJSONArray(2).optString(0, "") 83 | bardAnswer["textQuery"] = textQuery 84 | 85 | val choicesArray = JSONArray() 86 | val parsedChoices = parsedAnswer.getJSONArray(4) 87 | for (i in 0 until parsedChoices.length()) { 88 | val choice = parsedChoices.getJSONArray(i) 89 | val choiceObject = JSONObject() 90 | choiceObject.put("id", choice.getString(0)) 91 | choiceObject.put("content", choice.getString(1)) 92 | choicesArray.put(choiceObject) 93 | } 94 | bardAnswer["choices"] = choicesArray 95 | 96 | conversationId = bardAnswer["conversation_id"].toString() 97 | responseId = bardAnswer["response_id"].toString() 98 | choiceId = bardAnswer.getJSONArray("choices").getJSONObject(0).getString("id") 99 | reqId += 100000 100 | 101 | return bardAnswer 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.TS: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosResponse } from 'axios'; 2 | 3 | class Bard { 4 | private token: string | null; 5 | private session: AxiosInstance; 6 | private conversation_id: string = ''; 7 | private response_id: string = ''; 8 | private choice_id: string = ''; 9 | private SNlM0e: string = ''; 10 | 11 | private static HEADERS = { 12 | 'Host': 'bard.google.com', 13 | 'X-Same-Domain': '1', 14 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 15 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 16 | 'Origin': 'https://bard.google.com', 17 | 'Referer': 'https://bard.google.com/', 18 | }; 19 | 20 | constructor(token: string | null = null, private timeout: number = 20, private proxies?: { [key: string]: string }) { 21 | this.token = token || process.env._BARD_API_KEY || null; 22 | this.session = axios.create({ 23 | headers: Bard.HEADERS, 24 | timeout: this.timeout * 1000, 25 | proxy: this.proxies, 26 | withCredentials: true, 27 | }); 28 | } 29 | 30 | private async getSNlM0e(): Promise { 31 | if (!this.token || !this.token.endsWith('.')) { 32 | throw new Error('__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value.'); 33 | } 34 | try { 35 | const resp: AxiosResponse = await this.session.get('https://bard.google.com/'); 36 | if (resp.status !== 200) { 37 | throw new Error(`Response code not 200. Response Status is ${resp.status}`); 38 | } 39 | const snim0eMatch = resp.data.match(/SNlM0e":"(.*?)"/); 40 | if (!snim0eMatch) { 41 | throw new Error('SNlM0e value not found in response. Check __Secure-1PSID value.'); 42 | } 43 | return snim0eMatch[1]; 44 | } catch (error) { 45 | throw new Error(`Error occurred while fetching SNlM0e value: ${error.message}`); 46 | } 47 | } 48 | 49 | public async getAnswer(inputText: string): Promise { 50 | const params = { 51 | bl: 'boq_assistant-bard-web-server_20230419.00_p1', 52 | _reqid: String(Math.floor(Math.random() * 10000)), 53 | rt: 'c', 54 | }; 55 | const inputTextStruct = [ 56 | [inputText], 57 | null, 58 | [this.conversation_id, this.response_id, this.choice_id], 59 | ]; 60 | const data = { 61 | 'f.req': JSON.stringify([null, JSON.stringify(inputTextStruct)]), 62 | at: this.SNlM0e, 63 | }; 64 | try { 65 | const resp: AxiosResponse = await this.session.post( 66 | 'https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate', 67 | null, 68 | { params, data } 69 | ); 70 | const respDict = JSON.parse(resp.data.split('\n')[3])[0][2]; 71 | if (!respDict) { 72 | return { content: `Response Error: ${resp.data}.` }; 73 | } 74 | const parsedAnswer = JSON.parse(respDict); 75 | const bardAnswer = { 76 | content: parsedAnswer[0][0], 77 | conversation_id: parsedAnswer[1][0], 78 | response_id: parsedAnswer[1][1], 79 | factualityQueries: parsedAnswer[3], 80 | textQuery: parsedAnswer[2][0] || '', 81 | choices: parsedAnswer[4].map((i: any) => ({ id: i[0], content: i[1] })), 82 | }; 83 | this.conversation_id = bardAnswer.conversation_id; 84 | this.response_id = bardAnswer.response_id; 85 | this.choice_id = bardAnswer.choices[0].id; 86 | return bardAnswer; 87 | } catch (error) { 88 | throw new Error(`Error occurred while fetching Bard answer: ${error.message}`); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace BardNamespace 9 | { 10 | public class Bard 11 | { 12 | private const string BARD_HOST = "bard.google.com"; 13 | private const string BARD_URL = "https://bard.google.com/"; 14 | private const string STREAM_GENERATE_URL = "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate"; 15 | 16 | private static readonly Dictionary HEADERS = new Dictionary() 17 | { 18 | { "Host", BARD_HOST }, 19 | { "X-Same-Domain", "1" }, 20 | { "User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" }, 21 | { "Content-Type", "application/x-www-form-urlencoded;charset=UTF-8" }, 22 | { "Origin", BARD_URL }, 23 | { "Referer", BARD_URL } 24 | }; 25 | 26 | private readonly string token; 27 | private readonly int timeout; 28 | private readonly Dictionary proxies; 29 | private int reqId; 30 | private string conversationId; 31 | private string responseId; 32 | private string choiceId; 33 | private readonly HttpClient client; 34 | private string SNlM0e; 35 | 36 | public Bard(string token = null, int timeout = 20, Dictionary proxies = null, HttpClient session = null) 37 | { 38 | this.token = token ?? Environment.GetEnvironmentVariable("_BARD_API_KEY"); 39 | this.timeout = timeout; 40 | this.proxies = proxies; 41 | this.reqId = new Random().Next(1000, 9999); 42 | this.conversationId = ""; 43 | this.responseId = ""; 44 | this.choiceId = ""; 45 | this.client = session ?? new HttpClient(); 46 | this.SNlM0e = GetSnim0eAsync().GetAwaiter().GetResult(); 47 | } 48 | 49 | private async Task GetSnim0eAsync() 50 | { 51 | if (string.IsNullOrEmpty(token) || token[token.Length - 1] != '.') 52 | { 53 | throw new Exception("__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value."); 54 | } 55 | 56 | this.client.DefaultRequestHeaders.Clear(); 57 | foreach (var header in HEADERS) 58 | { 59 | if (header.Key == "Content-Type") break; 60 | this.client.DefaultRequestHeaders.Add(header.Key, header.Value); 61 | } 62 | this.client.DefaultRequestHeaders.Add("Cookie", $"__Secure-1PSID={this.token}"); 63 | 64 | HttpResponseMessage response = await client.GetAsync(BARD_URL); 65 | response.EnsureSuccessStatusCode(); 66 | string responseBody = await response.Content.ReadAsStringAsync(); 67 | Match match = Regex.Match(responseBody, "SNlM0e\":\"(.*?)\""); 68 | if (!match.Success) 69 | { 70 | throw new Exception("SNlM0e value not found in response. Check __Secure-1PSID value."); 71 | } 72 | return match.Groups[1].Value; 73 | } 74 | 75 | public async Task> GetAnswer(string inputText) 76 | { 77 | this.client.DefaultRequestHeaders.Clear(); 78 | foreach (var header in HEADERS) 79 | { 80 | if (header.Key == "Content-Type") break; 81 | this.client.DefaultRequestHeaders.Add(header.Key, header.Value); 82 | } 83 | this.client.DefaultRequestHeaders.Add("Cookie", $"__Secure-1PSID={this.token}"); 84 | 85 | var parameters = new Dictionary() 86 | { 87 | { "_reqid", reqId.ToString() }, 88 | { "rt", "c" } 89 | }; 90 | var inputTextStruct = new List 91 | { 92 | new object[] 93 | { 94 | new List { inputText }, 95 | null, 96 | new List { conversationId, responseId, choiceId } 97 | } 98 | }; 99 | var data = new Dictionary() 100 | { 101 | { "f.req", "[null,'[[\""+inputText+"\",null,null,[]],[\"en\"],[\"\",\"\",\"\"],null,null,null,[0]]']" }, 102 | { "at", SNlM0e } 103 | }; 104 | 105 | var formUrlEncodedContent = new FormUrlEncodedContent(data); 106 | formUrlEncodedContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded;charset=UTF-8"); 107 | 108 | var response = await client.PostAsync(STREAM_GENERATE_URL + GetQueryString(parameters), new FormUrlEncodedContent(data)); 109 | response.EnsureSuccessStatusCode(); 110 | var responseContent = await response.Content.ReadAsStringAsync(); 111 | responseContent = responseContent.Substring(responseContent.IndexOf("wrb.fr") - 3, responseContent.IndexOf("\"]]\"]]") - 4); 112 | var responseArray = JArray.Parse(responseContent); 113 | var parsedAnswer = responseArray[0][2]; 114 | if (parsedAnswer == null) 115 | { 116 | return new Dictionary { { "content", $"Response Error: {responseContent}." } }; 117 | } 118 | 119 | string s = parsedAnswer.ToString(); 120 | var js = JArray.Parse(s); 121 | 122 | 123 | var choices = new List>(); 124 | foreach (var choice in js[4]) 125 | { 126 | choices.Add(new Dictionary { { "id", choice[0] }, { "content", choice[1] } }); 127 | } 128 | 129 | var bardAnswer = new Dictionary 130 | { 131 | { "content", js[0][0] }, 132 | { "conversation_id", js[1][0] }, 133 | { "response_id", js[1][1] }, 134 | { "factualityQueries", js[3] }, 135 | { "textQuery", js[2][0]?.ToString() ?? "" }, 136 | { "choices", choices } 137 | }; 138 | 139 | conversationId = bardAnswer["conversation_id"].ToString(); 140 | responseId = bardAnswer["response_id"].ToString(); 141 | choiceId = choices[0]["id"].ToString(); 142 | reqId += 100000; 143 | 144 | return bardAnswer; 145 | } 146 | 147 | private string GetQueryString(Dictionary parameters) 148 | { 149 | var stringBuilder = new StringBuilder("?"); 150 | foreach (var parameter in parameters) 151 | { 152 | stringBuilder.Append($"{Uri.EscapeDataString(parameter.Key)}={Uri.EscapeDataString(parameter.Value)}&"); 153 | } 154 | return stringBuilder.ToString().TrimEnd('&'); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/url" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | const ( 14 | bardURL = "https://bard.google.com" 15 | streamGenerate = "/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate" 16 | contentType = "Content-Type" 17 | contentTypeValue = "application/x-www-form-urlencoded;charset=UTF-8" 18 | host = "Host" 19 | xSameDomain = "X-Same-Domain" 20 | referer = "Referer" 21 | userAgent = "User-Agent" 22 | origin = "Origin" 23 | cookie = "Cookie" 24 | ) 25 | 26 | type BardAnswer struct { 27 | Content string 28 | ConversationID string 29 | ResponseID string 30 | FactualityQueries []interface{} 31 | TextQuery string 32 | Choices []Choice 33 | } 34 | 35 | type Choice struct { 36 | ID string 37 | Content string 38 | } 39 | 40 | type Bard struct { 41 | Token string 42 | Timeout time.Duration 43 | ReqID int 44 | ConversationID string 45 | ResponseID string 46 | ChoiceID string 47 | Session *http.Client 48 | SNlM0e string 49 | } 50 | 51 | func NewBard(token string, timeout time.Duration, proxies map[string]string, session *http.Client) (*Bard, error) { 52 | b := &Bard{ 53 | Token: token, 54 | Timeout: timeout, 55 | ReqID: rand.Intn(10000), 56 | Session: session, 57 | } 58 | 59 | if b.Token == "" || !strings.HasSuffix(b.Token, ".") { 60 | return nil, fmt.Errorf("__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value.") 61 | } 62 | 63 | if b.Session == nil { 64 | b.Session = &http.Client{Timeout: b.Timeout} 65 | } 66 | 67 | err := b.getSNlM0e() 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | return b, nil 73 | } 74 | 75 | func (b *Bard) getSNlM0e() error { 76 | resp, err := b.Session.Get(bardURL) 77 | if err != nil { 78 | return err 79 | } 80 | defer resp.Body.Close() 81 | 82 | if resp.StatusCode != http.StatusOK { 83 | return fmt.Errorf("Response code not 200. Response Status is %d", resp.StatusCode) 84 | } 85 | 86 | body, err := ioutil.ReadAll(resp.Body) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | re := regexp.MustCompile(`SNlM0e":"(.*?)"`) 92 | matches := re.FindStringSubmatch(string(body)) 93 | if len(matches) != 2 { 94 | return fmt.Errorf("SNlM0e value not found in response. Check __Secure-1PSID value.") 95 | } 96 | 97 | b.SNlM0e = matches[1] 98 | return nil 99 | } 100 | 101 | func (b *Bard) GetAnswer(inputText string) (BardAnswer, error) { 102 | params := url.Values{ 103 | "_reqid": {strconv.Itoa(b.ReqID)}, 104 | "rt": {"c"}, 105 | } 106 | 107 | inputTextStruct := [][]interface{}{ 108 | {inputText}, 109 | nil, 110 | {b.ConversationID, b.ResponseID, b.ChoiceID}, 111 | } 112 | data := map[string]interface{}{ 113 | "f.req": json.RawMessage("[null," + json.Marshal(inputTextStruct) + "]"), 114 | "at": b.SNlM0e, 115 | } 116 | 117 | reqURL := bardURL + streamGenerate + "?" + params.Encode() 118 | reqBody := strings.NewReader(url.Values(data).Encode()) 119 | 120 | req, err := http.NewRequest(http.MethodPost, reqURL, reqBody) 121 | if err != nil { 122 | return BardAnswer{}, err 123 | } 124 | 125 | req.Header.Set(contentType, contentTypeValue) 126 | req.Header.Set(host, "bard.google.com") 127 | req.Header.Set(xSameDomain, "1") 128 | req.Header.Set(referer, "https://bard.google.com/") 129 | req.Header.Set(userAgent, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36") 130 | req.Header.Set(origin, "https://bard.google.com") 131 | req.Header.Set(cookie, "__Secure-1PSID="+b.Token) 132 | 133 | resp, err := b.Session.Do(req) 134 | if err != nil { 135 | return BardAnswer{}, err 136 | } 137 | defer resp.Body.Close() 138 | 139 | body, err := ioutil.ReadAll(resp.Body) 140 | if err != nil { 141 | return BardAnswer{}, err 142 | } 143 | 144 | var respDict []interface{} 145 | err = json.Unmarshal(body, &respDict) 146 | if err != nil { 147 | return BardAnswer{}, err 148 | } 149 | 150 | if len(respDict) < 4 || respDict[3] == nil { 151 | return BardAnswer{}, fmt.Errorf("Response Error: %s", string(body)) 152 | } 153 | 154 | parsedAnswer := respDict[3].([]interface{}) 155 | bardAnswer := BardAnswer{ 156 | Content: parsedAnswer[0].(string), 157 | ConversationID: parsedAnswer[1].([]interface{})[0].(string), 158 | ResponseID: parsedAnswer[1].([]interface{})[1].(string), 159 | } 160 | 161 | if parsedAnswer[3] != nil { 162 | bardAnswer.FactualityQueries = parsedAnswer[3].([]interface{}) 163 | } 164 | 165 | if parsedAnswer[2] != nil { 166 | bardAnswer.TextQuery = parsedAnswer[2].([]interface{})[0].(string) 167 | } 168 | 169 | if parsedAnswer[4] != nil { 170 | choices := parsedAnswer[4].([]interface{}) 171 | bardAnswer.Choices = make([]Choice, len(choices)) 172 | for i, choice := range choices { 173 | choiceMap := choice.([]interface{}) 174 | bardAnswer.Choices[i] = Choice{ 175 | ID: choiceMap[0].(string), 176 | Content: choiceMap[1].(string), 177 | } 178 | } 179 | } 180 | 181 | b.ConversationID = bardAnswer.ConversationID 182 | b.ResponseID = bardAnswer.ResponseID 183 | b.ChoiceID = bardAnswer.Choices[0].ID 184 | b.ReqID += 100000 185 | 186 | return bardAnswer, nil 187 | } 188 | 189 | func main() { 190 | token := os.Getenv("_BARD_API_KEY") 191 | timeout := 20 * time.Second 192 | 193 | bard, err := NewBard(token, timeout, nil, nil) 194 | if err != nil { 195 | fmt.Println("Error:", err) 196 | return 197 | } 198 | 199 | inputText := "Hello, Bard!" 200 | answer, err := bard.GetAnswer(inputText) 201 | if err != nil { 202 | fmt.Println("Error:", err) 203 | return 204 | } 205 | 206 | fmt.Println("Bard Answer:") 207 | fmt.Println("Content:", answer.Content) 208 | fmt.Println("Conversation ID:", answer.ConversationID) 209 | fmt.Println("Response ID:", answer.ResponseID) 210 | fmt.Println("Factuality Queries:", answer.FactualityQueries) 211 | fmt.Println("Text Query:", answer.TextQuery) 212 | fmt.Println("Choices:") 213 | for _, choice := range answer.Choices { 214 | fmt.Println(" - ID:", choice.ID) 215 | fmt.Println(" Content:", choice.Content) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.java: -------------------------------------------------------------------------------- 1 | import okhttp3.*; 2 | import org.json.*; 3 | 4 | import java.io.IOException; 5 | import java.util.*; 6 | 7 | public class Bard { 8 | private String token; 9 | private int timeout; 10 | private Map proxies; 11 | private int reqId; 12 | private String conversationId; 13 | private String responseId; 14 | private String choiceId; 15 | private OkHttpClient client; 16 | private String snim0e; 17 | 18 | public Bard(String token, int timeout, Map proxies) { 19 | this.token = token; 20 | this.timeout = timeout; 21 | this.proxies = proxies; 22 | this.reqId = new Random().nextInt(10000); 23 | this.conversationId = ""; 24 | this.responseId = ""; 25 | this.choiceId = ""; 26 | this.client = new OkHttpClient.Builder().cookieJar(new CookieJar() { 27 | @Override 28 | public void saveFromResponse(HttpUrl httpUrl, List list) { 29 | } 30 | 31 | @Override 32 | public List loadForRequest(HttpUrl httpUrl) { 33 | if (token != null) { 34 | return Collections.singletonList(new Cookie.Builder().name("__Secure-1PSID").value(token).build()); 35 | } 36 | return Collections.emptyList(); 37 | } 38 | }).build(); 39 | this.snim0e = getSNlM0e(); 40 | } 41 | 42 | private String getSNlM0e() { 43 | if (this.token == null || !this.token.endsWith(".")) { 44 | throw new IllegalArgumentException("__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value."); 45 | } 46 | 47 | Request request = new Request.Builder() 48 | .url("https://bard.google.com/") 49 | .build(); 50 | 51 | try (Response response = client.newCall(request).execute()) { 52 | if (!response.isSuccessful()) { 53 | throw new IOException("Response code not 200. Response Status is " + response.code()); 54 | } 55 | 56 | String responseBody = response.body().string(); 57 | Matcher matcher = Pattern.compile("SNlM0e\":\"(.*?)\"").matcher(responseBody); 58 | if (!matcher.find()) { 59 | throw new RuntimeException("SNlM0e value not found in response. Check __Secure-1PSID value."); 60 | } 61 | 62 | return matcher.group(1); 63 | } catch (IOException e) { 64 | throw new RuntimeException("Error occurred while fetching SNlM0e value: " + e.getMessage()); 65 | } 66 | } 67 | 68 | public JSONObject getAnswer(String inputText) { 69 | try { 70 | String inputTextStruct = "[[\"" + inputText + "\"],null,[\"" + conversationId + "\",\"" + responseId + "\",\"" + choiceId + "\"]]"; 71 | 72 | JSONObject data = new JSONObject() 73 | .put("f.req", new JSONArray().put(null).put(inputTextStruct)) 74 | .put("at", snim0e); 75 | 76 | RequestBody requestBody = RequestBody.create(data.toString(), MediaType.parse("application/json; charset=utf-8")); 77 | 78 | Request request = new Request.Builder() 79 | .url("https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate") 80 | .post(requestBody) 81 | .build(); 82 | 83 | try (Response response = client.newCall(request).execute()) { 84 | if (!response.isSuccessful()) { 85 | throw new IOException("Response code not 200. Response Status is " + response.code()); 86 | } 87 | 88 | String responseBody = response.body().string(); 89 | JSONArray parsedAnswer = new JSONArray(new JSONArray(responseBody).getJSONArray(0).getString(2)); 90 | 91 | if (parsedAnswer.isEmpty()) { 92 | return new JSONObject().put("content", "Response Error: " + responseBody); 93 | } 94 | 95 | JSONObject bardAnswer = new JSONObject(); 96 | bardAnswer.put("content", parsedAnswer.getJSONArray(0).getString(0)); 97 | bardAnswer.put("conversation_id", parsedAnswer.getJSONArray(1).getString(0)); 98 | bardAnswer.put("response_id", parsedAnswer.getJSONArray(1).getString(1)); 99 | bardAnswer.put("factualityQueries", parsedAnswer.getJSONArray(3)); 100 | bardAnswer.put("textQuery", parsedAnswer.getJSONArray(2).optString(0, "")); 101 | 102 | JSONArray choicesArray = new JSONArray(); 103 | JSONArray parsedChoices = parsedAnswer.getJSONArray(4); 104 | for (int i = 0; i < parsedChoices.length(); i++) { 105 | JSONArray choice = parsedChoices.getJSONArray(i); 106 | JSONObject choiceObject = new JSONObject(); 107 | choiceObject.put("id", choice.getString(0)); 108 | choiceObject.put("content", choice.getString(1)); 109 | choicesArray.put(choiceObject); 110 | } 111 | bardAnswer.put("choices", choicesArray); 112 | 113 | this.conversationId = bardAnswer.getString("conversation_id"); 114 | this.responseId = bardAnswer.getString("response_id"); 115 | this.choiceId = bardAnswer.getJSONArray("choices").getJSONObject(0).getString("id"); 116 | this.reqId += 100000; 117 | 118 | return bardAnswer; 119 | } 120 | } catch (IOException e) { 121 | throw new RuntimeException("Error occurred while fetching Bard answer: " + e.getMessage()); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const randomstring = require('randomstring'); 3 | const axios = require('axios'); 4 | 5 | class Bard { 6 | HEADERS = { 7 | Host: 'bard.google.com', 8 | 'X-Same-Domain': '1', 9 | 'User-Agent': 10 | 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 11 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 12 | Origin: 'https://bard.google.com', 13 | Referer: 'https://bard.google.com/', 14 | }; 15 | 16 | constructor(token = null, timeout = 20, proxies = null, session = null) { 17 | this.token = token || process.env._BARD_API_KEY; 18 | this.proxies = proxies; 19 | this.timeout = timeout; 20 | this._reqid = parseInt(randomstring.generate({ length: 4, charset: 'numeric' })); 21 | this.conversation_id = ''; 22 | this.response_id = ''; 23 | this.choice_id = ''; 24 | this.session = session || axios.create({ 25 | headers: this.HEADERS, 26 | withCredentials: true, 27 | timeout: this.timeout * 1000, 28 | proxy: this.proxies, 29 | }); 30 | this.SNlM0e = null; 31 | } 32 | 33 | async _get_snim0e() { 34 | if (!this.token || this.token[this.token.length - 1] !== '.') { 35 | throw new Error('__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value.'); 36 | } 37 | const resp = await this.session.get('https://bard.google.com/'); 38 | if (resp.status !== 200) { 39 | throw new Error(`Response code not 200. Response Status is ${resp.status}`); 40 | } 41 | const snim0eMatch = resp.data.match(/SNlM0e":"(.*?)"/); 42 | if (!snim0eMatch) { 43 | throw new Error('SNlM0e value not found in response. Check __Secure-1PSID value.'); 44 | } 45 | this.SNlM0e = snim0eMatch[1]; 46 | } 47 | 48 | async get_answer(input_text) { 49 | if (!this.SNlM0e) { 50 | await this._get_snim0e(); 51 | } 52 | 53 | const params = { 54 | bl: 'boq_assistant-bard-web-server_20230419.00_p1', 55 | _reqid: this._reqid.toString(), 56 | rt: 'c', 57 | }; 58 | const input_text_struct = [ 59 | [input_text], 60 | null, 61 | [this.conversation_id, this.response_id, this.choice_id], 62 | ]; 63 | const data = { 64 | 'f.req': JSON.stringify([null, JSON.stringify(input_text_struct)]), 65 | at: this.SNlM0e, 66 | }; 67 | const resp = await this.session.post( 68 | 'https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate', 69 | { params, data } 70 | ); 71 | const [, , resp_dict] = JSON.parse(resp.data.split('\n')[3]); 72 | 73 | if (!resp_dict) { 74 | return { content: `Response Error: ${resp.data}` }; 75 | } 76 | const parsed_answer = JSON.parse(resp_dict); 77 | const bard_answer = { 78 | content: parsed_answer[0][0], 79 | conversation_id: parsed_answer[1][0], 80 | response_id: parsed_answer[1][1], 81 | factualityQueries: parsed_answer[3], 82 | textQuery: parsed_answer[2][0] || '', 83 | choices: parsed_answer[4].map(([id, content]) => ({ id, content })), 84 | }; 85 | this.conversation_id = bard_answer.conversation_id; 86 | this.response_id = bard_answer.response_id; 87 | this.choice_id = bard_answer.choices[0].id; 88 | this._reqid += 100000; 89 | 90 | return bard_answer; 91 | } 92 | } 93 | 94 | module.exports = Bard; 95 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.php: -------------------------------------------------------------------------------- 1 | "bard.google.com", 6 | "X-Same-Domain" => "1", 7 | "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 8 | "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8", 9 | "Origin" => "https://bard.google.com", 10 | "Referer" => "https://bard.google.com/" 11 | ); 12 | 13 | private $token; 14 | private $proxies; 15 | private $timeout; 16 | private $reqid; 17 | private $conversation_id; 18 | private $response_id; 19 | private $choice_id; 20 | private $session; 21 | private $SNlM0e; 22 | 23 | public function __construct($token = null, $timeout = 20, $proxies = null, $session = null) { 24 | $this->token = $token ?: getenv("_BARD_API_KEY"); 25 | $this->proxies = $proxies; 26 | $this->timeout = $timeout; 27 | $this->reqid = (int)str_pad(rand(0, 9999), 4, "0", STR_PAD_LEFT); 28 | $this->conversation_id = ""; 29 | $this->response_id = ""; 30 | $this->choice_id = ""; 31 | $this->session = $session ?: new Requests_Session(); 32 | $this->session->headers = self::HEADERS; 33 | $this->session->cookies->set("__Secure-1PSID", $this->token); 34 | $this->SNlM0e = $this->_get_snim0e(); 35 | } 36 | 37 | private function _get_snim0e() { 38 | if (!$this->token || substr($this->token, -1) !== ".") { 39 | throw new Exception("__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value."); 40 | } 41 | $resp = $this->session->get("https://bard.google.com/", array("timeout" => $this->timeout, "proxies" => $this->proxies)); 42 | if ($resp->status_code !== 200) { 43 | throw new Exception("Response code not 200. Response Status is " . $resp->status_code); 44 | } 45 | preg_match('/SNlM0e":"(.*?)"/', $resp->text, $matches); 46 | if (!$matches) { 47 | throw new Exception("SNlM0e value not found in response. Check __Secure-1PSID value."); 48 | } 49 | return $matches[1]; 50 | } 51 | 52 | public function get_answer($input_text) { 53 | $params = array( 54 | "_reqid" => (string)$this->reqid, 55 | "rt" => "c" 56 | ); 57 | $input_text_struct = array( 58 | array($input_text), 59 | null, 60 | array($this->conversation_id, $this->response_id, $this->choice_id) 61 | ); 62 | $data = array( 63 | "f.req" => json_encode(array(null, json_encode($input_text_struct))), 64 | "at" => $this->SNlM0e 65 | ); 66 | $resp = $this->session->post( 67 | "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate", 68 | array("timeout" => $this->timeout, "proxies" => $this->proxies), 69 | $params, 70 | $data 71 | ); 72 | $resp_dict = json_decode(explode("\n", $resp->content)[3], true)[0][2]; 73 | 74 | if (!$resp_dict) { 75 | return array("content" => "Response Error: " . $resp->content); 76 | } 77 | $parsed_answer = json_decode($resp_dict, true); 78 | $choices = array_map(function($item) { 79 | return array("id" => $item[0], "content" => $item[1]); 80 | }, $parsed_answer[4]); 81 | $bard_answer = array( 82 | "content" => $parsed_answer[0][0], 83 | "conversation_id" => $parsed_answer[1][0], 84 | "response_id" => $parsed_answer[1][1], 85 | "factualityQueries" => $parsed_answer[3], 86 | "textQuery" => $parsed_answer[2][0] ?: "", 87 | "choices" => $choices 88 | ); 89 | $this->conversation_id = $bard_answer["conversation_id"]; 90 | $this->response_id = $bard_answer["response_id"]; 91 | $this->choice_id = $choices[0]["id"]; 92 | $this->reqid += 100000; 93 | 94 | return $bard_answer; 95 | } 96 | } 97 | 98 | ?> 99 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.rs: -------------------------------------------------------------------------------- 1 | use reqwest::{blocking::Client, header::HeaderMap, StatusCode}; 2 | use serde_json::{json, Value}; 3 | use regex::Regex; 4 | 5 | pub struct Bard { 6 | token: String, 7 | timeout: u64, 8 | proxies: Option, 9 | reqid: u32, 10 | conversation_id: String, 11 | response_id: String, 12 | choice_id: String, 13 | session: Client, 14 | snim0e: String, 15 | } 16 | 17 | impl Bard { 18 | const HEADERS: &str = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"; 19 | 20 | pub fn new(token: Option, timeout: Option, proxies: Option) -> Result { 21 | let token = token 22 | .or_else(|| std::env::var("_BARD_API_KEY").ok()) 23 | .ok_or_else(|| "Token not provided".to_string())?; 24 | 25 | let timeout = timeout.unwrap_or(20); 26 | 27 | let reqid: u32 = rand::random(); 28 | 29 | let session = Client::new(); 30 | 31 | let snim0e = Self::get_snim0e(&session, timeout, &proxies)?; 32 | 33 | Ok(Self { 34 | token, 35 | timeout, 36 | proxies, 37 | reqid, 38 | conversation_id: String::new(), 39 | response_id: String::new(), 40 | choice_id: String::new(), 41 | session, 42 | snim0e, 43 | }) 44 | } 45 | 46 | fn get_snim0e(client: &Client, timeout: u64, proxies: &Option) -> Result { 47 | let response = client 48 | .get("https://bard.google.com/") 49 | .timeout(std::time::Duration::from_secs(timeout)) 50 | .header(reqwest::header::USER_AGENT, Self::HEADERS) 51 | .headers(proxies.clone().unwrap_or_default()) 52 | .send() 53 | .map_err(|e| format!("Failed to send request: {}", e))?; 54 | 55 | if response.status() != StatusCode::OK { 56 | return Err(format!("Response code not 200. Response Status is {}", response.status())); 57 | } 58 | 59 | let response_text = response.text().map_err(|e| format!("Failed to read response body: {}", e))?; 60 | 61 | let re = Regex::new(r"SNlM0e\":\"(.*?)\"").unwrap(); 62 | let snim0e = re 63 | .captures(&response_text) 64 | .and_then(|caps| caps.get(1)) 65 | .map(|m| m.as_str().to_owned()) 66 | .ok_or_else(|| "SNlM0e value not found in response. Check __Secure-1PSID value.".to_string())?; 67 | 68 | Ok(snim0e) 69 | } 70 | 71 | pub fn get_answer(&mut self, input_text: &str) -> Result { 72 | let reqid = self.reqid; 73 | self.reqid += 100_000; 74 | 75 | let params = [ 76 | ("_reqid", &reqid.to_string()), 77 | ("rt", "c"), 78 | ]; 79 | 80 | let input_text_struct = json!([ 81 | [input_text], 82 | null, 83 | [self.conversation_id.clone(), self.response_id.clone(), self.choice_id.clone()], 84 | ]); 85 | 86 | let data = json!({ 87 | "f.req": [null, json!(input_text_struct)], 88 | "at": &self.snim0e, 89 | }); 90 | 91 | let response = self.session 92 | .post("https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate") 93 | .timeout(std::time::Duration::from_secs(self.timeout)) 94 | .header(reqwest::header::USER_AGENT, Self::HEADERS) 95 | .headers(self.proxies.clone().unwrap_or_default()) 96 | .query(¶ms) 97 | .form(&data) 98 | .send() 99 | .map_err(|e| format!("Failed to send request: {}", e))?; 100 | 101 | let response_text = response.text().map_err(|e| format!("Failed to read response body: {}", e))?; 102 | 103 | let resp_dict = response_text.lines().nth(3) 104 | .ok_or_else(|| format!("Failed to parse response: {}", response_text))?; 105 | 106 | let parsed_answer: Value = serde_json::from_str(resp_dict) 107 | .map_err(|e| format!("Failed to parse response JSON: {}", e))?; 108 | 109 | let parsed_answer = parsed_answer 110 | .as_array() 111 | .and_then(|array| array.get(0)) 112 | .and_then(|value| value.as_array()) 113 | .ok_or_else(|| format!("Invalid response format: {}", resp_dict))?; 114 | 115 | if parsed_answer.is_empty() { 116 | return Ok(json!({"content": format!("Response Error: {}.", response_text)})); 117 | } 118 | 119 | let parsed_answer = parsed_answer.as_slice().unwrap(); 120 | 121 | let bard_answer = json!({ 122 | "content": parsed_answer[0][0], 123 | "conversation_id": parsed_answer[1][0], 124 | "response_id": parsed_answer[1][1], 125 | "factualityQueries": parsed_answer[3], 126 | "textQuery": parsed_answer[2].get(0).cloned().unwrap_or_default(), 127 | "choices": parsed_answer[4] 128 | .as_array() 129 | .unwrap_or_default() 130 | .iter() 131 | .map(|choice| json!({"id": choice[0], "content": choice[1]})) 132 | .collect::>(), 133 | }); 134 | 135 | self.conversation_id = bard_answer["conversation_id"].to_string(); 136 | self.response_id = bard_answer["response_id"].to_string(); 137 | self.choice_id = bard_answer["choices"][0]["id"].to_string(); 138 | 139 | Ok(bard_answer) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/bardapi.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Bard { 4 | static let HEADERS: [String: String] = [ 5 | "Host": "bard.google.com", 6 | "X-Same-Domain": "1", 7 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 8 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", 9 | "Origin": "https://bard.google.com", 10 | "Referer": "https://bard.google.com/" 11 | ] 12 | 13 | let token: String? 14 | let timeout: TimeInterval 15 | let proxies: [String: String]? 16 | let session: URLSession 17 | 18 | private var reqid: Int 19 | private var conversationId: String 20 | private var responseId: String 21 | private var choiceId: String 22 | private var snim0e: String 23 | 24 | init(token: String? = nil, timeout: TimeInterval = 20, proxies: [String: String]? = nil, session: URLSession? = nil) { 25 | self.token = token ?? ProcessInfo.processInfo.environment["_BARD_API_KEY"] 26 | self.timeout = timeout 27 | self.proxies = proxies 28 | self.session = session ?? URLSession.shared 29 | 30 | self.reqid = Int.random(in: 0..<10_000) 31 | self.conversationId = "" 32 | self.responseId = "" 33 | self.choiceId = "" 34 | self.snim0e = "" 35 | } 36 | 37 | private func getSNlM0e(completion: @escaping (Result) -> Void) { 38 | guard let token = token, token.hasSuffix(".") else { 39 | completion(.failure(BardError.invalidToken)) 40 | return 41 | } 42 | 43 | guard let url = URL(string: "https://bard.google.com/") else { 44 | completion(.failure(BardError.invalidURL)) 45 | return 46 | } 47 | 48 | var request = URLRequest(url: url) 49 | request.timeoutInterval = timeout 50 | request.allHTTPHeaderFields = Bard.HEADERS 51 | request.httpMethod = "GET" 52 | request.setValue(token, forHTTPHeaderField: "__Secure-1PSID") 53 | 54 | let task = session.dataTask(with: request) { data, response, error in 55 | if let error = error { 56 | completion(.failure(error)) 57 | return 58 | } 59 | 60 | guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { 61 | completion(.failure(BardError.invalidResponse)) 62 | return 63 | } 64 | 65 | guard let data = data, 66 | let htmlString = String(data: data, encoding: .utf8), 67 | let snim0e = Bard.extractSNlM0e(from: htmlString) else { 68 | completion(.failure(BardError.snim0eNotFound)) 69 | return 70 | } 71 | 72 | completion(.success(snim0e)) 73 | } 74 | 75 | task.resume() 76 | } 77 | 78 | private static func extractSNlM0e(from htmlString: String) -> String? { 79 | let pattern = #"SNlM0e":"(.*?)""# 80 | let regex = try! NSRegularExpression(pattern: pattern) 81 | if let match = regex.firstMatch(in: htmlString, range: NSRange(htmlString.startIndex..., in: htmlString)), 82 | let range = Range(match.range(at: 1), in: htmlString) { 83 | return String(htmlString[range]) 84 | } 85 | return nil 86 | } 87 | 88 | private func generateRequest(inputText: String, completion: @escaping (Result<[String: Any], Error>) -> Void) { 89 | let params = [ 90 | "bl": "boq_assistant-bard-web-server_20230419.00_p1", 91 | "_reqid": "\(reqid)", 92 | "rt": "c" 93 | ] 94 | 95 | let inputTextStruct = [ 96 | [inputText], 97 | NSNull(), 98 | [conversationId, responseId, choiceId] 99 | ] 100 | 101 | let data = [ 102 | "f.req": "[null, \(Bard.jsonString(inputTextStruct))]", 103 | "at": snim0e 104 | ] 105 | 106 | guard let url = URL(string: "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate") else { 107 | completion(.failure(BardError.invalidURL)) 108 | return 109 | } 110 | 111 | var request = URLRequest(url: url) 112 | request.timeoutInterval = timeout 113 | request.allHTTPHeaderFields = Bard.HEADERS 114 | request.httpMethod = "POST" 115 | request.httpBody = try! JSONSerialization.data(withJSONObject: data) 116 | request.setValue("application/json", forHTTPHeaderField: "Content-Type") 117 | request.url = URL(string: url.absoluteString + "?" + params.map { "\($0.key)=\($0.value)" }.joined(separator: "&")) 118 | 119 | let task = session.dataTask(with: request) { data, response, error in 120 | if let error = error { 121 | completion(.failure(error)) 122 | return 123 | } 124 | 125 | guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { 126 | completion(.failure(BardError.invalidResponse)) 127 | return 128 | } 129 | 130 | guard let data = data, 131 | let jsonResponse = try? JSONSerialization.jsonObject(with: data, options: []), 132 | let responseArray = jsonResponse as? [Any], 133 | let respDict = responseArray[3] as? [String: Any] else { 134 | completion(.failure(BardError.invalidResponseData)) 135 | return 136 | } 137 | 138 | completion(.success(respDict)) 139 | } 140 | 141 | task.resume() 142 | } 143 | 144 | func getAnswer(inputText: String, completion: @escaping (Result<[String: Any], Error>) -> Void) { 145 | getSNlM0e { [weak self] result in 146 | switch result { 147 | case .success(let snim0e): 148 | self?.snim0e = snim0e 149 | self?.generateRequest(inputText: inputText, completion: completion) 150 | case .failure(let error): 151 | completion(.failure(error)) 152 | } 153 | } 154 | } 155 | 156 | private static func jsonString(_ object: Any) -> String { 157 | guard let data = try? JSONSerialization.data(withJSONObject: object) else { 158 | return "" 159 | } 160 | return String(data: data, encoding: .utf8) ?? "" 161 | } 162 | } 163 | 164 | enum BardError: Error { 165 | case invalidToken 166 | case invalidURL 167 | case invalidResponse 168 | case snim0eNotFound 169 | case invalidResponseData 170 | } 171 | -------------------------------------------------------------------------------- /translate_to_other_programming_language/core_async.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import string 5 | from re import search 6 | from bardapi.constants import ALLOWED_LANGUAGES, SESSION_HEADERS 7 | from deep_translator import GoogleTranslator 8 | from httpx import AsyncClient 9 | 10 | 11 | class BardAsync: 12 | """ 13 | Bard class for interacting with the Bard API using httpx[http2] 14 | Tested and working (could break in the future, if not kept up to date) 15 | """ 16 | 17 | def __init__( 18 | self, 19 | token: str = None, 20 | timeout: int = 20, 21 | proxies: dict = None, 22 | language: str = None, 23 | run_code: bool = False, 24 | ): 25 | """ 26 | Initialize the Bard instance. 27 | 28 | Args: 29 | token (str): Bard API token. 30 | timeout (int): Request timeout in seconds. 31 | proxies (dict): Proxy configuration for requests. 32 | language (str): Language code for translation (e.g., "en", "ko", "ja"). 33 | """ 34 | self.token = token or os.getenv("_BARD_API_KEY") 35 | self.proxies = proxies 36 | self.timeout = timeout 37 | self._reqid = int("".join(random.choices(string.digits, k=4))) 38 | self.conversation_id = "" 39 | self.response_id = "" 40 | self.choice_id = "" 41 | # Making httpx async client that will be used for all API calls 42 | self.client = AsyncClient( 43 | http2=True, 44 | headers=SESSION_HEADERS, 45 | cookies={"__Secure-1PSID": self.token}, 46 | timeout=self.timeout, 47 | proxies=self.proxies, 48 | ) 49 | self.SNlM0e = self._get_snim0e() 50 | self.language = language or os.getenv("_BARD_API_LANG", "en") 51 | self.run_code = run_code or False 52 | 53 | async def get_answer(self, input_text: str) -> dict: 54 | """ 55 | Get an answer from the Bard API for the given input text. 56 | 57 | Example: 58 | >>> token = 'xxxxxxxxxx' 59 | >>> bard = BardAsync(token=token) 60 | >>> response = await bard.get_answer("나와 내 동년배들이 좋아하는 뉴진스에 대해서 알려줘") 61 | >>> print(response['content']) 62 | 63 | Args: 64 | input_text (str): Input text for the query. 65 | 66 | Returns: 67 | dict: Answer from the Bard API in the following format: 68 | { 69 | "content": str, 70 | "conversation_id": str, 71 | "response_id": str, 72 | "factualityQueries": list, 73 | "textQuery": str, 74 | "choices": list, 75 | "links": list 76 | "imgaes": set 77 | } 78 | """ 79 | if not isinstance(self.SNlM0e, str): 80 | self.SNlM0e = await self.SNlM0e 81 | params = { 82 | "bl": "boq_assistant-bard-web-server_20230419.00_p1", 83 | "_reqid": str(self._reqid), 84 | "rt": "c", 85 | } 86 | 87 | # [Optional] set language 88 | if self.language is not None and self.language not in ALLOWED_LANGUAGES: 89 | translator_to_eng = GoogleTranslator(source="auto", target="en") 90 | input_text = translator_to_eng.translate(input_text) 91 | 92 | # Make post data structure and insert prompt 93 | input_text_struct = [ 94 | [input_text], 95 | None, 96 | [self.conversation_id, self.response_id, self.choice_id], 97 | ] 98 | data = { 99 | "f.req": json.dumps([None, json.dumps(input_text_struct)]), 100 | "at": self.SNlM0e, 101 | } 102 | 103 | resp = await self.client.post( 104 | "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate", 105 | params=params, 106 | data=data, 107 | timeout=self.timeout, 108 | follow_redirects=True, 109 | headers=SESSION_HEADERS, 110 | cookies={"__Secure-1PSID": self.token}, 111 | ) 112 | 113 | # Post-processing of response 114 | resp_dict = json.loads(resp.content.splitlines()[3])[0][2] 115 | 116 | if not resp_dict: 117 | return {"content": f"Response Error: {resp.content}."} 118 | resp_json = json.loads(resp_dict) 119 | 120 | # Gather image links 121 | images = list() 122 | if len(resp_json) >= 3: 123 | if len(resp_json[4][0]) >= 4 and resp_json[4][0][4] is not None: 124 | for img in resp_json[4][0][4]: 125 | try: 126 | images.append(img[0][0][0]) 127 | except Exception as e: 128 | # TODO: 129 | # handle exception using logging instead 130 | print(f"Unable to parse image from the response: {e}") 131 | parsed_answer = json.loads(resp_dict) 132 | 133 | # [Optional] translated by google translator 134 | if self.language is not None and self.language not in ALLOWED_LANGUAGES: 135 | translator_to_lang = GoogleTranslator(source="auto", target=self.language) 136 | parsed_answer[0][0] = translator_to_lang.translate(parsed_answer[0][0]) 137 | parsed_answer[4] = [ 138 | (x[0], translator_to_lang.translate(x[1][0])) for x in parsed_answer[4] 139 | ] 140 | 141 | # Get code 142 | try: 143 | code = parsed_answer[0][0].split("```")[1][6:] 144 | except Exception as e: 145 | # TODO: 146 | # handle exception using logging instead 147 | code = None 148 | print(f"Unable to parse answer from the response: {e}") 149 | 150 | # Returned dictionary object 151 | bard_answer = { 152 | "content": parsed_answer[4][0][1][0], 153 | "conversation_id": parsed_answer[1][0], 154 | "response_id": parsed_answer[1][1], 155 | "factualityQueries": parsed_answer[3], 156 | "textQuery": parsed_answer[2][0] if parsed_answer[2] else "", 157 | "choices": [{"id": x[0], "content": x[1]} for x in parsed_answer[4]], 158 | "links": self._extract_links(parsed_answer[4]), 159 | "images": images, 160 | "code": code, 161 | "status_code": resp.status_code, 162 | } 163 | 164 | self.conversation_id, self.response_id, self.choice_id = ( 165 | bard_answer["conversation_id"], 166 | bard_answer["response_id"], 167 | bard_answer["choices"][0]["id"], 168 | ) 169 | self._reqid += 100000 170 | 171 | # Execute code 172 | if self.run_code and bard_answer["code"] is not None: 173 | try: 174 | print(bard_answer["code"]) 175 | # TODO: 176 | # find a way to handle this following warning 177 | # EX100: use of builtin exec function for dynamic input is insecure and can leave your application 178 | # open to arbitrary code execution. Found in 'exec(bard_answer['code'])'. 179 | exec(bard_answer["code"]) 180 | except Exception as e: 181 | # TODO: 182 | # handle exception using logging instead 183 | print(f"Unable to execute the code: {e}") 184 | 185 | return bard_answer 186 | 187 | async def _get_snim0e(self): 188 | """ 189 | The _get_snim0e function is used to get the SNlM0e value from the Bard website. 190 | 191 | The function uses a regular expression to search for the SNlM0e value in the response text. 192 | If it finds it, then it returns that value. 193 | 194 | :param self: Represent the instance of the class 195 | :return: (`str`) The snlm0e value 196 | """ 197 | if not self.token or self.token[-1] != ".": 198 | raise Exception( 199 | "__Secure-1PSID value must end with a single dot. Enter correct __Secure-1PSID value." 200 | ) 201 | 202 | resp = await self.client.get( 203 | "https://bard.google.com/", timeout=self.timeout, follow_redirects=True 204 | ) 205 | if resp.status_code != 200: 206 | raise Exception( 207 | f"Response code not 200. Response Status is {resp.status_code}" 208 | ) 209 | snim0e = search(r"SNlM0e\":\"(.*?)\"", resp.text) 210 | if not snim0e: 211 | raise Exception( 212 | "SNlM0e value not found in response. Check __Secure-1PSID value." 213 | ) 214 | return snim0e.group(1) 215 | 216 | def _extract_links(self, data: list) -> list: 217 | """ 218 | Extract links from the given data. 219 | 220 | Args: 221 | data: Data to extract links from. 222 | 223 | Returns: 224 | list: Extracted links. 225 | """ 226 | links = [] 227 | if isinstance(data, list): 228 | for item in data: 229 | if isinstance(item, list): 230 | links.extend(self._extract_links(item)) 231 | elif ( 232 | isinstance(item, str) 233 | and item.startswith("http") 234 | and "favicon" not in item 235 | ): 236 | links.append(item) 237 | return links 238 | --------------------------------------------------------------------------------