MeUtils 2024.12.13.15.39.7__py3-none-any.whl → 2024.12.19.11.21.54__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/METADATA +26 -26
  2. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/RECORD +30 -21
  3. examples/_openaisdk/4v.py +2 -1
  4. examples/_openaisdk/gpt4all.py +0 -5
  5. examples/_openaisdk/open_router.py +5 -2
  6. examples/_openaisdk/openai_chatfire.py +8 -2
  7. examples/_openaisdk/openai_images.py +8 -6
  8. examples/caches/llmcache.py +18 -0
  9. meutils/apis/hailuoai/videos.py +1 -1
  10. meutils/apis/images/fal/files.py +4 -1
  11. meutils/apis/jimeng/__init__.py +11 -0
  12. meutils/apis/jimeng/common.py +253 -0
  13. meutils/apis/jimeng/files.py +180 -0
  14. meutils/apis/jimeng/images.py +105 -0
  15. meutils/apis/jimeng/sig.py +92 -0
  16. meutils/apis/jimeng/utils.py +177 -0
  17. meutils/apis/siliconflow/videos.py +38 -9
  18. meutils/data/VERSION +1 -1
  19. meutils/data/oneapi/NOTICE.md +12 -29
  20. meutils/io/files_utils.py +34 -3
  21. meutils/llm/completions/rag/fire.py +2 -1
  22. meutils/llm/mappers.py +15 -0
  23. meutils/office_automation/pdf.py +5 -1
  24. meutils/schemas/jimeng_types.py +28 -0
  25. meutils/schemas/oneapi/common.py +13 -0
  26. meutils/schemas/task_types.py +1 -1
  27. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/LICENSE +0 -0
  28. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/WHEEL +0 -0
  29. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/entry_points.txt +0 -0
  30. {MeUtils-2024.12.13.15.39.7.dist-info → MeUtils-2024.12.19.11.21.54.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : common
5
+ # @Time : 2024/12/16 18:19
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : https://github.com/LLM-Red-Team/jimeng-free-api/commit/acd362a4cecd115938bf4bc9bbb0067738aa0d5b#diff-e6a7354ac1431dc3751e91efaf1799200c1ce2fa8abe975a49c32644290988baR121
10
+ from openai import AsyncClient
11
+
12
+ from meutils.pipe import *
13
+ from meutils.hash_utils import md5
14
+ from meutils.schemas.image_types import ImageRequest
15
+ from meutils.schemas.jimeng_types import BASE_URL, MODELS_MAP
16
+ from meutils.str_utils.regular_expression import parse_url
17
+ from meutils.apis.jimeng.files import upload
18
+ from meutils.io.files_utils import to_bytes
19
+ from meutils.caches.redis_cache import cache
20
+
21
+ from fake_useragent import UserAgent
22
+
23
+ ua = UserAgent()
24
+
25
+
26
+ def get_headers(url, token="693701c43e477b7c405cc7e2fef0ddbd"):
27
+ device_time = f"{int(time.time())}"
28
+ sign = md5(
29
+ # f"9e2c|receive|7|5.8.0|{device_time}||11ac"
30
+ f"9e2c|{url[-7:]}|7|5.8.0|{device_time}||11ac"
31
+ )
32
+
33
+ headers = {
34
+ 'appid': '513695',
35
+ 'appvr': '5.8.0',
36
+ 'device-time': device_time,
37
+ 'pf': '7',
38
+ 'sign': sign,
39
+ 'sign-ver': '1',
40
+ 'Cookie': f'sid_guard={token}|{device_time}|5184000|Fri,+14-Feb-2025+00:51:51+GMT',
41
+ 'User-Agent': ua.random,
42
+
43
+ 'content-type': 'application/json',
44
+ # "Referer": "https://jimeng.jianying.com/ai-tool/image/generate",
45
+ }
46
+ return headers
47
+
48
+
49
+ @cache(ttl=3600 // 2)
50
+ async def get_upload_token(token): # 3600 跨账号?
51
+ url = "/artist/v2/tools/get_upload_token"
52
+ headers = get_headers(url, token)
53
+
54
+ payload = {"scene": 2}
55
+ client = AsyncClient(base_url=BASE_URL, default_headers=headers)
56
+ response = await client.post(url, body=payload, cast_to=object)
57
+ return response
58
+
59
+
60
+ @alru_cache(12 * 3600)
61
+ async def receive_credit(token):
62
+ # token = "eb4d120829cfd3ee957943f63d6152ed" # y
63
+ # token = "9ba826acc1a4bf0e10912eb01beccfe0" # w
64
+ url = "/commerce/v1/benefits/credit_receive"
65
+ headers = get_headers(url, token)
66
+ payload = {"time_zone": "Asia/Shanghai"}
67
+ client = AsyncClient(base_url=BASE_URL, default_headers=headers)
68
+ response = await client.post(url, body=payload, cast_to=object)
69
+ logger.debug(bjson(response))
70
+
71
+
72
+ async def get_credit(token):
73
+ # token = "eb4d120829cfd3ee957943f63d6152ed" # y
74
+ # token = "9ba826acc1a4bf0e10912eb01beccfe0" # w
75
+
76
+ url = "/commerce/v1/benefits/user_credit"
77
+ headers = get_headers(url, token)
78
+
79
+ payload = {}
80
+ client = AsyncClient(base_url=BASE_URL, default_headers=headers)
81
+ response = await client.post(url, body=payload, cast_to=object)
82
+ if response['data']['credit']['gift_credit'] == 0: # 签到
83
+ await receive_credit(token)
84
+
85
+ logger.debug(bjson(response))
86
+ return response
87
+
88
+
89
+ async def check_token(token, threshold: int = 1):
90
+ try:
91
+ response = await get_credit(token)
92
+ credits = sum(response['data']['credit'].values())
93
+ # logger.debug(credits)
94
+ return credits >= threshold
95
+ except Exception as e:
96
+ return False
97
+
98
+
99
+ async def create_draft_content(request: ImageRequest, token: str):
100
+ """
101
+ 创建草稿内容
102
+ """
103
+ request.model = MODELS_MAP.get(request.model, MODELS_MAP["default"])
104
+
105
+ height = width = 1360
106
+ if 'x' in request.size:
107
+ height, width = map(int, request.size.split('x'))
108
+
109
+ main_component_id = str(uuid.uuid4())
110
+
111
+ if urls := parse_url(request.prompt):
112
+ url = urls[-1]
113
+ upload_token = await get_upload_token(token)
114
+ image_uri = upload(await to_bytes(url), upload_token)
115
+
116
+ request.prompt = request.prompt.replace(url, '')
117
+ request.model = "high_aes_general_v20_L:general_v2.0_L" # 2.1不支持图片编辑
118
+
119
+ component = {
120
+ "type": "image_base_component",
121
+ "id": main_component_id,
122
+ "min_version": "3.0.2",
123
+ "generate_type": "blend",
124
+ "aigc_mode": "workbench",
125
+ "abilities": {
126
+ "type": "",
127
+ "id": str(uuid.uuid4()),
128
+ "blend": {
129
+ "type": "",
130
+ "id": str(uuid.uuid4()),
131
+ "core_param": {
132
+ "type": "",
133
+ "id": str(uuid.uuid4()),
134
+ "model": request.model,
135
+ "prompt": f"##{request.prompt}",
136
+ "sample_strength": 0.5,
137
+ "image_ratio": 1,
138
+ "large_image_info": {
139
+ "type": "",
140
+ "id": str(uuid.uuid4()),
141
+ "height": height,
142
+ "width": width
143
+ },
144
+ },
145
+ "ability_list": [
146
+ {
147
+ "type": "",
148
+ "id": str(uuid.uuid4()),
149
+ "name": "byte_edit",
150
+ "image_uri_list": [
151
+ image_uri
152
+ ],
153
+ "image_list": [
154
+ {
155
+ "type": "image",
156
+ "id": str(uuid.uuid4()),
157
+ "source_from": "upload",
158
+ "platform_type": 1,
159
+ "name": "",
160
+ "image_uri": image_uri,
161
+ "width": 0,
162
+ "height": 0,
163
+ "format": "",
164
+ "uri": image_uri
165
+ }
166
+ ],
167
+ "strength": 0.5
168
+ }
169
+ ],
170
+ "history_option": {
171
+ "type": "",
172
+ "id": str(uuid.uuid4()),
173
+ },
174
+ "prompt_placeholder_info_list": [
175
+ {
176
+ "type": "",
177
+ "id": str(uuid.uuid4()),
178
+ "ability_index": 0
179
+ }
180
+ ],
181
+ "postedit_param": {
182
+ "type": "",
183
+ "id": str(uuid.uuid4()),
184
+ "generate_type": 0
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ else:
191
+
192
+ component = {
193
+ "type": "image_base_component",
194
+ "id": main_component_id,
195
+ "min_version": "3.0.2",
196
+ "generate_type": "generate",
197
+ "aigc_mode": "workbench",
198
+ "abilities": {
199
+ "type": "",
200
+ "id": str(uuid.uuid4()),
201
+ "generate": {
202
+ "type": "",
203
+ "id": str(uuid.uuid4()),
204
+ "core_param": {
205
+ "type": "",
206
+ "id": str(uuid.uuid4()),
207
+ "model": request.model,
208
+ "prompt": request.prompt,
209
+ "negative_prompt": request.negative_prompt or "",
210
+ "seed": request.seed or 426999300,
211
+ "sample_strength": 0.5,
212
+ "image_ratio": 1,
213
+ "large_image_info": {
214
+ "type": "",
215
+ "id": str(uuid.uuid4()),
216
+ "height": height,
217
+ "width": width
218
+ }
219
+ },
220
+ "history_option": {
221
+ "type": "",
222
+ "id": str(uuid.uuid4()),
223
+ }
224
+ }
225
+ }
226
+ }
227
+
228
+ draft_content = {
229
+ "type": "draft",
230
+ "id": str(uuid.uuid4()),
231
+ "min_version": "3.0.2",
232
+ "min_features": [],
233
+ "is_from_tsn": True,
234
+ "version": "3.0.8",
235
+ "main_component_id": main_component_id,
236
+ "component_list": [component]
237
+ }
238
+
239
+ logger.debug(bjson(draft_content))
240
+
241
+ return draft_content
242
+
243
+
244
+ if __name__ == '__main__':
245
+ token = "693701c43e477b7c405cc7e2fef0ddbd"
246
+ token = "eb4d120829cfd3ee957943f63d6152ed"
247
+ # arun(get_credit(token))
248
+ arun(check_token(token))
249
+
250
+ # arun(get_upload_token(token))
251
+ #
252
+ # request = ImageRequest(prompt='https://oss.ffire.cc/files/kling_watermark.png笑起来')
253
+ # arun(create_draft_content(request, token))
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : kaiyuan
5
+ # @Time : 2024/12/18 16:03
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ import hmac
12
+ import zlib
13
+ import hashlib
14
+
15
+ from meutils.pipe import *
16
+ from meutils.caches.redis_cache import cache
17
+
18
+
19
+ def random_str(n):
20
+ return ''.join(random.sample('zyxwvutsrqponmlkjihgfedcba0123456789', n))
21
+
22
+
23
+ def hash256(msg):
24
+ return hashlib.sha256(msg.encode('utf-8')).hexdigest()
25
+
26
+
27
+ def hmac_hash256(key, msg):
28
+ if type(key) == str:
29
+ return hmac.new(key.encode('utf-8'), msg.encode('utf-8'), hashlib.sha256)
30
+ elif type(key) == hmac.HMAC:
31
+ return hmac.new(key.digest(), msg.encode('utf-8'), hashlib.sha256)
32
+
33
+
34
+ def fileCRC32(file_buffer):
35
+ return hex(zlib.crc32(file_buffer) & 0xFFFFFFFF)[2:]
36
+
37
+
38
+ def u(params):
39
+ new_params = sorted(params.items(), key=lambda x: x[0])
40
+ new_params = [f"{k}={v}" for k, v in new_params]
41
+ return "&".join(new_params)
42
+
43
+
44
+ class JJRequest:
45
+ def __init__(self, e, t, api, method="GET", params=None, data=None):
46
+ self.t = t
47
+ self.e = e
48
+ self.api = api
49
+ self.method = method
50
+ self.params = params
51
+ self.data = data
52
+
53
+ def getAuthorization(self):
54
+ return f"AWS4-HMAC-SHA256 Credential={self.e['access_key_id']}/{self.t[0:8]}/cn-north-1/imagex/aws4_request, SignedHeaders=x-amz-date;x-amz-security-token, Signature={self.signature()}"
55
+
56
+ def signature(self):
57
+ r = self.getSigningKey()
58
+ return hmac_hash256(r, self.stringToSign()).hexdigest()
59
+
60
+ def getSigningKey(self, r="cn-north-1", n="imagex"):
61
+ o = hmac_hash256("AWS4" + self.e['secret_access_key'], str(self.t[0:8]))
62
+ i = hmac_hash256(o, str(r))
63
+ s = hmac_hash256(i, str(n))
64
+ return hmac_hash256(s, "aws4_request")
65
+
66
+ def stringToSign(self):
67
+ t = []
68
+ t.append("AWS4-HMAC-SHA256")
69
+ t.append(self.t)
70
+ t.append(self.credentialString())
71
+ t.append(hash256(self.canonicalString()))
72
+ return "\n".join(t)
73
+
74
+ def credentialString(self, region="cn-north-1", serviceName="imagex"):
75
+ return "/".join([self.t[0:8], region, serviceName, "aws4_request"])
76
+
77
+ def canonicalString(self):
78
+ e = []
79
+ e.append(self.method)
80
+ e.append("/")
81
+ e.append(u(self.params))
82
+ e.append(self.canonicalHeaders())
83
+ e.append(self.signedHeaders())
84
+ e.append(self.hexEncodedBodyHash())
85
+ return "\n".join(e)
86
+
87
+ def canonicalHeaders(self):
88
+ return f"x-amz-date:{self.t}\nx-amz-security-token:{self.e['session_token']}\n"
89
+
90
+ def signedHeaders(self):
91
+ return "x-amz-date;x-amz-security-token"
92
+
93
+ def hexEncodedBodyHash(self):
94
+ return hash256("")
95
+
96
+
97
+ @cache(ttl=15 * 60)
98
+ def upload(image: bytes, upload_token: dict): # oss 跨账号不知道是否可以使用
99
+ # e = auth = upload_token['data']['auth'] # 豆包
100
+ data = upload_token['data']
101
+
102
+ service_id = data.get('service_id', '3jr8j4ixpe') # 即梦 3jr8j4ixpe
103
+
104
+ session_token = data['session_token']
105
+
106
+ t = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
107
+
108
+ params = {
109
+ "Action": "ApplyImageUpload",
110
+ "Version": "2018-08-01",
111
+ "ServiceId": service_id,
112
+ "s": random_str(10),
113
+
114
+ "FileExtension": ".png", #####
115
+ "FileSize": len(image),
116
+ }
117
+
118
+ r = JJRequest(data, t, "https://imagex.bytedanceapi.com/", method="GET", params=params)
119
+ headers = {
120
+ 'authorization': r.getAuthorization(),
121
+ 'x-amz-date': t,
122
+ 'x-amz-security-token': session_token,
123
+ }
124
+ # logger.debug(headers)
125
+ response = requests.get(r.api, params=params, headers=headers)
126
+ response.raise_for_status()
127
+ logger.debug(response.status_code)
128
+ response = response.json()
129
+
130
+ logger.debug(bjson(response))
131
+ if "Result" not in response:
132
+ return
133
+
134
+ store_info = response['Result']['UploadAddress']['StoreInfos'][0]
135
+ logger.debug(bjson(store_info))
136
+
137
+ oss_uri = store_info['StoreUri']
138
+ oss_token = store_info['Auth']
139
+
140
+ headers = {
141
+ "authorization": oss_token,
142
+ "content-length": str(len(image)),
143
+ "content-Type": "image/jpeg",
144
+ "content-crc32": fileCRC32(image),
145
+ }
146
+
147
+ # oss_url = f"https://{resp['Result']['UploadAddress']['UploadHosts'][0]}/{oss_uri}"
148
+
149
+ # image_resp = requests.put( # post
150
+ # oss_url,
151
+ # headers=headers,
152
+ # data=image,
153
+ # )
154
+ # logger.debug(image_resp.json())
155
+
156
+ # return get_url(StoreUri)
157
+
158
+ # upload_url = f"https://tos-hl-x.snssdk.com/upload/v1/{oss_uri}"
159
+ upload_url = f"https://{response['Result']['UploadAddress']['UploadHosts'][0]}/upload/v1/{oss_uri}"
160
+
161
+ response = requests.post(upload_url, headers=headers, data=image)
162
+ response.raise_for_status()
163
+ response = response.json()
164
+
165
+ logger.debug(response)
166
+
167
+ return oss_uri
168
+
169
+
170
+ if __name__ == "__main__":
171
+ from meutils.apis.jimeng.common import get_upload_token
172
+
173
+ token = "693701c43e477b7c405cc7e2fef0ddbd"
174
+
175
+ upload_token = arun(get_upload_token(token))
176
+
177
+ with open("11.jpg", "rb") as f:
178
+ file = image = f.read()
179
+
180
+ upload(image, upload_token)
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : images
5
+ # @Time : 2024/12/16 17:46
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+
13
+ from meutils.schemas.jimeng_types import BASE_URL, MODELS_MAP, FEISHU_URL
14
+ from meutils.schemas.image_types import ImageRequest
15
+ from meutils.schemas.task_types import TaskResponse
16
+ from meutils.apis.jimeng.common import create_draft_content, get_headers, check_token
17
+ from meutils.config_utils.lark_utils import get_next_token_for_polling
18
+
19
+ from fake_useragent import UserAgent
20
+
21
+ ua = UserAgent()
22
+
23
+
24
+ async def create_task(request: ImageRequest, token: Optional[str] = None):
25
+ token = token or await get_next_token_for_polling(FEISHU_URL, check_token)
26
+
27
+ url = "/mweb/v1/aigc_draft/generate"
28
+
29
+ headers = get_headers(url, token)
30
+
31
+ if "http" in request.prompt: # 图生
32
+ request.model = "high_aes_general_v20_L:general_v2.0_L"
33
+
34
+ draft_content = await create_draft_content(request, token)
35
+ payload = {
36
+ "extend": {
37
+ "root_model": request.model,
38
+ "template_id": ""
39
+ },
40
+ "submit_id": str(uuid.uuid4()),
41
+ "metrics_extra": "{\"templateId\":\"\",\"generateCount\":1,\"promptSource\":\"custom\",\"templateSource\":\"\",\"lastRequestId\":\"\",\"originRequestId\":\"\"}",
42
+ "draft_content": json.dumps(draft_content),
43
+ "http_common_info": {
44
+ "aid": 513695
45
+ }
46
+ }
47
+
48
+ logger.debug(bjson(payload))
49
+
50
+ async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
51
+ response = await client.post(url, json=payload)
52
+ response.raise_for_status()
53
+ data = response.json()
54
+ logger.debug(bjson(data))
55
+
56
+ task_id = data.get("data", {}).get("aigc_data", {}).get("history_record_id")
57
+ return TaskResponse(task_id=task_id, system_fingerprint=token)
58
+
59
+
60
+ async def get_task(task_id, token):
61
+ url = "/mweb/v1/get_history_by_ids"
62
+ headers = get_headers(url, token)
63
+ payload = {
64
+ "history_ids": [
65
+ task_id
66
+ ]
67
+ }
68
+
69
+ async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
70
+ response = await client.post(url, json=payload)
71
+ response.raise_for_status()
72
+ data = response.json()
73
+ # {'ret': '1015', 'errmsg': 'login error', 'systime': '1734524280', 'logid': '20241218201800AC3267447B287E9E6C46', 'data': None}
74
+ item_list = (data.get("data") or {}).get(task_id, {}).get("item_list")
75
+ image_data = map(lambda x: x.get("image", {}).get("large_images"), item_list)
76
+
77
+ task_data = sum(image_data, []) | xmap_(lambda x: {"url": x.get("image_url")})
78
+
79
+ return TaskResponse(
80
+ task_id=task_id,
81
+ data=task_data,
82
+ message=data.get("errmsg"),
83
+ status="success" if task_data else None,
84
+ )
85
+
86
+
87
+ if __name__ == '__main__':
88
+ token = "693701c43e477b7c405cc7e2fef0ddbd"
89
+
90
+ request = ImageRequest(prompt="一个漂亮的姑娘", size="1024x1024")
91
+ # request = ImageRequest(prompt="https://oss.ffire.cc/files/kling_watermark.png 让她带上墨镜", size="1024x1024")
92
+
93
+ arun(create_task(request))
94
+
95
+ # task_id = "10040025470722"
96
+
97
+ # task_id = "10053536381698"
98
+
99
+ # task_id = "10079694738434"
100
+
101
+ # task_id = "10080831230210" # 图片编辑
102
+
103
+ # task_id = "10082971040514"
104
+ #
105
+ # arun(get_task(task_id, token))
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : sig
5
+ # @Time : 2024/12/18 15:36
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+ import hashlib
11
+ import hmac
12
+ import datetime
13
+
14
+
15
+ def sign(key, msg):
16
+ return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
17
+
18
+
19
+ def getSignatureKey(key, dateStamp, regionName, serviceName):
20
+ kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
21
+ kRegion = sign(kDate, regionName)
22
+ kService = sign(kRegion, serviceName)
23
+ kSigning = sign(kService, 'aws4_request')
24
+ return kSigning
25
+
26
+
27
+ if __name__ == '__main__':
28
+ pass
29
+ from meutils.pipe import *
30
+ from meutils.apis.jimeng.utils import get_upload_token
31
+
32
+ # data = arun(get_upload_token())
33
+
34
+ # access_key_id = data['data']['auth']['access_key_id']
35
+ # secret_access_key = data['data']['auth']['secret_access_key']
36
+ # session_token = data['data']['auth']['session_token']
37
+
38
+ import hashlib
39
+ import hmac
40
+ import datetime
41
+
42
+
43
+ def sign(key, msg):
44
+ """计算 HMAC-SHA256"""
45
+ return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
46
+
47
+
48
+ def getSignatureKey(key, dateStamp, regionName, serviceName):
49
+ """生成签名密钥"""
50
+ kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
51
+ kRegion = sign(kDate, regionName)
52
+ kService = sign(kRegion, serviceName)
53
+ kSigning = sign(kService, 'aws4_request')
54
+ return kSigning
55
+
56
+
57
+ def calculate_signature(string_to_sign, secret_key, region, service, date):
58
+ """计算 AWS4-HMAC-SHA256 签名"""
59
+ # 生成签名密钥
60
+ signing_key = getSignatureKey(
61
+ secret_key,
62
+ date.strftime('%Y%m%d'),
63
+ region,
64
+ service
65
+ )
66
+
67
+ # 计算最终签名
68
+ signature = hmac.new(
69
+ signing_key,
70
+ string_to_sign.encode('utf-8'),
71
+ hashlib.sha256
72
+ ).hexdigest()
73
+
74
+ return signature
75
+
76
+ # 示例参数
77
+
78
+
79
+ secret_key = 'AKTPN2VkZWY2MWNhNjVlNGZhZThiZmVmNzEwODA3YjM1YTY'
80
+ region = 'cn-north-1'
81
+ service = 'imagex'
82
+ date = datetime.datetime.utcnow()
83
+ print(date)
84
+ hash_of_canonical_request = {
85
+ "SessionKey": "eyJhY2NvdW50VHlwZSI6IkltYWdlWCIsImFwcElkIjoiIiwiYml6VHlwZSI6IiIsImZpbGVUeXBlIjoiaW1hZ2UiLCJsZWdhbCI6IiIsInN0b3JlSW5mb3MiOiJbe1wiU3RvcmVVcmlcIjpcInRvcy1jbi1pLWE5cm5zMnJsOTgvYmQzZGNlZWIzN2Y3NDA5NjlkMTBiZjBiZjhhMzk0NmUuanBlZ1wiLFwiQXV0aFwiOlwiU3BhY2VLZXkvYTlybnMycmw5OC8xLzp2ZXJzaW9uOnYyOmV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUpsZUhBaU9qRTNNelExTXpBd016Z3NJbk5wWjI1aGRIVnlaVWx1Wm04aU9uc2lZV05qWlhOelMyVjVJam9pWm1GclpWOWhZMk5sYzNOZmEyVjVJaXdpWW5WamEyVjBJam9pZEc5ekxXTnVMV2t0WVRseWJuTXljbXc1T0NJc0ltVjRjR2x5WlNJNk1UY3pORFV6TURBek9Dd2labWxzWlVsdVptOXpJanBiZXlKdmFXUkxaWGtpT2lKaVpETmtZMlZsWWpNM1pqYzBNRGsyT1dReE1HSm1NR0ptT0dFek9UUTJaUzVxY0dWbklpd2labWxzWlZSNWNHVWlPaUl4SW4xZExDSmxlSFJ5WVNJNmV5SmliRzlqYTE5dGIyUmxJam9pSWl3aVkyOXVkR1Z1ZEY5MGVYQmxYMkpzYjJOcklqb2llMXdpYldsdFpWOXdZM1JjSWpvd0xGd2liVzlrWlZ3aU9qQXNYQ0p0YVcxbFgyeHBjM1JjSWpwdWRXeHNMRndpWTI5dVpteHBZM1JmWW14dlkydGNJanBtWVd4elpYMGlMQ0psYm1OeWVYQjBYMkZzWjI4aU9pSWlMQ0psYm1OeWVYQjBYMnRsZVNJNklpSXNJbVY0ZEY5amIyNTBaVzUwWDNSNWNHVWlPaUpwYldGblpTOXFjR1ZuSWl3aWFYTmZhVzFoWjJWNElqcDBjblZsTENKemNHRmpaU0k2SW1FNWNtNXpNbkpzT1RnaWZYMTkueVFadDJoYWFVMDBuMTFZREJXZDBCbTNIYWdtVlNUN0UzNXMwSkNnOGpzMFwiLFwiVXBsb2FkSURcIjpcIjE3ZThiODUxNzczNDRlYjFiYmM1MDAzMWU3NzQ3NGUyXCIsXCJVcGxvYWRIZWFkZXJcIjpudWxsLFwiU3RvcmFnZUhlYWRlclwiOm51bGx9XSIsInVwbG9hZEhvc3QiOiJ0b3MtZC14LWxmLnNuc3Nkay5jb20iLCJ1cmkiOiJ0b3MtY24taS1hOXJuczJybDk4L2JkM2RjZWViMzdmNzQwOTY5ZDEwYmYwYmY4YTM5NDZlLmpwZWciLCJ1c2VySWQiOiIifQ=="
86
+ }
87
+ hash_of_canonical_request = json.dumps(hash_of_canonical_request)
88
+ string_to_sign = f'AWS4-HMAC-SHA256\n20241218T075358Z\n20241218/cn-north-1/imagex/aws4_request\n{hash_of_canonical_request}'
89
+
90
+ # 计算签名
91
+ signature = calculate_signature(string_to_sign, secret_key, region, service, date)
92
+ print(f'签名结果: {signature}')