XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

feat: add GitHub Copilot provider with conversation handling and token management

d6dcb36c
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

1 个文件 +191 -0
Added g4f/Provider/needs_auth/GithubCopilot.py +191 -0
@@ -0,0 +1,191 @@
1 from __future__ import annotations
2
3 import json
4 from aiohttp import ClientSession
5
6 from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, BaseConversation
7 from ...typing import AsyncResult, Messages, Cookies
8 from ...requests.raise_for_status import raise_for_status
9 from ...requests.aiohttp import get_connector
10 from ...providers.helper import format_prompt, get_last_user_message
11 from ...cookies import get_cookies
12
13 class Conversation(BaseConversation):
14 conversation_id: str
15
16 def __init__(self, conversation_id: str):
17 self.conversation_id = conversation_id
18
19 class GithubCopilot(AsyncGeneratorProvider, ProviderModelMixin):
20 label = "GitHub Copilot"
21 url = "https://github.com/copilot"
22
23 working = True
24 needs_auth = True
25 supports_stream = True
26
27 default_model = "gpt-4.1"
28
29 models = [
30 # GPT-5 Series
31 "gpt-5",
32 "gpt-5-mini",
33 "gpt-5.1",
34 "gpt-5.2",
35
36 # GPT-5 Codex (optimized for code)
37 "gpt-5-codex",
38 "gpt-5.1-codex",
39 "gpt-5.1-codex-mini",
40 "gpt-5.1-codex-max",
41 "gpt-5.2-codex",
42 "gpt-5.3-codex",
43
44 # GPT-4 Series
45 "gpt-4.1",
46 "gpt-4.1-2025-04-14",
47 "gpt-4o",
48 "gpt-4o-mini",
49 "gpt-4o-2024-11-20",
50 "gpt-4o-2024-08-06",
51 "gpt-4o-2024-05-13",
52 "gpt-4o-mini-2024-07-18",
53 "gpt-4",
54 "gpt-4-0613",
55 "gpt-4-0125-preview",
56 "gpt-4-o-preview",
57
58 # Claude 4 Series
59 "claude-opus-4.6",
60 "claude-opus-4.6-fast",
61 "claude-opus-4.5",
62 "claude-sonnet-4.5",
63 "claude-sonnet-4",
64 "claude-haiku-4.5",
65
66 # Gemini Series
67 "gemini-3-pro-preview",
68 "gemini-3-flash-preview",
69 "gemini-2.5-pro",
70
71 # Grok
72 "grok-code-fast-1",
73
74 # Legacy GPT-3.5
75 "gpt-3.5-turbo",
76 "gpt-3.5-turbo-0613",
77
78 # Embeddings
79 "text-embedding-3-small",
80 "text-embedding-ada-002",
81 ]
82
83 @classmethod
84 async def create_async_generator(
85 cls,
86 model: str,
87 messages: Messages,
88 stream: bool = True,
89 api_key: str = None,
90 proxy: str = None,
91 cookies: Cookies = None,
92 conversation_id: str = None,
93 conversation: Conversation = None,
94 return_conversation: bool = True,
95 **kwargs
96 ) -> AsyncResult:
97 if not model:
98 model = cls.default_model
99
100 if cookies is None:
101 cookies = get_cookies("github.com")
102
103 async with ClientSession(
104 connector=get_connector(proxy=proxy),
105 cookies=cookies,
106 headers={
107 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0',
108 'Accept': 'application/json',
109 'Accept-Language': 'en-US,en;q=0.5',
110 'Referer': 'https://github.com/copilot',
111 'Content-Type': 'application/json',
112 'GitHub-Verified-Fetch': 'true',
113 'X-Requested-With': 'XMLHttpRequest',
114 'Origin': 'https://github.com',
115 'Connection': 'keep-alive',
116 'Sec-Fetch-Dest': 'empty',
117 'Sec-Fetch-Mode': 'cors',
118 'Sec-Fetch-Site': 'same-origin',
119 'Priority': 'u=1'
120 }
121 ) as session:
122 headers = {}
123 if api_key is None:
124 async with session.post("https://github.com/github-copilot/chat/token") as response:
125 await raise_for_status(response, "Get token")
126 api_key = (await response.json()).get("token")
127
128 headers = {
129 "Authorization": f"GitHub-Bearer {api_key}",
130 }
131
132 if conversation is not None:
133 conversation_id = conversation.conversation_id
134
135 if conversation_id is None:
136 async with session.post(
137 "https://api.individual.githubcopilot.com/github/chat/threads",
138 headers=headers
139 ) as response:
140 await raise_for_status(response)
141 conversation_id = (await response.json()).get("thread_id")
142
143 if return_conversation:
144 yield Conversation(conversation_id)
145 content = get_last_user_message(messages)
146 else:
147 content = format_prompt(messages)
148
149 json_data = {
150 "content": content,
151 "intent": "conversation",
152 "references": [],
153 "context": [],
154 "currentURL": f"https://github.com/copilot/c/{conversation_id}",
155 "streaming": stream,
156 "confirmations": [],
157 "customInstructions": [],
158 "model": model,
159 "mode": "immersive"
160 }
161
162 async with session.post(
163 f"https://api.individual.githubcopilot.com/github/chat/threads/{conversation_id}/messages",
164 json=json_data,
165 headers=headers
166 ) as response:
167 await raise_for_status(response, f"Send message with model {model}")
168
169 if stream:
170 async for line in response.content:
171 if line.startswith(b"data: "):
172 try:
173 data = json.loads(line[6:])
174 if data.get("type") == "content":
175 content = data.get("body", "")
176 if content:
177 yield content
178 except json.JSONDecodeError:
179 continue
180 else:
181 full_content = ""
182 async for line in response.content:
183 if line.startswith(b"data: "):
184 try:
185 data = json.loads(line[6:])
186 if data.get("type") == "content":
187 full_content += data.get("body", "")
188 except json.JSONDecodeError:
189 continue
190 if full_content:
191 yield full_content