dwani 0.1.18__tar.gz → 0.1.20__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dwani
3
- Version: 0.1.18
3
+ Version: 0.1.20
4
4
  Summary: Multimodal API for Indian + European languages (Chat, Vision, TTS, ASR, Translate, Docs)
5
5
  Author-email: sachin <python@dwani.ai>
6
6
  License: MIT License
@@ -78,7 +78,7 @@ dwani.api_base = os.getenv("DWANI_API_BASE_URL")
78
78
 
79
79
  #### Document - OCR
80
80
  ```python
81
- result = dwani.Documents.run_ocr_number(file_path="dwani-workshop.pdf", page_number=1, model="gemma3")
81
+ result = dwani.Documents.run_ocr_page(file_path="dwani-workshop.pdf", page_number=1, model="gemma3")
82
82
  print(result)
83
83
  ```
84
84
  ```json
@@ -86,6 +86,17 @@ print(result)
86
86
  ```
87
87
 
88
88
 
89
+ #### Document - Summary
90
+
91
+ ```python
92
+ result = dwani.Documents.summarize_all(
93
+ file_path="dwani-workshop.pdf", model="gemma3" , tgt_lang="english"
94
+ )
95
+
96
+ print("Document Query Response: gemma3- ", result["summary"])
97
+ ```
98
+
99
+
89
100
  ### Text Query
90
101
  ---
91
102
  - gemma3 (default)
@@ -168,4 +179,16 @@ python -m build
168
179
 
169
180
  python -m twine upload dist/*
170
181
 
182
+ -->
183
+
184
+ <!--
185
+ Without Batch
186
+ 2025-07-14 13:39:50,330 - dwani_api - INFO - Request to /indic-summarize-pdf-all took 245.381 seconds
187
+ INFO:dwani_api:Request to /indic-summarize-pdf-all took 245.381 seconds
188
+
189
+ With Batch
190
+
191
+ vllm serve google/gemma-3-4b-it --served-model-name gemma3 --host 0.0.0.0 --port 9000 --gpu-memory-utilization 0.8 --tensor-parallel-size 1 --max-model-len 65536 --dtype bfloat16
192
+
193
+
171
194
  -->
@@ -41,7 +41,7 @@ dwani.api_base = os.getenv("DWANI_API_BASE_URL")
41
41
 
42
42
  #### Document - OCR
43
43
  ```python
44
- result = dwani.Documents.run_ocr_number(file_path="dwani-workshop.pdf", page_number=1, model="gemma3")
44
+ result = dwani.Documents.run_ocr_page(file_path="dwani-workshop.pdf", page_number=1, model="gemma3")
45
45
  print(result)
46
46
  ```
47
47
  ```json
@@ -49,6 +49,17 @@ print(result)
49
49
  ```
50
50
 
51
51
 
52
+ #### Document - Summary
53
+
54
+ ```python
55
+ result = dwani.Documents.summarize_all(
56
+ file_path="dwani-workshop.pdf", model="gemma3" , tgt_lang="english"
57
+ )
58
+
59
+ print("Document Query Response: gemma3- ", result["summary"])
60
+ ```
61
+
62
+
52
63
  ### Text Query
53
64
  ---
54
65
  - gemma3 (default)
@@ -131,4 +142,16 @@ python -m build
131
142
 
132
143
  python -m twine upload dist/*
133
144
 
145
+ -->
146
+
147
+ <!--
148
+ Without Batch
149
+ 2025-07-14 13:39:50,330 - dwani_api - INFO - Request to /indic-summarize-pdf-all took 245.381 seconds
150
+ INFO:dwani_api:Request to /indic-summarize-pdf-all took 245.381 seconds
151
+
152
+ With Batch
153
+
154
+ vllm serve google/gemma-3-4b-it --served-model-name gemma3 --host 0.0.0.0 --port 9000 --gpu-memory-utilization 0.8 --tensor-parallel-size 1 --max-model-len 65536 --dtype bfloat16
155
+
156
+
134
157
  -->
@@ -53,25 +53,30 @@ class translate:
53
53
 
54
54
  class document:
55
55
  @staticmethod
56
- def run_ocr_number(file_path, page_number=1, model="gemma3"):
57
- return _get_client().document_ocr_number(file_path, page_number, model)
56
+ def run_ocr_page(file_path, page_number=1, model="gemma3"):
57
+ return _get_client().document_ocr_page(file_path, page_number, model)
58
58
 
59
59
  @staticmethod
60
60
  def run_ocr_all(file_path, model="gemma3"):
61
61
  return _get_client().document_ocr_all(file_path, model)
62
62
 
63
63
  @staticmethod
64
- def run_summarize(file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
65
- return _get_client().document_summarize(file_path, page_number, src_lang, tgt_lang, model)
64
+ def run_summarize_page(file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
65
+ return _get_client().document_summarize_page(file_path, page_number, tgt_lang, model)
66
+
67
+
68
+ @staticmethod
69
+ def run_summarize_all(file_path, tgt_lang="kan_Knda", model="gemma3"):
70
+ return _get_client().document_summarize_all(file_path, tgt_lang, model)
66
71
 
67
72
  @staticmethod
68
- def run_extract(file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
69
- return _get_client().extract(file_path, page_number, src_lang, tgt_lang, model)
73
+ def run_extract(file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
74
+ return _get_client().extract(file_path, page_number, tgt_lang, model)
70
75
 
71
76
  @staticmethod
72
77
  def run_doc_query(file_path, page_number=1, prompt="list the key points", src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
73
78
  return _get_client().doc_query(file_path, page_number, prompt, src_lang, tgt_lang, model)
74
79
 
75
80
  @staticmethod
76
- def run_doc_query_kannada(file_path, page_number=1, prompt="list key points", src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
81
+ def run_doc_query_kannada(file_path, page_number=1, prompt="list key points", src_lang="kan_Latn", tgt_lang="kan_Knda", model="gemma3"):
77
82
  return _get_client().doc_query_kannada(file_path, page_number, prompt, src_lang, tgt_lang, model)
@@ -42,7 +42,8 @@ def asr_transcribe(client, file_path, language):
42
42
  resp = requests.post(
43
43
  f"{client.api_base}/v1/transcribe/?language={api_language}",
44
44
  headers=client._headers(),
45
- files=files
45
+ files=files,
46
+ timeout=90
46
47
  )
47
48
  if resp.status_code != 200:
48
49
  raise DwaniAPIError(resp)
@@ -12,7 +12,8 @@ def audio_speech(client, input, response_format="mp3", output_file=None, languag
12
12
  headers={**client._headers(), "accept": "application/json"},
13
13
  params=params,
14
14
  data='', # Empty body, as in the curl example
15
- stream=True
15
+ stream=True,
16
+ timeout=90
16
17
  )
17
18
  if resp.status_code != 200:
18
19
  raise DwaniAPIError(resp)
@@ -46,7 +46,8 @@ def chat_direct(client, prompt, model="gemma3", system_prompt=""):
46
46
  resp = requests.post(
47
47
  url,
48
48
  headers={**client._headers(), "Content-Type": "application/json"},
49
- json=payload
49
+ json=payload,
50
+ timeout=90
50
51
  )
51
52
  if resp.status_code != 200:
52
53
  raise DwaniAPIError(resp)
@@ -72,7 +73,8 @@ def chat_create(client, prompt, src_lang, tgt_lang, model="gemma3"):
72
73
  resp = requests.post(
73
74
  url,
74
75
  headers={**client._headers(), "Content-Type": "application/json"},
75
- json=payload
76
+ json=payload,
77
+ timeout=90
76
78
  )
77
79
  if resp.status_code != 200:
78
80
  raise DwaniAPIError(resp)
@@ -51,13 +51,13 @@ class DwaniClient:
51
51
  from .docs import document_ocr_all
52
52
  return document_ocr_all(self, file_path=file_path, model=model)
53
53
 
54
- def document_summarize(self, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
54
+ def document_summarize(self, file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
55
55
  from .docs import document_summarize
56
- return document_summarize(self, file_path, page_number, src_lang, tgt_lang, model)
56
+ return document_summarize(self, file_path, page_number, tgt_lang, model)
57
57
 
58
- def extract(self, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
58
+ def extract(self, file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
59
59
  from .docs import extract
60
- return extract(self, file_path=file_path, page_number=page_number, src_lang=src_lang, tgt_lang=tgt_lang, model=model)
60
+ return extract(self, file_path=file_path, page_number=page_number, tgt_lang=tgt_lang, model=model)
61
61
 
62
62
  def doc_query(self, file_path, page_number=1, prompt="list the key points", src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
63
63
  from .docs import doc_query
@@ -56,7 +56,7 @@ def document_ocr_all(client, file_path, model="gemma3"):
56
56
  headers=client._headers(),
57
57
  files=files,
58
58
  data=data,
59
- timeout=60
59
+ timeout=90
60
60
  )
61
61
  resp.raise_for_status()
62
62
  except requests.RequestException as e:
@@ -67,7 +67,7 @@ def document_ocr_all(client, file_path, model="gemma3"):
67
67
  return resp.json()
68
68
 
69
69
 
70
- def document_ocr_number(client, file_path, page_number, model="gemma3"):
70
+ def document_ocr_page(client, file_path, page_number, model="gemma3"):
71
71
  """OCR a document (image/PDF) and return extracted text."""
72
72
  logger.debug(f"Calling document_ocr: file_path={file_path}, model={model}")
73
73
  validate_model(model)
@@ -85,7 +85,7 @@ def document_ocr_number(client, file_path, page_number, model="gemma3"):
85
85
  headers=client._headers(),
86
86
  files=files,
87
87
  params=params,
88
- timeout=60
88
+ timeout=90
89
89
  )
90
90
  resp.raise_for_status()
91
91
  except requests.RequestException as e:
@@ -94,9 +94,10 @@ def document_ocr_number(client, file_path, page_number, model="gemma3"):
94
94
 
95
95
  logger.debug(f"OCR response: {resp.status_code}")
96
96
  return resp.json()
97
- def document_summarize(client, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
97
+
98
+ def document_summarize_page(client, file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
98
99
  """Summarize a PDF document with language and page number options."""
99
- logger.debug(f"Calling document_summarize: file_path={file_path}, page_number={page_number}, src_lang={src_lang}, tgt_lang={tgt_lang}, model={model}")
100
+ logger.debug(f"Calling document_summarize: file_path={file_path}, page_number={page_number}, tgt_lang={tgt_lang}, model={model}")
100
101
  validate_model(model)
101
102
 
102
103
  if not file_path.lower().endswith('.pdf'):
@@ -104,7 +105,6 @@ def document_summarize(client, file_path, page_number=1, src_lang="eng_Latn", tg
104
105
  if page_number < 1:
105
106
  raise ValueError("Page number must be at least 1")
106
107
 
107
- src_lang_code = normalize_language(src_lang)
108
108
  tgt_lang_code = normalize_language(tgt_lang)
109
109
 
110
110
  url = f"{client.api_base}/v1/indic-summarize-pdf"
@@ -113,7 +113,6 @@ def document_summarize(client, file_path, page_number=1, src_lang="eng_Latn", tg
113
113
  files = {"file": (file_path, f, "application/pdf")}
114
114
  data = {
115
115
  "page_number": str(page_number),
116
- "src_lang": src_lang_code,
117
116
  "tgt_lang": tgt_lang_code,
118
117
  "model": model
119
118
  }
@@ -124,7 +123,44 @@ def document_summarize(client, file_path, page_number=1, src_lang="eng_Latn", tg
124
123
  headers=headers,
125
124
  files=files,
126
125
  data=data,
127
- timeout=60
126
+ timeout=90
127
+ )
128
+ resp.raise_for_status()
129
+ except requests.RequestException as e:
130
+ logger.error(f"Summarize request failed: {str(e)}")
131
+ raise DwaniAPIError(resp) if 'resp' in locals() else DwaniAPIError.from_exception(e)
132
+
133
+ logger.debug(f"Summarize response: {resp.status_code}")
134
+
135
+ return resp.json()
136
+
137
+
138
+ def document_summarize_all(client, file_path, tgt_lang="kan_Knda", model="gemma3"):
139
+ """Summarize a PDF document with language """
140
+ logger.debug(f"Calling document_summarize: file_path={file_path}, tgt_lang={tgt_lang}, model={model}")
141
+ validate_model(model)
142
+
143
+ if not file_path.lower().endswith('.pdf'):
144
+ raise ValueError("File must be a PDF")
145
+
146
+ tgt_lang_code = normalize_language(tgt_lang)
147
+
148
+ url = f"{client.api_base}/v1/indic-summarize-pdf-all"
149
+ headers = client._headers()
150
+ with open(file_path, "rb") as f:
151
+ files = {"file": (file_path, f, "application/pdf")}
152
+ data = {
153
+ "tgt_lang": tgt_lang_code,
154
+ "model": model
155
+ }
156
+
157
+ try:
158
+ resp = requests.post(
159
+ url,
160
+ headers=headers,
161
+ files=files,
162
+ data=data,
163
+ timeout=90
128
164
  )
129
165
  resp.raise_for_status()
130
166
  except requests.RequestException as e:
@@ -135,9 +171,10 @@ def document_summarize(client, file_path, page_number=1, src_lang="eng_Latn", tg
135
171
 
136
172
  return resp.json()
137
173
 
138
- def extract(client, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
174
+
175
+ def extract(client, file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
139
176
  """Extract and translate text from a PDF document using form data."""
140
- logger.debug(f"Calling extract: file_path={file_path}, page_number={page_number}, src_lang={src_lang}, tgt_lang={tgt_lang}, model={model}")
177
+ logger.debug(f"Calling extract: file_path={file_path}, page_number={page_number}, tgt_lang={tgt_lang}, model={model}")
141
178
  validate_model(model)
142
179
 
143
180
  if not file_path.lower().endswith('.pdf'):
@@ -145,7 +182,6 @@ def extract(client, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan
145
182
  if page_number < 1:
146
183
  raise ValueError("Page number must be at least 1")
147
184
 
148
- src_lang_code = normalize_language(src_lang)
149
185
  tgt_lang_code = normalize_language(tgt_lang)
150
186
 
151
187
  url = f"{client.api_base}/v1/indic-extract-text/"
@@ -155,7 +191,6 @@ def extract(client, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan
155
191
 
156
192
  data = {
157
193
  "page_number": str(page_number),
158
- "src_lang": src_lang_code,
159
194
  "tgt_lang": tgt_lang_code,
160
195
  "model": model
161
196
  }
@@ -165,7 +200,7 @@ def extract(client, file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan
165
200
  headers=headers,
166
201
  files=files,
167
202
  data=data,
168
- timeout=60
203
+ timeout=90
169
204
  )
170
205
  resp.raise_for_status()
171
206
  except requests.RequestException as e:
@@ -181,12 +216,12 @@ def doc_query(
181
216
  file_path,
182
217
  page_number=1,
183
218
  prompt="list the key points",
184
- src_lang="eng_Latn",
185
219
  tgt_lang="kan_Knda",
220
+ src_lang="eng_Latn",
186
221
  model="gemma3"
187
222
  ):
188
223
  """Query a document with a custom prompt and language options."""
189
- logger.debug(f"Calling doc_query: file_path={file_path}, page_number={page_number}, prompt={prompt}, src_lang={src_lang}, tgt_lang={tgt_lang}, model={model}")
224
+ logger.debug(f"Calling doc_query: file_path={file_path}, page_number={page_number}, prompt={prompt}, tgt_lang={tgt_lang}, model={model}")
190
225
  validate_model(model)
191
226
 
192
227
  if not file_path.lower().endswith('.pdf'):
@@ -196,9 +231,10 @@ def doc_query(
196
231
  if not prompt.strip():
197
232
  raise ValueError("Prompt cannot be empty")
198
233
 
199
- src_lang_code = normalize_language(src_lang)
200
234
  tgt_lang_code = normalize_language(tgt_lang)
201
235
 
236
+ src_lang_code = normalize_language(src_lang)
237
+
202
238
  url = f"{client.api_base}/v1/indic-custom-prompt-pdf"
203
239
  headers = client._headers()
204
240
  with open(file_path, "rb") as f:
@@ -206,8 +242,8 @@ def doc_query(
206
242
  data = {
207
243
  "page_number": str(page_number),
208
244
  "prompt": prompt,
209
- "src_lang": src_lang_code,
210
245
  "tgt_lang": tgt_lang_code,
246
+ "src_lang": src_lang_code,
211
247
  "model": model
212
248
  }
213
249
 
@@ -217,7 +253,7 @@ def doc_query(
217
253
  headers=headers,
218
254
  files=files,
219
255
  data=data,
220
- timeout=60
256
+ timeout=90
221
257
  )
222
258
  resp.raise_for_status()
223
259
  except requests.RequestException as e:
@@ -233,12 +269,12 @@ def doc_query_kannada(
233
269
  file_path,
234
270
  page_number=1,
235
271
  prompt="list key points",
236
- src_lang="eng_Latn",
237
272
  tgt_lang="kan_Knda",
273
+ src_lang="kan_Knda",
238
274
  model="gemma3"
239
275
  ):
240
276
  """Query a document with a custom prompt, outputting in Kannada."""
241
- logger.debug(f"Calling doc_query_kannada: file_path={file_path}, page_number={page_number}, prompt={prompt}, src_lang={src_lang}, tgt_lang={tgt_lang}, model={model}")
277
+ logger.debug(f"Calling doc_query_kannada: file_path={file_path}, page_number={page_number}, prompt={prompt}, tgt_lang={tgt_lang}, model={model}")
242
278
  validate_model(model)
243
279
 
244
280
  if not file_path.lower().endswith('.pdf'):
@@ -248,8 +284,10 @@ def doc_query_kannada(
248
284
  if not prompt.strip():
249
285
  raise ValueError("Prompt cannot be empty")
250
286
 
251
- src_lang_code = normalize_language(src_lang)
252
287
  tgt_lang_code = normalize_language(tgt_lang) if tgt_lang else "kan_Knda"
288
+
289
+ src_lang_code = normalize_language(src_lang)
290
+
253
291
 
254
292
  url = f"{client.api_base}/v1/indic-custom-prompt-pdf"
255
293
  headers = client._headers()
@@ -259,8 +297,8 @@ def doc_query_kannada(
259
297
  data = {
260
298
  "page_number": str(page_number),
261
299
  "prompt": prompt,
262
- "src_lang": src_lang_code,
263
300
  "tgt_lang": tgt_lang_code,
301
+ "src_lang": src_lang_code,
264
302
  "model": model
265
303
  }
266
304
  try:
@@ -269,7 +307,7 @@ def doc_query_kannada(
269
307
  headers=headers,
270
308
  files=files,
271
309
  data=data,
272
- timeout=60
310
+ timeout=90
273
311
  )
274
312
  resp.raise_for_status()
275
313
  except requests.RequestException as e:
@@ -285,7 +323,7 @@ class Documents:
285
323
  def run_ocr_number(file_path, page_number=2,model="gemma3"):
286
324
  from .client import DwaniClient
287
325
  client = DwaniClient()
288
- return document_ocr_number(client, file_path, page_number, model)
326
+ return document_ocr_page(client, file_path, page_number, model)
289
327
  @staticmethod
290
328
  def run_ocr_all(file_path, model="gemma3"):
291
329
  from .client import DwaniClient
@@ -293,25 +331,32 @@ class Documents:
293
331
  return document_ocr_all(client, file_path, model)
294
332
 
295
333
  @staticmethod
296
- def summarize(file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
334
+ def summarize_page(file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
297
335
  from .client import DwaniClient
298
336
  client = DwaniClient()
299
- return document_summarize(client, file_path, page_number, src_lang, tgt_lang, model)
300
-
337
+ return document_summarize_page(client, file_path, page_number, tgt_lang, model)
338
+
339
+
340
+ @staticmethod
341
+ def summarize_all(file_path, tgt_lang="kan_Knda", model="gemma3"):
342
+ from .client import DwaniClient
343
+ client = DwaniClient()
344
+ return document_summarize_all(client, file_path, tgt_lang, model)
345
+
301
346
  @staticmethod
302
- def run_extract(file_path, page_number=1, src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
347
+ def run_extract(file_path, page_number=1, tgt_lang="kan_Knda", model="gemma3"):
303
348
  from .client import DwaniClient
304
349
  client = DwaniClient()
305
- return extract(client, file_path, page_number, src_lang, tgt_lang, model)
350
+ return extract(client, file_path, page_number, tgt_lang, model)
306
351
 
307
352
  @staticmethod
308
- def run_doc_query(file_path, page_number=1, prompt="list the key points", src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
353
+ def run_doc_query(file_path, page_number=1, prompt="list the key points", tgt_lang="kan_Knda", model="gemma3"):
309
354
  from .client import DwaniClient
310
355
  client = DwaniClient()
311
- return doc_query(client, file_path, page_number, prompt, src_lang, tgt_lang, model)
356
+ return doc_query(client, file_path, page_number, prompt, tgt_lang, model)
312
357
 
313
358
  @staticmethod
314
- def run_doc_query_kannada(file_path, page_number=1, prompt="list key points", src_lang="eng_Latn", tgt_lang="kan_Knda", model="gemma3"):
359
+ def run_doc_query_kannada(file_path, page_number=1, prompt="list key points", tgt_lang="kan_Knda", model="gemma3"):
315
360
  from .client import DwaniClient
316
361
  client = DwaniClient()
317
- return doc_query_kannada(client, file_path, page_number, prompt, src_lang, tgt_lang, model)
362
+ return doc_query_kannada(client, file_path, page_number, prompt, tgt_lang, model)
@@ -66,7 +66,8 @@ def run_translate(client, sentences, src_lang, tgt_lang):
66
66
  resp = requests.post(
67
67
  url,
68
68
  headers={**client._headers(), "Content-Type": "application/json", "accept": "application/json"},
69
- json=payload
69
+ json=payload,
70
+ timeout=90
70
71
  )
71
72
  if resp.status_code != 200:
72
73
  raise DwaniAPIError(resp)
@@ -52,7 +52,8 @@ def vision_direct(client, file_path, query="describe this image", model="gemma3"
52
52
  url,
53
53
  headers=headers,
54
54
  files=files,
55
- data=data
55
+ data=data,
56
+ timeout=90
56
57
  )
57
58
  if resp.status_code != 200:
58
59
  raise DwaniAPIError(resp)
@@ -84,7 +85,8 @@ def vision_caption(client, file_path, query="describe the image", src_lang="eng_
84
85
  url,
85
86
  headers=headers,
86
87
  files=files,
87
- data=data
88
+ data=data,
89
+ timeout=90
88
90
  )
89
91
  if resp.status_code != 200:
90
92
  raise DwaniAPIError(resp)
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "dwani"
7
7
 
8
- version = "0.1.18"
8
+ version = "0.1.20"
9
9
  description = "Multimodal API for Indian + European languages (Chat, Vision, TTS, ASR, Translate, Docs)"
10
10
  authors = [
11
11
  { name="sachin", email="python@dwani.ai" }
File without changes
File without changes
File without changes
File without changes