gaoqilan commited on
Commit
1f1b4db
·
verified ·
1 Parent(s): 1466ff0

Upload 103 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. __pycache__/init_pool.cpython-311.pyc +0 -0
  2. __pycache__/init_pool.cpython-312.pyc +0 -0
  3. api/__pycache__/telemetry.cpython-311.pyc +0 -0
  4. api/__pycache__/telemetry.cpython-312.pyc +0 -0
  5. api/chat/__init__.py +4 -0
  6. api/chat/__pycache__/__init__.cpython-311.pyc +0 -0
  7. api/chat/__pycache__/__init__.cpython-312.pyc +0 -0
  8. api/chat/__pycache__/chat_api.cpython-311.pyc +0 -0
  9. api/chat/__pycache__/chat_api.cpython-312.pyc +0 -0
  10. api/chat/__pycache__/chat_config.cpython-311.pyc +0 -0
  11. api/chat/__pycache__/chat_config.cpython-312.pyc +0 -0
  12. api/chat/chat_api.py +276 -0
  13. api/chat/chat_config.py +21 -0
  14. api/telemetry.py +92 -0
  15. auth/__pycache__/jwt_handler.cpython-311.pyc +0 -0
  16. auth/__pycache__/jwt_handler.cpython-312.pyc +0 -0
  17. auth/__pycache__/login.cpython-312.pyc +0 -0
  18. auth/__pycache__/register.cpython-312.pyc +0 -0
  19. auth/jwt_handler.py +41 -0
  20. auth/login.py +27 -0
  21. auth/register.py +33 -0
  22. boot.sh +17 -0
  23. config/__pycache__/api_keys.cpython-311.pyc +0 -0
  24. config/__pycache__/api_keys.cpython-312.pyc +0 -0
  25. config/__pycache__/constants.cpython-311.pyc +0 -0
  26. config/__pycache__/constants.cpython-312.pyc +0 -0
  27. config/__pycache__/models.cpython-311.pyc +0 -0
  28. config/__pycache__/models.cpython-312.pyc +0 -0
  29. config/api_keys.py +62 -0
  30. config/api_keys.xml +2 -0
  31. config/constants.py +96 -0
  32. config/models.py +93 -0
  33. docker.txt +9 -0
  34. gen_account.py +232 -0
  35. init_pool.py +21 -0
  36. main.py +119 -0
  37. managers/__pycache__/chat_manager.cpython-311.pyc +0 -0
  38. managers/__pycache__/chat_manager.cpython-312.pyc +0 -0
  39. managers/__pycache__/global_chat_manager.cpython-311.pyc +0 -0
  40. managers/__pycache__/global_chat_manager.cpython-312.pyc +0 -0
  41. managers/chat_manager.py +32 -0
  42. managers/global_chat_manager.py +106 -0
  43. managers/queue/__pycache__/base.cpython-311.pyc +0 -0
  44. managers/queue/__pycache__/base.cpython-312.pyc +0 -0
  45. managers/queue/__pycache__/deque_queue.cpython-311.pyc +0 -0
  46. managers/queue/__pycache__/deque_queue.cpython-312.pyc +0 -0
  47. managers/queue/__pycache__/rabbitmq_queue.cpython-312.pyc +0 -0
  48. managers/queue/__pycache__/redis_queue.cpython-312.pyc +0 -0
  49. managers/queue/base.py +16 -0
  50. managers/queue/deque_queue.py +21 -0
__pycache__/init_pool.cpython-311.pyc ADDED
Binary file (972 Bytes). View file
 
__pycache__/init_pool.cpython-312.pyc ADDED
Binary file (830 Bytes). View file
 
api/__pycache__/telemetry.cpython-311.pyc ADDED
Binary file (5.04 kB). View file
 
api/__pycache__/telemetry.cpython-312.pyc ADDED
Binary file (4.76 kB). View file
 
api/chat/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .chat_config import ChatConfig
2
+ from .chat_api import ChatAPI
3
+
4
+ __all__ = ['ChatConfig', 'ChatAPI']
api/chat/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (319 Bytes). View file
 
api/chat/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (283 Bytes). View file
 
api/chat/__pycache__/chat_api.cpython-311.pyc ADDED
Binary file (14 kB). View file
 
api/chat/__pycache__/chat_api.cpython-312.pyc ADDED
Binary file (13.3 kB). View file
 
api/chat/__pycache__/chat_config.cpython-311.pyc ADDED
Binary file (1.1 kB). View file
 
api/chat/__pycache__/chat_config.cpython-312.pyc ADDED
Binary file (982 Bytes). View file
 
api/chat/chat_api.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import binascii
2
+ import json
3
+ from typing import List, Optional, AsyncGenerator
4
+ from time import time
5
+
6
+ # Remove aioredis import
7
+ # from aioredis import Redis
8
+
9
+ # import tiktoken
10
+ from api.chat import ChatConfig
11
+ from api.telemetry import TelemetryAPI
12
+ from auth.jwt_handler import JWTHandler
13
+ from config.constants import ENCRYPTION_KEY
14
+ from utils.encrypt import encrypt
15
+ from utils.http import HTTPClient
16
+ from config.constants import (
17
+ APP_LANGUAGE,
18
+ APP_NAME,
19
+ APP_VERSION,
20
+ DISPLAY_NAME,
21
+ HADWARE_INFO,
22
+ INFERENCE_URL,
23
+ SYSTEM_INFO,
24
+ )
25
+ from utils.compression import decompress_chunks
26
+
27
+ from protos import request_pb2, response_pb2
28
+
29
+
30
+ class ChatAPI:
31
+ def __init__(self, api_key: str, http_client: HTTPClient = HTTPClient()):
32
+ self.api_key = api_key
33
+ self.jwt_token = None
34
+ self.jwt_token_timestamp = 0
35
+ self.http_client = http_client
36
+
37
+ async def renew_jwt_token(self):
38
+ """Renew JWT token asynchronously if it's expired or missing"""
39
+ current_time = time()
40
+
41
+ # Check if token is still valid (within 2500 seconds)
42
+ if self.jwt_token and current_time - self.jwt_token_timestamp < 2500:
43
+ return
44
+
45
+ jwt_handler = JWTHandler(api_key=self.api_key, http_client=self.http_client)
46
+ jwt_token = await jwt_handler.get_jwt_token()
47
+ tele = TelemetryAPI(api_key=self.api_key)
48
+ await tele.do_telemetry()
49
+
50
+ if jwt_token:
51
+ self.jwt_token = jwt_token
52
+ self.jwt_token_timestamp = current_time
53
+
54
+ async def _create_chat_request(
55
+ self,
56
+ messages: List[dict],
57
+ config: ChatConfig,
58
+ system_prompt: str = "You are a helpful assistant.",
59
+ ) -> request_pb2.ChatRequestMessage:
60
+ try:
61
+ await self.renew_jwt_token()
62
+ except Exception as e:
63
+ print(e)
64
+ ...
65
+
66
+ msg = request_pb2.ChatRequestMessage()
67
+
68
+ # Set client info
69
+ self._set_client_info(msg)
70
+
71
+ # Set system prompt and model config
72
+ msg.system_prompt = system_prompt
73
+ msg.model_id = config.model_id.value
74
+ msg.idk13.idk13nn = 1
75
+ msg.idk_id = 5
76
+ self._set_model_config(msg, config)
77
+
78
+ # Set tool config
79
+ # self._set_tool_config(msg)
80
+
81
+ # Convert messages
82
+ self._add_messages(msg, messages)
83
+
84
+ return msg
85
+
86
+ def _set_client_info(self, msg: request_pb2.ChatRequestMessage) -> None:
87
+ """Set client information in the request message"""
88
+ msg.client_info.api_key = self.api_key
89
+ msg.client_info.user_jwt = self.jwt_token
90
+ msg.client_info.locale = APP_LANGUAGE
91
+ msg.client_info.extension_name = APP_NAME
92
+ msg.client_info.ide_name = APP_NAME
93
+ msg.client_info.extension_version = APP_VERSION
94
+ msg.client_info.os = SYSTEM_INFO
95
+ msg.client_info.ide_version = DISPLAY_NAME
96
+ msg.client_info.hardware = HADWARE_INFO
97
+
98
+ def _set_model_config(
99
+ self, msg: request_pb2.ChatRequestMessage, config: ChatConfig
100
+ ) -> None:
101
+ """Set model configuration"""
102
+ msg.model_config.parallel_stream = 1
103
+ msg.model_config.max_tokens = config.max_tokens
104
+ msg.model_config.temperature = config.temperature
105
+ msg.model_config.top_k = config.top_k
106
+ msg.model_config.top_P = config.top_p
107
+
108
+ def _set_special_tokens(self, msg: request_pb2.ChatRequestMessage) -> None:
109
+ msg.model_config.special_tokens.extend(
110
+ [
111
+ "<|user|>",
112
+ "<|bot|>",
113
+ "<|context_request|>",
114
+ "<|endoftext|>",
115
+ "<|end_of_turn|>",
116
+ ]
117
+ )
118
+
119
+ def _set_tool_config(self, msg: request_pb2.ChatRequestMessage) -> None:
120
+ """Set tool configuration"""
121
+ msg.tool_use.mode = "auto"
122
+ msg.tool_config.tool_name = "do_not_call"
123
+ msg.tool_config.description = "Do not call this tool."
124
+ msg.tool_config.schema = '{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"additionalProperties":false,"type":"object"}'
125
+
126
+ def _add_messages(
127
+ self, msg: request_pb2.ChatRequestMessage, messages: List[dict]
128
+ ) -> None:
129
+ """Add chat messages to the request"""
130
+ role_map = {"user": 1, "assistant": 2, "system": 3}
131
+
132
+ for chat_msg in messages:
133
+ role = role_map.get(chat_msg["role"], 1)
134
+ content = chat_msg["content"]
135
+
136
+ # Override system prompt
137
+ if role == 3:
138
+ if isinstance(content, str):
139
+ msg.system_prompt = content
140
+
141
+ elif isinstance(content, list):
142
+ for item in content:
143
+ if item.get("type", "") == "text" and "text" in item and isinstance(item["text"], str):
144
+ msg.system_prompt = item["text"]
145
+ break
146
+ continue
147
+
148
+ if isinstance(content, list):
149
+ pb_msg = self._create_multipart_message(role, content)
150
+ else:
151
+ pb_msg = self._create_text_message(role, content)
152
+
153
+ msg.chat_messages.append(pb_msg)
154
+
155
+ def _create_multipart_message(
156
+ self, role: int, content: List[dict]
157
+ ) -> request_pb2.ChatMessage:
158
+ """Create a message with multiple parts (text and images)"""
159
+ text_parts = []
160
+ image_parts = []
161
+
162
+ for item in content:
163
+ if item["type"] == "text":
164
+ text_parts.append(item["text"])
165
+ elif item["type"] == "image_url":
166
+ image_url = item["image_url"]["url"]
167
+ if image_url.startswith("data:image/") and "base64," in image_url:
168
+ prefix, image_data = image_url.split("base64,", 1)
169
+ mime_type = prefix.split("data:")[1].split(";")[0]
170
+ image_parts.append(
171
+ request_pb2.ImagePart(
172
+ image_data=image_data, image_mime_type=mime_type
173
+ )
174
+ )
175
+
176
+ return self._create_message(role, " ".join(text_parts), image_parts)
177
+
178
+ def _create_text_message(self, role: int, content: str) -> request_pb2.ChatMessage:
179
+ """Create a simple text message"""
180
+ return self._create_message(role, content)
181
+
182
+ def _create_message(
183
+ self, role: int, content: str, image_parts: List[request_pb2.ImagePart] = None
184
+ ) -> request_pb2.ChatMessage:
185
+ """Create a chat message with common attributes"""
186
+ pb_msg = request_pb2.ChatMessage(
187
+ role=role, content=content
188
+ )
189
+ if role == 1: pb_msg.idk2 = 1
190
+ # pb_msg.cache_control.prompt_caching = 1
191
+
192
+ if image_parts:
193
+ pb_msg.image_parts.extend(image_parts)
194
+ return pb_msg
195
+
196
+ async def _process_chat_response(self, type: int, data: bytes) -> tuple[str, int]:
197
+ """Process a single chat response chunk and return (message, count)"""
198
+ if type == 3: # end of message
199
+ try:
200
+ response = json.loads(data)
201
+ return (encrypt(str(response), ENCRYPTION_KEY), 0) if response else ("", 0)
202
+ except Exception as e:
203
+ raise e
204
+
205
+ try:
206
+ search_response = response_pb2.ChatResponse()
207
+ search_response.ParseFromString(data)
208
+ return (search_response.message, search_response.count) if search_response.message else ("", 0)
209
+ except:
210
+ return ("", 0)
211
+
212
+ async def _handle_stream_response(self, chunk_iterator) -> AsyncGenerator[tuple[str, int], None]:
213
+ """Handle streaming response chunks"""
214
+ async for chunk in chunk_iterator:
215
+ for type, data in decompress_chunks(chunk):
216
+ result = await self._process_chat_response(type, data)
217
+ yield result
218
+
219
+ async def _handle_response(self, chunk) -> AsyncGenerator[tuple[str, int], None]:
220
+ """Handle non-streaming response chunks"""
221
+ for type, data in decompress_chunks(chunk):
222
+ result = await self._process_chat_response(type, data)
223
+ yield result
224
+
225
+ async def send_message(
226
+ self,
227
+ messages: List[dict],
228
+ config: Optional[ChatConfig] = None,
229
+ system_prompt: str = "You are a helpful assistant.",
230
+ stream: bool = False,
231
+ ) -> AsyncGenerator[tuple[str, int], None]:
232
+ """Send chat messages and yield response chunks"""
233
+ if config is None:
234
+ config = ChatConfig()
235
+
236
+ request = await self._create_chat_request(messages, config, system_prompt)
237
+
238
+ headers = {
239
+ "User-Agent": "connect-go/1.16.2 (go1.23.2 X:nocoverageredesign)",
240
+ "Connect-Accept-Encoding": "gzip",
241
+ "Connect-Content-Encoding": "gzip",
242
+ "Connect-Protocol-Version": "1",
243
+ "Content-Type": "application/connect+proto",
244
+ }
245
+
246
+ url = f"{INFERENCE_URL}/exa.api_server_pb.ApiServerService/GetChatMessage"
247
+ request_data = request.SerializeToString()
248
+
249
+ if stream:
250
+ stream_iterator = self.http_client.stream_post(
251
+ url=url,
252
+ data=request_data,
253
+ headers=headers,
254
+ compress=True,
255
+ )
256
+ async for result in self._handle_stream_response(stream_iterator):
257
+ yield result
258
+ else:
259
+ response = await self.http_client.post(
260
+ url=url,
261
+ data=request_data,
262
+ headers=headers,
263
+ compress=True,
264
+ )
265
+
266
+ if response.status_code != 200:
267
+ raise Exception(f"Chat request failed: {response.status_code}")
268
+
269
+ if response.headers.get("connect-content-encoding") == "gzip":
270
+ async for result in self._handle_response(response.content):
271
+ yield result
272
+ else:
273
+ search_response = response_pb2.ChatResponse()
274
+ search_response.ParseFromString(response.content)
275
+ if search_response.message:
276
+ yield (search_response.message, search_response.count)
api/chat/chat_config.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from dataclasses import dataclass
3
+
4
+ from config.models import ModelID
5
+
6
+
7
+ @dataclass
8
+ class ChatConfig:
9
+ def __init__(
10
+ self,
11
+ model_id: ModelID = ModelID.MODEL_CLAUDE_3_5_HAIKU_20241022,
12
+ temperature: float = 0.7,
13
+ max_tokens: int = 4096,
14
+ top_p: float = 1.0,
15
+ top_k: int = 50
16
+ ):
17
+ self.model_id = model_id
18
+ self.temperature = temperature
19
+ self.max_tokens = max_tokens
20
+ self.top_p = top_p
21
+ self.top_k = top_k
api/telemetry.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import httpx
3
+ import uuid
4
+ from config.constants import (
5
+ APP_LANGUAGE,
6
+ BASE_URL,
7
+ APP_NAME,
8
+ APP_VERSION,
9
+ DISPLAY_NAME,
10
+ HADWARE_INFO,
11
+ SYSTEM_INFO,
12
+ )
13
+ from protos import telemetry_pb2
14
+
15
+
16
+ class TelemetryAPI:
17
+ def __init__(self, api_key: str):
18
+ self.api_key = api_key
19
+ self.client = httpx.AsyncClient(verify=False, timeout=3)
20
+
21
+ async def do_telemetry(self):
22
+ await self.send_telemetry()
23
+ await self.send_ping()
24
+ await self.send_unleash_request()
25
+
26
+ async def send_telemetry(self):
27
+ telemetry = telemetry_pb2.TelemetryData()
28
+
29
+ # System info
30
+ system_info = telemetry.system_info
31
+ system_info.api_key = self.api_key
32
+ system_info.locale = APP_LANGUAGE
33
+ system_info.extension_name = APP_NAME
34
+ system_info.ide_name = APP_NAME
35
+ system_info.extension_version = APP_VERSION
36
+ system_info.os = SYSTEM_INFO
37
+ system_info.ide_version = DISPLAY_NAME
38
+ system_info.hardware = HADWARE_INFO
39
+
40
+ system_info.session_id = str(uuid.uuid4())
41
+
42
+ response = await self.client.post(
43
+ url=f"{BASE_URL}/exa.api_server_pb.ApiServerService/RecordAsyncTelemetry",
44
+ headers={
45
+ "Content-Type": "application/proto",
46
+ },
47
+ content=telemetry.SerializeToString(),
48
+ )
49
+
50
+ return response.status_code == 200
51
+
52
+ async def send_ping(self):
53
+ url = f"{BASE_URL}/exa.api_server_pb.ApiServerService/Ping"
54
+
55
+ headers = {
56
+ 'User-Agent': 'connect-go/1.16.2 (go1.23.2 X:nocoverageredesign)',
57
+ 'Accept-Encoding': 'gzip',
58
+ 'Connect-Protocol-Version': '1',
59
+ 'Content-Type': 'application/proto'
60
+ }
61
+
62
+ try:
63
+ response = await self.client.post(url, headers=headers)
64
+ print(f"Ping Status Code: {response.status_code}")
65
+ except httpx.RequestError as e:
66
+ print(f"请求发生错误: {e}")
67
+
68
+ async def send_unleash_request(self):
69
+ url = f"{BASE_URL}/exa.api_server_pb.ApiServerService/GetUnleashContextFields"
70
+
71
+ headers = {
72
+ 'User-Agent': 'connect-go/1.16.2 (go1.23.2 X:nocoverageredesign)',
73
+ 'Accept-Encoding': 'gzip',
74
+ 'Connect-Protocol-Version': '1',
75
+ 'Content-Type': 'application/proto'
76
+ }
77
+
78
+ try:
79
+ response = await self.client.post(url, headers=headers)
80
+
81
+ print(f"GetUnleashContextFields Status Code: {response.status_code}")
82
+ print(f"地区:")
83
+ print(f"{response.text}")
84
+
85
+ except httpx.RequestError as e:
86
+ print(f"请求发生错误: {e}")
87
+
88
+ async def __aenter__(self):
89
+ return self
90
+
91
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
92
+ await self.client.aclose()
auth/__pycache__/jwt_handler.cpython-311.pyc ADDED
Binary file (2.49 kB). View file
 
auth/__pycache__/jwt_handler.cpython-312.pyc ADDED
Binary file (2.33 kB). View file
 
auth/__pycache__/login.cpython-312.pyc ADDED
Binary file (1.03 kB). View file
 
auth/__pycache__/register.cpython-312.pyc ADDED
Binary file (1.58 kB). View file
 
auth/jwt_handler.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils.http import HTTPClient
2
+ from config.constants import APP_LANGUAGE, BASE_URL, APP_NAME, APP_VERSION, DISPLAY_NAME
3
+ from protos import jwt_pb2
4
+
5
+
6
+ class JWTHandler:
7
+ def __init__(self, api_key: str, server_url: str = BASE_URL, http_client: HTTPClient = HTTPClient()):
8
+ self.server_url = server_url
9
+ self.api_key = api_key
10
+ self.jwt_token = None
11
+ self.http_client = http_client
12
+
13
+ async def get_jwt_token(self) -> str:
14
+ """Get JWT token from server"""
15
+ request = jwt_pb2.jwt_request(
16
+ surfwind_jwt_request=jwt_pb2.surfwind_jwt_request(
17
+ app_name=APP_NAME,
18
+ version=APP_VERSION,
19
+ api_key=self.api_key,
20
+ language=APP_LANGUAGE,
21
+ display_name=DISPLAY_NAME,
22
+ app_identifier=APP_NAME,
23
+ )
24
+ )
25
+
26
+ response = await self.http_client.post(
27
+ url=f"{self.server_url}/exa.auth_pb.AuthService/GetUserJwt",
28
+ headers={
29
+ "Content-Type": "application/proto",
30
+ },
31
+ data=request.SerializeToString(),
32
+ )
33
+
34
+ if response.status_code == 200:
35
+ jwt_response = jwt_pb2.jwt_response()
36
+ jwt_response.ParseFromString(response.content)
37
+ self.jwt_token = jwt_response.jwt_token
38
+ return self.jwt_token
39
+
40
+ print(response.content)
41
+ raise Exception(f"Failed to get JWT token: {response.status_code}")
auth/login.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import uuid
2
+ import webbrowser
3
+ from config.constants import WINDSURF_ID
4
+
5
+
6
+ def open_auth_url() -> str:
7
+ """Open authentication URL in browser"""
8
+ state = str(uuid.uuid4())
9
+ base_url = "https://www.codeium.com/windsurf/signin"
10
+
11
+ auth_url = (
12
+ f"{base_url}?"
13
+ f"response_type=token&"
14
+ f"client_id={WINDSURF_ID}&"
15
+ f"redirect_uri=show-auth-token&"
16
+ f"state={state}&"
17
+ f"prompt=login&"
18
+ f"redirect_parameters_type=query&"
19
+ f"workflow="
20
+ )
21
+
22
+ try:
23
+ webbrowser.open(auth_url)
24
+ return state
25
+ except Exception as e:
26
+ print(f"Failed to open browser: {e}")
27
+ return None
auth/register.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils.http import HTTPClient
2
+ from config.constants import API_URL
3
+
4
+
5
+ class Registration:
6
+ @staticmethod
7
+ async def register_user(firebase_token: str) -> str:
8
+ """
9
+ Register user with firebase token and return API key
10
+ """
11
+ headers = {
12
+ "User-Agent": "Go-http-client/1.1",
13
+ "Content-Type": "application/json",
14
+ "Accept-Encoding": "gzip",
15
+ }
16
+
17
+ data = {"firebase_id_token": firebase_token}
18
+
19
+ response = await HTTPClient().post(
20
+ f"{API_URL}/register_user/", headers=headers, default_headers=False, json=data, verify=False
21
+ )
22
+
23
+ if response.status_code != 200:
24
+ print(response.text)
25
+ raise Exception(f"Registration failed: {response.status_code}")
26
+
27
+ response_json = response.json()
28
+ api_key = response_json.get("api_key")
29
+
30
+ if not api_key:
31
+ raise Exception("No API key in response")
32
+
33
+ return api_key
boot.sh ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # start.sh
4
+
5
+ # 初始化聊天队列
6
+ # pypy/bin/python init_pool.py
7
+
8
+ # 启动 Gunicorn 服务器
9
+
10
+ pypy/bin/gunicorn service.server:app \
11
+ --worker-class uvicorn.workers.UvicornWorker \
12
+ --workers 16 \
13
+ --bind 0.0.0.0:8000 \
14
+ --timeout 30 \
15
+ --keep-alive 5 \
16
+ --access-logfile - \
17
+ --error-logfile -
config/__pycache__/api_keys.cpython-311.pyc ADDED
Binary file (4.61 kB). View file
 
config/__pycache__/api_keys.cpython-312.pyc ADDED
Binary file (4.07 kB). View file
 
config/__pycache__/constants.cpython-311.pyc ADDED
Binary file (3.05 kB). View file
 
config/__pycache__/constants.cpython-312.pyc ADDED
Binary file (3.1 kB). View file
 
config/__pycache__/models.cpython-311.pyc ADDED
Binary file (4.04 kB). View file
 
config/__pycache__/models.cpython-312.pyc ADDED
Binary file (3.95 kB). View file
 
config/api_keys.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as ET
2
+ from pathlib import Path
3
+ from typing import Optional, List
4
+
5
+
6
+ class APIKeyManager:
7
+ def __init__(self, config_path: str = "config/api_keys.xml"):
8
+ self.config_path = Path(config_path)
9
+ self._api_keys: List[str] = []
10
+ self._load_keys()
11
+
12
+ def _load_keys(self):
13
+ """Load API keys from XML file"""
14
+ if not self.config_path.exists():
15
+ self._create_default_config()
16
+
17
+ tree = ET.parse(self.config_path)
18
+ root = tree.getroot()
19
+
20
+ self._api_keys = [key.text for key in root.findall("key")]
21
+
22
+ def _create_default_config(self):
23
+ """Create default XML config file"""
24
+ self.config_path.parent.mkdir(parents=True, exist_ok=True)
25
+
26
+ root = ET.Element("api_keys")
27
+ tree = ET.ElementTree(root)
28
+ tree.write(self.config_path, encoding="utf-8", xml_declaration=True)
29
+
30
+ def get_key(self, index: int = 0) -> Optional[str]:
31
+ """Get API key by index"""
32
+ try:
33
+ return self._api_keys[index]
34
+ except IndexError:
35
+ return None
36
+
37
+ def add_key(self, api_key: str):
38
+ """Add new API key"""
39
+ root = ET.parse(self.config_path).getroot()
40
+ new_key = ET.SubElement(root, "key")
41
+ new_key.text = api_key
42
+
43
+ tree = ET.ElementTree(root)
44
+ tree.write(self.config_path, encoding="utf-8", xml_declaration=True)
45
+
46
+ self._api_keys.append(api_key)
47
+
48
+ def remove_key(self, index: int):
49
+ """Remove API key by index"""
50
+ root = ET.parse(self.config_path).getroot()
51
+ keys = root.findall("key")
52
+
53
+ if 0 <= index < len(keys):
54
+ root.remove(keys[index])
55
+ tree = ET.ElementTree(root)
56
+ tree.write(self.config_path, encoding="utf-8", xml_declaration=True)
57
+
58
+ self._api_keys.pop(index)
59
+
60
+ def list_keys(self) -> List[str]:
61
+ """List all API keys"""
62
+ return self._api_keys.copy()
config/api_keys.xml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ <?xml version='1.0' encoding='utf-8'?>
2
+ <api_keys><key>33cbbd76-bdb4-4d28-bc65-38c56dca3768</key><key>7e5ab17a-ec08-4037-8b30-186e86d8595a</key><key>637b9327-cfef-4808-bdeb-3d83e8ecca1b</key><key>82651d96-5d2c-4387-886f-70d501865994</key></api_keys>
config/constants.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # API endpoints
2
+ import json
3
+
4
+ from config.models import ModelID
5
+
6
+ DEFAULT_API_ACCOUNT_EXPIRATION_SECONDS = 4 * 24 * 60 * 60
7
+
8
+ ENCRYPTION_KEY = "1923a821"
9
+ BASE_URL = "https://server.codeium.com"
10
+ API_URL = "https://api.codeium.com"
11
+ INFERENCE_URL = "https://inference.codeium.com"
12
+
13
+ # API keys and identifiers
14
+ WINDSURF_ID = "3GUryQ7ldAeKEuD2obYnppsnmj58eP5u"
15
+
16
+ # Application info
17
+ APP_NAME = "windsurf"
18
+ APP_VERSION = "1.30.0"
19
+ DISPLAY_NAME = "Windsurf 1.94.0"
20
+ APP_LANGUAGE = "en"
21
+
22
+ HADWARE_INFO = json.dumps(
23
+ {
24
+ "NumSockets": 1,
25
+ "NumCores": 8,
26
+ "NumThreads": 16,
27
+ "VendorID": "GenuineIntel",
28
+ "Family": "6",
29
+ "Model": "158",
30
+ "ModelName": "Intel(R) Core(TM) i9-12900K CPU @ 3.60GHz",
31
+ "Memory": 34359738368,
32
+ }
33
+ )
34
+ SYSTEM_INFO = json.dumps(
35
+ {
36
+ "Os": "windows",
37
+ "Arch": "amd64",
38
+ "Version": "11",
39
+ "ProductName": "Windows 11 Pro",
40
+ "MajorVersionNumber": 11,
41
+ "MinorVersionNumber": 0,
42
+ "Build": "26100",
43
+ }
44
+ )
45
+
46
+ # HTTP headers
47
+ DEFAULT_HEADERS = {
48
+ "User-Agent": "connect-go/1.16.2 (go1.23.2 X:nocoverageredesign)",
49
+ "Connect-Protocol-Version": "1",
50
+ "Accept-Encoding": "identity",
51
+ "Connection": "keep-alive",
52
+ "Keep-Alive": "timeout=120, max=10000"
53
+ }
54
+
55
+ REDIS_URL = "redis://localhost:6379"
56
+ REDIS_PASSWORD = "$546a"
57
+ JWT_SECRET_INFO = "0982d83c-969a-4a53-8243-9d215a2fe7a2"
58
+ ALLOWED_HOSTS = ["*"]
59
+ BLOCK_DURATION = 3600
60
+ OPTIONS_DURATION = 600
61
+ THREE_MIN_LIMIT = 90
62
+ HOURLY_LIMIT = 550
63
+ BLOCK_LIMIT = 600
64
+ MAX_UPLOAD_SIZE = 1048576 * 100 # 100 MB
65
+ MAX_REQUEST_SIZE = 1048576 * 8 # 8 MB
66
+
67
+ # Model mappings can also be placed here if applicable
68
+ MODEL_MAPPING = {
69
+ # OpenAI Models
70
+ "gpt-3.5-turbo": ModelID.MODEL_CHAT_3_5_TURBO,
71
+ "gpt-4": ModelID.MODEL_CHAT_GPT_4,
72
+ "gpt-4o": ModelID.MODEL_CHAT_GPT_4O_2024_08_06,
73
+ "gpt-4o-2024-08-06": ModelID.MODEL_CHAT_GPT_4O_2024_08_06,
74
+ "gpt-4o-mini-2024-07-18": ModelID.MODEL_CHAT_GPT_4O_MINI_2024_07_18,
75
+ "gpt-4o-mini": ModelID.MODEL_CHAT_GPT_4O_MINI_2024_07_18,
76
+ "gpt-4-turbo-preview": ModelID.MODEL_CHAT_GPT_4_1106_PREVIEW,
77
+ # Claude Models
78
+ "claude-3-opus-20240229": ModelID.MODEL_CLAUDE_3_OPUS_20240229,
79
+ "claude-3-opus": ModelID.MODEL_CLAUDE_3_OPUS_20240229,
80
+ # "claude-3-sonnet-20240229": ModelID.MODEL_CLAUDE_3_SONNET_20240229,
81
+ "claude-3.5-sonnet-20240620": ModelID.MODEL_CLAUDE_3_5_SONNET_20240620,
82
+ "claude-3.5-sonnet-20241022": ModelID.MODEL_CLAUDE_3_5_SONNET_20241022,
83
+ "claude-3.5-sonnet": ModelID.MODEL_CLAUDE_3_5_SONNET_20241022,
84
+ "claude-3.5-haiku": ModelID.MODEL_CLAUDE_3_5_HAIKU_20241022,
85
+ "claude-3-haiku": ModelID.MODEL_CLAUDE_3_HAIKU_20240307,
86
+ "claude": ModelID.MODEL_CLAUDE_3_5_SONNET_20241022,
87
+ # O1 Models
88
+ "o1-mini": ModelID.MODEL_CHAT_O1_MINI,
89
+ "o1-preview": ModelID.MODEL_CHAT_O1_PREVIEW,
90
+ # "o1": ModelID.MODEL_CHAT_O1,
91
+ }
92
+
93
+ # Authorization keys for API access
94
+ AUTH_KEYS = [
95
+ "sk-upuyyds"
96
+ ]
config/models.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+
4
+ class ModelID(Enum):
5
+ MODEL_UNSPECIFIED = 0
6
+ MODEL_EMBED_6591 = 20
7
+ MODEL_8341 = 33
8
+ MODEL_8528 = 42
9
+ MODEL_9024 = 41
10
+ MODEL_14602 = 112
11
+ MODEL_15133 = 115
12
+ MODEL_15302 = 119
13
+ MODEL_15335 = 121
14
+ MODEL_15336 = 122
15
+ MODEL_15931 = 167
16
+ MODEL_QUERY_9905 = 48
17
+ MODEL_QUERY_11791 = 66
18
+ MODEL_CHAT_11120 = 57
19
+ MODEL_CHAT_11121 = 58
20
+ MODEL_CHAT_12119 = 70
21
+ MODEL_CHAT_12121 = 69
22
+ MODEL_CHAT_12437 = 74
23
+ MODEL_CHAT_12491 = 76
24
+ MODEL_CHAT_12623 = 78
25
+ MODEL_CHAT_12950 = 79
26
+ MODEL_CHAT_12968 = 101
27
+ MODEL_CHAT_13404 = 102
28
+ MODEL_CHAT_13566 = 103
29
+ MODEL_CHAT_13930 = 108
30
+ MODEL_CHAT_14255 = 110
31
+ MODEL_CHAT_14256 = 111
32
+ MODEL_CHAT_14942 = 114
33
+ MODEL_CHAT_15305 = 120
34
+ MODEL_CHAT_15600 = 123
35
+ MODEL_CHAT_16718 = 175
36
+ MODEL_CHAT_15729 = 168
37
+ MODEL_CHAT_16579 = 173
38
+ MODEL_CHAT_16579_CRUSOE = 174
39
+ MODEL_DRAFT_11408 = 65
40
+ MODEL_DRAFT_CHAT_11883 = 67
41
+ MODEL_DRAFT_CHAT_12196 = 72
42
+ MODEL_DRAFT_CHAT_12413 = 73
43
+ MODEL_DRAFT_CHAT_13175 = 104
44
+ MODEL_CHAT_3_5_TURBO = 28
45
+ MODEL_CHAT_GPT_4 = 30
46
+ MODEL_CHAT_GPT_4_1106_PREVIEW = 37
47
+ MODEL_TEXT_EMBEDDING_OPENAI_ADA = 91
48
+ MODEL_TEXT_EMBEDDING_OPENAI_3_SMALL = 163
49
+ MODEL_TEXT_EMBEDDING_OPENAI_3_LARGE = 164
50
+ MODEL_CHAT_GPT_4O_2024_05_13 = 71
51
+ MODEL_CHAT_GPT_4O_2024_08_06 = 109
52
+ MODEL_CHAT_GPT_4O_MINI_2024_07_18 = 113
53
+ MODEL_CHAT_O1_PREVIEW = 117
54
+ MODEL_CHAT_O1_MINI = 118
55
+ MODEL_CHAT_O1 = 170
56
+ MODEL_GOOGLE_GEMINI_1_0_PRO = 61
57
+ MODEL_GOOGLE_GEMINI_1_5_PRO = 62
58
+ MODEL_CLAUDE_3_OPUS_20240229 = 63
59
+ MODEL_CLAUDE_3_SONNET_20240229 = 64
60
+ MODEL_CLAUDE_3_5_SONNET_20240620 = 80
61
+ MODEL_CLAUDE_3_5_SONNET_20241022 = 166
62
+ MODEL_CLAUDE_3_5_HAIKU_20241022 = 171
63
+ MODEL_CLAUDE_3_HAIKU_20240307 = 172
64
+ MODEL_TOGETHERAI_TEXT_EMBEDDING_M2_BERT = 81
65
+ MODEL_TOGETHERAI_LLAMA_3_1_8B_INSTRUCT = 165
66
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_M2_BERT = 82
67
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_UAE_CODE = 83
68
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_BGE = 84
69
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_BLADE = 85
70
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_ARCTIC_LARGE = 86
71
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_E5_BASE = 87
72
+ MODEL_HUGGING_FACE_TEXT_EMBEDDING_MXBAI = 88
73
+ MODEL_LLAMA_3_1_8B_INSTRUCT = 106
74
+ MODEL_LLAMA_3_1_70B_INSTRUCT = 107
75
+ MODEL_LLAMA_3_1_405B_INSTRUCT = 105
76
+ MODEL_LLAMA_3_1_70B_INSTRUCT_LONG_CONTEXT = 116
77
+ MODEL_NOMIC_TEXT_EMBEDDING_V1 = 89
78
+ MODEL_NOMIC_TEXT_EMBEDDING_V1_5 = 90
79
+ MODEL_MISTRAL_7B = 77
80
+ MODEL_SALESFORCE_EMBEDDING_2R = 99
81
+ MODEL_TEI_BGE_M3 = 92
82
+ MODEL_TEI_NOMIC_EMBED_TEXT_V1 = 93
83
+ MODEL_TEI_INTFLOAT_E5_LARGE_INSTRUCT = 94
84
+ MODEL_TEI_SNOWFLAKE_ARCTIC_EMBED_L = 95
85
+ MODEL_TEI_UAE_CODE_LARGE_V1 = 96
86
+ MODEL_TEI_B1ADE = 97
87
+ MODEL_TEI_WHEREISAI_UAE_LARGE_V1 = 98
88
+ MODEL_TEI_WHEREISAI_UAE_CODE_LARGE_V1 = 100
89
+ MODEL_OPENAI_COMPATIBLE = 200
90
+ MODEL_ANTHROPIC_COMPATIBLE = 201
91
+ MODEL_VERTEX_COMPATIBLE = 202
92
+ MODEL_BEDROCK_COMPATIBLE = 203
93
+ MODEL_AZURE_COMPATIBLE = 204
docker.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ docker run -d \
2
+ -p 127.0.0.1:9000:8080 \
3
+ -v open-webui:/app/backend/data \
4
+ -e OPENAI_API_BASE_URLS="http://host.docker.internal:8000/v1" \
5
+ -e OPENAI_API_KEYS="Ga_test_key1" \
6
+ --add-host=host.docker.internal:host-gateway \
7
+ --name open-webui \
8
+ --restart unless-stopped \
9
+ ghcr.io/open-webui/open-webui:main
gen_account.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from time import time
2
+ import httpx
3
+ import asyncio
4
+ from faker import Faker
5
+ import random
6
+ import string
7
+ import base64
8
+ import json
9
+ from datetime import datetime
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+ from rich.table import Table
13
+ from rich import print as rprint
14
+ from typing import List
15
+
16
+ from auth.register import Registration
17
+ from config.api_keys import APIKeyManager
18
+ from protos import request_pb2, response_pb2
19
+
20
+ console = Console()
21
+
22
+ async def generate_firebase_client():
23
+ # Create heartbeat data with current date
24
+ heartbeat_data = {
25
+ "version": 2,
26
+ "heartbeats": [{
27
+ "agent": "fire-core/0.10.2 fire-core-esm2017/0.10.2 fire-js/ fire-auth/1.7.2 fire-auth-esm2017/1.7.2 fire-js-all-app/10.11.1",
28
+ "dates": [datetime.now().strftime("%Y-%m-%d")]
29
+ }]
30
+ }
31
+ return base64.b64encode(json.dumps(heartbeat_data).encode()).decode()
32
+
33
+ async def generate_account():
34
+ faker = Faker()
35
+
36
+ # Generate random email and password
37
+ email = faker.email(safe=True, domain='outlook.com')
38
+ password = ''.join(random.choices(string.ascii_letters + string.digits, k=random.randint(9, 15)))
39
+
40
+ firebase_client = await generate_firebase_client()
41
+
42
+ async with httpx.AsyncClient() as client:
43
+ # Step 1: Firebase Sign Up
44
+ signup_response = await client.post(
45
+ 'https://identitytoolkit.googleapis.com/v1/accounts:signUp',
46
+ params={'key': 'AIzaSyDsOl-1XpT5err0Tcnx8FFod1H8gVGIycY'},
47
+ headers={
48
+ 'X-Firebase-Client': firebase_client,
49
+ 'Content-Type': 'application/json',
50
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36'
51
+ },
52
+ json={
53
+ 'returnSecureToken': True,
54
+ 'email': email,
55
+ 'password': password,
56
+ 'clientType': 'CLIENT_TYPE_WEB'
57
+ }
58
+ )
59
+
60
+ id_token = signup_response.json()['idToken']
61
+
62
+ # Step 2: Get Current User
63
+ current_user = request_pb2.CurrentUser()
64
+ current_user.jwt = id_token
65
+ current_user.f1 = 1
66
+ current_user.f2 = 1
67
+
68
+ current_user_response = await client.post(
69
+ 'https://web-backend.codeium.com/exa.seat_management_pb.SeatManagementService/GetCurrentUser',
70
+ headers={
71
+ 'Content-Type': 'application/proto',
72
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36',
73
+ 'Accept-Language': 'en',
74
+ 'Sec-Ch-Ua-Platform': '"Windows"',
75
+ 'Sec-Ch-Ua': '"Not?A_Brand";v="99", "Chromium";v="130"',
76
+ 'Sec-Ch-Ua-Mobile': '?0',
77
+ 'Connect-Protocol-Version': '1',
78
+ 'Accept': '*/*',
79
+ 'Origin': 'https://codeium.com',
80
+ 'Sec-Fetch-Site': 'same-site',
81
+ 'Sec-Fetch-Mode': 'cors',
82
+ 'Sec-Fetch-Dest': 'empty',
83
+ 'Referer': 'https://codeium.com/',
84
+ "X-Auth-Token": id_token,
85
+ 'Accept-Encoding': 'gzip, deflate, br',
86
+ },
87
+ content=current_user.SerializeToString()
88
+ )
89
+ assert current_user_response.status_code == 200
90
+ response_proto = response_pb2.CurrentUserResponse()
91
+ response_proto.ParseFromString(current_user_response.content)
92
+ console.print(Panel(f"[bold green]User Created[/bold green]\nName: {response_proto.user.name}\nStatus: {response_proto.status.status}"))
93
+
94
+ # Step 3: Get Preapproval For User
95
+ get_preapproval_for_user = request_pb2.GetPreapprovalForUser()
96
+ get_preapproval_for_user.jwt = id_token
97
+ get_preapproval_for_user_response = await client.post(
98
+ 'https://web-backend.codeium.com/exa.seat_management_pb.SeatManagementService/GetPreapprovalForUser',
99
+ headers={
100
+ 'Content-Type': 'application/proto',
101
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36',
102
+ 'Accept-Language': 'en',
103
+ 'Sec-Ch-Ua-Platform': '"Windows"',
104
+ 'Sec-Ch-Ua': '"Not?A_Brand";v="99", "Chromium";v="130"',
105
+ 'Sec-Ch-Ua-Mobile': '?0',
106
+ 'Connect-Protocol-Version': '1',
107
+ 'Accept': '*/*',
108
+ 'Origin': 'https://codeium.com',
109
+ 'Sec-Fetch-Site': 'same-site',
110
+ 'Sec-Fetch-Mode': 'cors',
111
+ 'Sec-Fetch-Dest': 'empty',
112
+ 'Referer': 'https://codeium.com/',
113
+ 'Accept-Encoding': 'gzip, deflate, br',
114
+ "X-Auth-Token": id_token,
115
+ 'Priority': 'u=1, i'
116
+ },
117
+ content=get_preapproval_for_user.SerializeToString()
118
+ )
119
+ assert get_preapproval_for_user_response.status_code == 200
120
+
121
+ # Step 4: Update Name using Protobuf
122
+ change_name = request_pb2.ChangeName()
123
+ change_name.jwt = id_token
124
+ change_name.name = faker.name()
125
+
126
+ name_response = await client.post(
127
+ 'https://web-backend.codeium.com/exa.seat_management_pb.SeatManagementService/UpdateName',
128
+ headers={
129
+ 'Content-Type': 'application/proto',
130
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36',
131
+ 'Accept-Language': 'en',
132
+ 'Sec-Ch-Ua-Platform': '"Windows"',
133
+ 'Sec-Ch-Ua': '"Not?A_Brand";v="99", "Chromium";v="130"',
134
+ 'Sec-Ch-Ua-Mobile': '?0',
135
+ 'Connect-Protocol-Version': '1',
136
+ 'Accept': '*/*',
137
+ 'Origin': 'https://codeium.com',
138
+ 'Sec-Fetch-Site': 'same-site',
139
+ 'Sec-Fetch-Mode': 'cors',
140
+ 'Sec-Fetch-Dest': 'empty',
141
+ 'Referer': 'https://codeium.com/',
142
+ 'Accept-Encoding': 'gzip, deflate, br',
143
+ 'Priority': 'u=1, i'
144
+ },
145
+ content=change_name.SerializeToString()
146
+ )
147
+
148
+ return {
149
+ 'email': email,
150
+ 'password': password,
151
+ 'id_token': id_token,
152
+ 'name_response': name_response.status_code
153
+ }
154
+
155
+ async def generate_multiple_accounts(num_accounts: int):
156
+ tasks = []
157
+ for _ in range(num_accounts):
158
+ tasks.append(generate_account())
159
+
160
+ results = await asyncio.gather(*tasks)
161
+ return results
162
+
163
+ async def main():
164
+ # 获取命令行参数,默认创建3个账号
165
+ num_accounts = 3
166
+
167
+ with console.status(f"[bold green]Generating {num_accounts} accounts...", spinner="dots"):
168
+ results = await generate_multiple_accounts(num_accounts)
169
+
170
+ for result in results:
171
+ id_token = result['id_token']
172
+ email = result['email']
173
+ name_response = result['name_response']
174
+
175
+ if name_response != 200:
176
+ console.print(f"[bold red]Failed to update name. Status code: {name_response}[/bold red]")
177
+ continue
178
+
179
+ key_manager = APIKeyManager()
180
+
181
+ with console.status("[bold green]Registering user...", spinner="dots"):
182
+ api_key = await Registration.register_user(id_token.strip())
183
+
184
+ # Add GetCurrentUser call after registration
185
+ async with httpx.AsyncClient() as client:
186
+ current_user = request_pb2.CurrentUser()
187
+ current_user.jwt = id_token
188
+ current_user.f1 = 1
189
+ current_user.f2 = 1
190
+
191
+ current_user_response = await client.post(
192
+ 'https://web-backend.codeium.com/exa.seat_management_pb.SeatManagementService/GetCurrentUser',
193
+ headers={
194
+ 'Content-Type': 'application/proto',
195
+ 'X-Auth-Token': id_token,
196
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36',
197
+ 'Accept-Language': 'en',
198
+ 'Sec-Ch-Ua-Platform': '"Windows"',
199
+ 'Sec-Ch-Ua': '"Not?A_Brand";v="99", "Chromium";v="130"',
200
+ 'Sec-Ch-Ua-Mobile': '?0',
201
+ 'Connect-Protocol-Version': '1',
202
+ 'Accept': '*/*',
203
+ 'Origin': 'https://codeium.com',
204
+ 'Sec-Fetch-Site': 'same-site',
205
+ 'Sec-Fetch-Mode': 'cors',
206
+ 'Sec-Fetch-Dest': 'empty',
207
+ 'Referer': 'https://codeium.com/',
208
+ 'Accept-Encoding': 'gzip, deflate, br',
209
+ },
210
+ content=current_user.SerializeToString()
211
+ )
212
+
213
+ response_proto = response_pb2.CurrentUserResponse()
214
+ response_proto.ParseFromString(current_user_response.content)
215
+
216
+ key_manager.add_key(api_key)
217
+
218
+ # Update table to include password
219
+ table = Table(title=f"Registration Results - {email}")
220
+ table.add_column("Field", style="cyan")
221
+ table.add_column("Value", style="green")
222
+
223
+ table.add_row("Email", email)
224
+ table.add_row("Password", result['password'])
225
+ table.add_row("API Key", api_key)
226
+ table.add_row("Status", str(response_proto.status.status))
227
+
228
+ console.print(table)
229
+ console.print("\n") # Add a blank line between tables
230
+
231
+ if __name__ == "__main__":
232
+ asyncio.run(main())
init_pool.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from managers.global_chat_manager import GlobalChatManager
2
+ import uvicorn
3
+ import signal
4
+ import sys
5
+ import multiprocessing
6
+ import asyncio
7
+ from rich.console import Console
8
+
9
+ console = Console()
10
+
11
+ async def init_chat_queue():
12
+ # 初始化全局chat manager
13
+ chat_manager = GlobalChatManager(
14
+ console=console,
15
+ queue_type="deque",
16
+ )
17
+
18
+ await chat_manager.initialize_queue()
19
+
20
+ if __name__ == "__main__":
21
+ asyncio.run(init_chat_queue())
main.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from managers.chat_manager import ChatManager
2
+ from api.telemetry import TelemetryAPI
3
+ from config.api_keys import APIKeyManager
4
+ from config.models import ModelID
5
+ from auth.register import Registration
6
+ from auth.login import open_auth_url
7
+ from api.chat.chat_api import ChatAPI, ChatConfig
8
+
9
+ import urllib3
10
+ import asyncio
11
+
12
+ urllib3.disable_warnings()
13
+
14
+ from rich.console import Console
15
+ from rich.progress import Progress, SpinnerColumn, TextColumn
16
+
17
+ console = Console()
18
+
19
+
20
+ def select_api_key(key_manager: APIKeyManager) -> str:
21
+ """Let user select an API key from available keys"""
22
+ keys = key_manager.list_keys()
23
+ if not keys:
24
+ return None
25
+
26
+ console.print("\n[bold cyan]Available API keys:[/]")
27
+ for i, key in enumerate(keys):
28
+ console.print(f"[green]{i + 1}[/]. {key}")
29
+
30
+ while True:
31
+ try:
32
+ choice = int(input("\nSelect API key (number) or 0 for new login: "))
33
+ if choice == 0:
34
+ return None
35
+ if 1 <= choice <= len(keys):
36
+ return keys[choice - 1]
37
+ except ValueError:
38
+ return keys[0]
39
+ print("Invalid selection. Please try again.")
40
+
41
+
42
+ async def main():
43
+ key_manager = APIKeyManager()
44
+ chat_manager = ChatManager()
45
+ api_key = select_api_key(key_manager)
46
+
47
+ # If no API key selected or available, do registration
48
+ if api_key is None:
49
+ _ = open_auth_url()
50
+ firebase_token = input("Please paste your firebase token: ")
51
+ api_key = await Registration.register_user(firebase_token.strip())
52
+ key_manager.add_key(api_key)
53
+ print(f"Registered successfully. API key: {api_key}")
54
+
55
+ with Progress(
56
+ SpinnerColumn(),
57
+ TextColumn("[progress.description]{task.description}"),
58
+ console=console,
59
+ ) as progress:
60
+ progress.add_task("Initializing Chat API...", total=None)
61
+ tele = TelemetryAPI(api_key=api_key)
62
+ await tele.do_telemetry()
63
+
64
+ await chat_manager.add_chat(api_key)
65
+
66
+ progress.stop()
67
+
68
+ with Progress(
69
+ SpinnerColumn(),
70
+ TextColumn("[progress.description]{task.description}"),
71
+ console=console,
72
+ ) as progress:
73
+ _ = progress.add_task("Sending message...", total=None)
74
+
75
+ config = ChatConfig(
76
+ model_id=ModelID.MODEL_CLAUDE_3_OPUS_20240229,
77
+ temperature=0.7,
78
+ max_tokens=8192,
79
+ )
80
+
81
+ message = [
82
+ {"role": "user", "content": "1234567890"},
83
+ {"role": "assistant", "content": "1234567890"},
84
+ {"role": "user", "content": "1234567890"},
85
+ {"role": "assistant", "content": "1234567890"},
86
+ {"role": "user", "content": "1234567890"},
87
+ {"role": "assistant", "content": "1234567890"},
88
+ {"role": "user", "content": "1234567890"},
89
+ {"role": "assistant", "content": "1234567890"},
90
+ {"role": "user", "content": "1234567890"},
91
+ {"role": "assistant", "content": "1234567890"},
92
+ {"role": "user", "content": "tell me a joke"},
93
+ ]
94
+ first_chunk = True
95
+ chat = await chat_manager.get_chat()
96
+
97
+ tokens = 0
98
+
99
+ async for chunk, token_count in chat.send_message(
100
+ messages=message,
101
+ config=config,
102
+ system_prompt="You are a helpful assistant.",
103
+ stream=True,
104
+ ):
105
+ if first_chunk:
106
+ progress.stop()
107
+ first_chunk = False
108
+ console.print("=" * 20)
109
+ if chunk:
110
+ console.print(
111
+ chunk, end="", markup=True, highlight=True, emoji=True
112
+ )
113
+ tokens += token_count
114
+
115
+ console.print(f"\n[bold green]Tokens: {tokens}[/]")
116
+
117
+
118
+ if __name__ == "__main__":
119
+ asyncio.run(main())
managers/__pycache__/chat_manager.cpython-311.pyc ADDED
Binary file (2.32 kB). View file
 
managers/__pycache__/chat_manager.cpython-312.pyc ADDED
Binary file (2.09 kB). View file
 
managers/__pycache__/global_chat_manager.cpython-311.pyc ADDED
Binary file (7 kB). View file
 
managers/__pycache__/global_chat_manager.cpython-312.pyc ADDED
Binary file (6.31 kB). View file
 
managers/chat_manager.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+ from managers.queue.base import ChatQueueBase
3
+ from managers.queue.deque_queue import DequeQueue
4
+
5
+ from api.chat.chat_api import ChatAPI
6
+
7
+
8
+ class ChatManager:
9
+ def __init__(self, queue_type: str = "deque", **kwargs):
10
+ self.queue: ChatQueueBase = self._create_queue(queue_type, **kwargs)
11
+
12
+ def _create_queue(self, queue_type: str, **kwargs) -> ChatQueueBase:
13
+ queue_types = {
14
+ "deque": DequeQueue,
15
+ }
16
+
17
+ if queue_type not in queue_types:
18
+ raise ValueError(f"Unsupported queue type: {queue_type}")
19
+
20
+ return queue_types[queue_type](**kwargs)
21
+
22
+ async def add_chat(self, api_key: str):
23
+ """添加一个新的chat实例到队列"""
24
+ await self.queue.add(api_key)
25
+
26
+ async def get_chat(self) -> Optional[ChatAPI]:
27
+ """获取队列中的下一个chat实例"""
28
+ return await self.queue.get()
29
+
30
+ async def length(self) -> int:
31
+ """获取队列长度"""
32
+ return await self.queue.length()
managers/global_chat_manager.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional, List
2
+ from rich.console import Console
3
+ from rich.progress import Progress, SpinnerColumn, TextColumn
4
+
5
+ from managers.chat_manager import ChatManager
6
+ from api.telemetry import TelemetryAPI
7
+ from config.api_keys import APIKeyManager
8
+
9
+
10
+ class GlobalChatManager:
11
+ """
12
+ 全局聊天管理器
13
+ 专注于管理分布式队列(Redis/RabbitMQ)中的API密钥
14
+ """
15
+
16
+ _instance: Optional["GlobalChatManager"] = None
17
+
18
+ def __new__(cls, *args, **kwargs):
19
+ if cls._instance is None:
20
+ cls._instance = super().__new__(cls)
21
+ return cls._instance
22
+
23
+ def __init__(self, console: Console, queue_type: str = "deque", **kwargs):
24
+ # 防止重复初始化
25
+ if hasattr(self, "initialized"):
26
+ return
27
+
28
+ self.console = console
29
+ self.queue_type = queue_type
30
+
31
+ if queue_type != "deque":
32
+ raise ValueError("GlobalChatManager only supports 'deque' queue type")
33
+
34
+ self.chat_manager = ChatManager(queue_type=queue_type, **kwargs)
35
+ self.key_manager = APIKeyManager()
36
+ self.initialized = True
37
+
38
+ async def _register_single_key(self, api_key: str) -> None:
39
+ """注册单个API key到队列"""
40
+ try:
41
+ await self.chat_manager.add_chat(api_key)
42
+ await self._send_registration_signals(api_key)
43
+ self.console.log(
44
+ f"[bold green]✓[/] API key registered successfully: {api_key[:8]}..."
45
+ )
46
+ except Exception as e:
47
+ self.console.log(
48
+ f"[bold red]✗[/] Failed to register API key {api_key[:8]}\n"
49
+ f" Error: {str(e)}"
50
+ )
51
+ raise
52
+ finally:
53
+ self.console.log("─" * 80)
54
+
55
+ async def _send_registration_signals(self, api_key: str) -> None:
56
+ """发送注册相关的信号"""
57
+ self.console.log(
58
+ f"[bold yellow]⚡[/] Sending registration signals for {api_key[:8]}..."
59
+ )
60
+ await TelemetryAPI(api_key=api_key).do_telemetry()
61
+
62
+ async def initialize_queue(self, api_keys: List[str] = None) -> None:
63
+ """初始化分布式队列"""
64
+ with Progress(
65
+ SpinnerColumn(),
66
+ TextColumn("[progress.description]{task.description}"),
67
+ console=self.console,
68
+ ) as progress:
69
+ task = progress.add_task(
70
+ f"[bold blue]Initializing {self.queue_type.upper()} queue...[/]",
71
+ total=None
72
+ )
73
+
74
+ # 如果没有提供API keys,则从配置中读取
75
+ if not api_keys:
76
+ api_keys = self.key_manager.list_keys()
77
+ # 对API keys进行去重
78
+ api_keys = list(dict.fromkeys(api_keys))
79
+
80
+ if not api_keys:
81
+ raise ValueError("No API keys provided or found in configuration")
82
+
83
+ # 注册所有API keys
84
+ for api_key in api_keys:
85
+ await self._register_single_key(api_key)
86
+ progress.update(task, advance=1)
87
+
88
+ # 验证队列状态
89
+ queue_size = await self.chat_manager.length()
90
+ if queue_size == 0:
91
+ raise RuntimeError(f"Failed to initialize {self.queue_type} queue")
92
+
93
+ self.console.log(f"号池已初始化,当前容量: {queue_size} 个API密钥")
94
+
95
+ progress.update(
96
+ task,
97
+ description=f"{self.queue_type.upper()} queue initialized with {queue_size} keys",
98
+ )
99
+
100
+ async def add_api_key(self, api_key: str) -> None:
101
+ """添加新的API key到队列"""
102
+ await self._register_single_key(api_key)
103
+
104
+ async def get_queue_size(self) -> int:
105
+ """获取当前队列大小"""
106
+ return await self.chat_manager.length()
managers/queue/__pycache__/base.cpython-311.pyc ADDED
Binary file (1.22 kB). View file
 
managers/queue/__pycache__/base.cpython-312.pyc ADDED
Binary file (1.04 kB). View file
 
managers/queue/__pycache__/deque_queue.cpython-311.pyc ADDED
Binary file (1.77 kB). View file
 
managers/queue/__pycache__/deque_queue.cpython-312.pyc ADDED
Binary file (1.57 kB). View file
 
managers/queue/__pycache__/rabbitmq_queue.cpython-312.pyc ADDED
Binary file (3.25 kB). View file
 
managers/queue/__pycache__/redis_queue.cpython-312.pyc ADDED
Binary file (2.13 kB). View file
 
managers/queue/base.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+ from typing import Optional
3
+ from api.chat.chat_api import ChatAPI
4
+
5
+ class ChatQueueBase(ABC):
6
+ @abstractmethod
7
+ async def add(self, api_key: str) -> None:
8
+ pass
9
+
10
+ @abstractmethod
11
+ async def get(self) -> Optional[ChatAPI]:
12
+ pass
13
+
14
+ @abstractmethod
15
+ async def length(self) -> int:
16
+ pass
managers/queue/deque_queue.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import deque
2
+ from typing import Optional
3
+ from api.chat.chat_api import ChatAPI
4
+ from .base import ChatQueueBase
5
+
6
+ class DequeQueue(ChatQueueBase):
7
+ def __init__(self):
8
+ self.queue = deque()
9
+
10
+ async def add(self, api_key: str) -> None:
11
+ self.queue.append(ChatAPI(api_key=api_key))
12
+
13
+ async def get(self) -> Optional[ChatAPI]:
14
+ if not self.queue:
15
+ return None
16
+ chat = self.queue.popleft()
17
+ self.queue.append(chat)
18
+ return chat
19
+
20
+ async def length(self) -> int:
21
+ return len(self.queue)