返回提交历史
Added
g4f/Provider/needs_auth/GithubCopilot.py
+191
-0
XFEstudio/gpt4free
feat: add GitHub Copilot provider with conversation handling and token management
d6dcb36c
代码差异
1 个文件
+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