Skip to content

WinstonAI Image AI Detection #201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 3, 2024
17 changes: 16 additions & 1 deletion edenai_apis/apis/winstonai/info.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
{
"text": {
"ai_detection":{
"version" : "v2"
"version" : "v2",
"constraints": {
"languages": [
"en",
"fr",
"es",
"de",
"nl",
"zh-CN"
]
}
},
"plagia_detection":{
"version" : "v2"
}
},
"image": {
"ai_detection":{
"version" : "v1"
}
}
}
67 changes: 67 additions & 0 deletions edenai_apis/apis/winstonai/outputs/image/ai_detection_output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"original_response": {
"score": 97.05,
"human_probability": 0.9705126881599426,
"ai_probability": 0.02948736399412155,
"version": "1.0",
"mime_type": "image/jpeg",
"c2pa": null,
"exif": {
"SpecialInstructions": "This photo is for metadata testing purposes only",
"DateCreated": "2020-01-08T13:30:01+01:00",
"TimeCreated": "133001+0100",
"Byline": "Jane Photosty",
"Headline": "The railway and the cars",
"Credit": "IPTC/Jane Photosty",
"CopyrightNotice": "\u00a9 Copyright 2020 IPTC (Test Images) - www.iptc.org",
"Caption": "The railways of the S45 line are running very close to a small street with parking cars",
"ApplicationRecordVersion": "\u0000\u0004",
"creator": "Jane Photosty",
"description": {
"lang": "x-default",
"value": "The railways of the S45 line are running very close to a small street with parking cars"
},
"rights": {
"lang": "x-default",
"value": "\u00a9 Copyright 2020 IPTC (Test Images) - www.iptc.org"
},
"Instructions": "This photo is for metadata testing purposes only",
"CopyrightOwner": {
"parseType": "Resource",
"CopyrightOwnerID": "https://iptc.org",
"CopyrightOwnerName": "IPTC - International Press Telecommunications Council"
},
"ImageCreator": {
"parseType": "Resource",
"ImageCreatorID": "https://example.com/photogs/JanePhotosty",
"ImageCreatorName": "Jane Photosty"
},
"Licensor": {
"parseType": "Resource",
"LicensorID": "https://iptc.org",
"LicensorName": "IPTC - International Press Telecommunications Council",
"LicensorURL": "https://iptc.org/tests/licensing-of-images-test-page/"
},
"UsageTerms": {
"lang": "x-default",
"value": "All rights reserved. To use this image an explicit license granted by IPTC is required."
},
"WebStatement": "https://iptc.org/tests/copyright-and-licenses-of-images-test-page/",
"ImageDescription": "The railways of the S45 line are running very close to a small street with parking cars",
"XResolution": 72,
"YResolution": 72,
"ResolutionUnit": "inches",
"Artist": "Jane Photosty",
"YCbCrPositioning": 1,
"Copyright": "\u00a9 Copyright 2020 IPTC (Test Images) - www.iptc.org"
},
"ai_watermark_detected": false,
"ai_watermark_issuers": [],
"credits_used": 300,
"credits_remaining": 273132
},
"standardized_response": {
"ai_score": 0.9704999999999999,
"prediction": "ai-generated"
}
}
43 changes: 37 additions & 6 deletions edenai_apis/apis/winstonai/winstonai_api.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import json
from typing import Dict, Sequence, Any, Optional

import requests

from edenai_apis.apis.winstonai.config import WINSTON_AI_API_URL
from edenai_apis.features import ProviderInterface, TextInterface
from edenai_apis.features import ProviderInterface, TextInterface, ImageInterface
from edenai_apis.features.image.ai_detection.ai_detection_dataclass import AiDetectionDataClass as ImageAiDetectionDataclass
from edenai_apis.features.text.ai_detection.ai_detection_dataclass import (
AiDetectionDataClass,
AiDetectionItem,
@@ -20,7 +19,7 @@
from edenai_apis.utils.types import ResponseType


class WinstonaiApi(ProviderInterface, TextInterface):
class WinstonaiApi(ProviderInterface, TextInterface, ImageInterface):
provider_name = "winstonai"

def __init__(self, api_keys: Optional[Dict[str, Any]] = None):
@@ -35,6 +34,37 @@ def __init__(self, api_keys: Optional[Dict[str, Any]] = None):
"Authorization": f'Bearer {self.api_settings["api_key"]}',
}

def image__ai_detection(self, file_url: str) -> ResponseType[ImageAiDetectionDataclass]:

payload = json.dumps({
"url": file_url,
})

response = requests.request(
"POST", f"{self.api_url}/image-detection", headers=self.headers, data=payload
)

if response.status_code != 200:
raise ProviderException(response.json(), code=response.status_code)

original_response = response.json()

score = original_response.get("score") / 100
prediction = AiDetectionDataClass.set_label_based_on_score(score)
if score is None:
raise ProviderException(response.json())


standardized_response = AiDetectionDataClass(
ai_score=score,
prediction=prediction,
)

return ResponseType[AiDetectionDataClass](
original_response=original_response,
standardized_response=standardized_response,
)

def text__ai_detection(
self, text: str, provider_params: Optional[Dict[str, Any]] = None
) -> ResponseType[AiDetectionDataClass]:
@@ -68,13 +98,14 @@ def text__ai_detection(
text=sentence["text"],
ai_score=1-(sentence["score"] / 100),
prediction=AiDetectionItem.set_label_based_on_score(
1- (sentence["score"] / 100)
1 - (sentence["score"] / 100)
),
)
for sentence in sentences
]

standardized_response = AiDetectionDataClass(ai_score=1-score, items=items)
standardized_response = AiDetectionDataClass(
ai_score=1-score, items=items)

return ResponseType[AiDetectionDataClass](
original_response=original_response,
1 change: 1 addition & 0 deletions edenai_apis/features/image/__init__.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
AnonymizationDataClass,
anonymization_arguments,
)
from .ai_detection import ai_detection_arguments
from .automl_classification import (
automl_classification_create_project_arguments,
automl_classification_upload_data_async_arguments,
2 changes: 2 additions & 0 deletions edenai_apis/features/image/ai_detection/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .ai_detection_args import ai_detection_arguments
from .ai_detection_dataclass import AiDetectionDataClass
6 changes: 6 additions & 0 deletions edenai_apis/features/image/ai_detection/ai_detection_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
HUMAN_IMAGE_EXAMPLE = ('https://www.iptc.org/std-dev/photometadata/examples/google-licensable/images/IPTC-GoogleImgSrcPmd_testimg01.jpg')

def ai_detection_arguments(provider_name: str) -> dict:
return {
"file_url": HUMAN_IMAGE_EXAMPLE
}
14 changes: 14 additions & 0 deletions edenai_apis/features/image/ai_detection/ai_detection_dataclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import Literal
from pydantic import BaseModel, Field


class AiDetectionDataClass(BaseModel):
ai_score: float = Field(ge=0, le=1)
prediction: Literal["ai-generated", "original"]

@staticmethod
def set_label_based_on_score(ai_score: float):
if ai_score > 0.5:
return "ai-generated"
else:
return "original"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ai_score": 0.9704999999999999,
"prediction": "ai-generated"
}
18 changes: 16 additions & 2 deletions edenai_apis/features/image/image_interface.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from abc import ABC, abstractmethod
from io import BufferedReader
from abc import abstractmethod
from typing import Literal, Optional, Dict, Any, List

from edenai_apis.features.image import (
GenerationFineTuningCreateProjectAsyncDataClass,
GenerationFineTuningGenerateImageAsyncDataClass,
)
from edenai_apis.features.image.ai_detection.ai_detection_dataclass import AiDetectionDataClass
from edenai_apis.features.image.anonymization.anonymization_dataclass import (
AnonymizationDataClass,
)
@@ -91,7 +91,21 @@
)



class ImageInterface:

@abstractmethod
def image__ai_detection(
self, file_url: str
) -> ResponseType[AiDetectionDataClass]:
"""
Detect if an image was generated by AI

Args:
file_url (str): url of the image to analyze
"""
raise NotImplementedError

@abstractmethod
def image__anonymization(
self, file: str, file_url: str = ""