willisapi-client 1.9.6__tar.gz → 1.9.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/PKG-INFO +1 -1
  2. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/__version__.py +1 -1
  3. willisapi_client-1.9.7/willisapi_client/services/metadata/archive.py +83 -0
  4. willisapi_client-1.9.7/willisapi_client/services/metadata/language_choices.py +124 -0
  5. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/metadata/upload.py +42 -0
  6. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/metadata/utils.py +6 -4
  7. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/willisapi_client.py +15 -8
  8. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/PKG-INFO +1 -1
  9. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/SOURCES.txt +1 -0
  10. willisapi_client-1.9.6/willisapi_client/services/metadata/language_choices.py +0 -86
  11. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/LICENSE +0 -0
  12. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/MANIFEST.in +0 -0
  13. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/README.md +0 -0
  14. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/RELEASE.md +0 -0
  15. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/requirements.txt +0 -0
  16. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/setup.cfg +0 -0
  17. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/setup.py +0 -0
  18. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/tests/test_diarize.py +0 -0
  19. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/tests/test_diarize_call_remaining.py +0 -0
  20. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/__init__.py +0 -0
  21. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/logging_setup.py +0 -0
  22. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/__init__.py +0 -0
  23. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/api.py +0 -0
  24. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/diarize/__init__.py +0 -0
  25. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/diarize/diarize_utils.py +0 -0
  26. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/diarize/willisdiarize.py +0 -0
  27. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/diarize/willisdiarize_call_remaining.py +0 -0
  28. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/exceptions.py +0 -0
  29. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/services/metadata/__init__.py +0 -0
  30. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client/timer.py +0 -0
  31. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/dependency_links.txt +0 -0
  32. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/not-zip-safe +0 -0
  33. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/requires.txt +0 -0
  34. {willisapi_client-1.9.6 → willisapi_client-1.9.7}/willisapi_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: willisapi_client
3
- Version: 1.9.6
3
+ Version: 1.9.7
4
4
  Summary: A Python client for willisapi
5
5
  Home-page: https://github.com/bklynhlth/willsiapi_client
6
6
  Author: bklynhlth
@@ -1,7 +1,7 @@
1
1
  """Version details for willisapi_client"""
2
2
 
3
3
  __client__ = "willisapi_client"
4
- __latestVersion__ = "1.9.6"
4
+ __latestVersion__ = "1.9.7"
5
5
  __url__ = "https://github.com/bklynhlth/willsiapi_client"
6
6
  __short_description__ = "A Python client for willisapi"
7
7
  __content_type__ = "text/markdown"
@@ -0,0 +1,83 @@
1
+ import os
2
+ import requests
3
+
4
+ from willisapi_client.willisapi_client import WillisapiClient
5
+ from willisapi_client.logging_setup import logger as logger
6
+
7
+
8
+ def _archive_headers(api_key):
9
+ return {
10
+ "Content-Type": "application/json",
11
+ "Accept": "application/json",
12
+ "Authorization": f"token {api_key}",
13
+ }
14
+
15
+
16
+ def archive_metadata_csv(api_key, csv_path, total_rows, upload_type, env=None):
17
+ """Archive the source metadata CSV alongside the data upload.
18
+
19
+ Creates a server-side tracking row, then PUTs the raw CSV to the returned
20
+ presigned S3 URL. Returns the tracking ``record_id`` on success (so the
21
+ caller can finalize it with row counts), or ``None`` on failure.
22
+
23
+ All failures are logged and swallowed — archiving must never abort the
24
+ actual data upload.
25
+ """
26
+ try:
27
+ wc = WillisapiClient(env=env)
28
+ payload = {
29
+ "filename": os.path.basename(csv_path),
30
+ "total_rows": total_rows,
31
+ "upload_type": upload_type,
32
+ }
33
+ res = requests.post(
34
+ wc.get_csv_archive_url(), headers=_archive_headers(api_key), json=payload
35
+ )
36
+ if res.status_code != 201:
37
+ logger.warning(f"CSV archive init failed: {res.status_code} {res.text}")
38
+ return None
39
+
40
+ body = res.json()
41
+ record_id = body.get("record_id")
42
+ presigned = body.get("presigned_url")
43
+ if not presigned:
44
+ logger.warning("CSV archive: no presigned URL returned")
45
+ return None
46
+
47
+ with open(csv_path, "rb") as f:
48
+ put_res = requests.put(
49
+ presigned, data=f, headers={"Content-Type": "text/csv"}
50
+ )
51
+ if put_res.status_code not in (200, 204):
52
+ logger.warning(f"CSV archive S3 upload failed: {put_res.status_code}")
53
+ finalize_metadata_csv(api_key, record_id, "failed", 0, 0, env=env)
54
+ return None
55
+
56
+ return record_id
57
+ except Exception as ex:
58
+ logger.warning(f"CSV archive error: {ex}")
59
+ return None
60
+
61
+
62
+ def finalize_metadata_csv(
63
+ api_key, record_id, status, successful_rows, failed_rows, env=None
64
+ ):
65
+ """Report the CSV archive outcome and parsed row counts to the server."""
66
+ if not record_id:
67
+ return
68
+ try:
69
+ wc = WillisapiClient(env=env)
70
+ payload = {
71
+ "status": status,
72
+ "successful_rows": successful_rows,
73
+ "failed_rows": failed_rows,
74
+ }
75
+ res = requests.patch(
76
+ wc.get_csv_archive_finalize_url(record_id),
77
+ headers=_archive_headers(api_key),
78
+ json=payload,
79
+ )
80
+ if res.status_code != 200:
81
+ logger.warning(f"CSV archive finalize failed: {res.status_code} {res.text}")
82
+ except Exception as ex:
83
+ logger.warning(f"CSV archive finalize error: {ex}")
@@ -0,0 +1,124 @@
1
+ # https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html
2
+ # (language_code, display_name)
3
+ SUPPORTED_LANGUAGES = [
4
+ ("en-US", "English (US)"),
5
+ ("es-US", "Spanish (US)"),
6
+ ("ab-GE", "Abkhaz"),
7
+ ("af-ZA", "Afrikaans"),
8
+ ("sq-AL", "Albanian"),
9
+ ("am-ET", "Amharic"),
10
+ ("ar-AE", "Arabic, Gulf"),
11
+ ("ar-SA", "Arabic, Modern Standard"),
12
+ ("hy-AM", "Armenian"),
13
+ ("ast-ES", "Asturian"),
14
+ ("az-AZ", "Azerbaijani"),
15
+ ("ba-RU", "Bashkir"),
16
+ ("eu-ES", "Basque"),
17
+ ("be-BY", "Belarusian"),
18
+ ("bn-IN", "Bengali"),
19
+ ("bs-BA", "Bosnian"),
20
+ ("my-MM", "Burmese"),
21
+ ("bg-BG", "Bulgarian"),
22
+ ("ca-ES", "Catalan"),
23
+ ("ckb-IR", "Central Kurdish (Iran)"),
24
+ ("ckb-IQ", "Central Kurdish (Iraq)"),
25
+ ("zh-HK", "Chinese, Cantonese"),
26
+ ("zh-CN", "Chinese, Simplified"),
27
+ ("zh-TW", "Chinese, Traditional"),
28
+ ("hr-HR", "Croatian"),
29
+ ("cs-CZ", "Czech"),
30
+ ("da-DK", "Danish"),
31
+ ("nl-NL", "Dutch"),
32
+ ("en-AU", "English, Australian"),
33
+ ("en-GB", "English, British"),
34
+ ("en-IN", "English, Indian"),
35
+ ("en-IE", "English, Irish"),
36
+ ("en-NZ", "English, New Zealand"),
37
+ ("en-AB", "English, Scottish"),
38
+ ("en-ZA", "English, South African"),
39
+ ("en-WL", "English, Welsh"),
40
+ ("et-EE", "Estonian"),
41
+ ("et-ET", "Estonian (et-ET)"),
42
+ ("fa-IR", "Farsi"),
43
+ ("fa-AF", "Farsi, Afghan"),
44
+ ("fi-FI", "Finnish"),
45
+ ("fr-FR", "French"),
46
+ ("fr-CA", "French, Canadian"),
47
+ ("gl-ES", "Galician"),
48
+ ("ka-GE", "Georgian"),
49
+ ("de-DE", "German"),
50
+ ("de-CH", "German, Swiss"),
51
+ ("el-GR", "Greek"),
52
+ ("gu-IN", "Gujarati"),
53
+ ("ht-HT", "Haitian Creole"),
54
+ ("ha-NG", "Hausa"),
55
+ ("he-IL", "Hebrew"),
56
+ ("hi-IN", "Hindi, Indian"),
57
+ ("hu-HU", "Hungarian"),
58
+ ("is-IS", "Icelandic"),
59
+ ("id-ID", "Indonesian"),
60
+ ("it-IT", "Italian"),
61
+ ("ja-JP", "Japanese"),
62
+ ("jv-ID", "Javanese"),
63
+ ("kab-DZ", "Kabyle"),
64
+ ("kn-IN", "Kannada"),
65
+ ("kk-KZ", "Kazakh"),
66
+ ("km-KH", "Khmer"),
67
+ ("rw-RW", "Kinyarwanda"),
68
+ ("ko-KR", "Korean"),
69
+ ("ky-KG", "Kyrgyz"),
70
+ ("lv-LV", "Latvian"),
71
+ ("lt-LT", "Lithuanian"),
72
+ ("lg-IN", "Luganda"),
73
+ ("mk-MK", "Macedonian"),
74
+ ("ms-MY", "Malay"),
75
+ ("ml-IN", "Malayalam"),
76
+ ("mt-MT", "Maltese"),
77
+ ("mr-IN", "Marathi"),
78
+ ("mhr-RU", "Meadow Mari"),
79
+ ("mn-MN", "Mongolian"),
80
+ ("ne-NP", "Nepali"),
81
+ ("no-NO", "Norwegian Bokmål"),
82
+ ("or-IN", "Odia/Oriya"),
83
+ ("ps-AF", "Pashto"),
84
+ ("pl-PL", "Polish"),
85
+ ("pt-PT", "Portuguese"),
86
+ ("pt-BR", "Portuguese, Brazilian"),
87
+ ("pa-IN", "Punjabi"),
88
+ ("ro-RO", "Romanian"),
89
+ ("ru-RU", "Russian"),
90
+ ("sr-RS", "Serbian"),
91
+ ("si-LK", "Sinhala"),
92
+ ("sk-SK", "Slovak"),
93
+ ("sl-SI", "Slovenian"),
94
+ ("so-SO", "Somali"),
95
+ ("es-ES", "Spanish"),
96
+ ("es-MX", "Spanish, Mexican"),
97
+ ("su-ID", "Sundanese"),
98
+ ("sw-KE", "Swahili, Kenya"),
99
+ ("sw-BI", "Swahili, Burundi"),
100
+ ("sw-RW", "Swahili, Rwanda"),
101
+ ("sw-TZ", "Swahili, Tanzania"),
102
+ ("sw-UG", "Swahili, Uganda"),
103
+ ("sv-SE", "Swedish"),
104
+ ("tl-PH", "Tagalog/Filipino"),
105
+ ("ta-IN", "Tamil"),
106
+ ("tt-RU", "Tatar"),
107
+ ("te-IN", "Telugu"),
108
+ ("th-TH", "Thai"),
109
+ ("tr-TR", "Turkish"),
110
+ ("uk-UA", "Ukrainian"),
111
+ ("ug-CN", "Uyghur"),
112
+ ("uz-UZ", "Uzbek"),
113
+ ("vi-VN", "Vietnamese"),
114
+ ("cy-WL", "Welsh"),
115
+ ("wo-SN", "Wolof"),
116
+ ("zu-ZA", "Zulu"),
117
+ ]
118
+
119
+ LANGUAGE_CHOICES = [code for code, _ in SUPPORTED_LANGUAGES]
120
+
121
+ SEX_CHOICES = [
122
+ ("Male", "M"),
123
+ ("Female", "F"),
124
+ ]
@@ -19,6 +19,10 @@ from willisapi_client.services.metadata.utils import (
19
19
  find_files_with_pattern,
20
20
  get_last_n_directories,
21
21
  )
22
+ from willisapi_client.services.metadata.archive import (
23
+ archive_metadata_csv,
24
+ finalize_metadata_csv,
25
+ )
22
26
 
23
27
  VALID_SCORE_TYPES = ["rater", "reviewer"]
24
28
 
@@ -38,6 +42,15 @@ def upload(api_key: str, csv_path: str, **kwargs):
38
42
  headers["Authorization"] = f"token {api_key}"
39
43
  logger.info(f'{datetime.now().strftime("%H:%M:%S")}: beginning upload')
40
44
 
45
+ # Archive the source metadata CSV and open a tracking record.
46
+ archive_record_id = archive_metadata_csv(
47
+ api_key,
48
+ csv_path,
49
+ int(csv.transformed_df.shape[0]),
50
+ upload_type="data",
51
+ env=kwargs.get("env"),
52
+ )
53
+
41
54
  results = []
42
55
  for index, row in tqdm(
43
56
  csv.transformed_df.iterrows(), total=csv.transformed_df.shape[0]
@@ -96,6 +109,16 @@ def upload(api_key: str, csv_path: str, **kwargs):
96
109
  result_row["error"] = f"{err}"
97
110
  results.append(result_row)
98
111
 
112
+ successful_rows = sum(1 for r in results if r.get("upload_status") == "Success")
113
+ finalize_metadata_csv(
114
+ api_key,
115
+ archive_record_id,
116
+ "successful",
117
+ successful_rows,
118
+ len(results) - successful_rows,
119
+ env=kwargs.get("env"),
120
+ )
121
+
99
122
  results_df = pd.DataFrame(results)
100
123
  return results_df
101
124
  else:
@@ -128,6 +151,15 @@ def processed_upload(api_key: str, csv_path: str, output_path: str, **kwargs):
128
151
  headers["Authorization"] = f"token {api_key}"
129
152
  logger.info(f'{datetime.now().strftime("%H:%M:%S")}: beginning upload')
130
153
 
154
+ # Archive the source processed-data metadata CSV and open a tracking record.
155
+ archive_record_id = archive_metadata_csv(
156
+ api_key,
157
+ csv_path,
158
+ int(csv.transformed_df.shape[0]),
159
+ upload_type="processed_data",
160
+ env=kwargs.get("env"),
161
+ )
162
+
131
163
  results = []
132
164
  for index, row in tqdm(
133
165
  csv.transformed_df.iterrows(), total=csv.transformed_df.shape[0]
@@ -205,6 +237,16 @@ def processed_upload(api_key: str, csv_path: str, output_path: str, **kwargs):
205
237
  result_row["error"] = f"{err}"
206
238
  results.append(result_row)
207
239
 
240
+ successful_rows = sum(1 for r in results if r.get("upload_status") == "Success")
241
+ finalize_metadata_csv(
242
+ api_key,
243
+ archive_record_id,
244
+ "successful",
245
+ successful_rows,
246
+ len(results) - successful_rows,
247
+ env=kwargs.get("env"),
248
+ )
249
+
208
250
  results_df = pd.DataFrame(results)
209
251
  return results_df
210
252
  else:
@@ -421,13 +421,15 @@ class UploadUtils:
421
421
  def validate_row(self):
422
422
  if not os.path.exists(self.row.file_path):
423
423
  return (False, "File path does not exist")
424
- if self.row.language not in LANGUAGE_CHOICES:
425
- return (False, f"Invalid language: {self.row.language}")
424
+ language = getattr(self.row, "language", None)
425
+ if language and language not in LANGUAGE_CHOICES:
426
+ return (False, f"Invalid language: {language}")
426
427
  return (True, None)
427
428
 
428
429
  def validate_processed_data_row(self):
429
- if self.row.language not in LANGUAGE_CHOICES:
430
- return (False, f"Invalid language: {self.row.language}")
430
+ language = getattr(self.row, "language", None)
431
+ if language and language not in LANGUAGE_CHOICES:
432
+ return (False, f"Invalid language: {language}")
431
433
  return (True, None)
432
434
 
433
435
  def calculate_file_checksum(self, file_path: str) -> str:
@@ -14,18 +14,19 @@ class WillisapiClient:
14
14
  def __init__(self, *args, **kwargs) -> None:
15
15
  self.client_version = get_client_version()
16
16
  self.api_version = math.floor(self.client_version)
17
- self.api_uri = "api.brooklyn.health"
17
+ self.api_uri = "api.willis.health"
18
18
  self.env = kwargs["env"] if "env" in kwargs else None
19
19
 
20
- def get_base_url(self):
20
+ def get_api_host(self):
21
21
  if self.env:
22
- return f"https://{self.env}-{self.api_uri}/v{self.api_version}/"
23
- return f"https://{self.api_uri}/v{self.api_version}/"
22
+ return f"api.{self.env}.willis.health"
23
+ return self.api_uri
24
+
25
+ def get_base_url(self):
26
+ return f"https://{self.get_api_host()}/v{self.api_version}/"
24
27
 
25
28
  def get_base_v2_url(self):
26
- if self.env:
27
- return f"https://{self.env}-{self.api_uri}/api/v2/"
28
- return f"https://{self.api_uri}/api/v2/"
29
+ return f"https://{self.get_api_host()}/api/v2/"
29
30
 
30
31
  def get_diarize_remaining_calls_url(self):
31
32
  return self.get_base_url() + "willis-diarize-call-remaining"
@@ -35,9 +36,15 @@ class WillisapiClient:
35
36
 
36
37
  def get_upload_url(self):
37
38
  return self.get_base_v2_url() + "metadata/upload"
38
-
39
+
39
40
  def get_processed_upload_url(self):
40
41
  return self.get_base_v2_url() + "metadata/processed-data/upload"
41
42
 
43
+ def get_csv_archive_url(self):
44
+ return self.get_base_v2_url() + "metadata/csv-archive"
45
+
46
+ def get_csv_archive_finalize_url(self, record_id):
47
+ return self.get_csv_archive_url() + f"/{record_id}"
48
+
42
49
  def get_headers(self):
43
50
  return {"Content-Type": "application/json", "Accept": "application/json"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: willisapi-client
3
- Version: 1.9.6
3
+ Version: 1.9.7
4
4
  Summary: A Python client for willisapi
5
5
  Home-page: https://github.com/bklynhlth/willsiapi_client
6
6
  Author: bklynhlth
@@ -26,6 +26,7 @@ willisapi_client/services/diarize/diarize_utils.py
26
26
  willisapi_client/services/diarize/willisdiarize.py
27
27
  willisapi_client/services/diarize/willisdiarize_call_remaining.py
28
28
  willisapi_client/services/metadata/__init__.py
29
+ willisapi_client/services/metadata/archive.py
29
30
  willisapi_client/services/metadata/language_choices.py
30
31
  willisapi_client/services/metadata/upload.py
31
32
  willisapi_client/services/metadata/utils.py
@@ -1,86 +0,0 @@
1
- # https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html
2
- Afrikaans = "af-ZA"
3
- Arabic_gulf = "ar-AE"
4
- Arabic_modern_standard = "ar-SA"
5
- Chinese_simplified = "zh-CN"
6
- Chinese_traditional = "zh-TW"
7
- Danish = "da-DK"
8
- Dutch = "nl-NL"
9
- English_aus = "en-AU"
10
- English_birtish = "en-GB"
11
- English_ind = "en-IN"
12
- English_irish = "en-IE"
13
- English_new_zealand = "en-NZ"
14
- English_scottish = "en-AB"
15
- English_south_african = "en-ZA"
16
- English_us = "en-US"
17
- English_welsh = "en-WL"
18
- French = "fr-FR"
19
- French_canadian = "fr-CA"
20
- Farsi = "fa-IR"
21
- German = "de-DE"
22
- German_swiss = "de-CH"
23
- Hebrew = "he-IL"
24
- Hindi_ind = "hi-IN"
25
- Indonesian = "id-ID"
26
- Italian = "it-IT"
27
- Japanese = "ja-JP"
28
- Korean = "ko-KR"
29
- Malay = "ms-MY"
30
- Portuguese = "pt-PT"
31
- Portuguese_brazilian = "pt-BR"
32
- Russian = "ru-RU"
33
- Spanish = "es-ES"
34
- Spanish_us = "es-US"
35
- Swedish = "sv-SE"
36
- Tamil = "ta-IN"
37
- Telugu = "te-IN"
38
- Thai = "th-TH"
39
- Turkish = "tr-TR"
40
- Vietnamese = "vi-VN"
41
-
42
- LANGUAGE_CHOICES = [
43
- Afrikaans,
44
- Arabic_gulf,
45
- Arabic_modern_standard,
46
- Chinese_simplified,
47
- Chinese_traditional,
48
- Danish,
49
- Dutch,
50
- English_aus,
51
- English_birtish,
52
- English_ind,
53
- English_irish,
54
- English_new_zealand,
55
- English_scottish,
56
- English_south_african,
57
- English_us,
58
- English_welsh,
59
- French,
60
- French_canadian,
61
- Farsi,
62
- German,
63
- German_swiss,
64
- Hebrew,
65
- Hindi_ind,
66
- Indonesian,
67
- Italian,
68
- Japanese,
69
- Korean,
70
- Malay,
71
- Portuguese,
72
- Portuguese_brazilian,
73
- Russian,
74
- Spanish,
75
- Spanish_us,
76
- Swedish,
77
- Tamil,
78
- Telugu,
79
- Thai,
80
- Turkish,
81
- Vietnamese,
82
- ]
83
- SEX_CHOICES = [
84
- ("Male", "M"),
85
- ("Female", "F"),
86
- ]