xiaoyukkkk commited on
Commit
a56a2ae
·
verified ·
1 Parent(s): f0bf113

Upload 2 files

Browse files
util/streaming_parser.py CHANGED
@@ -190,10 +190,7 @@ async def parse_json_array_stream_async(line_iterator: AsyncIterator[str]) -> As
190
  if not in_array:
191
  raise ValueError("数据流不是以一个JSON数组 ( '[' ) 开始。")
192
 
193
- # 2. 遍历流,逐个字符地构建和解析对象
194
- in_string = False # 是否在字符串内部
195
- escape_next = False # 下一个字符是否被转义
196
-
197
  async for line in line_iterator:
198
  for char in line:
199
  # 处理转义字符
 
190
  if not in_array:
191
  raise ValueError("数据流不是以一个JSON数组 ( '[' ) 开始。")
192
 
193
+ # 2. 遍历流,逐个字符地构建和解析对象(保持第一行处理后的状态)
 
 
 
194
  async for line in line_iterator:
195
  for char in line:
196
  # 处理转义字符
util/template_helpers.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 模板数据准备函数
3
+ 用于为 Jinja2 模板准备数据(纯数据,不包含 HTML)
4
+ """
5
+
6
+ from core.config import config_manager, config
7
+ from core.account import format_account_expiration
8
+
9
+
10
+ def get_base_url_from_request(request) -> str:
11
+ """从请求中获取完整的base URL"""
12
+ # 优先使用配置的 BASE_URL
13
+ if config.basic.base_url:
14
+ return config.basic.base_url.rstrip("/")
15
+
16
+ # 自动从请求获取(兼容反向代理)
17
+ forwarded_proto = request.headers.get("x-forwarded-proto", request.url.scheme)
18
+ forwarded_host = request.headers.get("x-forwarded-host", request.headers.get("host"))
19
+
20
+ return f"{forwarded_proto}://{forwarded_host}"
21
+
22
+
23
+ def _get_account_status(account_manager):
24
+ """提取账户状态判断逻辑(返回纯数据)"""
25
+ config_obj = account_manager.config
26
+ remaining_hours = config_obj.get_remaining_hours()
27
+ expire_status_text, _, expire_display = format_account_expiration(remaining_hours)
28
+
29
+ is_expired = config_obj.is_expired()
30
+ is_disabled = config_obj.disabled
31
+ cooldown_seconds, cooldown_reason = account_manager.get_cooldown_info()
32
+
33
+ # 确定账户状态和颜色
34
+ if is_expired:
35
+ status_text = "过期禁用"
36
+ status_color = "#9e9e9e"
37
+ dot_color = "#9e9e9e"
38
+ row_opacity = "0.5"
39
+ is_permanently_failed = False
40
+ elif is_disabled:
41
+ status_text = "手动禁用"
42
+ status_color = "#9e9e9e"
43
+ dot_color = "#9e9e9e"
44
+ row_opacity = "0.5"
45
+ is_permanently_failed = False
46
+ elif cooldown_seconds == -1:
47
+ status_text = cooldown_reason
48
+ status_color = "#f44336"
49
+ dot_color = "#f44336"
50
+ row_opacity = "0.5"
51
+ is_permanently_failed = True
52
+ elif cooldown_seconds > 0:
53
+ status_text = f"{cooldown_reason} ({cooldown_seconds}s)"
54
+ status_color = "#ff9800"
55
+ dot_color = "#ff9800"
56
+ row_opacity = "1"
57
+ is_permanently_failed = False
58
+ else:
59
+ is_avail = account_manager.is_available
60
+ if is_avail:
61
+ status_text = expire_status_text
62
+ if expire_status_text == "正常":
63
+ status_color = "#4caf50"
64
+ dot_color = "#34c759"
65
+ elif expire_status_text == "即将过期":
66
+ status_color = "#ff9800"
67
+ dot_color = "#ff9800"
68
+ else:
69
+ status_color = "#f44336"
70
+ dot_color = "#f44336"
71
+ else:
72
+ status_text = "不可用"
73
+ status_color = "#f44336"
74
+ dot_color = "#ff3b30"
75
+ row_opacity = "1"
76
+ is_permanently_failed = False
77
+
78
+ return {
79
+ "account_id": config_obj.account_id,
80
+ "status_text": status_text,
81
+ "status_color": status_color,
82
+ "dot_color": dot_color,
83
+ "row_opacity": row_opacity,
84
+ "expire_display": expire_display,
85
+ "expires_at": config_obj.expires_at,
86
+ "conversation_count": account_manager.conversation_count,
87
+ "is_expired": is_expired,
88
+ "is_disabled": is_disabled,
89
+ "is_permanently_failed": is_permanently_failed,
90
+ }
91
+
92
+
93
+ def prepare_admin_template_data(
94
+ request, multi_account_mgr, log_buffer, log_lock,
95
+ api_key, base_url, proxy, logo_url, chat_url, path_prefix,
96
+ max_new_session_tries, max_request_retries, max_account_switch_tries,
97
+ account_failure_threshold, rate_limit_cooldown_seconds, session_cache_ttl_seconds
98
+ ) -> dict:
99
+ """准备完整的管理页面模板数据(纯数据,不包含 HTML)"""
100
+ # 获取当前页面的完整URL
101
+ current_url = get_base_url_from_request(request)
102
+
103
+ # 获取错误统计
104
+ error_count = 0
105
+ with log_lock:
106
+ for log in log_buffer:
107
+ if log.get("level") in ["ERROR", "CRITICAL"]:
108
+ error_count += 1
109
+
110
+ # API接口信息
111
+ admin_path_segment = f"{path_prefix}" if path_prefix else "admin"
112
+ api_path_segment = f"{path_prefix}/" if path_prefix else ""
113
+
114
+ # 构建不同客户端需要的接口
115
+ api_base_url = f"{current_url}/{api_path_segment.rstrip('/')}" if api_path_segment else current_url
116
+ api_base_v1 = f"{current_url}/{api_path_segment}v1"
117
+ api_endpoint = f"{current_url}/{api_path_segment}v1/chat/completions"
118
+
119
+ # 准备账户数据列表
120
+ accounts_data = []
121
+ for account_id, account_manager in multi_account_mgr.accounts.items():
122
+ account_data = _get_account_status(account_manager)
123
+ accounts_data.append(account_data)
124
+
125
+ # 返回所有模板变量(纯数据)
126
+ return {
127
+ "request": request,
128
+ "current_url": current_url,
129
+ "has_api_key": bool(api_key),
130
+ "error_count": error_count,
131
+ "api_base_url": api_base_url,
132
+ "api_base_v1": api_base_v1,
133
+ "api_endpoint": api_endpoint,
134
+ "accounts_data": accounts_data,
135
+ "admin_path_segment": admin_path_segment,
136
+ "api_path_segment": api_path_segment,
137
+ "multi_account_mgr": multi_account_mgr,
138
+ # 配置变量(用于 JavaScript)
139
+ "main": {
140
+ "PATH_PREFIX": path_prefix,
141
+ "API_KEY": api_key,
142
+ "BASE_URL": base_url,
143
+ "PROXY": proxy,
144
+ "LOGO_URL": logo_url,
145
+ "CHAT_URL": chat_url,
146
+ "MAX_NEW_SESSION_TRIES": max_new_session_tries,
147
+ "MAX_REQUEST_RETRIES": max_request_retries,
148
+ "MAX_ACCOUNT_SWITCH_TRIES": max_account_switch_tries,
149
+ "ACCOUNT_FAILURE_THRESHOLD": account_failure_threshold,
150
+ "RATE_LIMIT_COOLDOWN_SECONDS": rate_limit_cooldown_seconds,
151
+ "SESSION_CACHE_TTL_SECONDS": session_cache_ttl_seconds,
152
+ }
153
+ }