GithubCopilot.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from __future__ import annotations
  2. import json
  3. from aiohttp import ClientSession
  4. from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, BaseConversation
  5. from ...typing import AsyncResult, Messages, Cookies
  6. from ...requests.raise_for_status import raise_for_status
  7. from ...requests.aiohttp import get_connector
  8. from ...providers.helper import format_prompt, get_last_user_message
  9. from ...cookies import get_cookies
  10. class Conversation(BaseConversation):
  11. conversation_id: str
  12. def __init__(self, conversation_id: str):
  13. self.conversation_id = conversation_id
  14. class GithubCopilot(AsyncGeneratorProvider, ProviderModelMixin):
  15. label = "GitHub Copilot"
  16. url = "https://github.com/copilot"
  17. working = True
  18. needs_auth = True
  19. supports_stream = True
  20. default_model = "gpt-4o"
  21. models = [default_model, "o1-mini", "o1-preview", "claude-3.5-sonnet"]
  22. @classmethod
  23. async def create_async_generator(
  24. cls,
  25. model: str,
  26. messages: Messages,
  27. stream: bool = False,
  28. api_key: str = None,
  29. proxy: str = None,
  30. cookies: Cookies = None,
  31. conversation_id: str = None,
  32. conversation: Conversation = None,
  33. return_conversation: bool = False,
  34. **kwargs
  35. ) -> AsyncResult:
  36. if not model:
  37. model = cls.default_model
  38. if cookies is None:
  39. cookies = get_cookies("github.com")
  40. async with ClientSession(
  41. connector=get_connector(proxy=proxy),
  42. cookies=cookies,
  43. headers={
  44. 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0',
  45. 'Accept-Language': 'en-US,en;q=0.5',
  46. 'Referer': 'https://github.com/copilot',
  47. 'Content-Type': 'application/json',
  48. 'GitHub-Verified-Fetch': 'true',
  49. 'X-Requested-With': 'XMLHttpRequest',
  50. 'Origin': 'https://github.com',
  51. 'Connection': 'keep-alive',
  52. 'Sec-Fetch-Dest': 'empty',
  53. 'Sec-Fetch-Mode': 'cors',
  54. 'Sec-Fetch-Site': 'same-origin',
  55. }
  56. ) as session:
  57. headers = {}
  58. if api_key is None:
  59. async with session.post("https://github.com/github-copilot/chat/token") as response:
  60. await raise_for_status(response, "Get token")
  61. api_key = (await response.json()).get("token")
  62. headers = {
  63. "Authorization": f"GitHub-Bearer {api_key}",
  64. }
  65. if conversation is not None:
  66. conversation_id = conversation.conversation_id
  67. if conversation_id is None:
  68. async with session.post("https://api.individual.githubcopilot.com/github/chat/threads", headers=headers) as response:
  69. await raise_for_status(response)
  70. conversation_id = (await response.json()).get("thread_id")
  71. if return_conversation:
  72. yield Conversation(conversation_id)
  73. content = get_last_user_message(messages)
  74. else:
  75. content = format_prompt(messages)
  76. json_data = {
  77. "content": content,
  78. "intent": "conversation",
  79. "references":[],
  80. "context": [],
  81. "currentURL": f"https://github.com/copilot/c/{conversation_id}",
  82. "streaming": True,
  83. "confirmations": [],
  84. "customInstructions": [],
  85. "model": model,
  86. "mode": "immersive"
  87. }
  88. async with session.post(
  89. f"https://api.individual.githubcopilot.com/github/chat/threads/{conversation_id}/messages",
  90. json=json_data,
  91. headers=headers
  92. ) as response:
  93. async for line in response.content:
  94. if line.startswith(b"data: "):
  95. data = json.loads(line[6:])
  96. if data.get("type") == "content":
  97. yield data.get("body")