Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions kindwise/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ def conversation_url(self, token: str):
def conversation_feedback_url(self, token: str):
return f'{self.identification_url}/{token}/conversation/feedback'

def _make_api_call(self, url, method: str, data: dict | None = None):
def _make_api_call(self, url, method: str, data: dict | None = None, timeout: float = 60.0):
headers = {
'Content-Type': 'application/json',
'Api-Key': self.api_key,
}
response = requests.request(method, url, json=data, headers=headers)
response = requests.request(method, url, json=data, headers=headers, timeout=timeout)
if not response.ok:
raise ValueError(f'Error while making an API call: {response.status_code=} {response.text=}')
return response
Expand Down Expand Up @@ -174,6 +174,7 @@ def identify(
max_image_size: int | None = 1500,
extra_get_params: str | dict[str | Any] = None,
extra_post_params: dict[str, Any] = None,
timeout: float = 60.0,
**kwargs,
) -> IdentificationType | dict:
payload = self._build_payload(
Expand All @@ -190,7 +191,7 @@ def identify(
details=details, language=language, asynchronous=asynchronous, extra_get_params=extra_get_params, **kwargs
)
url = f'{self.identification_url}{query}'
response = self._make_api_call(url, 'POST', payload)
response = self._make_api_call(url, 'POST', payload, timeout=timeout)
data = response.json()
return data if as_dict else self.identification_class.from_dict(data)

Expand Down Expand Up @@ -232,26 +233,35 @@ def get_identification(
language: str | list[str] = None,
extra_get_params: str | dict[str, str] = None,
as_dict: bool = False,
timeout: float = 60.0,
) -> IdentificationType | dict:
query = self._build_query(details=details, language=language, extra_get_params=extra_get_params)
url = f'{self.identification_url}/{token}{query}'
response = self._make_api_call(url, 'GET')
response = self._make_api_call(url, 'GET', timeout=timeout)
data = response.json()
return data if as_dict else self.identification_class.from_dict(data)

def delete_identification(self, identification: IdentificationType | str | int) -> bool:
def delete_identification(
self,
identification: IdentificationType | str | int,
timeout: float = 60.0,
) -> bool:
token = identification.access_token if isinstance(identification, Identification) else identification
url = f'{self.identification_url}/{token}'
self._make_api_call(url, 'DELETE')
self._make_api_call(url, 'DELETE', timeout=timeout)
return True

def usage_info(self, as_dict: bool = False) -> UsageInfo | dict:
response = self._make_api_call(self.usage_info_url, 'GET')
def usage_info(self, as_dict: bool = False, timeout: float = 60.0) -> UsageInfo | dict:
response = self._make_api_call(self.usage_info_url, 'GET', timeout=timeout)
data = response.json()
return data if as_dict else UsageInfo.from_dict(data)

def feedback(
self, identification: IdentificationType | str | int, comment: str | None = None, rating: int | None = None
self,
identification: IdentificationType | str | int,
comment: str | None = None,
rating: int | None = None,
timeout: float = 60.0,
) -> bool:
token = identification.access_token if isinstance(identification, Identification) else identification
if comment is None and rating is None:
Expand All @@ -261,7 +271,7 @@ def feedback(
data['comment'] = comment
if rating is not None:
data['rating'] = rating
self._make_api_call(self.feedback_url(token), 'POST', data)
self._make_api_call(self.feedback_url(token), 'POST', data, timeout=timeout)
return True

@property
Expand All @@ -280,6 +290,7 @@ def search(
language: str = None,
kb_type: KBType | str = None,
as_dict=False,
timeout: float = 60.0,
) -> SearchResult | dict:
if not query:
raise ValueError('Query parameter q must be provided')
Expand All @@ -290,20 +301,25 @@ def search(
if isinstance(kb_type, enum.Enum):
kb_type = kb_type.value
url = f'{self.kb_api_url}/{kb_type}/name_search{self._build_query(query=query, limit=limit, language=language)}'
response = self._make_api_call(url, 'GET')
response = self._make_api_call(url, 'GET', timeout=timeout)
if not response.ok:
raise ValueError(f'Error while searching knowledge base: {response.status_code=} {response.text=}')
return response.json() if as_dict else SearchResult.from_dict(response.json())

def get_kb_detail(
self, access_token: str, details: str | list[str], language: str = None, kb_type: KBType | str = None
self,
access_token: str,
details: str | list[str],
language: str = None,
kb_type: KBType | str = None,
timeout: float = 60.0,
) -> dict:
if kb_type is None:
kb_type = self.default_kb_type
if isinstance(kb_type, enum.Enum):
kb_type = kb_type.value
url = f'{self.kb_api_url}/{kb_type}/{access_token}{self._build_query(language=language, details=details)}'
response = self._make_api_call(url, 'GET')
response = self._make_api_call(url, 'GET', timeout=timeout)
if not response.ok:
raise ValueError(f'Error while getting knowledge base detail: {response.status_code=} {response.text=}')
return response.json()
Expand All @@ -317,27 +333,30 @@ def ask_question(
prompt: str = None,
temperature: float = None,
as_dict: bool = False,
timeout: float = 60.0,
) -> Conversation:
token = identification.access_token if isinstance(identification, Identification) else identification
data = {'question': question}
for key, value in [('model', model), ('app_name', app_name), ('prompt', prompt), ('temperature', temperature)]:
if value is not None:
data[key] = value
response = self._make_api_call(self.conversation_url(token), 'POST', data)
response = self._make_api_call(self.conversation_url(token), 'POST', data, timeout=timeout)
data = response.json()
return data if as_dict else Conversation.from_dict(data)

def get_conversation(self, identification: IdentificationType | str | int) -> Conversation:
def get_conversation(self, identification: IdentificationType | str | int, timeout: float = 60.0) -> Conversation:
token = identification.access_token if isinstance(identification, Identification) else identification
response = self._make_api_call(self.conversation_url(token), 'GET')
response = self._make_api_call(self.conversation_url(token), 'GET', timeout=timeout)
return Conversation.from_dict(response.json())

def delete_conversation(self, identification: IdentificationType | str | int) -> bool:
def delete_conversation(self, identification: IdentificationType | str | int, timeout: float = 60.0) -> bool:
token = identification.access_token if isinstance(identification, Identification) else identification
self._make_api_call(self.conversation_url(token), 'DELETE')
self._make_api_call(self.conversation_url(token), 'DELETE', timeout=timeout)
return True

def conversation_feedback(self, identification: IdentificationType | str | int, feedback: str | int | dict) -> bool:
def conversation_feedback(
self, identification: IdentificationType | str | int, feedback: str | int | dict, timeout: float = 60.0
) -> bool:
token = identification.access_token if isinstance(identification, Identification) else identification
self._make_api_call(self.conversation_feedback_url(token), 'POST', {'feedback': feedback})
self._make_api_call(self.conversation_feedback_url(token), 'POST', {'feedback': feedback}, timeout=timeout)
return True
1 change: 1 addition & 0 deletions kindwise/crop_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ def ask_question(
prompt: str = None,
temperature: float = None,
as_dict: bool = False,
timeout=60.0,
) -> Conversation:
raise NotImplementedError('Asking questions is currently not supported by crop.health.')
5 changes: 5 additions & 0 deletions kindwise/insect.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def identify(
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
extra_post_params: str | dict[str, dict[str, str]] | dict[str, str] = None,
timeout=60.0,
) -> InsectIdentification | dict:
identification = super().identify(
image=image,
Expand All @@ -111,6 +112,7 @@ def identify(
as_dict=True,
extra_get_params=extra_get_params,
extra_post_params=extra_post_params,
timeout=timeout,
)
if as_dict:
return identification
Expand All @@ -124,13 +126,15 @@ def get_identification(
language: str | list[str] = None,
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
timeout=60.0,
) -> InsectIdentification | dict:
identification = super().get_identification(
token=token,
details=details,
language=language,
as_dict=True,
extra_get_params=extra_get_params,
timeout=timeout,
)
return identification if as_dict else InsectIdentification.from_dict(identification)

Expand All @@ -147,5 +151,6 @@ def ask_question(
prompt: str = None,
temperature: float = None,
as_dict: bool = False,
timeout=60.0,
) -> Conversation:
raise NotImplementedError('Asking questions is currently not supported by insect.id')
5 changes: 5 additions & 0 deletions kindwise/mushroom.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def identify(
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
extra_post_params: str | dict[str, dict[str, str]] | dict[str, str] = None,
timeout=60.0,
) -> MushroomIdentification | dict:
identification = super().identify(
image=image,
Expand All @@ -115,6 +116,7 @@ def identify(
as_dict=True,
extra_get_params=extra_get_params,
extra_post_params=extra_post_params,
timeout=timeout,
)
if as_dict:
return identification
Expand All @@ -128,13 +130,15 @@ def get_identification(
language: str | list[str] = None,
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
timeout=60.0,
) -> MushroomIdentification | dict:
identification = super().get_identification(
token=token,
details=details,
language=language,
as_dict=True,
extra_get_params=extra_get_params,
timeout=timeout,
)
return identification if as_dict else MushroomIdentification.from_dict(identification)

Expand All @@ -151,5 +155,6 @@ def ask_question(
prompt: str = None,
temperature: float = None,
as_dict: bool = False,
timeout=60.0,
) -> Conversation:
raise NotImplementedError('Asking questions is currently not supported by mushroom.id')
18 changes: 14 additions & 4 deletions kindwise/plant.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ def identify(
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
extra_post_params: str | dict[str, dict[str, str]] | dict[str, str] = None,
timeout=60.0,
) -> PlantIdentification | RawPlantIdentification | HealthAssessment | dict:
identification = super().identify(
image=image,
Expand All @@ -279,6 +280,7 @@ def identify(
as_dict=True,
extra_get_params=extra_get_params,
extra_post_params=extra_post_params,
timeout=timeout,
)
if as_dict:
return identification
Expand All @@ -296,13 +298,15 @@ def get_identification(
language: str | list[str] = None,
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
timeout=60.0,
) -> PlantIdentification | dict:
identification = super().get_identification(
token=token,
details=self._build_details(details, disease_details),
language=language,
as_dict=True,
extra_get_params=extra_get_params,
timeout=timeout,
) # todo might be RawPlantIdentification
return identification if as_dict else PlantIdentification.from_dict(identification)

Expand Down Expand Up @@ -335,6 +339,7 @@ def health_assessment(
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
extra_post_params: str = None,
timeout=60.0,
) -> HealthAssessment | dict:
query = self._build_query(
details=details,
Expand All @@ -353,7 +358,7 @@ def health_assessment(
max_image_size=max_image_size,
extra_post_params=extra_post_params,
)
response = self._make_api_call(url, 'POST', payload)
response = self._make_api_call(url, 'POST', payload, timeout=timeout)
if not response.ok:
raise ValueError(f'Error while creating a health assessment: {response.status_code=} {response.text=}')
health_assessment = response.json()
Expand All @@ -367,19 +372,24 @@ def get_health_assessment(
full_disease_list: bool = False,
as_dict: bool = False,
extra_get_params: str | dict[str, str] = None,
timeout=60.0,
) -> HealthAssessment | dict:
query = self._build_query(
details=details, language=language, full_disease_list=full_disease_list, extra_get_params=extra_get_params
)
url = f'{self.identification_url}/{token}{query}'
response = self._make_api_call(url, 'GET')
response = self._make_api_call(url, 'GET', timeout=timeout)
if not response.ok:
raise ValueError(f'Error while getting a health assessment: {response.status_code=} {response.text=}')
health_assessment = response.json()
return health_assessment if as_dict else HealthAssessment.from_dict(health_assessment)

def delete_health_assessment(self, identification: HealthAssessment | str | int) -> bool:
return self.delete_identification(identification)
def delete_health_assessment(
self,
identification: HealthAssessment | str | int,
timeout=60.0,
) -> bool:
return self.delete_identification(identification, timeout=timeout)

@property
def views_path(self) -> Path:
Expand Down