Bard.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. from __future__ import annotations
  2. import time
  3. import os
  4. try:
  5. from selenium.webdriver.common.by import By
  6. from selenium.webdriver.support.ui import WebDriverWait
  7. from selenium.webdriver.support import expected_conditions as EC
  8. except ImportError:
  9. pass
  10. from ...typing import CreateResult, Messages
  11. from ..base_provider import AbstractProvider
  12. from ..helper import format_prompt
  13. from ...webdriver import WebDriver, WebDriverSession, element_send_text
  14. class Bard(AbstractProvider):
  15. url = "https://bard.google.com"
  16. working = True
  17. needs_auth = True
  18. webdriver = True
  19. @classmethod
  20. def create_completion(
  21. cls,
  22. model: str,
  23. messages: Messages,
  24. stream: bool,
  25. proxy: str = None,
  26. webdriver: WebDriver = None,
  27. user_data_dir: str = None,
  28. headless: bool = True,
  29. **kwargs
  30. ) -> CreateResult:
  31. prompt = format_prompt(messages)
  32. session = WebDriverSession(webdriver, user_data_dir, headless, proxy=proxy)
  33. with session as driver:
  34. try:
  35. driver.get(f"{cls.url}/chat")
  36. wait = WebDriverWait(driver, 10 if headless else 240)
  37. wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.ql-editor.textarea")))
  38. except:
  39. # Reopen browser for login
  40. if not webdriver:
  41. driver = session.reopen()
  42. driver.get(f"{cls.url}/chat")
  43. login_url = os.environ.get("G4F_LOGIN_URL")
  44. if login_url:
  45. yield f"Please login: [Google Bard]({login_url})\n\n"
  46. wait = WebDriverWait(driver, 240)
  47. wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.ql-editor.textarea")))
  48. else:
  49. raise RuntimeError("Prompt textarea not found. You may not be logged in.")
  50. # Add hook in XMLHttpRequest
  51. script = """
  52. const _http_request_open = XMLHttpRequest.prototype.open;
  53. window._message = "";
  54. XMLHttpRequest.prototype.open = function(method, url) {
  55. if (url.includes("/assistant.lamda.BardFrontendService/StreamGenerate")) {
  56. this.addEventListener("load", (event) => {
  57. window._message = JSON.parse(JSON.parse(this.responseText.split("\\n")[3])[0][2])[4][0][1][0];
  58. });
  59. }
  60. return _http_request_open.call(this, method, url);
  61. }
  62. """
  63. driver.execute_script(script)
  64. element_send_text(driver.find_element(By.CSS_SELECTOR, "div.ql-editor.textarea"), prompt)
  65. while True:
  66. chunk = driver.execute_script("return window._message;")
  67. if chunk:
  68. yield chunk
  69. return
  70. else:
  71. time.sleep(0.1)