Skip to content

Commit

Permalink
Merge pull request #22 from Copyleaks/features/1207019394509570/add-w…
Browse files Browse the repository at this point in the history
…riting-feedback-and-ai-detector

Features/1207019394509570/add writing feedback and ai detector
  • Loading branch information
AihamAR authored Sep 10, 2024
2 parents d2d1945 + aa6b7f9 commit adb2fc3
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 1 deletion.
Empty file added copyleaks/clients/__init__.py
Empty file.
81 changes: 81 additions & 0 deletions copyleaks/clients/ai_detection_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

'''
The MIT License(MIT)
Copyright(c) 2016 Copyleaks LTD (https://copyleaks.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

from aifc import Error
import requests
from copyleaks.consts import Consts
from copyleaks.helpers.copyleaks_client_helper import CopyleaksClientHelper

class _AIDetectionClient:
@staticmethod
def __submit(url, auth_token, scan_id, submission):
assert url and scan_id and submission

CopyleaksClientHelper.verify_auth_token(auth_token)

headers = {
'Content-Type': 'application/json',
'User-Agent': Consts.USER_AGENT,
'Authorization': f"Bearer {auth_token['access_token']}"
}
json = submission.toJSON()
response = requests.post(url, headers=headers, data=json)
if response.ok:
return response.json()
elif response.status_code == 503:
raise Error()
else:
raise Error(response)

@staticmethod
def submit_natural_language(auth_token, scan_id, submission):
'''
Use Copyleaks AI Content Detection to differentiate between human texts and AI written texts.
This endpoint will receive submitted text to be checked. At the end of the processing stage,
the result will be shown as classifications. Text classification is divided into sections.
Each section may have a different classification
Raises:
`CommandError`: Server reject the request. See response status code, headers and content for more info.
`UnderMaintenanceError`: Copyleaks servers are unavailable for maintenance. We recommend to implement exponential backoff algorithm as described here: https://api.copyleaks.com/documentation/v3/exponential-backoff
'''
url = f"{Consts.API_SERVER_URI}/v2/writer-detector/{scan_id}/check"
return _AIDetectionClient.__submit(url, auth_token, scan_id, submission)


@staticmethod
def submit_source_code(auth_token, scan_id, submission):
'''
Use Copyleaks AI Content Detection to differentiate between human source code and AI written source code.
This endpoint will receive submitted source code to be checked.
At the end of the processing stage, the result will be shown as classifications.
Source code classification is divided into sections. Each section may have a different classification.
Raises:
`CommandError`: Server reject the request. See response status code, headers and content for more info.
`UnderMaintenanceError`: Copyleaks servers are unavailable for maintenance. We recommend to implement exponential backoff algorithm as described here: https://api.copyleaks.com/documentation/v3/exponential-backoff
'''
url = f"{Consts.API_SERVER_URI}/v2/writer-detector/source-code/{scan_id}/check"
return _AIDetectionClient.__submit(url, auth_token, scan_id, submission)
92 changes: 92 additions & 0 deletions copyleaks/clients/writing_assistant_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

'''
The MIT License(MIT)
Copyright(c) 2016 Copyleaks LTD (https://copyleaks.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

import requests
from copyleaks.consts import Consts
from copyleaks.exceptions.command_error import CommandError
from copyleaks.exceptions.under_maintenance_error import UnderMaintenanceError
from copyleaks.helpers.copyleaks_client_helper import CopyleaksClientHelper

class _WritingAssistantClient:
@staticmethod
def __submit(url, auth_token, scan_id, submission):
assert url and scan_id and submission

CopyleaksClientHelper.verify_auth_token(auth_token)

headers = {
'Content-Type': 'application/json',
'User-Agent': Consts.USER_AGENT,
'Authorization': f"Bearer {auth_token['access_token']}"
}
json = submission.toJSON()
response = requests.post(url, headers=headers, data=json)
if response.ok:
return response.json()
elif response.status_code == 503:
raise UnderMaintenanceError()
else:
raise CommandError(response)

@staticmethod
def submit_text(auth_token, scan_id, submission):
'''
Use Copyleaks Writing Assistant to generate grammar, spelling and sentence corrections for a given text.
This endpoint will receive submitted text to be checked. The response will show the suggested corrections to the input text.
Raises:
`CommandError`: Server reject the request. See response status code, headers and content for more info.
`UnderMaintenanceError`: Copyleaks servers are unavailable for maintenance. We recommend to implement exponential backoff algorithm as described here: https://api.copyleaks.com/documentation/v3/exponential-backoff
'''
url = f"{Consts.API_SERVER_URI}/v1/writing-feedback/{scan_id}/check"
return _WritingAssistantClient.__submit(url, auth_token, scan_id, submission)

@staticmethod
def get_correction_types(language_code):
'''
Get a list of correction types supported within the Writing Assistant API.
Correction types apply to all supported languages.
The supplied language code for this request is used to determine the language of the texts returned.
Raises:
`CommandError`: Server reject the request. See response status code, headers and content for more info.
`UnderMaintenanceError`: Copyleaks servers are unavailable for maintenance. We recommend to implement exponential backoff algorithm as described here: https://api.copyleaks.com/documentation/v3/exponential-backoff
Returns:
List of supported correction types.
'''

url = f"{Consts.API_SERVER_URI}/v1/writing-feedback/correction-types/{language_code}"
headers = {
'User-Agent': Consts.USER_AGENT
}

response = requests.get(url, headers=headers)
if response.ok:
return response.json()
elif response.status_code == 503:
raise UnderMaintenanceError()
else:
raise CommandError(response.content)
5 changes: 5 additions & 0 deletions copyleaks/copyleaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@
from copyleaks.exceptions.rate_limit_error import RateLimitError
from copyleaks.exceptions.auth_expired_error import AuthExipredError
from enum import Enum
from copyleaks.clients.ai_detection_client import _AIDetectionClient
from copyleaks.clients.writing_assistant_client import _WritingAssistantClient


class Copyleaks(object):

WritingAssistantClient = _WritingAssistantClient
AiDetectionClient = _AIDetectionClient

@staticmethod
def set_identity_uri(uri):
'''
Expand Down
Empty file added copyleaks/helpers/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions copyleaks/helpers/copyleaks_client_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from datetime import datetime, timedelta
import dateutil.parser
import pytz
from copyleaks.exceptions.auth_expired_error import AuthExipredError

class CopyleaksClientHelper:
@staticmethod
def verify_auth_token(auth_token):
'''
Verify that Copyleaks authentication token is exists and not expired.
Parameters:
auth_token: Copyleaks authentication token
Raises:
`AuthExipredError`: authentication expired. Need to login again.
'''
assert auth_token and auth_token['.expires'] and auth_token['access_token']

now = pytz.UTC.localize(datetime.utcnow() + timedelta(0, 5 * 60)) # adds 5 minutes ahead for a safety shield.
upTo = dateutil.parser.parse(auth_token['.expires'])

if upTo <= now:
raise AuthExipredError() # expired
72 changes: 72 additions & 0 deletions copyleaks/models/submit/ai_detection_document.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'''
The MIT License(MIT)
Copyright(c) 2016 Copyleaks LTD (https://copyleaks.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

from abc import ABC
import json

class AiDetectionDocument(ABC):
def __init__(self, text):
assert text
self.text = text

def get_text(self):
return self.text

def set_text(self, value):
assert value
self.text = value

def get_sandbox(self):
return self.sandbox

def set_sandbox(self, value):
self.sandbox = value

def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)


class NaturalLanguageDocument(AiDetectionDocument):
def __init__(self, text):
super().__init__(text)

def get_language(self):
return self.language

def set_language(self, value):
self.language = value


class SourceCodeDocument(AiDetectionDocument):
def __init__(self, text, filename):
super().__init__(text)
self.filename = filename

def get_filename(self):
return self.filename

def set_filename(self, value):
assert value
self.filename = value
52 changes: 52 additions & 0 deletions copyleaks/models/submit/score_weights.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'''
The MIT License(MIT)
Copyright(c) 2016 Copyleaks LTD (https://copyleaks.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

class ScoreWeights:
def get_grammar_score_weight(self):
return self.grammarScoreWeight

def set_grammar_score_weight(self, value):
assert value
self.grammarScoreWeight = value

def get_mechanics_score_weight(self):
return self.mechanicsScoreWeight

def set_mechanics_score_weight(self, value):
assert value
self.mechanicsScoreWeight = value

def get_sentence_structure_score_weight(self):
return self.sentenceStructureScoreWeight

def set_sentence_structure_score_weight(self, value):
assert value
self.sentenceStructureScoreWeight = value

def get_word_choice_score_weight(self):
return self.wordChoiceScoreWeight

def set_word_choice_score_weight(self, value):
self.wordChoiceScoreWeight = value
assert value
Loading

0 comments on commit adb2fc3

Please sign in to comment.