Phind.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from __future__ import annotations
  2. import time
  3. from urllib.parse import quote
  4. from ...typing import CreateResult, Messages
  5. from ..base_provider import AbstractProvider
  6. from ..helper import format_prompt
  7. from ...webdriver import WebDriver, WebDriverSession
  8. class Phind(AbstractProvider):
  9. url = "https://www.phind.com"
  10. working = False
  11. supports_gpt_4 = True
  12. supports_stream = True
  13. @classmethod
  14. def create_completion(
  15. cls,
  16. model: str,
  17. messages: Messages,
  18. stream: bool,
  19. proxy: str = None,
  20. timeout: int = 120,
  21. webdriver: WebDriver = None,
  22. creative_mode: bool = None,
  23. **kwargs
  24. ) -> CreateResult:
  25. with WebDriverSession(webdriver, "", proxy=proxy) as driver:
  26. from selenium.webdriver.common.by import By
  27. from selenium.webdriver.support.ui import WebDriverWait
  28. from selenium.webdriver.support import expected_conditions as EC
  29. # Register fetch hook
  30. source = """
  31. window._fetch = window.fetch;
  32. window.fetch = async (url, options) => {
  33. const response = await window._fetch(url, options);
  34. if (url != "/api/infer/answer") {
  35. return response;
  36. }
  37. copy = response.clone();
  38. window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
  39. return copy;
  40. }
  41. """
  42. driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  43. "source": source
  44. })
  45. prompt = quote(format_prompt(messages))
  46. driver.get(f"{cls.url}/search?q={prompt}&source=searchbox")
  47. # Need to change settings
  48. wait = WebDriverWait(driver, timeout)
  49. def open_dropdown():
  50. # Open settings dropdown
  51. wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "button.text-dark.dropdown-toggle")))
  52. driver.find_element(By.CSS_SELECTOR, "button.text-dark.dropdown-toggle").click()
  53. # Wait for dropdown toggle
  54. wait.until(EC.visibility_of_element_located((By.XPATH, "//button[text()='GPT-4']")))
  55. if model.startswith("gpt-4") or creative_mode:
  56. # Enable GPT-4
  57. if model.startswith("gpt-4"):
  58. open_dropdown()
  59. driver.find_element(By.XPATH, "//button[text()='GPT-4']").click()
  60. # Enable creative mode
  61. if creative_mode or creative_mode == None:
  62. open_dropdown()
  63. driver.find_element(By.ID, "Creative Mode").click()
  64. # Submit changes
  65. driver.find_element(By.CSS_SELECTOR, ".search-bar-input-group button[type='submit']").click()
  66. # Wait for page reload
  67. wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".search-container")))
  68. while True:
  69. chunk = driver.execute_script("""
  70. if(window._reader) {
  71. chunk = await window._reader.read();
  72. if (chunk['done']) {
  73. return null;
  74. }
  75. content = '';
  76. chunk['value'].split('\\r\\n').forEach((line, index) => {
  77. if (line.startsWith('data: ')) {
  78. line = line.substring('data: '.length);
  79. if (!line.startsWith('<PHIND_METADATA>')) {
  80. if (line) content += line;
  81. else content += '\\n';
  82. }
  83. }
  84. });
  85. return content.replace('\\n\\n', '\\n');
  86. } else {
  87. return ''
  88. }
  89. """)
  90. if chunk:
  91. yield chunk
  92. elif chunk != "":
  93. break
  94. else:
  95. time.sleep(0.1)