yangtb24 commited on
Commit
5ad3e05
·
verified ·
1 Parent(s): a2ef26f

Upload 53 files

Browse files
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(236, 72, 153, 0.1)",
34
- "border-color": "rgba(236, 72, 153, 0.3)",
35
- "color": "#be185d"
36
  },
37
  "openai": {
38
- "background-color": "rgba(16, 185, 129, 0.1)",
39
- "border-color": "rgba(16, 185, 129, 0.3)",
40
- "color": "#047857"
41
  },
42
  "google": {
43
- "background-color": "rgba(59, 130, 246, 0.1)",
44
- "border-color": "rgba(59, 130, 246, 0.3)",
45
- "color": "#1d4ed8"
 
 
 
 
 
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
- <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
  <span>{{ platform.name }}</span>
129
- <span
130
  x-show="getPlatformKeyCount('{{ platform.id }}') > 0"
131
  x-text="getPlatformKeyCount('{{ platform.id }}')"
132
- class="ml-2 platform-title-counter rounded-full"
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] ? {background: 'rgba(' + getPlatformStyle(platform.id).color.replace('#', '').match(/.{2}/g).map(hex => parseInt(hex, 16)).join(',') + ',0.1)'} : {}"
 
 
 
 
 
 
 
 
 
 
 
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>