Updata:适配调用2.0接口
This commit is contained in:
parent
8d3115d613
commit
62b860726d
171
README.md
171
README.md
@ -1,173 +1,4 @@
|
||||
# 阿里云内容安全2.0 Demo
|
||||
|
||||
这是一个使用Go语言编写的阿里云内容安全2.0服务演示程序,支持对视频、图片和文字进行内容安全审核。
|
||||
阿里云内容安全2.0服务demo,支持对视频、图片和文字进行内容安全审核。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 🖼️ **图片内容安全审核**
|
||||
- 支持通过URL或本地文件进行图片审核
|
||||
- 支持多种图片格式:JPG、PNG、BMP、GIF、WEBP
|
||||
- 检测场景:色情、暴恐、广告、直播、Logo等
|
||||
|
||||
- 📝 **文本内容安全审核**
|
||||
- 支持单条文本和批量文本审核
|
||||
- 检测场景:反垃圾信息
|
||||
- 提供详细的违规内容定位信息
|
||||
|
||||
- 🎥 **视频内容安全审核**
|
||||
- 支持异步和同步视频审核
|
||||
- 自动截帧分析
|
||||
- 提供帧级别的违规内容定位
|
||||
|
||||
## 环境要求
|
||||
|
||||
- Go 1.21 或更高版本
|
||||
- 阿里云账号并开通内容安全2.0服务
|
||||
- 有效的阿里云AccessKey
|
||||
|
||||
## 安装和配置
|
||||
|
||||
### 1. 克隆项目
|
||||
|
||||
```bash
|
||||
git clone <your-repo-url>
|
||||
cd content-security-demo
|
||||
```
|
||||
|
||||
### 2. 安装依赖
|
||||
|
||||
```bash
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
### 3. 配置阿里云AccessKey
|
||||
|
||||
有两种方式配置AccessKey:
|
||||
|
||||
#### 方式一:使用环境变量
|
||||
|
||||
```bash
|
||||
export ALIBABA_CLOUD_ACCESS_KEY_ID="your_access_key_id"
|
||||
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="your_access_key_secret"
|
||||
```
|
||||
|
||||
#### 方式二:使用.env文件
|
||||
|
||||
1. 复制配置文件:
|
||||
```bash
|
||||
cp env.example .env
|
||||
```
|
||||
|
||||
2. 编辑`.env`文件,填入您的AccessKey信息:
|
||||
```env
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID=your_access_key_id_here
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your_access_key_secret_here
|
||||
ALIBABA_CLOUD_REGION=cn-shanghai
|
||||
ALIBABA_CLOUD_ENDPOINT=green.cn-shanghai.aliyuncs.com
|
||||
```
|
||||
|
||||
### 4. 运行程序
|
||||
|
||||
```bash
|
||||
go run .
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
运行程序后,会显示交互式菜单:
|
||||
|
||||
```
|
||||
=== 阿里云内容安全2.0 Demo ===
|
||||
支持视频、图片、文字内容安全审核
|
||||
|
||||
请选择要测试的功能:
|
||||
1. 图片内容安全审核
|
||||
2. 文本内容安全审核
|
||||
3. 视频内容安全审核
|
||||
4. 退出
|
||||
```
|
||||
|
||||
### 图片审核
|
||||
|
||||
- **通过URL审核**:输入图片的公开URL地址
|
||||
- **通过文件审核**:输入本地图片文件的完整路径
|
||||
|
||||
支持的图片格式:JPG、JPEG、PNG、BMP、GIF、WEBP
|
||||
文件大小限制:最大9MB
|
||||
|
||||
### 文本审核
|
||||
|
||||
- **单条文本**:输入一段文本进行审核
|
||||
- **批量文本**:输入多行文本,每行一条,空行结束
|
||||
|
||||
### 视频审核
|
||||
|
||||
- **异步扫描**:提交任务后立即返回任务ID,可稍后查询结果
|
||||
- **同步扫描**:等待审核完成并返回结果(可能需要几分钟)
|
||||
|
||||
## 审核结果说明
|
||||
|
||||
### 建议类型
|
||||
- `pass`:通过
|
||||
- `review`:需要人工审核
|
||||
- `block`:拒绝
|
||||
|
||||
### 检测场景
|
||||
- `porn`:色情内容
|
||||
- `terrorism`:暴恐内容
|
||||
- `ad`:广告内容
|
||||
- `live`:直播内容
|
||||
- `logo`:Logo识别
|
||||
- `antispam`:反垃圾信息
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
.
|
||||
├── main.go # 主程序入口
|
||||
├── config.go # 配置管理
|
||||
├── image_scanner.go # 图片审核功能
|
||||
├── text_scanner.go # 文本审核功能
|
||||
├── video_scanner.go # 视频审核功能
|
||||
├── go.mod # Go模块文件
|
||||
├── env.example # 环境变量示例
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **费用说明**:阿里云内容安全服务按调用次数计费,请查看[官方定价](https://www.alibabacloud.com/help/zh/content-moderation/latest/billing-overview)
|
||||
|
||||
2. **权限配置**:建议为RAM用户创建AccessKey,并授予`AliyunYundunGreenWebFullAccess`权限
|
||||
|
||||
3. **文件限制**:
|
||||
- 图片:最大9MB,建议分辨率大于256×256像素
|
||||
- 视频:支持多种格式,建议使用异步审核
|
||||
|
||||
4. **网络要求**:需要能够访问阿里云服务端点
|
||||
|
||||
## 错误处理
|
||||
|
||||
程序包含完善的错误处理机制:
|
||||
- 配置验证
|
||||
- 网络请求错误处理
|
||||
- 文件格式和大小验证
|
||||
- API响应解析错误处理
|
||||
|
||||
## 扩展功能
|
||||
|
||||
可以根据需要扩展以下功能:
|
||||
- 添加更多检测场景
|
||||
- 实现结果缓存机制
|
||||
- 添加批量处理功能
|
||||
- 集成到Web服务中
|
||||
|
||||
## 技术支持
|
||||
|
||||
如有问题,请参考:
|
||||
- [阿里云内容安全官方文档](https://www.alibabacloud.com/help/zh/content-moderation/)
|
||||
- [Go SDK文档](https://github.com/aliyun/alibaba-cloud-sdk-go)
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
|
160
cmd/main.go
160
cmd/main.go
@ -25,31 +25,69 @@ func main() {
|
||||
|
||||
// 显示配置信息(隐藏敏感信息)
|
||||
fmt.Printf("✅ 配置加载成功\n")
|
||||
fmt.Printf(" 登录模式: %s\n", config.LoginMode)
|
||||
fmt.Printf(" 区域: %s\n", config.Region)
|
||||
fmt.Printf(" 端点: %s\n", config.Endpoint)
|
||||
if config.AccessKeyID != "" {
|
||||
fmt.Printf(" AccessKey ID: %s...\n", config.AccessKeyID[:8])
|
||||
}
|
||||
if config.AccessKeySecret != "" {
|
||||
fmt.Printf(" AccessKey Secret: %s...\n", config.AccessKeySecret[:8])
|
||||
|
||||
if config.LoginMode == "sts" {
|
||||
fmt.Printf(" RAM AccessKey ID: %s...\n", config.RAMAccessKeyID[:8])
|
||||
fmt.Printf(" RAM角色ARN: %s\n", config.RAMRoleArn)
|
||||
} else {
|
||||
if config.AccessKeyID != "" {
|
||||
fmt.Printf(" AccessKey ID: %s...\n", config.AccessKeyID[:8])
|
||||
}
|
||||
if config.AccessKeySecret != "" {
|
||||
fmt.Printf(" AccessKey Secret: %s...\n", config.AccessKeySecret[:8])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// 检查必要的配置
|
||||
if config.AccessKeyID == "" || config.AccessKeySecret == "" {
|
||||
fmt.Println("❌ 缺少必要的配置信息:")
|
||||
if config.AccessKeyID == "" {
|
||||
fmt.Println(" - ALIBABA_CLOUD_ACCESS_KEY_ID 未设置")
|
||||
if config.LoginMode == "sts" {
|
||||
// STS模式检查
|
||||
if config.RAMAccessKeyID == "" || config.RAMAccessKeySecret == "" || config.RAMRoleArn == "" {
|
||||
fmt.Println("❌ STS模式缺少必要的配置信息:")
|
||||
if config.RAMAccessKeyID == "" {
|
||||
fmt.Println(" - RAM_ACCESS_KEY_ID 未设置")
|
||||
}
|
||||
if config.RAMAccessKeySecret == "" {
|
||||
fmt.Println(" - RAM_ACCESS_KEY_SECRET 未设置")
|
||||
}
|
||||
if config.RAMRoleArn == "" {
|
||||
fmt.Println(" - RAM_ROLE_ARN 未设置")
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Println("请检查以下配置文件:")
|
||||
fmt.Println(" - .env")
|
||||
fmt.Println(" - conf/alibabacloud.env")
|
||||
fmt.Println(" - 环境变量")
|
||||
return
|
||||
}
|
||||
if config.AccessKeySecret == "" {
|
||||
fmt.Println(" - ALIBABA_CLOUD_ACCESS_KEY_SECRET 未设置")
|
||||
|
||||
// 获取STS临时凭证
|
||||
fmt.Println("正在获取STS临时凭证...")
|
||||
if err := config.GetSTSToken(); err != nil {
|
||||
fmt.Printf("❌ 获取STS临时凭证失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("✅ STS临时凭证获取成功")
|
||||
} else {
|
||||
// 直接模式检查
|
||||
if config.AccessKeyID == "" || config.AccessKeySecret == "" {
|
||||
fmt.Println("❌ 直接模式缺少必要的配置信息:")
|
||||
if config.AccessKeyID == "" {
|
||||
fmt.Println(" - ALIBABA_CLOUD_ACCESS_KEY_ID 未设置")
|
||||
}
|
||||
if config.AccessKeySecret == "" {
|
||||
fmt.Println(" - ALIBABA_CLOUD_ACCESS_KEY_SECRET 未设置")
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Println("请检查以下配置文件:")
|
||||
fmt.Println(" - .env")
|
||||
fmt.Println(" - conf/alibabacloud.env")
|
||||
fmt.Println(" - 环境变量")
|
||||
return
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Println("请检查以下配置文件:")
|
||||
fmt.Println(" - .env")
|
||||
fmt.Println(" - conf/alibabacloud.env")
|
||||
fmt.Println(" - 环境变量")
|
||||
return
|
||||
}
|
||||
|
||||
// 显示菜单
|
||||
@ -85,7 +123,7 @@ func showMenu() {
|
||||
}
|
||||
|
||||
func handleImageScan(config *conf.Config) {
|
||||
fmt.Println("\n=== 图片内容安全审核 ===")
|
||||
fmt.Println("\n=== 图片内容安全审核(2.0版本)===")
|
||||
|
||||
scanner, err := api.NewImageScanner(config)
|
||||
if err != nil {
|
||||
@ -93,7 +131,31 @@ func handleImageScan(config *conf.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("请选择图片输入方式:")
|
||||
// 选择服务类型
|
||||
fmt.Println("请选择图片审核服务类型:")
|
||||
fmt.Println("1. 通用基线检测(baselineCheck_global)")
|
||||
fmt.Println("2. 大小模型融合图片审核服务(postImageCheckByVL_global)")
|
||||
fmt.Println("3. AI生成图片鉴别(aigcDetector_global)")
|
||||
|
||||
serviceChoice := getUserInput("请选择服务类型 (1-3): ")
|
||||
var serviceType api.ImageServiceType
|
||||
|
||||
switch serviceChoice {
|
||||
case "1":
|
||||
serviceType = api.BaselineCheckGlobal
|
||||
fmt.Println("✅ 已选择:通用基线检测")
|
||||
case "2":
|
||||
serviceType = api.PostImageCheckByVLGlobal
|
||||
fmt.Println("✅ 已选择:大小模型融合图片审核服务")
|
||||
case "3":
|
||||
serviceType = api.AigcDetectorGlobal
|
||||
fmt.Println("✅ 已选择:AI生成图片鉴别")
|
||||
default:
|
||||
fmt.Println("❌ 无效选择")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\n请选择图片输入方式:")
|
||||
fmt.Println("1. 通过URL")
|
||||
fmt.Println("2. 通过本地文件")
|
||||
|
||||
@ -108,7 +170,7 @@ func handleImageScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
fmt.Println("正在扫描图片...")
|
||||
result, err := scanner.ScanImageByURL(url, "image_"+time.Now().Format("20060102150405"))
|
||||
result, err := scanner.ScanImageByURL(url, "image_"+time.Now().Format("20060102150405"), serviceType)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 扫描失败: %v\n", err)
|
||||
return
|
||||
@ -123,7 +185,7 @@ func handleImageScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
fmt.Println("正在扫描图片...")
|
||||
result, err := scanner.ScanImageByFile(filePath, "image_"+time.Now().Format("20060102150405"))
|
||||
result, err := scanner.ScanImageByFile(filePath, "image_"+time.Now().Format("20060102150405"), serviceType)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 扫描失败: %v\n", err)
|
||||
return
|
||||
@ -136,7 +198,7 @@ func handleImageScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
func handleTextScan(config *conf.Config) {
|
||||
fmt.Println("\n=== 文本内容安全审核 ===")
|
||||
fmt.Println("\n=== 文本内容安全审核(2.0版本)===")
|
||||
|
||||
scanner, err := api.NewTextScanner(config)
|
||||
if err != nil {
|
||||
@ -144,7 +206,27 @@ func handleTextScan(config *conf.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("请选择文本输入方式:")
|
||||
// 选择服务类型
|
||||
fmt.Println("请选择文本审核服务类型:")
|
||||
fmt.Println("1. 通用基线检测(baselineCheck_global)")
|
||||
fmt.Println("2. 大小模型融合文本审核服务(postTextCheckByVL_global)")
|
||||
|
||||
serviceChoice := getUserInput("请选择服务类型 (1-2): ")
|
||||
var serviceType api.TextServiceType
|
||||
|
||||
switch serviceChoice {
|
||||
case "1":
|
||||
serviceType = api.TextBaselineCheckGlobal
|
||||
fmt.Println("✅ 已选择:通用基线检测")
|
||||
case "2":
|
||||
serviceType = api.TextPostCheckByVLGlobal
|
||||
fmt.Println("✅ 已选择:大小模型融合文本审核服务")
|
||||
default:
|
||||
fmt.Println("❌ 无效选择")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\n请选择文本输入方式:")
|
||||
fmt.Println("1. 单条文本")
|
||||
fmt.Println("2. 批量文本")
|
||||
|
||||
@ -159,7 +241,7 @@ func handleTextScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
fmt.Println("正在扫描文本...")
|
||||
result, err := scanner.ScanText(text, "text_"+time.Now().Format("20060102150405"))
|
||||
result, err := scanner.ScanText(text, "text_"+time.Now().Format("20060102150405"), serviceType)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 扫描失败: %v\n", err)
|
||||
return
|
||||
@ -186,7 +268,7 @@ func handleTextScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
fmt.Printf("正在批量扫描 %d 条文本...\n", len(texts))
|
||||
result, err := scanner.ScanTextBatch(texts, dataIDs)
|
||||
result, err := scanner.ScanTextBatch(texts, dataIDs, serviceType)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 扫描失败: %v\n", err)
|
||||
return
|
||||
@ -199,7 +281,7 @@ func handleTextScan(config *conf.Config) {
|
||||
}
|
||||
|
||||
func handleVideoScan(config *conf.Config) {
|
||||
fmt.Println("\n=== 视频内容安全审核 ===")
|
||||
fmt.Println("\n=== 视频内容安全审核(2.0版本)===")
|
||||
|
||||
scanner, err := api.NewVideoScanner(config)
|
||||
if err != nil {
|
||||
@ -207,7 +289,27 @@ func handleVideoScan(config *conf.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("请选择视频审核方式:")
|
||||
// 选择服务类型
|
||||
fmt.Println("请选择视频审核服务类型:")
|
||||
fmt.Println("1. 通用基线检测(baselineCheck_global)")
|
||||
fmt.Println("2. 大小模型融合视频审核服务(postVideoCheckByVL_global)")
|
||||
|
||||
serviceChoice := getUserInput("请选择服务类型 (1-2): ")
|
||||
var serviceType api.VideoServiceType
|
||||
|
||||
switch serviceChoice {
|
||||
case "1":
|
||||
serviceType = api.VideoBaselineCheckGlobal
|
||||
fmt.Println("✅ 已选择:通用基线检测")
|
||||
case "2":
|
||||
serviceType = api.VideoPostCheckByVLGlobal
|
||||
fmt.Println("✅ 已选择:大小模型融合视频审核服务")
|
||||
default:
|
||||
fmt.Println("❌ 无效选择")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\n请选择视频审核方式:")
|
||||
fmt.Println("1. 异步扫描(提交任务后立即返回)")
|
||||
fmt.Println("2. 同步扫描(等待结果返回)")
|
||||
|
||||
@ -224,7 +326,7 @@ func handleVideoScan(config *conf.Config) {
|
||||
switch choice {
|
||||
case "1":
|
||||
fmt.Println("正在提交视频扫描任务...")
|
||||
result, err := scanner.ScanVideoAsync(videoURL, dataID)
|
||||
result, err := scanner.ScanVideoAsync(videoURL, dataID, serviceType)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 提交任务失败: %v\n", err)
|
||||
return
|
||||
@ -237,7 +339,7 @@ func handleVideoScan(config *conf.Config) {
|
||||
|
||||
case "2":
|
||||
fmt.Println("正在扫描视频(这可能需要几分钟)...")
|
||||
result, err := scanner.ScanVideoAndWait(videoURL, dataID, 10*time.Minute)
|
||||
result, err := scanner.ScanVideoAndWait(videoURL, dataID, serviceType, 10*time.Minute)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 扫描失败: %v\n", err)
|
||||
return
|
||||
|
@ -1,9 +1,23 @@
|
||||
#=========== 阿里云内容安全配置 ===========
|
||||
# 登录模式:direct(直接使用AccessKey)或 sts(使用STS临时凭证)
|
||||
LOGIN_MODE=sts
|
||||
|
||||
# 直接登录模式配置
|
||||
# 阿里云AccessKey ID
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID=your_access_key_id_here
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI5tNBzbeEbG1yCitvHsMb
|
||||
|
||||
# 阿里云AccessKey Secret
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your_access_key_secret_here
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET=G1xAUB8G6WDVo0SLr6DJaJjNWIlpmO
|
||||
|
||||
# STS登录模式配置
|
||||
# RAM用户AccessKey ID(用于获取STS临时凭证)
|
||||
RAM_ACCESS_KEY_ID=LTAI5tNBzbeEbG1yCitvHsMb
|
||||
|
||||
# RAM用户AccessKey Secret
|
||||
RAM_ACCESS_KEY_SECRET=G1xAUB8G6WDVo0SLr6DJaJjNWIlpmO
|
||||
|
||||
# 要扮演的RAM角色ARN
|
||||
RAM_ROLE_ARN=acs:ram::5828544250383902:role/content-secret
|
||||
|
||||
# 阿里云区域(可选,默认为cn-shanghai)
|
||||
ALIBABA_CLOUD_REGION=cn-shanghai
|
||||
|
@ -3,17 +3,33 @@ package conf
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
// Config 配置结构体
|
||||
type Config struct {
|
||||
// 登录模式
|
||||
LoginMode string
|
||||
|
||||
// 直接登录模式配置
|
||||
AccessKeyID string
|
||||
AccessKeySecret string
|
||||
Region string
|
||||
Endpoint string
|
||||
|
||||
// STS登录模式配置
|
||||
RAMAccessKeyID string
|
||||
RAMAccessKeySecret string
|
||||
RAMRoleArn string
|
||||
|
||||
// 通用配置
|
||||
Region string
|
||||
Endpoint string
|
||||
|
||||
// STS临时凭证(运行时获取)
|
||||
TempAccessKeyID string
|
||||
TempAccessKeySecret string
|
||||
SecurityToken string
|
||||
}
|
||||
|
||||
// LoadConfig 加载配置
|
||||
@ -34,10 +50,14 @@ func LoadConfig() (*Config, error) {
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
AccessKeyID: getEnv("ALIBABA_CLOUD_ACCESS_KEY_ID", ""),
|
||||
AccessKeySecret: getEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", ""),
|
||||
Region: getEnv("ALIBABA_CLOUD_REGION", "cn-shanghai"),
|
||||
Endpoint: getEnv("ALIBABA_CLOUD_ENDPOINT", "green.cn-shanghai.aliyuncs.com"),
|
||||
LoginMode: getEnv("LOGIN_MODE", "direct"),
|
||||
AccessKeyID: getEnv("ALIBABA_CLOUD_ACCESS_KEY_ID", ""),
|
||||
AccessKeySecret: getEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", ""),
|
||||
RAMAccessKeyID: getEnv("RAM_ACCESS_KEY_ID", ""),
|
||||
RAMAccessKeySecret: getEnv("RAM_ACCESS_KEY_SECRET", ""),
|
||||
RAMRoleArn: getEnv("RAM_ROLE_ARN", ""),
|
||||
Region: getEnv("ALIBABA_CLOUD_REGION", "cn-shanghai"),
|
||||
Endpoint: getEnv("ALIBABA_CLOUD_ENDPOINT", "green-v2.cn-shanghai.aliyuncs.com"), // 2.0版本端点
|
||||
}
|
||||
|
||||
return config, nil
|
||||
@ -53,10 +73,14 @@ func LoadConfigFromFile(configFile string) (*Config, error) {
|
||||
fmt.Printf("成功加载配置文件: %s\n", configFile)
|
||||
|
||||
config := &Config{
|
||||
AccessKeyID: getEnv("ALIBABA_CLOUD_ACCESS_KEY_ID", ""),
|
||||
AccessKeySecret: getEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", ""),
|
||||
Region: getEnv("ALIBABA_CLOUD_REGION", "cn-shanghai"),
|
||||
Endpoint: getEnv("ALIBABA_CLOUD_ENDPOINT", "green.cn-shanghai.aliyuncs.com"),
|
||||
LoginMode: getEnv("LOGIN_MODE", "direct"),
|
||||
AccessKeyID: getEnv("ALIBABA_CLOUD_ACCESS_KEY_ID", ""),
|
||||
AccessKeySecret: getEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", ""),
|
||||
RAMAccessKeyID: getEnv("RAM_ACCESS_KEY_ID", ""),
|
||||
RAMAccessKeySecret: getEnv("RAM_ACCESS_KEY_SECRET", ""),
|
||||
RAMRoleArn: getEnv("RAM_ROLE_ARN", ""),
|
||||
Region: getEnv("ALIBABA_CLOUD_REGION", "cn-shanghai"),
|
||||
Endpoint: getEnv("ALIBABA_CLOUD_ENDPOINT", "green-v2.cn-shanghai.aliyuncs.com"), // 2.0版本端点
|
||||
}
|
||||
|
||||
return config, nil
|
||||
@ -70,12 +94,44 @@ func getEnv(key, defaultValue string) string {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getEnvAsInt 获取环境变量并转换为整数
|
||||
func getEnvAsInt(key string, defaultValue int) int {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
if intValue, err := strconv.Atoi(value); err == nil {
|
||||
return intValue
|
||||
}
|
||||
// GetSTSToken 获取STS临时凭证
|
||||
func (c *Config) GetSTSToken() error {
|
||||
if c.LoginMode != "sts" {
|
||||
return nil // 非STS模式,不需要获取临时凭证
|
||||
}
|
||||
return defaultValue
|
||||
|
||||
// 创建STS客户端
|
||||
stsClient, err := sts.NewClientWithAccessKey(c.Region, c.RAMAccessKeyID, c.RAMAccessKeySecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建STS客户端失败: %w", err)
|
||||
}
|
||||
|
||||
// 构造AssumeRole请求
|
||||
request := sts.CreateAssumeRoleRequest()
|
||||
request.Scheme = "https"
|
||||
request.RoleArn = c.RAMRoleArn
|
||||
request.RoleSessionName = "content-security-session" // 会话名称可自定义
|
||||
|
||||
// 调用接口获取凭证
|
||||
response, err := stsClient.AssumeRole(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取临时凭证失败: %w", err)
|
||||
}
|
||||
|
||||
// 保存临时凭证
|
||||
c.TempAccessKeyID = response.Credentials.AccessKeyId
|
||||
c.TempAccessKeySecret = response.Credentials.AccessKeySecret
|
||||
c.SecurityToken = response.Credentials.SecurityToken
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEffectiveCredentials 获取有效的访问凭证
|
||||
func (c *Config) GetEffectiveCredentials() (accessKeyID, accessKeySecret, securityToken string) {
|
||||
if c.LoginMode == "sts" && c.TempAccessKeyID != "" {
|
||||
// 使用STS临时凭证
|
||||
return c.TempAccessKeyID, c.TempAccessKeySecret, c.SecurityToken
|
||||
}
|
||||
// 使用直接凭证
|
||||
return c.AccessKeyID, c.AccessKeySecret, ""
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -3,6 +3,10 @@ module contentSecurityDemo
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.4
|
||||
github.com/alibabacloud-go/green-20220302/v2 v2.0.0
|
||||
github.com/alibabacloud-go/tea v1.2.1
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.1
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.706
|
||||
github.com/joho/godotenv v1.5.1
|
||||
)
|
||||
|
@ -15,15 +15,40 @@ import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/green"
|
||||
)
|
||||
|
||||
// ImageScanner 图片内容安全扫描器
|
||||
// ImageScanner 图片内容安全扫描器2.0
|
||||
type ImageScanner struct {
|
||||
Client *green.Client
|
||||
Config *conf.Config
|
||||
}
|
||||
|
||||
// ImageServiceType 图片审核服务类型
|
||||
type ImageServiceType string
|
||||
|
||||
const (
|
||||
// BaselineCheckGlobal 通用基线检测
|
||||
BaselineCheckGlobal ImageServiceType = "baselineCheck_global"
|
||||
// PostImageCheckByVLGlobal 大小模型融合图片审核服务
|
||||
PostImageCheckByVLGlobal ImageServiceType = "postImageCheckByVL_global"
|
||||
// AigcDetectorGlobal AI生成图片鉴别
|
||||
AigcDetectorGlobal ImageServiceType = "aigcDetector_global"
|
||||
)
|
||||
|
||||
// NewImageScanner 创建图片扫描器
|
||||
func NewImageScanner(config *conf.Config) (*ImageScanner, error) {
|
||||
client, err := green.NewClientWithAccessKey(config.Region, config.AccessKeyID, config.AccessKeySecret)
|
||||
// 获取有效的访问凭证
|
||||
accessKeyID, accessKeySecret, securityToken := config.GetEffectiveCredentials()
|
||||
|
||||
var client *green.Client
|
||||
var err error
|
||||
|
||||
if securityToken != "" {
|
||||
// 使用STS临时凭证
|
||||
client, err = green.NewClientWithStsToken(config.Region, accessKeyID, accessKeySecret, securityToken)
|
||||
} else {
|
||||
// 使用直接凭证
|
||||
client, err = green.NewClientWithAccessKey(config.Region, accessKeyID, accessKeySecret)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建客户端失败: %v", err)
|
||||
}
|
||||
@ -34,13 +59,13 @@ func NewImageScanner(config *conf.Config) (*ImageScanner, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScanImageByURL 通过URL扫描图片
|
||||
func (s *ImageScanner) ScanImageByURL(imageURL string, dataID string) (*model.ImageScanResponse, error) {
|
||||
// ScanImageByURL 通过URL扫描图片(2.0版本)
|
||||
func (s *ImageScanner) ScanImageByURL(imageURL string, dataID string, serviceType ImageServiceType) (*model.ImageScanResponse, error) {
|
||||
request := requests.NewCommonRequest()
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0图片审核API版本
|
||||
request.ApiName = "ImageSyncScan"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -51,7 +76,7 @@ func (s *ImageScanner) ScanImageByURL(imageURL string, dataID string) (*model.Im
|
||||
URL: imageURL,
|
||||
},
|
||||
},
|
||||
Scenes: []string{"porn", "terrorism", "ad", "live", "logo"},
|
||||
Services: []string{string(serviceType)}, // 使用服务类型而不是场景
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(scanRequest)
|
||||
@ -74,8 +99,8 @@ func (s *ImageScanner) ScanImageByURL(imageURL string, dataID string) (*model.Im
|
||||
return &scanResponse, nil
|
||||
}
|
||||
|
||||
// ScanImageByFile 通过文件扫描图片
|
||||
func (s *ImageScanner) ScanImageByFile(filePath string, dataID string) (*model.ImageScanResponse, error) {
|
||||
// ScanImageByFile 通过文件扫描图片(2.0版本)
|
||||
func (s *ImageScanner) ScanImageByFile(filePath string, dataID string, serviceType ImageServiceType) (*model.ImageScanResponse, error) {
|
||||
// 读取文件
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
@ -99,9 +124,9 @@ func (s *ImageScanner) ScanImageByFile(filePath string, dataID string) (*model.I
|
||||
return nil, fmt.Errorf("读取文件失败: %v", err)
|
||||
}
|
||||
|
||||
// 检查文件类型
|
||||
// 检查文件类型 - 2.0版本支持更多格式
|
||||
ext := strings.ToLower(filepath.Ext(filePath))
|
||||
supportedExts := []string{".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp"}
|
||||
supportedExts := []string{".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp", ".tiff", ".svg", ".ico", ".heic"}
|
||||
isSupported := false
|
||||
for _, supportedExt := range supportedExts {
|
||||
if ext == supportedExt {
|
||||
@ -122,7 +147,7 @@ func (s *ImageScanner) ScanImageByFile(filePath string, dataID string) (*model.I
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0图片审核API版本
|
||||
request.ApiName = "ImageSyncScan"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -133,7 +158,7 @@ func (s *ImageScanner) ScanImageByFile(filePath string, dataID string) (*model.I
|
||||
Content: base64Content,
|
||||
},
|
||||
},
|
||||
Scenes: []string{"porn", "terrorism", "ad", "live", "logo"},
|
||||
Services: []string{string(serviceType)}, // 使用服务类型而不是场景
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(scanRequest)
|
||||
@ -156,9 +181,9 @@ func (s *ImageScanner) ScanImageByFile(filePath string, dataID string) (*model.I
|
||||
return &scanResponse, nil
|
||||
}
|
||||
|
||||
// PrintResult 打印扫描结果
|
||||
// PrintResult 打印扫描结果(2.0版本)
|
||||
func (s *ImageScanner) PrintResult(response *model.ImageScanResponse) {
|
||||
fmt.Println("=== 图片内容安全审核结果 ===")
|
||||
fmt.Println("=== 图片内容安全审核结果(2.0版本)===")
|
||||
fmt.Printf("状态码: %d\n", response.Code)
|
||||
fmt.Printf("消息: %s\n", response.Message)
|
||||
|
||||
@ -174,8 +199,30 @@ func (s *ImageScanner) PrintResult(response *model.ImageScanResponse) {
|
||||
for _, result := range data.Results {
|
||||
fmt.Printf("场景: %s\n", result.Scene)
|
||||
fmt.Printf("标签: %s\n", result.Label)
|
||||
if result.SubLabel != "" {
|
||||
fmt.Printf("子标签: %s\n", result.SubLabel)
|
||||
}
|
||||
fmt.Printf("建议: %s\n", result.Suggestion)
|
||||
fmt.Printf("置信度: %.2f\n", result.Rate)
|
||||
|
||||
// 打印详细信息
|
||||
if len(result.Details) > 0 {
|
||||
fmt.Println("详细信息:")
|
||||
for _, detail := range result.Details {
|
||||
fmt.Printf(" 内容: %s\n", detail.Context.Context)
|
||||
if len(detail.Context.Pos) > 0 {
|
||||
fmt.Printf(" 位置: %v\n", detail.Context.Pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打印扩展信息
|
||||
if len(result.Extras) > 0 {
|
||||
fmt.Println("扩展信息:")
|
||||
for key, value := range result.Extras {
|
||||
fmt.Printf(" %s: %v\n", key, value)
|
||||
}
|
||||
}
|
||||
fmt.Println("---")
|
||||
}
|
||||
}
|
||||
|
@ -11,15 +11,38 @@ import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/green"
|
||||
)
|
||||
|
||||
// TextScanner 文本内容安全扫描器
|
||||
// TextScanner 文本内容安全扫描器2.0
|
||||
type TextScanner struct {
|
||||
Client *green.Client
|
||||
Config *conf.Config
|
||||
}
|
||||
|
||||
// TextServiceType 文本审核服务类型
|
||||
type TextServiceType string
|
||||
|
||||
const (
|
||||
// TextBaselineCheckGlobal 文本通用基线检测
|
||||
TextBaselineCheckGlobal TextServiceType = "baselineCheck_global"
|
||||
// TextPostCheckByVLGlobal 文本大小模型融合审核服务
|
||||
TextPostCheckByVLGlobal TextServiceType = "postTextCheckByVL_global"
|
||||
)
|
||||
|
||||
// NewTextScanner 创建文本扫描器
|
||||
func NewTextScanner(config *conf.Config) (*TextScanner, error) {
|
||||
client, err := green.NewClientWithAccessKey(config.Region, config.AccessKeyID, config.AccessKeySecret)
|
||||
// 获取有效的访问凭证
|
||||
accessKeyID, accessKeySecret, securityToken := config.GetEffectiveCredentials()
|
||||
|
||||
var client *green.Client
|
||||
var err error
|
||||
|
||||
if securityToken != "" {
|
||||
// 使用STS临时凭证
|
||||
client, err = green.NewClientWithStsToken(config.Region, accessKeyID, accessKeySecret, securityToken)
|
||||
} else {
|
||||
// 使用直接凭证
|
||||
client, err = green.NewClientWithAccessKey(config.Region, accessKeyID, accessKeySecret)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建客户端失败: %v", err)
|
||||
}
|
||||
@ -30,13 +53,13 @@ func NewTextScanner(config *conf.Config) (*TextScanner, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScanText 扫描文本内容
|
||||
func (s *TextScanner) ScanText(content string, dataID string) (*model.TextScanResponse, error) {
|
||||
// ScanText 扫描文本内容(2.0版本)
|
||||
func (s *TextScanner) ScanText(content string, dataID string, serviceType TextServiceType) (*model.TextScanResponse, error) {
|
||||
request := requests.NewCommonRequest()
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0文本审核API版本
|
||||
request.ApiName = "TextScan"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -47,7 +70,7 @@ func (s *TextScanner) ScanText(content string, dataID string) (*model.TextScanRe
|
||||
Content: content,
|
||||
},
|
||||
},
|
||||
Scenes: []string{"antispam"},
|
||||
Services: []string{string(serviceType)}, // 使用服务类型而不是场景
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(scanRequest)
|
||||
@ -70,8 +93,8 @@ func (s *TextScanner) ScanText(content string, dataID string) (*model.TextScanRe
|
||||
return &scanResponse, nil
|
||||
}
|
||||
|
||||
// ScanTextBatch 批量扫描文本内容
|
||||
func (s *TextScanner) ScanTextBatch(texts []string, dataIDs []string) (*model.TextScanResponse, error) {
|
||||
// ScanTextBatch 批量扫描文本内容(2.0版本)
|
||||
func (s *TextScanner) ScanTextBatch(texts []string, dataIDs []string, serviceType TextServiceType) (*model.TextScanResponse, error) {
|
||||
if len(texts) != len(dataIDs) {
|
||||
return nil, fmt.Errorf("文本数量和ID数量不匹配")
|
||||
}
|
||||
@ -80,7 +103,7 @@ func (s *TextScanner) ScanTextBatch(texts []string, dataIDs []string) (*model.Te
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0文本审核API版本
|
||||
request.ApiName = "TextScan"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -93,8 +116,8 @@ func (s *TextScanner) ScanTextBatch(texts []string, dataIDs []string) (*model.Te
|
||||
}
|
||||
|
||||
scanRequest := model.TextScanRequest{
|
||||
Tasks: tasks,
|
||||
Scenes: []string{"antispam"},
|
||||
Tasks: tasks,
|
||||
Services: []string{string(serviceType)}, // 使用服务类型而不是场景
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(scanRequest)
|
||||
@ -117,9 +140,9 @@ func (s *TextScanner) ScanTextBatch(texts []string, dataIDs []string) (*model.Te
|
||||
return &scanResponse, nil
|
||||
}
|
||||
|
||||
// PrintResult 打印扫描结果
|
||||
// PrintResult 打印扫描结果(2.0版本)
|
||||
func (s *TextScanner) PrintResult(response *model.TextScanResponse) {
|
||||
fmt.Println("=== 文本内容安全审核结果 ===")
|
||||
fmt.Println("=== 文本内容安全审核结果(2.0版本)===")
|
||||
fmt.Printf("状态码: %d\n", response.Code)
|
||||
fmt.Printf("消息: %s\n", response.Message)
|
||||
|
||||
@ -135,6 +158,9 @@ func (s *TextScanner) PrintResult(response *model.TextScanResponse) {
|
||||
for _, result := range data.Results {
|
||||
fmt.Printf("场景: %s\n", result.Scene)
|
||||
fmt.Printf("标签: %s\n", result.Label)
|
||||
if result.SubLabel != "" {
|
||||
fmt.Printf("子标签: %s\n", result.SubLabel)
|
||||
}
|
||||
fmt.Printf("建议: %s\n", result.Suggestion)
|
||||
fmt.Printf("置信度: %.2f\n", result.Rate)
|
||||
|
||||
@ -143,7 +169,17 @@ func (s *TextScanner) PrintResult(response *model.TextScanResponse) {
|
||||
fmt.Println("违规详情:")
|
||||
for _, detail := range result.Details {
|
||||
fmt.Printf(" 内容: %s\n", detail.Context.Context)
|
||||
fmt.Printf(" 位置: %v\n", detail.Context.Pos)
|
||||
if len(detail.Context.Pos) > 0 {
|
||||
fmt.Printf(" 位置: %v\n", detail.Context.Pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打印扩展信息
|
||||
if len(result.Extras) > 0 {
|
||||
fmt.Println("扩展信息:")
|
||||
for key, value := range result.Extras {
|
||||
fmt.Printf(" %s: %v\n", key, value)
|
||||
}
|
||||
}
|
||||
fmt.Println("---")
|
||||
|
@ -12,15 +12,38 @@ import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/green"
|
||||
)
|
||||
|
||||
// VideoScanner 视频内容安全扫描器
|
||||
// VideoScanner 视频内容安全扫描器2.0
|
||||
type VideoScanner struct {
|
||||
Client *green.Client
|
||||
Config *conf.Config
|
||||
}
|
||||
|
||||
// VideoServiceType 视频审核服务类型
|
||||
type VideoServiceType string
|
||||
|
||||
const (
|
||||
// VideoBaselineCheckGlobal 视频通用基线检测
|
||||
VideoBaselineCheckGlobal VideoServiceType = "baselineCheck_global"
|
||||
// VideoPostCheckByVLGlobal 视频大小模型融合审核服务
|
||||
VideoPostCheckByVLGlobal VideoServiceType = "postVideoCheckByVL_global"
|
||||
)
|
||||
|
||||
// NewVideoScanner 创建视频扫描器
|
||||
func NewVideoScanner(config *conf.Config) (*VideoScanner, error) {
|
||||
client, err := green.NewClientWithAccessKey(config.Region, config.AccessKeyID, config.AccessKeySecret)
|
||||
// 获取有效的访问凭证
|
||||
accessKeyID, accessKeySecret, securityToken := config.GetEffectiveCredentials()
|
||||
|
||||
var client *green.Client
|
||||
var err error
|
||||
|
||||
if securityToken != "" {
|
||||
// 使用STS临时凭证
|
||||
client, err = green.NewClientWithStsToken(config.Region, accessKeyID, accessKeySecret, securityToken)
|
||||
} else {
|
||||
// 使用直接凭证
|
||||
client, err = green.NewClientWithAccessKey(config.Region, accessKeyID, accessKeySecret)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建客户端失败: %v", err)
|
||||
}
|
||||
@ -31,13 +54,13 @@ func NewVideoScanner(config *conf.Config) (*VideoScanner, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScanVideoAsync 异步扫描视频
|
||||
func (s *VideoScanner) ScanVideoAsync(videoURL string, dataID string) (*model.VideoScanResponse, error) {
|
||||
// ScanVideoAsync 异步扫描视频(2.0版本)
|
||||
func (s *VideoScanner) ScanVideoAsync(videoURL string, dataID string, serviceType VideoServiceType) (*model.VideoScanResponse, error) {
|
||||
request := requests.NewCommonRequest()
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0视频审核API版本
|
||||
request.ApiName = "VideoAsyncScan"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -50,7 +73,7 @@ func (s *VideoScanner) ScanVideoAsync(videoURL string, dataID string) (*model.Vi
|
||||
MaxFrames: 100, // 最多截取100帧
|
||||
},
|
||||
},
|
||||
Scenes: []string{"porn", "terrorism", "ad", "live"},
|
||||
Services: []string{string(serviceType)}, // 使用服务类型而不是场景
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(scanRequest)
|
||||
@ -73,13 +96,13 @@ func (s *VideoScanner) ScanVideoAsync(videoURL string, dataID string) (*model.Vi
|
||||
return &scanResponse, nil
|
||||
}
|
||||
|
||||
// GetVideoResult 获取视频审核结果
|
||||
// GetVideoResult 获取视频审核结果(2.0版本)
|
||||
func (s *VideoScanner) GetVideoResult(taskID string) (*model.VideoResultResponse, error) {
|
||||
request := requests.NewCommonRequest()
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.Domain = s.Config.Endpoint
|
||||
request.Version = "2018-05-09"
|
||||
request.Version = "2022-03-02" // 内容安全2.0视频审核API版本
|
||||
request.ApiName = "VideoAsyncScanResults"
|
||||
request.QueryParams["RegionId"] = s.Config.Region
|
||||
|
||||
@ -99,10 +122,10 @@ func (s *VideoScanner) GetVideoResult(taskID string) (*model.VideoResultResponse
|
||||
return &resultResponse, nil
|
||||
}
|
||||
|
||||
// ScanVideoAndWait 扫描视频并等待结果
|
||||
func (s *VideoScanner) ScanVideoAndWait(videoURL string, dataID string, maxWaitTime time.Duration) (*model.VideoResultResponse, error) {
|
||||
// ScanVideoAndWait 扫描视频并等待结果(2.0版本)
|
||||
func (s *VideoScanner) ScanVideoAndWait(videoURL string, dataID string, serviceType VideoServiceType, maxWaitTime time.Duration) (*model.VideoResultResponse, error) {
|
||||
// 提交扫描任务
|
||||
scanResponse, err := s.ScanVideoAsync(videoURL, dataID)
|
||||
scanResponse, err := s.ScanVideoAsync(videoURL, dataID, serviceType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("提交扫描任务失败: %v", err)
|
||||
}
|
||||
@ -159,9 +182,9 @@ func (s *VideoScanner) PrintScanResult(response *model.VideoScanResponse) {
|
||||
}
|
||||
}
|
||||
|
||||
// PrintResult 打印审核结果
|
||||
// PrintResult 打印审核结果(2.0版本)
|
||||
func (s *VideoScanner) PrintResult(response *model.VideoResultResponse) {
|
||||
fmt.Println("=== 视频内容安全审核结果 ===")
|
||||
fmt.Println("=== 视频内容安全审核结果(2.0版本)===")
|
||||
fmt.Printf("状态码: %d\n", response.Code)
|
||||
fmt.Printf("消息: %s\n", response.Message)
|
||||
|
||||
@ -179,9 +202,31 @@ func (s *VideoScanner) PrintResult(response *model.VideoResultResponse) {
|
||||
for _, result := range data.Results {
|
||||
fmt.Printf("场景: %s\n", result.Scene)
|
||||
fmt.Printf("标签: %s\n", result.Label)
|
||||
if result.SubLabel != "" {
|
||||
fmt.Printf("子标签: %s\n", result.SubLabel)
|
||||
}
|
||||
fmt.Printf("建议: %s\n", result.Suggestion)
|
||||
fmt.Printf("置信度: %.2f\n", result.Rate)
|
||||
|
||||
// 打印详细信息
|
||||
if len(result.Details) > 0 {
|
||||
fmt.Println("详细信息:")
|
||||
for _, detail := range result.Details {
|
||||
fmt.Printf(" 内容: %s\n", detail.Context.Context)
|
||||
if len(detail.Context.Pos) > 0 {
|
||||
fmt.Printf(" 位置: %v\n", detail.Context.Pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打印扩展信息
|
||||
if len(result.Extras) > 0 {
|
||||
fmt.Println("扩展信息:")
|
||||
for key, value := range result.Extras {
|
||||
fmt.Printf(" %s: %v\n", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 打印帧级别的结果
|
||||
if len(result.Frames) > 0 {
|
||||
fmt.Println("违规帧详情:")
|
||||
@ -191,6 +236,12 @@ func (s *VideoScanner) PrintResult(response *model.VideoResultResponse) {
|
||||
for _, frameResult := range frame.Results {
|
||||
fmt.Printf(" 场景: %s, 标签: %s, 建议: %s, 置信度: %.2f\n",
|
||||
frameResult.Scene, frameResult.Label, frameResult.Suggestion, frameResult.Rate)
|
||||
if frameResult.SubLabel != "" {
|
||||
fmt.Printf(" 子标签: %s\n", frameResult.SubLabel)
|
||||
}
|
||||
if len(frameResult.Details) > 0 {
|
||||
fmt.Printf(" 详细信息: %v\n", frameResult.Details)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package model
|
||||
|
||||
// ImageScanRequest 图片审核请求结构
|
||||
// ImageScanRequest 图片审核请求结构(2.0版本)
|
||||
type ImageScanRequest struct {
|
||||
Tasks []ImageTask `json:"tasks"`
|
||||
Scenes []string `json:"scenes"`
|
||||
Tasks []ImageTask `json:"tasks"`
|
||||
Services []string `json:"services"` // 2.0版本使用services而不是scenes
|
||||
}
|
||||
|
||||
// ImageTask 图片任务结构
|
||||
@ -13,7 +13,7 @@ type ImageTask struct {
|
||||
Content string `json:"content,omitempty"` // base64编码的图片内容
|
||||
}
|
||||
|
||||
// ImageScanResponse 图片审核响应结构
|
||||
// ImageScanResponse 图片审核响应结构(2.0版本)
|
||||
type ImageScanResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
@ -26,6 +26,18 @@ type ImageScanResponse struct {
|
||||
Label string `json:"label"`
|
||||
Suggestion string `json:"suggestion"`
|
||||
Rate float64 `json:"rate"`
|
||||
// 2.0版本新增字段
|
||||
SubLabel string `json:"subLabel,omitempty"` // 子标签
|
||||
Details []ImageDetail `json:"details,omitempty"` // 详细信息
|
||||
Extras map[string]interface{} `json:"extras,omitempty"` // 扩展信息
|
||||
} `json:"results"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// ImageDetail 图片审核详细信息
|
||||
type ImageDetail struct {
|
||||
Context struct {
|
||||
Context string `json:"context"`
|
||||
Pos []int `json:"pos"`
|
||||
} `json:"context"`
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package model
|
||||
|
||||
// TextScanRequest 文本审核请求结构
|
||||
// TextScanRequest 文本审核请求结构(2.0版本)
|
||||
type TextScanRequest struct {
|
||||
Tasks []TextTask `json:"tasks"`
|
||||
Scenes []string `json:"scenes"`
|
||||
Tasks []TextTask `json:"tasks"`
|
||||
Services []string `json:"services"` // 2.0版本使用services而不是scenes
|
||||
}
|
||||
|
||||
// TextTask 文本任务结构
|
||||
@ -12,7 +12,7 @@ type TextTask struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// TextScanResponse 文本审核响应结构
|
||||
// TextScanResponse 文本审核响应结构(2.0版本)
|
||||
type TextScanResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
@ -25,12 +25,18 @@ type TextScanResponse struct {
|
||||
Label string `json:"label"`
|
||||
Suggestion string `json:"suggestion"`
|
||||
Rate float64 `json:"rate"`
|
||||
Details []struct {
|
||||
Context struct {
|
||||
Context string `json:"context"`
|
||||
Pos []int `json:"pos"`
|
||||
} `json:"context"`
|
||||
} `json:"details"`
|
||||
// 2.0版本新增字段
|
||||
SubLabel string `json:"subLabel,omitempty"` // 子标签
|
||||
Details []TextDetail `json:"details,omitempty"` // 详细信息
|
||||
Extras map[string]interface{} `json:"extras,omitempty"` // 扩展信息
|
||||
} `json:"results"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// TextDetail 文本审核详细信息
|
||||
type TextDetail struct {
|
||||
Context struct {
|
||||
Context string `json:"context"`
|
||||
Pos []int `json:"pos"`
|
||||
} `json:"context"`
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package model
|
||||
|
||||
// VideoScanRequest 视频审核请求结构
|
||||
// VideoScanRequest 视频审核请求结构(2.0版本)
|
||||
type VideoScanRequest struct {
|
||||
Tasks []VideoTask `json:"tasks"`
|
||||
Scenes []string `json:"scenes"`
|
||||
Tasks []VideoTask `json:"tasks"`
|
||||
Services []string `json:"services"` // 2.0版本使用services而不是scenes
|
||||
}
|
||||
|
||||
// VideoTask 视频任务结构
|
||||
@ -27,7 +27,7 @@ type VideoScanResponse struct {
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// VideoResultResponse 视频审核结果响应结构
|
||||
// VideoResultResponse 视频审核结果响应结构(2.0版本)
|
||||
type VideoResultResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
@ -42,7 +42,11 @@ type VideoResultResponse struct {
|
||||
Label string `json:"label"`
|
||||
Suggestion string `json:"suggestion"`
|
||||
Rate float64 `json:"rate"`
|
||||
Frames []struct {
|
||||
// 2.0版本新增字段
|
||||
SubLabel string `json:"subLabel,omitempty"` // 子标签
|
||||
Details []VideoDetail `json:"details,omitempty"` // 详细信息
|
||||
Extras map[string]interface{} `json:"extras,omitempty"` // 扩展信息
|
||||
Frames []struct {
|
||||
Offset int `json:"offset"`
|
||||
URL string `json:"url"`
|
||||
Results []struct {
|
||||
@ -50,8 +54,20 @@ type VideoResultResponse struct {
|
||||
Label string `json:"label"`
|
||||
Suggestion string `json:"suggestion"`
|
||||
Rate float64 `json:"rate"`
|
||||
// 2.0版本新增字段
|
||||
SubLabel string `json:"subLabel,omitempty"`
|
||||
Details []VideoDetail `json:"details,omitempty"`
|
||||
Extras map[string]interface{} `json:"extras,omitempty"`
|
||||
} `json:"results"`
|
||||
} `json:"frames"`
|
||||
} `json:"results"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// VideoDetail 视频审核详细信息
|
||||
type VideoDetail struct {
|
||||
Context struct {
|
||||
Context string `json:"context"`
|
||||
Pos []int `json:"pos"`
|
||||
} `json:"context"`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user