pixelarraylib 1.0.0__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.
@@ -0,0 +1,253 @@
1
+ import json
2
+ import traceback
3
+ from typing import Union
4
+ from alibabacloud_green20220302.client import Client
5
+ from alibabacloud_green20220302.models import (
6
+ TextModerationRequest,
7
+ TextModerationPlusRequest,
8
+ ImageModerationRequest,
9
+ VideoModerationRequest,
10
+ VideoModerationResultRequest,
11
+ VoiceModerationRequest,
12
+ VoiceModerationResultRequest,
13
+ )
14
+ from alibabacloud_tea_openapi.models import Config
15
+ from alibabacloud_tea_util import models as util_models
16
+ from arraylib.monitor.feishu import Feishu
17
+ feishu_alert = Feishu("devtoolkit服务报警")
18
+
19
+ class ContentScanner:
20
+ def __init__(self, access_key_id, access_key_secret, region_id):
21
+ self.client = Client(
22
+ Config(
23
+ access_key_id=access_key_id,
24
+ access_key_secret=access_key_secret,
25
+ region_id=region_id,
26
+ connect_timeout=30000,
27
+ read_timeout=60000,
28
+ endpoint=f"green-cip.{region_id}.aliyuncs.com",
29
+ )
30
+ )
31
+
32
+ def scan_text(
33
+ self, content: str, service: str = "ugc_moderation_byllm", use_plus: bool = True
34
+ ) -> Union[dict, bool]:
35
+ """
36
+ description:
37
+ 文本内容检测
38
+ parameters:
39
+ content(str): 要检测的文本内容,不同的service有不同的上限,具体可以查看官网
40
+ service(str): 服务类型,可选值 comment_detection(普通版), llm_query_moderation(Plus版), ugc_moderation_byllm(Plus版)
41
+ use_plus(bool): 是否使用Plus版API
42
+ return:
43
+ result(dict): 检测结果
44
+ status(bool): 是否成功
45
+ """
46
+
47
+ if not content.strip():
48
+ return {}, False
49
+
50
+ try:
51
+ if use_plus:
52
+ response = self.client.text_moderation_plus(
53
+ TextModerationPlusRequest(
54
+ service=service,
55
+ service_parameters=json.dumps({"content": content}),
56
+ )
57
+ )
58
+ else:
59
+ response = self.client.text_moderation_with_options(
60
+ TextModerationRequest(
61
+ service=service,
62
+ service_parameters=json.dumps({"content": content}),
63
+ ),
64
+ util_models.RuntimeOptions(
65
+ read_timeout=10000, connect_timeout=10000
66
+ ),
67
+ )
68
+ return (
69
+ (response.body.to_map(), True)
70
+ if response.status_code == 200
71
+ else ({}, False)
72
+ )
73
+ except Exception as e:
74
+ feishu_alert.send(traceback.format_exc())
75
+ return {}, False
76
+
77
+ def scan_image(
78
+ self, oss_region_id: str, oss_bucket_name: str, oss_object_key: str, service: str = "baselineCheck"
79
+ ) -> Union[dict, bool]:
80
+ """
81
+ description:
82
+ 图片内容检测(同步方式)
83
+ parameters:
84
+ oss_region_id(str): 图片OSS地域ID
85
+ oss_bucket_name(str): 图片OSS桶名
86
+ oss_object_key(str): 图片OSS对象key
87
+ service(str): 服务类型,可选值:enhance(增强版), baselineCheck(基础版)
88
+ return:
89
+ result(dict): 检测结果
90
+ status(bool): 是否成功
91
+ """
92
+
93
+ try:
94
+ response = self.client.image_moderation_with_options(
95
+ ImageModerationRequest(
96
+ service=service,
97
+ service_parameters=json.dumps(
98
+ {
99
+ "ossRegionId": oss_region_id,
100
+ "ossBucketName": oss_bucket_name,
101
+ "ossObjectName": oss_object_key,
102
+ }
103
+ ),
104
+ ),
105
+ util_models.RuntimeOptions(read_timeout=10000, connect_timeout=10000),
106
+ )
107
+ return (
108
+ (response.body.to_map(), True)
109
+ if response.status_code == 200
110
+ else ({}, False)
111
+ )
112
+ except Exception as e:
113
+ feishu_alert.send(traceback.format_exc())
114
+ return {}, False
115
+
116
+ def scan_video(
117
+ self, oss_region_id: str, oss_bucket_name: str, oss_object_key: str, service: str = "videoDetection"
118
+ ) -> Union[dict, bool]:
119
+ """
120
+ description:
121
+ 视频内容异步检测
122
+ parameters:
123
+ oss_region_id(str): 视频OSS地域ID
124
+ oss_bucket_name(str): 视频OSS桶名
125
+ oss_object_key(str): 视频OSS对象key
126
+ service(str): 服务类型,默认为"videoDetection"
127
+ return:
128
+ task_id(str): 任务ID
129
+ status(bool): 是否成功
130
+ """
131
+ try:
132
+ response = self.client.video_moderation_with_options(
133
+ VideoModerationRequest(
134
+ service=service,
135
+ service_parameters=json.dumps(
136
+ {
137
+ "ossRegionId": oss_region_id,
138
+ "ossBucketName": oss_bucket_name,
139
+ "ossObjectName": oss_object_key,
140
+ "audioScenes": ["antispam"],
141
+ "scenes": ["porn", "terrorism"],
142
+ "bizType": "default",
143
+ }
144
+ ),
145
+ ),
146
+ util_models.RuntimeOptions(read_timeout=10000, connect_timeout=10000),
147
+ )
148
+ return (
149
+ (response.body.to_map()["Data"]["TaskId"], True)
150
+ if response.status_code == 200
151
+ else ("", False)
152
+ )
153
+ except Exception as e:
154
+ feishu_alert.send(traceback.format_exc())
155
+ return "", False
156
+
157
+ def get_video_result(
158
+ self, task_id: str, service: str = "videoDetection"
159
+ ) -> Union[dict, bool]:
160
+ """
161
+ 描述:
162
+ 获取视频内容检测结果
163
+ 参数:
164
+ task_id(str): 任务ID
165
+ service(str): 服务类型,默认为"videoDetection"
166
+ 返回:
167
+ result(dict): 检测结果
168
+ status(bool): 是否成功
169
+ """
170
+ try:
171
+ response = self.client.video_moderation_result_with_options(
172
+ VideoModerationResultRequest(
173
+ service=service,
174
+ service_parameters=json.dumps({"taskId": task_id}),
175
+ ),
176
+ util_models.RuntimeOptions(read_timeout=10000, connect_timeout=10000),
177
+ )
178
+ return (
179
+ (response.body.to_map(), True)
180
+ if response.status_code == 200
181
+ else ({}, False)
182
+ )
183
+ except Exception as e:
184
+ feishu_alert.send(traceback.format_exc())
185
+ return {}, False
186
+
187
+ def scan_voice(
188
+ self, oss_region_id: str, oss_bucket_name: str, oss_object_key: str, service: str = "audio_media_detection"
189
+ ) -> Union[str, bool]:
190
+ """
191
+ 描述:
192
+ 语音内容检测
193
+ 参数:
194
+ oss_region_id(str): 语音OSS地域ID
195
+ oss_bucket_name(str): 语音OSS桶名
196
+ oss_object_key(str): 语音OSS对象key
197
+ service(str): 服务类型,默认为"audio_media_detection"
198
+ 返回:
199
+ task_id(str): 任务ID
200
+ status(bool): 是否成功
201
+ """
202
+ try:
203
+ response = self.client.voice_moderation_with_options(
204
+ VoiceModerationRequest(
205
+ service=service,
206
+ service_parameters=json.dumps(
207
+ {
208
+ "ossRegionId": oss_region_id,
209
+ "ossBucketName": oss_bucket_name,
210
+ "ossObjectName": oss_object_key,
211
+ }
212
+ ),
213
+ ),
214
+ util_models.RuntimeOptions(read_timeout=10000, connect_timeout=10000),
215
+ )
216
+ return (
217
+ (response.body.to_map()["Data"]["TaskId"], True)
218
+ if response.status_code == 200
219
+ else ("", False)
220
+ )
221
+ except Exception as e:
222
+ feishu_alert.send(traceback.format_exc())
223
+ return "", False
224
+
225
+ def get_voice_result(
226
+ self, task_id: str, service: str = "audio_media_detection"
227
+ ) -> Union[dict, bool]:
228
+ """
229
+ 描述:
230
+ 获取语音内容检测结果
231
+ 参数:
232
+ task_id(str): 任务ID
233
+ service(str): 服务类型,默认为"audio_media_detection"
234
+ 返回:
235
+ result(dict): 检测结果
236
+ status(bool): 是否成功
237
+ """
238
+ try:
239
+ response = self.client.voice_moderation_result_with_options(
240
+ VoiceModerationResultRequest(
241
+ service=service,
242
+ service_parameters=json.dumps({"taskId": task_id}),
243
+ ),
244
+ util_models.RuntimeOptions(read_timeout=10000, connect_timeout=10000),
245
+ )
246
+ return (
247
+ (response.body.to_map(), True)
248
+ if response.status_code == 200
249
+ else ({}, False)
250
+ )
251
+ except Exception as e:
252
+ feishu_alert.send(traceback.format_exc())
253
+ return {}, False
@@ -0,0 +1,434 @@
1
+ from alibabacloud_alidns20150109.client import Client as Alidns20150109Client
2
+ from alibabacloud_tea_openapi import models as open_api_models
3
+ from alibabacloud_alidns20150109 import models as alidns_20150109_models
4
+ from alibabacloud_tea_util import models as util_models
5
+ from typing import Optional, Dict, Any
6
+
7
+
8
+ class DomainUtils:
9
+ def __init__(self, access_key_id: str, access_key_secret: str, domain_name: str):
10
+ self.domain_name = domain_name
11
+ self.client = self._create_client(access_key_id, access_key_secret)
12
+
13
+ def _create_client(
14
+ self, access_key_id: str, access_key_secret: str
15
+ ) -> Alidns20150109Client:
16
+ config = open_api_models.Config(
17
+ access_key_id=access_key_id,
18
+ access_key_secret=access_key_secret,
19
+ )
20
+ config.endpoint = "alidns.cn-hangzhou.aliyuncs.com"
21
+ return Alidns20150109Client(config)
22
+
23
+ def list_domain_records(self) -> tuple[list, bool]:
24
+ """
25
+ description:
26
+ 列出域名解析记录
27
+ return:
28
+ records: 解析记录列表
29
+ success: 操作是否成功
30
+ """
31
+ all_records = []
32
+ page_number = 1
33
+ page_size = 20
34
+ runtime = util_models.RuntimeOptions()
35
+ try:
36
+ while True:
37
+ describe_domain_records_request = (
38
+ alidns_20150109_models.DescribeDomainRecordsRequest(
39
+ domain_name=self.domain_name,
40
+ page_number=page_number,
41
+ page_size=page_size,
42
+ )
43
+ )
44
+ response = self.client.describe_domain_records_with_options(
45
+ describe_domain_records_request, runtime
46
+ )
47
+ records = response.body.domain_records.to_map()["Record"]
48
+ if records:
49
+ all_records.extend(records)
50
+ total_count = getattr(response.body, "total_count", None)
51
+ if total_count is not None:
52
+ if page_number * page_size >= total_count:
53
+ break
54
+ else:
55
+ # 如果没有total_count字段,判断本次返回数量是否小于page_size
56
+ if not records or len(records) < page_size:
57
+ break
58
+ page_number += 1
59
+ return all_records, True
60
+ except Exception as error:
61
+ return [], False
62
+
63
+ async def list_domain_records_async(self) -> tuple[list, bool]:
64
+ """
65
+ description:
66
+ 异步列出域名解析记录
67
+ return:
68
+ records: 解析记录列表
69
+ success: 操作是否成功
70
+ """
71
+ all_records = []
72
+ page_number = 1
73
+ page_size = 20
74
+ runtime = util_models.RuntimeOptions()
75
+ try:
76
+ while True:
77
+ describe_domain_records_request = (
78
+ alidns_20150109_models.DescribeDomainRecordsRequest(
79
+ domain_name=self.domain_name,
80
+ page_number=page_number,
81
+ page_size=page_size,
82
+ )
83
+ )
84
+ response = await self.client.describe_domain_records_with_options_async(
85
+ describe_domain_records_request, runtime
86
+ )
87
+ # 兼容同步接口的处理方式
88
+ records = response.body.domain_records.to_map()["Record"]
89
+ if records:
90
+ all_records.extend(records)
91
+ total_count = getattr(response.body, "total_count", None)
92
+ if total_count is not None:
93
+ if page_number * page_size >= total_count:
94
+ break
95
+ else:
96
+ # 如果没有total_count字段,判断本次返回数量是否小于page_size
97
+ if not records or len(records) < page_size:
98
+ break
99
+ page_number += 1
100
+ return all_records, True
101
+ except Exception as error:
102
+ return [], False
103
+
104
+ def add_domain_record(
105
+ self,
106
+ rr: str,
107
+ type: str,
108
+ value: str,
109
+ ttl: int = 600,
110
+ line: str = "default",
111
+ priority: Optional[int] = None,
112
+ ) -> tuple[bool, str]:
113
+ """
114
+ description:
115
+ 添加域名解析记录
116
+ parameters:
117
+ rr: 主机记录,如 www, @, *
118
+ type: 记录类型,如 A, CNAME, MX, TXT 等
119
+ value: 记录值
120
+ ttl: TTL值,默认600秒
121
+ line: 解析线路,默认default
122
+ priority: 优先级,仅MX记录需要
123
+ return:
124
+ success: 操作是否成功
125
+ record_id: 记录ID
126
+ """
127
+ runtime = util_models.RuntimeOptions()
128
+ try:
129
+ request = alidns_20150109_models.AddDomainRecordRequest(
130
+ domain_name=self.domain_name,
131
+ rr=rr,
132
+ type=type,
133
+ value=value,
134
+ ttl=ttl,
135
+ line=line,
136
+ )
137
+
138
+ if priority is not None:
139
+ request.priority = priority
140
+
141
+ response = self.client.add_domain_record_with_options(request, runtime)
142
+
143
+ if response.body.record_id:
144
+ return True, response.body.record_id
145
+ else:
146
+ return False, None
147
+
148
+ except Exception as error:
149
+ return False, None
150
+
151
+ async def add_domain_record_async(
152
+ self,
153
+ rr: str,
154
+ type: str,
155
+ value: str,
156
+ ttl: int = 600,
157
+ line: str = "default",
158
+ priority: Optional[int] = None,
159
+ ) -> tuple[bool, str]:
160
+ """
161
+ description:
162
+ 异步添加域名解析记录
163
+ parameters:
164
+ rr: 主机记录,如 www, @, *
165
+ type: 记录类型,如 A, CNAME, MX, TXT 等
166
+ value: 记录值
167
+ ttl: TTL值,默认600秒
168
+ line: 解析线路,默认default
169
+ priority: 优先级,仅MX记录需要
170
+ return:
171
+ success: 操作是否成功
172
+ record_id: 记录ID
173
+ """
174
+ runtime = util_models.RuntimeOptions()
175
+ try:
176
+ request = alidns_20150109_models.AddDomainRecordRequest(
177
+ domain_name=self.domain_name,
178
+ rr=rr,
179
+ type=type,
180
+ value=value,
181
+ ttl=ttl,
182
+ line=line,
183
+ )
184
+
185
+ if priority is not None:
186
+ request.priority = priority
187
+
188
+ response = await self.client.add_domain_record_with_options_async(
189
+ request, runtime
190
+ )
191
+
192
+ if response.body.record_id:
193
+ return True, response.body.record_id
194
+ else:
195
+ return False, None
196
+
197
+ except Exception as error:
198
+ return False, None
199
+
200
+ def delete_domain_record(self, record_id: str) -> bool:
201
+ """
202
+ description:
203
+ 删除域名解析记录
204
+ parameters:
205
+ record_id: 记录ID
206
+ return:
207
+ success: 操作是否成功
208
+ """
209
+ runtime = util_models.RuntimeOptions()
210
+ try:
211
+ request = alidns_20150109_models.DeleteDomainRecordRequest(
212
+ record_id=record_id
213
+ )
214
+
215
+ response = self.client.delete_domain_record_with_options(request, runtime)
216
+
217
+ if response.body.request_id:
218
+ return True
219
+ else:
220
+ return False
221
+
222
+ except Exception as error:
223
+ return False
224
+
225
+ async def delete_domain_record_async(self, record_id: str) -> bool:
226
+ """
227
+ description:
228
+ 异步删除域名解析记录
229
+ parameters:
230
+ record_id: 记录ID
231
+ return:
232
+ success: 操作是否成功
233
+ """
234
+ runtime = util_models.RuntimeOptions()
235
+ try:
236
+ request = alidns_20150109_models.DeleteDomainRecordRequest(
237
+ record_id=record_id
238
+ )
239
+
240
+ response = await self.client.delete_domain_record_with_options_async(
241
+ request, runtime
242
+ )
243
+
244
+ if response.body.request_id:
245
+ return True
246
+ else:
247
+ return False
248
+
249
+ except Exception as error:
250
+ return False
251
+
252
+ def update_domain_record(
253
+ self,
254
+ record_id: str,
255
+ rr: str,
256
+ type: str,
257
+ value: str,
258
+ ttl: int = 600,
259
+ line: str = "default",
260
+ priority: Optional[int] = None,
261
+ ) -> tuple[bool, str]:
262
+ """
263
+ description:
264
+ 更新域名解析记录
265
+ parameters:
266
+ record_id: 记录ID
267
+ rr: 主机记录,如 www, @, *
268
+ type: 记录类型,如 A, CNAME, MX, TXT 等
269
+ value: 记录值
270
+ ttl: TTL值,默认600秒
271
+ line: 解析线路,默认default
272
+ priority: 优先级,仅MX记录需要
273
+ return:
274
+ success: 操作是否成功
275
+ record_id: 记录ID
276
+ """
277
+ runtime = util_models.RuntimeOptions()
278
+ try:
279
+ request = alidns_20150109_models.UpdateDomainRecordRequest(
280
+ record_id=record_id,
281
+ rr=rr,
282
+ type=type,
283
+ value=value,
284
+ ttl=ttl,
285
+ line=line,
286
+ )
287
+
288
+ if priority is not None:
289
+ request.priority = priority
290
+
291
+ response = self.client.update_domain_record_with_options(request, runtime)
292
+
293
+ if response.body.record_id:
294
+ return True, response.body.record_id
295
+ else:
296
+ return False, None
297
+
298
+ except Exception as error:
299
+ return False, None
300
+
301
+ async def update_domain_record_async(
302
+ self,
303
+ record_id: str,
304
+ rr: str,
305
+ type: str,
306
+ value: str,
307
+ ttl: int = 600,
308
+ line: str = "default",
309
+ priority: Optional[int] = None,
310
+ ) -> tuple[bool, str]:
311
+ """
312
+ description:
313
+ 异步更新域名解析记录
314
+ parameters:
315
+ record_id: 记录ID
316
+ rr: 主机记录,如 www, @, *
317
+ type: 记录类型,如 A, CNAME, MX, TXT 等
318
+ value: 记录值
319
+ ttl: TTL值,默认600秒
320
+ line: 解析线路,默认default
321
+ priority: 优先级,仅MX记录需要
322
+ return:
323
+ success: 操作是否成功
324
+ record_id: 记录ID
325
+ """
326
+ runtime = util_models.RuntimeOptions()
327
+ try:
328
+ request = alidns_20150109_models.UpdateDomainRecordRequest(
329
+ record_id=record_id,
330
+ rr=rr,
331
+ type=type,
332
+ value=value,
333
+ ttl=ttl,
334
+ line=line,
335
+ )
336
+
337
+ if priority is not None:
338
+ request.priority = priority
339
+
340
+ response = await self.client.update_domain_record_with_options_async(
341
+ request, runtime
342
+ )
343
+
344
+ if response.body.record_id:
345
+ return True, response.body.record_id
346
+ else:
347
+ return False, None
348
+
349
+ except Exception as error:
350
+ return False, None
351
+
352
+ def find_record_by_rr_and_type(
353
+ self, rr: str, type: str
354
+ ) -> Optional[Dict[str, Any]]:
355
+ """
356
+ description:
357
+ 根据主机记录和记录类型查找记录
358
+ parameters:
359
+ rr: 主机记录
360
+ type: 记录类型
361
+ return:
362
+ 找到的记录字典,如果没找到返回None
363
+ """
364
+ records, success = self.list_domain_records()
365
+ if not success:
366
+ return None
367
+
368
+ for record in records:
369
+ if record.get("RR") == rr and record.get("Type") == type:
370
+ return record
371
+ return None
372
+
373
+ async def find_record_by_rr_and_type_async(
374
+ self, rr: str, type: str
375
+ ) -> Optional[Dict[str, Any]]:
376
+ """
377
+ description:
378
+ 异步根据主机记录和记录类型查找记录
379
+ parameters:
380
+ rr: 主机记录
381
+ type: 记录类型
382
+ return:
383
+ 找到的记录字典,如果没找到返回None
384
+ """
385
+ records, success = await self.list_domain_records_async()
386
+ if not success:
387
+ return None
388
+
389
+ for record in records:
390
+ if record.get("RR") == rr and record.get("Type") == type:
391
+ return record
392
+ return None
393
+
394
+ def delete_record_by_rr_and_type(self, rr: str, type: str) -> tuple[bool, str]:
395
+ """
396
+ description:
397
+ 根据主机记录和记录类型删除记录
398
+ parameters:
399
+ rr: 主机记录
400
+ type: 记录类型
401
+ return:
402
+ success: 操作是否成功
403
+ """
404
+ record = self.find_record_by_rr_and_type(rr, type)
405
+ if not record:
406
+ return False
407
+
408
+ record_id = record.get("RecordId")
409
+ if not record_id:
410
+ return False
411
+
412
+ return self.delete_domain_record(record_id)
413
+
414
+ async def delete_record_by_rr_and_type_async(
415
+ self, rr: str, type: str
416
+ ) -> tuple[bool, str]:
417
+ """
418
+ description:
419
+ 异步根据主机记录和记录类型删除记录
420
+ parameters:
421
+ rr: 主机记录
422
+ type: 记录类型
423
+ return:
424
+ success: 操作是否成功
425
+ """
426
+ record = await self.find_record_by_rr_and_type_async(rr, type)
427
+ if not record:
428
+ return False
429
+
430
+ record_id = record.get("RecordId")
431
+ if not record_id:
432
+ return False
433
+
434
+ return await self.delete_domain_record_async(record_id)