Upload 53 files
Browse files- config.py +16 -10
- core/api/__pycache__/anthropic.cpython-313.pyc +0 -0
- core/api/__pycache__/deepseek.cpython-313.pyc +0 -0
- core/api/__pycache__/google.cpython-313.pyc +0 -0
- core/api/__pycache__/openai.cpython-313.pyc +0 -0
- core/api/anthropic.py +85 -0
- core/api/deepseek.py +110 -0
- core/api/google.py +113 -0
- core/api/openai.py +86 -0
- static/img/claude.svg +1 -0
- static/img/deepseek.svg +1 -0
- static/img/gemini.svg +1 -0
- static/img/openai.svg +1 -0
- templates/components/api_key_list.html +11 -5
- templates/components/toolbar.html +15 -1
config.py
CHANGED
@@ -24,24 +24,30 @@ TOKEN_EXPIRY_DAYS = 30
|
|
24 |
PLATFORMS = [
|
25 |
{"id": "anthropic", "name": "Anthropic"},
|
26 |
{"id": "openai", "name": "OpenAI"},
|
27 |
-
{"id": "google", "name": "Google"}
|
|
|
28 |
]
|
29 |
|
30 |
# 平台标签样式
|
31 |
PLATFORM_STYLES = {
|
32 |
"anthropic": {
|
33 |
-
"background-color": "rgba(
|
34 |
-
"border-color": "rgba(
|
35 |
-
"color": "#
|
36 |
},
|
37 |
"openai": {
|
38 |
-
"background-color": "rgba(16,
|
39 |
-
"border-color": "rgba(16,
|
40 |
-
"color": "#
|
41 |
},
|
42 |
"google": {
|
43 |
-
"background-color": "rgba(
|
44 |
-
"border-color": "rgba(
|
45 |
-
"color": "#
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
}
|
|
|
24 |
PLATFORMS = [
|
25 |
{"id": "anthropic", "name": "Anthropic"},
|
26 |
{"id": "openai", "name": "OpenAI"},
|
27 |
+
{"id": "google", "name": "Google"},
|
28 |
+
{"id": "deepseek", "name": "Deepseek"}
|
29 |
]
|
30 |
|
31 |
# 平台标签样式
|
32 |
PLATFORM_STYLES = {
|
33 |
"anthropic": {
|
34 |
+
"background-color": "rgba(217, 119, 87, 0.1)",
|
35 |
+
"border-color": "rgba(217, 119, 87, 0.3)",
|
36 |
+
"color": "#c25032"
|
37 |
},
|
38 |
"openai": {
|
39 |
+
"background-color": "rgba(16, 163, 127, 0.1)",
|
40 |
+
"border-color": "rgba(16, 163, 127, 0.3)",
|
41 |
+
"color": "#0e8c6b"
|
42 |
},
|
43 |
"google": {
|
44 |
+
"background-color": "rgba(28, 125, 255, 0.1)",
|
45 |
+
"border-color": "rgba(28, 125, 255, 0.3)",
|
46 |
+
"color": "#0051c3"
|
47 |
+
},
|
48 |
+
"deepseek": {
|
49 |
+
"background-color": "rgba(77, 107, 254, 0.1)",
|
50 |
+
"border-color": "rgba(77, 107, 254, 0.3)",
|
51 |
+
"color": "#3246d3"
|
52 |
}
|
53 |
}
|
core/api/__pycache__/anthropic.cpython-313.pyc
ADDED
Binary file (2.64 kB). View file
|
|
core/api/__pycache__/deepseek.cpython-313.pyc
ADDED
Binary file (3.46 kB). View file
|
|
core/api/__pycache__/google.cpython-313.pyc
ADDED
Binary file (3.54 kB). View file
|
|
core/api/__pycache__/openai.cpython-313.pyc
ADDED
Binary file (2.62 kB). View file
|
|
core/api/anthropic.py
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Anthropic API相关功能模块 - 提供Anthropic Claude API的调用和验证功能
|
3 |
+
"""
|
4 |
+
import requests
|
5 |
+
|
6 |
+
def validate_api_key(api_key):
|
7 |
+
"""
|
8 |
+
验证Anthropic API密钥是否有效
|
9 |
+
|
10 |
+
Args:
|
11 |
+
api_key (str): 需要验证的Anthropic API密钥
|
12 |
+
|
13 |
+
Returns:
|
14 |
+
dict: 包含验证结果的字典,包括:
|
15 |
+
- success (bool): API密钥验证成功为True,失败为False
|
16 |
+
- return_message (str): 验证响应的具体消息,成功时为"200: Success!",失败时为错误详情
|
17 |
+
- balance (float): 账户余额,固定为0
|
18 |
+
- states (str): 账户状态,付费版或免费版
|
19 |
+
"""
|
20 |
+
url = "https://api.anthropic.com/v1/messages"
|
21 |
+
|
22 |
+
headers = {
|
23 |
+
"x-api-key": api_key,
|
24 |
+
"content-type": "application/json",
|
25 |
+
"anthropic-version": "2023-06-01"
|
26 |
+
}
|
27 |
+
|
28 |
+
payload = {
|
29 |
+
"model": "claude-3-5-sonnet-20241022",
|
30 |
+
"max_tokens": 1,
|
31 |
+
"messages": [
|
32 |
+
{"role": "user", "content": "Hello"}
|
33 |
+
]
|
34 |
+
}
|
35 |
+
|
36 |
+
try:
|
37 |
+
response = requests.post(url, headers=headers, json=payload)
|
38 |
+
|
39 |
+
if response.status_code == 200:
|
40 |
+
states = ""
|
41 |
+
rateLimit = response.headers.get("anthropic-ratelimit-input-tokens-limit")
|
42 |
+
if rateLimit:
|
43 |
+
tokens = int(rateLimit)
|
44 |
+
if tokens == 40000:
|
45 |
+
states = "Tier1"
|
46 |
+
elif tokens == 80000:
|
47 |
+
states = "Tier2"
|
48 |
+
elif tokens == 160000:
|
49 |
+
states = "Tier3"
|
50 |
+
elif tokens == 400000:
|
51 |
+
states = "Tier4"
|
52 |
+
else:
|
53 |
+
states = "Unknown"
|
54 |
+
|
55 |
+
return {
|
56 |
+
"success": True,
|
57 |
+
"return_message": "200: Success!",
|
58 |
+
"balance": 0,
|
59 |
+
"states": states
|
60 |
+
}
|
61 |
+
else:
|
62 |
+
return_message = ""
|
63 |
+
try:
|
64 |
+
error_data = response.json()
|
65 |
+
if "error" in error_data:
|
66 |
+
return_message = error_data["error"].get("message", "")
|
67 |
+
return_message = f"{response.status_code}: {return_message}"
|
68 |
+
except:
|
69 |
+
return_message = f"{response.status_code}: {response.text or f'HTTP错误'}"
|
70 |
+
|
71 |
+
return {
|
72 |
+
"success": False,
|
73 |
+
"return_message": return_message,
|
74 |
+
"balance": 0,
|
75 |
+
"states": ""
|
76 |
+
}
|
77 |
+
except Exception as e:
|
78 |
+
error_str = str(e)
|
79 |
+
print(f"验证API密钥时出错: {error_str}")
|
80 |
+
return {
|
81 |
+
"success": False,
|
82 |
+
"return_message": f"500: 请求异常: {error_str}",
|
83 |
+
"balance": 0,
|
84 |
+
"states": ""
|
85 |
+
}
|
core/api/deepseek.py
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Deepseek API相关功能模块 - 提供Deepseek API的调用和验证功能
|
3 |
+
"""
|
4 |
+
import requests
|
5 |
+
|
6 |
+
def validate_api_key(api_key):
|
7 |
+
"""
|
8 |
+
验证Deepseek API密钥是否有效并获取账户余额
|
9 |
+
|
10 |
+
Args:
|
11 |
+
api_key (str): 需要验证的Deepseek API密钥
|
12 |
+
|
13 |
+
Returns:
|
14 |
+
dict: 包含验证结果的字典,包括:
|
15 |
+
- success (bool): API密钥验证成功为True,失败为False
|
16 |
+
- return_message (str): 验证响应的具体消息,成功时为"200: Success!",失败时为错误详情
|
17 |
+
- balance (float): 账户余额,成功时为账户总余额,失败时为0
|
18 |
+
- states (str): 账户状态
|
19 |
+
"""
|
20 |
+
url = "https://api.deepseek.com/v1/user/balance"
|
21 |
+
|
22 |
+
headers = {
|
23 |
+
"Authorization": f"Bearer {api_key}"
|
24 |
+
}
|
25 |
+
|
26 |
+
try:
|
27 |
+
response = requests.get(url, headers=headers)
|
28 |
+
|
29 |
+
if response.status_code == 200:
|
30 |
+
response_data = response.json()
|
31 |
+
is_available = response_data.get("is_available", False)
|
32 |
+
|
33 |
+
if not is_available:
|
34 |
+
return {
|
35 |
+
"success": False,
|
36 |
+
"return_message": "429: Insufficient balance",
|
37 |
+
"balance": 0,
|
38 |
+
"states": ""
|
39 |
+
}
|
40 |
+
|
41 |
+
balance_infos = response_data.get("balance_infos", [])
|
42 |
+
|
43 |
+
balance = 0.0
|
44 |
+
|
45 |
+
try:
|
46 |
+
exchange_rate_response = requests.get("https://api.exchangerate-api.com/v4/latest/USD")
|
47 |
+
exchange_rate_response.raise_for_status()
|
48 |
+
exchange_rate_data = exchange_rate_response.json()
|
49 |
+
exchange_rate = exchange_rate_data.get("rates", {}).get("CNY")
|
50 |
+
|
51 |
+
if exchange_rate is None:
|
52 |
+
exchange_rate = 7.2
|
53 |
+
except Exception as e:
|
54 |
+
exchange_rate = 7.2
|
55 |
+
|
56 |
+
has_cny = False
|
57 |
+
has_usd = False
|
58 |
+
|
59 |
+
for balance_info in balance_infos:
|
60 |
+
currency = balance_info.get("currency")
|
61 |
+
total_balance = float(balance_info.get("total_balance", 0))
|
62 |
+
|
63 |
+
if currency == "CNY":
|
64 |
+
balance += total_balance
|
65 |
+
if total_balance > 0:
|
66 |
+
has_cny = True
|
67 |
+
elif currency == "USD":
|
68 |
+
balance += total_balance * exchange_rate
|
69 |
+
if total_balance > 0:
|
70 |
+
has_usd = True
|
71 |
+
|
72 |
+
states = ""
|
73 |
+
if has_cny and has_usd:
|
74 |
+
states = "CNY/USD"
|
75 |
+
elif has_cny:
|
76 |
+
states = "CNY"
|
77 |
+
elif has_usd:
|
78 |
+
states = "USD"
|
79 |
+
|
80 |
+
return {
|
81 |
+
"success": True,
|
82 |
+
"return_message": "200: Success!",
|
83 |
+
"balance": balance,
|
84 |
+
"states": states
|
85 |
+
}
|
86 |
+
else:
|
87 |
+
return_message = ""
|
88 |
+
try:
|
89 |
+
error_data = response.json()
|
90 |
+
if "error" in error_data:
|
91 |
+
return_message = error_data["error"].get("message", "")
|
92 |
+
return_message = f"{response.status_code}: {return_message}"
|
93 |
+
except:
|
94 |
+
return_message = f"{response.status_code}: {response.text or f'HTTP错误'}"
|
95 |
+
|
96 |
+
return {
|
97 |
+
"success": False,
|
98 |
+
"return_message": return_message,
|
99 |
+
"balance": 0,
|
100 |
+
"states": ""
|
101 |
+
}
|
102 |
+
except Exception as e:
|
103 |
+
error_str = str(e)
|
104 |
+
print(f"验证API密钥时出错: {error_str}")
|
105 |
+
return {
|
106 |
+
"success": False,
|
107 |
+
"return_message": f"500: 请求异常: {error_str}",
|
108 |
+
"balance": 0,
|
109 |
+
"states": ""
|
110 |
+
}
|
core/api/google.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Google API相关功能模块 - 提供Google API的调用和验证功能
|
3 |
+
"""
|
4 |
+
import requests
|
5 |
+
|
6 |
+
def validate_api_key(api_key):
|
7 |
+
"""
|
8 |
+
验证Google API密钥是否有效
|
9 |
+
|
10 |
+
Args:
|
11 |
+
api_key (str): 需要验证的Google API密钥
|
12 |
+
|
13 |
+
Returns:
|
14 |
+
dict: 包含验证结果的字典,包括:
|
15 |
+
- success (bool): API密钥验证成功为True,失败为False
|
16 |
+
- return_message (str): 验证响应的具体消息,成功时为空字符串,失败时为错误详情
|
17 |
+
- balance (float): 账户余额,固定为0
|
18 |
+
- states (str): 账户状态,付费版或免费版
|
19 |
+
"""
|
20 |
+
url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent"
|
21 |
+
|
22 |
+
params = {
|
23 |
+
"key": api_key
|
24 |
+
}
|
25 |
+
|
26 |
+
payload = {
|
27 |
+
"contents": [
|
28 |
+
{
|
29 |
+
"parts": [{"text": "Hello"}]
|
30 |
+
}
|
31 |
+
],
|
32 |
+
"generationConfig": {
|
33 |
+
"maxOutputTokens": 1
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
try:
|
38 |
+
response = requests.post(url, params=params, json=payload)
|
39 |
+
|
40 |
+
if response.status_code == 200:
|
41 |
+
states = check_paid_account(api_key)
|
42 |
+
|
43 |
+
return {
|
44 |
+
"success": True,
|
45 |
+
"return_message": "200: Success!",
|
46 |
+
"balance": 0,
|
47 |
+
"states": states
|
48 |
+
}
|
49 |
+
else:
|
50 |
+
return_message = ""
|
51 |
+
try:
|
52 |
+
error_data = response.json()
|
53 |
+
if "error" in error_data:
|
54 |
+
return_message = error_data["error"].get("message", "")
|
55 |
+
if "details" in error_data["error"]:
|
56 |
+
for detail in error_data["error"]["details"]:
|
57 |
+
if detail.get("errorMessage"):
|
58 |
+
return_message += f" {detail['errorMessage']}"
|
59 |
+
return_message = f"{response.status_code}: {return_message}"
|
60 |
+
except:
|
61 |
+
return_message = f"{response.status_code}: {response.text or f'HTTP错误'}"
|
62 |
+
|
63 |
+
return {
|
64 |
+
"success": False,
|
65 |
+
"return_message": return_message,
|
66 |
+
"balance": 0,
|
67 |
+
"states": ""
|
68 |
+
}
|
69 |
+
except Exception as e:
|
70 |
+
error_str = str(e)
|
71 |
+
print(f"验证API密钥时出错: {error_str}")
|
72 |
+
return {
|
73 |
+
"success": False,
|
74 |
+
"return_message": f"500: 请求异常: {error_str}",
|
75 |
+
"balance": 0,
|
76 |
+
"states": ""
|
77 |
+
}
|
78 |
+
|
79 |
+
def check_paid_account(api_key):
|
80 |
+
"""
|
81 |
+
检查Google API密钥是否为付费账户
|
82 |
+
|
83 |
+
Args:
|
84 |
+
api_key (str): Google API密钥
|
85 |
+
|
86 |
+
Returns:
|
87 |
+
str: 账户状态,付费版返回"Paid",免费版返回"Free"
|
88 |
+
"""
|
89 |
+
try:
|
90 |
+
imagen_url = "https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predict"
|
91 |
+
params = {"key": api_key}
|
92 |
+
payload = {
|
93 |
+
"instances": [{"prompt": "Hi"}]
|
94 |
+
}
|
95 |
+
|
96 |
+
timeout = 1
|
97 |
+
|
98 |
+
try:
|
99 |
+
response = requests.post(imagen_url, params=params, json=payload, timeout=timeout)
|
100 |
+
|
101 |
+
if response.status_code == 200:
|
102 |
+
return "Paid"
|
103 |
+
else:
|
104 |
+
return "Free"
|
105 |
+
|
106 |
+
except requests.exceptions.Timeout:
|
107 |
+
return "Paid"
|
108 |
+
except Exception:
|
109 |
+
return "Free"
|
110 |
+
|
111 |
+
except Exception as e:
|
112 |
+
print(f"检查账户类型时出错: {str(e)}")
|
113 |
+
return "Free"
|
core/api/openai.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
OpenAI API相关功能模块 - 提供OpenAI API的调用和验证功能
|
3 |
+
"""
|
4 |
+
import requests
|
5 |
+
|
6 |
+
def validate_api_key(api_key):
|
7 |
+
"""
|
8 |
+
验证OpenAI API密钥是否有效
|
9 |
+
|
10 |
+
Args:
|
11 |
+
api_key (str): 需要验证的OpenAI API密钥
|
12 |
+
|
13 |
+
Returns:
|
14 |
+
dict: 包含验证结果的字典,包括:
|
15 |
+
- success (bool): API密钥验证成功为True,失败为False
|
16 |
+
- return_message (str): 验证响应的具体消息,成功时为"200: Success!",失败时为错误详情
|
17 |
+
- balance (float): 账户余额,固定为0
|
18 |
+
- states (str): 账户状态,对应的Tier等级
|
19 |
+
"""
|
20 |
+
url = "https://api.openai.com/v1/chat/completions"
|
21 |
+
|
22 |
+
headers = {
|
23 |
+
"Authorization": f"Bearer {api_key}",
|
24 |
+
"Content-Type": "application/json"
|
25 |
+
}
|
26 |
+
|
27 |
+
payload = {
|
28 |
+
"model": "gpt-4o",
|
29 |
+
"max_tokens": 1,
|
30 |
+
"messages": [
|
31 |
+
{"role": "user", "content": "Hello"}
|
32 |
+
]
|
33 |
+
}
|
34 |
+
|
35 |
+
try:
|
36 |
+
response = requests.post(url, headers=headers, json=payload)
|
37 |
+
|
38 |
+
if response.status_code == 200:
|
39 |
+
states = ""
|
40 |
+
rateLimit = response.headers.get("x-ratelimit-limit-tokens")
|
41 |
+
if rateLimit:
|
42 |
+
tokens = int(rateLimit)
|
43 |
+
if tokens == 30000:
|
44 |
+
states = "Tier1"
|
45 |
+
elif tokens == 450000:
|
46 |
+
states = "Tier2"
|
47 |
+
elif tokens == 800000:
|
48 |
+
states = "Tier3"
|
49 |
+
elif tokens == 2000000:
|
50 |
+
states = "Tier4"
|
51 |
+
elif tokens == 150000000:
|
52 |
+
states = "Tier5"
|
53 |
+
else:
|
54 |
+
states = "Unknown"
|
55 |
+
|
56 |
+
return {
|
57 |
+
"success": True,
|
58 |
+
"return_message": "200: Success!",
|
59 |
+
"balance": 0,
|
60 |
+
"states": states
|
61 |
+
}
|
62 |
+
else:
|
63 |
+
return_message = ""
|
64 |
+
try:
|
65 |
+
error_data = response.json()
|
66 |
+
if "error" in error_data:
|
67 |
+
return_message = error_data["error"].get("message", "")
|
68 |
+
return_message = f"{response.status_code}: {return_message}"
|
69 |
+
except:
|
70 |
+
return_message = f"{response.status_code}: {response.text or f'HTTP错误'}"
|
71 |
+
|
72 |
+
return {
|
73 |
+
"success": False,
|
74 |
+
"return_message": return_message,
|
75 |
+
"balance": 0,
|
76 |
+
"states": ""
|
77 |
+
}
|
78 |
+
except Exception as e:
|
79 |
+
error_str = str(e)
|
80 |
+
print(f"验证API密钥时出错: {error_str}")
|
81 |
+
return {
|
82 |
+
"success": False,
|
83 |
+
"return_message": f"500: 请求异常: {error_str}",
|
84 |
+
"balance": 0,
|
85 |
+
"states": ""
|
86 |
+
}
|
static/img/claude.svg
ADDED
|
static/img/deepseek.svg
ADDED
|
static/img/gemini.svg
ADDED
|
static/img/openai.svg
ADDED
|
templates/components/api_key_list.html
CHANGED
@@ -13,7 +13,7 @@
|
|
13 |
>
|
14 |
<!-- 精美的选中数量显示 -->
|
15 |
<div class="flex items-center space-x-3">
|
16 |
-
<div class="flex items-center justify-center h-8 w-8 rounded-full bg-gradient-to-r from-blue-400 to-indigo-500 text-white font-semibold text-sm shadow-sm">
|
17 |
<span x-text="selectedKeys.length"></span>
|
18 |
</div>
|
19 |
|
@@ -120,19 +120,25 @@
|
|
120 |
</div>
|
121 |
</div>
|
122 |
|
123 |
-
|
124 |
:style="{
|
125 |
color: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}').color : '#111827'
|
126 |
}"
|
127 |
>
|
|
|
|
|
128 |
<span>{{ platform.name }}</span>
|
129 |
-
|
130 |
x-show="getPlatformKeyCount('{{ platform.id }}') > 0"
|
131 |
x-text="getPlatformKeyCount('{{ platform.id }}')"
|
132 |
-
class="ml-2 platform-title-counter
|
133 |
:style="{
|
134 |
backgroundColor: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}')['background-color'] : 'rgba(224, 242, 254, 1)',
|
135 |
-
color: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}').color : '#0369a1'
|
|
|
|
|
|
|
|
|
136 |
}"
|
137 |
></span>
|
138 |
</h2>
|
|
|
13 |
>
|
14 |
<!-- 精美的选中数量显示 -->
|
15 |
<div class="flex items-center space-x-3">
|
16 |
+
<div class="flex items-center justify-center h-8 min-w-8 px-2 rounded-full bg-gradient-to-r from-blue-400 to-indigo-500 text-white font-semibold text-sm shadow-sm">
|
17 |
<span x-text="selectedKeys.length"></span>
|
18 |
</div>
|
19 |
|
|
|
120 |
</div>
|
121 |
</div>
|
122 |
|
123 |
+
<h2 class="text-lg font-medium flex items-center"
|
124 |
:style="{
|
125 |
color: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}').color : '#111827'
|
126 |
}"
|
127 |
>
|
128 |
+
<!-- 添加平台图标 -->
|
129 |
+
<img src="/static/img/{% if platform.id == 'anthropic' %}claude.svg{% elif platform.id == 'google' %}gemini.svg{% else %}{{ platform.id }}.svg{% endif %}" class="w-5 h-5 mr-2" alt="{{ platform.name }} 图标">
|
130 |
<span>{{ platform.name }}</span>
|
131 |
+
<span
|
132 |
x-show="getPlatformKeyCount('{{ platform.id }}') > 0"
|
133 |
x-text="getPlatformKeyCount('{{ platform.id }}')"
|
134 |
+
class="ml-2 platform-title-counter"
|
135 |
:style="{
|
136 |
backgroundColor: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}')['background-color'] : 'rgba(224, 242, 254, 1)',
|
137 |
+
color: '{{ platform.id }}' in getPlatformStyles() ? getPlatformStyle('{{ platform.id }}').color : '#0369a1',
|
138 |
+
borderRadius: '12px',
|
139 |
+
minWidth: '1.6rem',
|
140 |
+
padding: '0 0.4rem',
|
141 |
+
width: 'auto'
|
142 |
}"
|
143 |
></span>
|
144 |
</h2>
|
templates/components/toolbar.html
CHANGED
@@ -41,6 +41,7 @@
|
|
41 |
class="tag-counter"
|
42 |
:class="allPlatformsSelected ? 'bg-primary-700 text-white' : 'bg-gray-200 text-gray-700'"
|
43 |
x-text="totalKeyCount()"
|
|
|
44 |
></span>
|
45 |
</button>
|
46 |
|
@@ -55,13 +56,26 @@
|
|
55 |
}"
|
56 |
:style="platformFilters[platform.id] ? getPlatformStyle(platform.id) : {}"
|
57 |
>
|
|
|
|
|
58 |
<span x-text="platform.name"></span>
|
59 |
<span
|
60 |
class="tag-counter"
|
61 |
:class="{
|
62 |
'bg-gray-200 text-gray-700': !platformFilters[platform.id]
|
63 |
}"
|
64 |
-
:style="platformFilters[platform.id] ? {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
x-text="getPlatformKeyCount(platform.id)"
|
66 |
></span>
|
67 |
</button>
|
|
|
41 |
class="tag-counter"
|
42 |
:class="allPlatformsSelected ? 'bg-primary-700 text-white' : 'bg-gray-200 text-gray-700'"
|
43 |
x-text="totalKeyCount()"
|
44 |
+
style="border-radius: 12px; min-width: 1.6rem; padding: 0 0.4rem; width: auto;"
|
45 |
></span>
|
46 |
</button>
|
47 |
|
|
|
56 |
}"
|
57 |
:style="platformFilters[platform.id] ? getPlatformStyle(platform.id) : {}"
|
58 |
>
|
59 |
+
<!-- 添加平台图标 -->
|
60 |
+
<img :src="'/static/img/' + (platform.id === 'anthropic' ? 'claude.svg' : platform.id === 'google' ? 'gemini.svg' : platform.id + '.svg')" class="w-4 h-4 mr-1.5" :alt="platform.name + ' 图标'">
|
61 |
<span x-text="platform.name"></span>
|
62 |
<span
|
63 |
class="tag-counter"
|
64 |
:class="{
|
65 |
'bg-gray-200 text-gray-700': !platformFilters[platform.id]
|
66 |
}"
|
67 |
+
:style="platformFilters[platform.id] ? {
|
68 |
+
background: 'rgba(' + getPlatformStyle(platform.id).color.replace('#', '').match(/.{2}/g).map(hex => parseInt(hex, 16)).join(',') + ',0.1)',
|
69 |
+
borderRadius: '12px',
|
70 |
+
minWidth: '1.6rem',
|
71 |
+
padding: '0 0.4rem',
|
72 |
+
width: 'auto'
|
73 |
+
} : {
|
74 |
+
borderRadius: '12px',
|
75 |
+
minWidth: '1.6rem',
|
76 |
+
padding: '0 0.4rem',
|
77 |
+
width: 'auto'
|
78 |
+
}"
|
79 |
x-text="getPlatformKeyCount(platform.id)"
|
80 |
></span>
|
81 |
</button>
|