Browse Source

ci 内容审核

tags/v0.7.11^2
jojoliang 4 years ago
parent
commit
695c4466f5
  1. 143
      ci.go
  2. 8
      cos.go
  3. 2
      cos_test.go
  4. 11
      example/object/ci_image_process.go
  5. 14
      example/object/ci_image_recognition.go
  6. 71
      example/object/ci_video_auditing_job.go
  7. 20
      object.go

143
ci.go

@ -4,15 +4,15 @@ import (
"context"
"encoding/json"
"encoding/xml"
"io"
"net/http"
)
type CIService service
type PicOperations struct {
IsPicInfo int `json:"is_pic_info,omitempty"`
Rules []PicOperationsRules `json:"rules,omitemtpy"`
}
type PicOperationsRules struct {
Bucket string `json:"bucket,omitempty"`
FileId string `json:"fileid"`
@ -20,6 +20,9 @@ type PicOperationsRules struct {
}
func EncodePicOperations(pic *PicOperations) string {
if pic == nil {
return ""
}
bs, err := json.Marshal(pic)
if err != nil {
return ""
@ -27,18 +30,16 @@ func EncodePicOperations(pic *PicOperations) string {
return string(bs)
}
type CloudImageReuslt struct {
type ImageProcessResult struct {
XMLName xml.Name `xml:"UploadResult"`
OriginalInfo *PicOriginalInfo `xml:"OriginalInfo,omitempty"`
ProcessObject *PicProcessObject `xml:"ProcessResults>Object,omitempty"`
}
type PicOriginalInfo struct {
Key string `xml:"Key,omitempty"`
Location string `xml:"Location,omitempty"`
ImageInfo *PicImageInfo `xml:"ImageInfo,omitempty"`
}
type PicImageInfo struct {
Format string `xml:"Format,omitempty"`
Width int `xml:"Width,omitempty"`
@ -46,7 +47,6 @@ type PicImageInfo struct {
Size int `xml:"Size,omitempty"`
Quality int `xml:"Quality,omitempty"`
}
type PicProcessObject struct {
Key string `xml:"Key,omitempty"`
Location string `xml:"Location,omitempty"`
@ -57,24 +57,42 @@ type PicProcessObject struct {
Quality int `xml:"Quality,omitempty"`
}
type CloudImageOptions struct {
type picOperationsHeader struct {
PicOperations string `header:"Pic-Operations" xml:"-" url:"-"`
}
func (s *ObjectService) PostCI(ctx context.Context, name string, opt *CloudImageOptions) (*CloudImageReuslt, *Response, error) {
var res CloudImageReuslt
type ImageProcessOptions = PicOperations
// 云上数据处理 https://cloud.tencent.com/document/product/460/18147
func (s *CIService) ImageProcess(ctx context.Context, name string, opt *ImageProcessOptions) (*ImageProcessResult, *Response, error) {
header := &picOperationsHeader{
PicOperations: EncodePicOperations(opt),
}
var res ImageProcessResult
sendOpt := sendOptions{
baseURL: s.client.BaseURL.BucketURL,
uri: "/" + encodeURIComponent(name) + "?image_process",
method: http.MethodPost,
optHeader: opt,
optHeader: header,
result: &res,
}
resp, err := s.client.send(ctx, &sendOpt)
return &res, resp, err
}
type CloudImageRecognitionInfo struct {
type ImageRecognitionOptions struct {
CIProcess string `url:"ci-process,omitempty"`
DetectType string `url:"detect-type,omitempty"`
}
type ImageRecognitionResult struct {
XMLName xml.Name `xml:"RecognitionResult"`
PornInfo *RecognitionInfo `xml:"PornInfo,omitempty"`
TerroristInfo *RecognitionInfo `xml:"TerroristInfo,omitempty"`
PoliticsInfo *RecognitionInfo `xml:"PoliticsInfo,omitempty"`
AdsInfo *RecognitionInfo `xml:"AdsInfo,omitempty"`
}
type RecognitionInfo struct {
Code int `xml:"Code,omitempty"`
Msg string `xml:"Msg,omitempty"`
HitFlag int `xml:"HitFlag,omitempty"`
@ -83,18 +101,99 @@ type CloudImageRecognitionInfo struct {
Count int `xml:"Count,omitempty"`
}
type CloudImageRecognitionResult struct {
PornInfo *CloudImageRecognitionInfo `xml:"PornInfo,omitempty"`
TerroristInfo *CloudImageRecognitionInfo `xml:"TerroristInfo,omitempty"`
PoliticsInfo *CloudImageRecognitionInfo `xml:"PoliticsInfo,omitempty"`
AdsInfo *CloudImageRecognitionInfo `xml:"AdsInfo,omitempty"`
// 图片审核 https://cloud.tencent.com/document/product/460/37318
func (s *CIService) ImageRecognition(ctx context.Context, name string, opt *ImageRecognitionOptions) (*ImageRecognitionResult, *Response, error) {
if opt != nil && opt.CIProcess == "" {
opt.CIProcess = "sensitive-content-recognition"
}
var res ImageRecognitionResult
sendOpt := sendOptions{
baseURL: s.client.BaseURL.BucketURL,
uri: "/" + encodeURIComponent(name),
method: http.MethodGet,
optQuery: opt,
result: &res,
}
resp, err := s.client.send(ctx, &sendOpt)
return &res, resp, err
}
type PutVideoAuditingJobOptions struct {
XMLName xml.Name `xml:"Request"`
InputObject string `xml:"Input>Object"`
Conf *VideoAuditingJobConf `xml:"Conf"`
}
type VideoAuditingJobConf struct {
DetectType string `xml:",omitempty"`
Snapshot *PutVideoAuditingJobSnapshot `xml:",omitempty"`
Callback string `xml:",omitempty"`
}
type PutVideoAuditingJobSnapshot struct {
Mode string `xml:",omitempty"`
Count int `xml:",omitempty"`
TimeInterval float32 `xml:",omitempty"`
Start float32 `xml:",omitempty"`
}
type PutVideoAuditingJobResult struct {
XMLName xml.Name `xml:"Response"`
JobsDetail struct {
JobId string `xml:"JobId,omitempty"`
State string `xml:"State,omitempty"`
CreationTime string `xml:"CreationTime,omitempty"`
Object string `xml:"Object,omitempty"`
} `xml:"JobsDetail,omitempty"`
}
func (s *CIService) PutVideoAuditingJob(ctx context.Context, opt *PutVideoAuditingJobOptions) (*PutVideoAuditingJobResult, *Response, error) {
var res PutVideoAuditingJobResult
sendOpt := sendOptions{
baseURL: s.client.BaseURL.CIURL,
uri: "/video/auditing",
method: http.MethodPost,
body: opt,
result: &res,
}
resp, err := s.client.send(ctx, &sendOpt)
return &res, resp, err
}
type GetVideoAuditingJobResult struct {
XMLName xml.Name `xml:"Response"`
JobsDetail *VideoAuditingJobDetail `xml:",omitempty"`
NonExistJobIds string `xml:",omitempty"`
}
type VideoAuditingJobDetail struct {
Code string `xml:",omitempty"`
Message string `xml:",omitempty"`
JobId string `xml:",omitempty"`
State string `xml:",omitempty"`
CreationTime string `xml:",omitempty"`
Object string `xml:",omitempty"`
SnapshotCount string `xml:",omitempty"`
result int `xml:",omitempty"`
PornInfo *RecognitionInfo `xml:",omitempty"`
TerrorismInfo *RecognitionInfo `xml:",omitempty"`
PoliticsInfo *RecognitionInfo `xml:",omitempty"`
AdsInfo *RecognitionInfo `xml:",omitempty"`
Snapshot *GetVideoAuditingJobSnapshot `xml:",omitempty"`
}
type GetVideoAuditingJobSnapshot struct {
Url string `xml:",omitempty"`
PornInfo *RecognitionInfo `xml:",omitempty"`
TerrorismInfo *RecognitionInfo `xml:",omitempty"`
PoliticsInfo *RecognitionInfo `xml:",omitempty"`
AdsInfo *RecognitionInfo `xml:",omitempty"`
}
func GetRecognitionResult(body io.ReadCloser) *CloudImageRecognitionResult {
var res CloudImageRecognitionResult
err := xml.NewDecoder(body).Decode(&res)
if err != nil && err != io.EOF {
return nil
func (s *CIService) GetVideoAuditingJob(ctx context.Context, jobid string) (*GetVideoAuditingJobResult, *Response, error) {
var res GetVideoAuditingJobResult
sendOpt := sendOptions{
baseURL: s.client.BaseURL.CIURL,
uri: "/video/auditing/" + jobid,
method: http.MethodGet,
result: &res,
}
return &res
resp, err := s.client.send(ctx, &sendOpt)
return &res, resp, err
}

8
cos.go

@ -42,6 +42,8 @@ type BaseURL struct {
ServiceURL *url.URL
// 访问 job API 的基础 URL (不包含 path 部分): http://example.com
BatchURL *url.URL
// 访问 CI 的基础 URL
CIURL *url.URL
}
// NewBucketURL 生成 BaseURL 所需的 BucketURL
@ -82,6 +84,7 @@ type Client struct {
Bucket *BucketService
Object *ObjectService
Batch *BatchService
CI *CIService
}
type service struct {
@ -99,6 +102,7 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client {
baseURL.BucketURL = uri.BucketURL
baseURL.ServiceURL = uri.ServiceURL
baseURL.BatchURL = uri.BatchURL
baseURL.CIURL = uri.CIURL
}
if baseURL.ServiceURL == nil {
baseURL.ServiceURL, _ = url.Parse(defaultServiceBaseURL)
@ -114,6 +118,7 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client {
c.Bucket = (*BucketService)(&c.common)
c.Object = (*ObjectService)(&c.common)
c.Batch = (*BatchService)(&c.common)
c.CI = (*CIService)(&c.common)
return c
}
@ -244,9 +249,6 @@ func (c *Client) send(ctx context.Context, opt *sendOptions) (resp *Response, er
}
resp, err = c.doAPI(ctx, req, opt.result, !opt.disableCloseBody)
if err != nil {
return
}
return
}

2
cos_test.go

@ -32,7 +32,7 @@ func setup() {
server = httptest.NewServer(mux)
u, _ := url.Parse(server.URL)
client = NewClient(&BaseURL{u, u, u}, nil)
client = NewClient(&BaseURL{u, u, u, u}, nil)
}
// teardown closes the test HTTP server.

11
example/object/ci_post.go → example/object/ci_image_process.go

@ -2,7 +2,6 @@ package main
import (
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
@ -48,7 +47,7 @@ func main() {
},
})
pic := &cos.PicOperations{
opt := &cos.ImageProcessOptions{
IsPicInfo: 1,
Rules: []cos.PicOperationsRules{
{
@ -57,12 +56,8 @@ func main() {
},
},
}
opt := &cos.CloudImageOptions{
PicOperations: cos.EncodePicOperations(pic),
}
name := "test.jpg"
res, _, err := c.Object.PostCI(context.Background(), name, opt)
data, _ := xml.Marshal(res)
fmt.Printf("%+v\n", string(data))
res, _, err := c.CI.ImageProcess(context.Background(), name, opt)
log_status(err)
fmt.Printf("%+v\n", res)
}

14
example/object/ci_get.go → example/object/ci_image_recognition.go

@ -45,18 +45,12 @@ func main() {
},
},
})
opt := &cos.ObjectGetOptions{
CIProcess: "sensitive-content-recognition",
CIDetectType: "porn,terrorist,politics,ads",
opt := &cos.ImageRecognitionOptions{
DetectType: "porn,terrorist,politics",
}
// Case1 Download object into ReadCloser(). the body needs to be closed
name := "test.jpg"
resp, err := c.Object.Get(context.Background(), name, opt)
res, _, err := c.CI.ImageRecognition(context.Background(), name, opt)
log_status(err)
resp.Body.Close()
res := cos.GetRecognitionResult(resp.Body)
if res != nil {
fmt.Printf("%+v\n", res)
}
fmt.Printf("%+v\n", res)
}

71
example/object/ci_video_auditing_job.go

@ -0,0 +1,71 @@
package main
import (
"context"
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/tencentyun/cos-go-sdk-v5"
"github.com/tencentyun/cos-go-sdk-v5/debug"
)
func log_status(err error) {
if err == nil {
return
}
if cos.IsNotFoundError(err) {
// WARN
fmt.Println("WARN: Resource is not existed")
} else if e, ok := cos.IsCOSError(err); ok {
fmt.Printf("ERROR: Code: %v\n", e.Code)
fmt.Printf("ERROR: Message: %v\n", e.Message)
fmt.Printf("ERROR: Resource: %v\n", e.Resource)
fmt.Printf("ERROR: RequestId: %v\n", e.RequestID)
// ERROR
} else {
fmt.Printf("ERROR: %v\n", err)
// ERROR
}
}
func main() {
bu, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
cu, _ := url.Parse("https://test-1259654469.ci.ap-guangzhou.myqcloud.com")
b := &cos.BaseURL{BucketURL: bu, CIURL: cu}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: os.Getenv("COS_SECRETID"),
SecretKey: os.Getenv("COS_SECRETKEY"),
Transport: &debug.DebugRequestTransport{
RequestHeader: true,
RequestBody: true,
ResponseHeader: true,
ResponseBody: true,
},
},
})
opt := &cos.PutVideoAuditingJobOptions{
InputObject: "demo.mp4",
Conf: &cos.VideoAuditingJobConf{
DetectType: "Porn,Terrorism,Politics,Ads",
Snapshot: &cos.PutVideoAuditingJobSnapshot{
Mode: "Interval",
Start: 0.5,
TimeInterval: 50.5,
Count: 100,
},
},
}
res, _, err := c.CI.PutVideoAuditingJob(context.Background(), opt)
log_status(err)
fmt.Printf("%+v\n", res)
time.Sleep(3 * time.Second)
res2, _, err := c.CI.GetVideoAuditingJob(context.Background(), res.JobsDetail.JobId)
log_status(err)
fmt.Printf("%+v\n", res2)
}

20
object.go

@ -35,10 +35,6 @@ type ObjectGetOptions struct {
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
XCosTrafficLimit int `header:"x-cos-traffic-limit,omitempty" url:"-" xml:"-"`
// CI 图片审核
CIProcess string `header:"-" url:"ci-process" xml:"-"`
CIDetectType string `header:"-" url:"detect-type" xml:"-"`
}
// presignedURLTestingOptions is the opt of presigned url
@ -501,6 +497,7 @@ type Chunk struct {
OffSet int64
Size int64
Done bool
ETag string
}
// jobs
@ -662,8 +659,9 @@ func (s *ObjectService) checkUploadedParts(ctx context.Context, name, UploadID,
defer fd.Close()
// 某个分块出错, 重置chunks
ret := func(e error) error {
for _, chunk := range chunks {
chunk.Done = false
for i, _ := range chunks {
chunks[i].Done = false
chunks[i].ETag = ""
}
return e
}
@ -683,6 +681,7 @@ func (s *ObjectService) checkUploadedParts(ctx context.Context, name, UploadID,
return ret(errors.New(fmt.Sprintf("CheckSum Failed in Part[%d]", part.PartNumber)))
}
chunks[partNumber].Done = true
chunks[partNumber].ETag = part.ETag
}
return nil
}
@ -706,6 +705,7 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string
if err != nil {
return nil, nil, err
}
// filesize=0 , use simple upload
if partNum == 0 {
var opt0 *ObjectPutOptions
if opt.OptIni != nil {
@ -787,7 +787,13 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string
close(chjobs)
// 5.Recv the resp etag to complete
for i := 1; i <= partNum; i++ {
for i := 0; i < partNum; i++ {
if chunks[i].Done {
optcom.Parts = append(optcom.Parts, Object{
PartNumber: chunks[i].Number, ETag: chunks[i].ETag},
)
continue
}
res := <-chresults
// Notice one part fail can not get the etag according.
if res.Resp == nil || res.err != nil {

Loading…
Cancel
Save