clarifai 11.3.0rc2__py3-none-any.whl → 11.4.0__py3-none-any.whl

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 (300) hide show
  1. clarifai/__init__.py +1 -1
  2. clarifai/cli/__main__.py +1 -1
  3. clarifai/cli/base.py +144 -136
  4. clarifai/cli/compute_cluster.py +45 -31
  5. clarifai/cli/deployment.py +93 -76
  6. clarifai/cli/model.py +578 -180
  7. clarifai/cli/nodepool.py +100 -82
  8. clarifai/client/__init__.py +12 -2
  9. clarifai/client/app.py +973 -911
  10. clarifai/client/auth/helper.py +345 -342
  11. clarifai/client/auth/register.py +7 -7
  12. clarifai/client/auth/stub.py +107 -106
  13. clarifai/client/base.py +185 -178
  14. clarifai/client/compute_cluster.py +214 -180
  15. clarifai/client/dataset.py +793 -698
  16. clarifai/client/deployment.py +55 -50
  17. clarifai/client/input.py +1223 -1088
  18. clarifai/client/lister.py +47 -45
  19. clarifai/client/model.py +1939 -1717
  20. clarifai/client/model_client.py +525 -502
  21. clarifai/client/module.py +82 -73
  22. clarifai/client/nodepool.py +358 -213
  23. clarifai/client/runner.py +58 -0
  24. clarifai/client/search.py +342 -309
  25. clarifai/client/user.py +419 -414
  26. clarifai/client/workflow.py +294 -274
  27. clarifai/constants/dataset.py +11 -17
  28. clarifai/constants/model.py +8 -2
  29. clarifai/datasets/export/inputs_annotations.py +233 -217
  30. clarifai/datasets/upload/base.py +63 -51
  31. clarifai/datasets/upload/features.py +43 -38
  32. clarifai/datasets/upload/image.py +237 -207
  33. clarifai/datasets/upload/loaders/coco_captions.py +34 -32
  34. clarifai/datasets/upload/loaders/coco_detection.py +72 -65
  35. clarifai/datasets/upload/loaders/imagenet_classification.py +57 -53
  36. clarifai/datasets/upload/loaders/xview_detection.py +274 -132
  37. clarifai/datasets/upload/multimodal.py +55 -46
  38. clarifai/datasets/upload/text.py +55 -47
  39. clarifai/datasets/upload/utils.py +250 -234
  40. clarifai/errors.py +51 -50
  41. clarifai/models/api.py +260 -238
  42. clarifai/modules/css.py +50 -50
  43. clarifai/modules/pages.py +33 -33
  44. clarifai/rag/rag.py +312 -288
  45. clarifai/rag/utils.py +91 -84
  46. clarifai/runners/models/model_builder.py +906 -802
  47. clarifai/runners/models/model_class.py +370 -331
  48. clarifai/runners/models/model_run_locally.py +459 -419
  49. clarifai/runners/models/model_runner.py +170 -162
  50. clarifai/runners/models/model_servicer.py +78 -70
  51. clarifai/runners/server.py +111 -101
  52. clarifai/runners/utils/code_script.py +225 -187
  53. clarifai/runners/utils/const.py +4 -1
  54. clarifai/runners/utils/data_types/__init__.py +12 -0
  55. clarifai/runners/utils/data_types/data_types.py +598 -0
  56. clarifai/runners/utils/data_utils.py +387 -440
  57. clarifai/runners/utils/loader.py +247 -227
  58. clarifai/runners/utils/method_signatures.py +411 -386
  59. clarifai/runners/utils/openai_convertor.py +108 -109
  60. clarifai/runners/utils/serializers.py +175 -179
  61. clarifai/runners/utils/url_fetcher.py +35 -35
  62. clarifai/schema/search.py +56 -63
  63. clarifai/urls/helper.py +125 -102
  64. clarifai/utils/cli.py +129 -123
  65. clarifai/utils/config.py +127 -87
  66. clarifai/utils/constants.py +49 -0
  67. clarifai/utils/evaluation/helpers.py +503 -466
  68. clarifai/utils/evaluation/main.py +431 -393
  69. clarifai/utils/evaluation/testset_annotation_parser.py +154 -144
  70. clarifai/utils/logging.py +324 -306
  71. clarifai/utils/misc.py +60 -56
  72. clarifai/utils/model_train.py +165 -146
  73. clarifai/utils/protobuf.py +126 -103
  74. clarifai/versions.py +3 -1
  75. clarifai/workflows/export.py +48 -50
  76. clarifai/workflows/utils.py +39 -36
  77. clarifai/workflows/validate.py +55 -43
  78. {clarifai-11.3.0rc2.dist-info → clarifai-11.4.0.dist-info}/METADATA +16 -6
  79. clarifai-11.4.0.dist-info/RECORD +109 -0
  80. {clarifai-11.3.0rc2.dist-info → clarifai-11.4.0.dist-info}/WHEEL +1 -1
  81. clarifai/__pycache__/__init__.cpython-310.pyc +0 -0
  82. clarifai/__pycache__/__init__.cpython-311.pyc +0 -0
  83. clarifai/__pycache__/__init__.cpython-39.pyc +0 -0
  84. clarifai/__pycache__/errors.cpython-310.pyc +0 -0
  85. clarifai/__pycache__/errors.cpython-311.pyc +0 -0
  86. clarifai/__pycache__/versions.cpython-310.pyc +0 -0
  87. clarifai/__pycache__/versions.cpython-311.pyc +0 -0
  88. clarifai/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  89. clarifai/cli/__pycache__/__init__.cpython-311.pyc +0 -0
  90. clarifai/cli/__pycache__/base.cpython-310.pyc +0 -0
  91. clarifai/cli/__pycache__/base.cpython-311.pyc +0 -0
  92. clarifai/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
  93. clarifai/cli/__pycache__/compute_cluster.cpython-310.pyc +0 -0
  94. clarifai/cli/__pycache__/compute_cluster.cpython-311.pyc +0 -0
  95. clarifai/cli/__pycache__/deployment.cpython-310.pyc +0 -0
  96. clarifai/cli/__pycache__/deployment.cpython-311.pyc +0 -0
  97. clarifai/cli/__pycache__/model.cpython-310.pyc +0 -0
  98. clarifai/cli/__pycache__/model.cpython-311.pyc +0 -0
  99. clarifai/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
  100. clarifai/cli/__pycache__/nodepool.cpython-310.pyc +0 -0
  101. clarifai/cli/__pycache__/nodepool.cpython-311.pyc +0 -0
  102. clarifai/client/__pycache__/__init__.cpython-310.pyc +0 -0
  103. clarifai/client/__pycache__/__init__.cpython-311.pyc +0 -0
  104. clarifai/client/__pycache__/__init__.cpython-39.pyc +0 -0
  105. clarifai/client/__pycache__/app.cpython-310.pyc +0 -0
  106. clarifai/client/__pycache__/app.cpython-311.pyc +0 -0
  107. clarifai/client/__pycache__/app.cpython-39.pyc +0 -0
  108. clarifai/client/__pycache__/base.cpython-310.pyc +0 -0
  109. clarifai/client/__pycache__/base.cpython-311.pyc +0 -0
  110. clarifai/client/__pycache__/compute_cluster.cpython-310.pyc +0 -0
  111. clarifai/client/__pycache__/compute_cluster.cpython-311.pyc +0 -0
  112. clarifai/client/__pycache__/dataset.cpython-310.pyc +0 -0
  113. clarifai/client/__pycache__/dataset.cpython-311.pyc +0 -0
  114. clarifai/client/__pycache__/deployment.cpython-310.pyc +0 -0
  115. clarifai/client/__pycache__/deployment.cpython-311.pyc +0 -0
  116. clarifai/client/__pycache__/input.cpython-310.pyc +0 -0
  117. clarifai/client/__pycache__/input.cpython-311.pyc +0 -0
  118. clarifai/client/__pycache__/lister.cpython-310.pyc +0 -0
  119. clarifai/client/__pycache__/lister.cpython-311.pyc +0 -0
  120. clarifai/client/__pycache__/model.cpython-310.pyc +0 -0
  121. clarifai/client/__pycache__/model.cpython-311.pyc +0 -0
  122. clarifai/client/__pycache__/module.cpython-310.pyc +0 -0
  123. clarifai/client/__pycache__/module.cpython-311.pyc +0 -0
  124. clarifai/client/__pycache__/nodepool.cpython-310.pyc +0 -0
  125. clarifai/client/__pycache__/nodepool.cpython-311.pyc +0 -0
  126. clarifai/client/__pycache__/search.cpython-310.pyc +0 -0
  127. clarifai/client/__pycache__/search.cpython-311.pyc +0 -0
  128. clarifai/client/__pycache__/user.cpython-310.pyc +0 -0
  129. clarifai/client/__pycache__/user.cpython-311.pyc +0 -0
  130. clarifai/client/__pycache__/workflow.cpython-310.pyc +0 -0
  131. clarifai/client/__pycache__/workflow.cpython-311.pyc +0 -0
  132. clarifai/client/auth/__pycache__/__init__.cpython-310.pyc +0 -0
  133. clarifai/client/auth/__pycache__/__init__.cpython-311.pyc +0 -0
  134. clarifai/client/auth/__pycache__/helper.cpython-310.pyc +0 -0
  135. clarifai/client/auth/__pycache__/helper.cpython-311.pyc +0 -0
  136. clarifai/client/auth/__pycache__/register.cpython-310.pyc +0 -0
  137. clarifai/client/auth/__pycache__/register.cpython-311.pyc +0 -0
  138. clarifai/client/auth/__pycache__/stub.cpython-310.pyc +0 -0
  139. clarifai/client/auth/__pycache__/stub.cpython-311.pyc +0 -0
  140. clarifai/client/cli/__init__.py +0 -0
  141. clarifai/client/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  142. clarifai/client/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
  143. clarifai/client/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
  144. clarifai/client/cli/base_cli.py +0 -88
  145. clarifai/client/cli/model_cli.py +0 -29
  146. clarifai/constants/__pycache__/base.cpython-310.pyc +0 -0
  147. clarifai/constants/__pycache__/base.cpython-311.pyc +0 -0
  148. clarifai/constants/__pycache__/dataset.cpython-310.pyc +0 -0
  149. clarifai/constants/__pycache__/dataset.cpython-311.pyc +0 -0
  150. clarifai/constants/__pycache__/input.cpython-310.pyc +0 -0
  151. clarifai/constants/__pycache__/input.cpython-311.pyc +0 -0
  152. clarifai/constants/__pycache__/model.cpython-310.pyc +0 -0
  153. clarifai/constants/__pycache__/model.cpython-311.pyc +0 -0
  154. clarifai/constants/__pycache__/rag.cpython-310.pyc +0 -0
  155. clarifai/constants/__pycache__/rag.cpython-311.pyc +0 -0
  156. clarifai/constants/__pycache__/search.cpython-310.pyc +0 -0
  157. clarifai/constants/__pycache__/search.cpython-311.pyc +0 -0
  158. clarifai/constants/__pycache__/workflow.cpython-310.pyc +0 -0
  159. clarifai/constants/__pycache__/workflow.cpython-311.pyc +0 -0
  160. clarifai/datasets/__pycache__/__init__.cpython-310.pyc +0 -0
  161. clarifai/datasets/__pycache__/__init__.cpython-311.pyc +0 -0
  162. clarifai/datasets/__pycache__/__init__.cpython-39.pyc +0 -0
  163. clarifai/datasets/export/__pycache__/__init__.cpython-310.pyc +0 -0
  164. clarifai/datasets/export/__pycache__/__init__.cpython-311.pyc +0 -0
  165. clarifai/datasets/export/__pycache__/__init__.cpython-39.pyc +0 -0
  166. clarifai/datasets/export/__pycache__/inputs_annotations.cpython-310.pyc +0 -0
  167. clarifai/datasets/export/__pycache__/inputs_annotations.cpython-311.pyc +0 -0
  168. clarifai/datasets/upload/__pycache__/__init__.cpython-310.pyc +0 -0
  169. clarifai/datasets/upload/__pycache__/__init__.cpython-311.pyc +0 -0
  170. clarifai/datasets/upload/__pycache__/__init__.cpython-39.pyc +0 -0
  171. clarifai/datasets/upload/__pycache__/base.cpython-310.pyc +0 -0
  172. clarifai/datasets/upload/__pycache__/base.cpython-311.pyc +0 -0
  173. clarifai/datasets/upload/__pycache__/features.cpython-310.pyc +0 -0
  174. clarifai/datasets/upload/__pycache__/features.cpython-311.pyc +0 -0
  175. clarifai/datasets/upload/__pycache__/image.cpython-310.pyc +0 -0
  176. clarifai/datasets/upload/__pycache__/image.cpython-311.pyc +0 -0
  177. clarifai/datasets/upload/__pycache__/multimodal.cpython-310.pyc +0 -0
  178. clarifai/datasets/upload/__pycache__/multimodal.cpython-311.pyc +0 -0
  179. clarifai/datasets/upload/__pycache__/text.cpython-310.pyc +0 -0
  180. clarifai/datasets/upload/__pycache__/text.cpython-311.pyc +0 -0
  181. clarifai/datasets/upload/__pycache__/utils.cpython-310.pyc +0 -0
  182. clarifai/datasets/upload/__pycache__/utils.cpython-311.pyc +0 -0
  183. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-311.pyc +0 -0
  184. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-39.pyc +0 -0
  185. clarifai/datasets/upload/loaders/__pycache__/coco_detection.cpython-311.pyc +0 -0
  186. clarifai/datasets/upload/loaders/__pycache__/imagenet_classification.cpython-311.pyc +0 -0
  187. clarifai/models/__pycache__/__init__.cpython-39.pyc +0 -0
  188. clarifai/modules/__pycache__/__init__.cpython-39.pyc +0 -0
  189. clarifai/rag/__pycache__/__init__.cpython-310.pyc +0 -0
  190. clarifai/rag/__pycache__/__init__.cpython-311.pyc +0 -0
  191. clarifai/rag/__pycache__/__init__.cpython-39.pyc +0 -0
  192. clarifai/rag/__pycache__/rag.cpython-310.pyc +0 -0
  193. clarifai/rag/__pycache__/rag.cpython-311.pyc +0 -0
  194. clarifai/rag/__pycache__/rag.cpython-39.pyc +0 -0
  195. clarifai/rag/__pycache__/utils.cpython-310.pyc +0 -0
  196. clarifai/rag/__pycache__/utils.cpython-311.pyc +0 -0
  197. clarifai/runners/__pycache__/__init__.cpython-310.pyc +0 -0
  198. clarifai/runners/__pycache__/__init__.cpython-311.pyc +0 -0
  199. clarifai/runners/__pycache__/__init__.cpython-39.pyc +0 -0
  200. clarifai/runners/dockerfile_template/Dockerfile.cpu.template +0 -31
  201. clarifai/runners/dockerfile_template/Dockerfile.cuda.template +0 -42
  202. clarifai/runners/dockerfile_template/Dockerfile.nim +0 -71
  203. clarifai/runners/models/__pycache__/__init__.cpython-310.pyc +0 -0
  204. clarifai/runners/models/__pycache__/__init__.cpython-311.pyc +0 -0
  205. clarifai/runners/models/__pycache__/__init__.cpython-39.pyc +0 -0
  206. clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc +0 -0
  207. clarifai/runners/models/__pycache__/base_typed_model.cpython-311.pyc +0 -0
  208. clarifai/runners/models/__pycache__/base_typed_model.cpython-39.pyc +0 -0
  209. clarifai/runners/models/__pycache__/model_builder.cpython-311.pyc +0 -0
  210. clarifai/runners/models/__pycache__/model_class.cpython-310.pyc +0 -0
  211. clarifai/runners/models/__pycache__/model_class.cpython-311.pyc +0 -0
  212. clarifai/runners/models/__pycache__/model_run_locally.cpython-310-pytest-7.1.2.pyc +0 -0
  213. clarifai/runners/models/__pycache__/model_run_locally.cpython-310.pyc +0 -0
  214. clarifai/runners/models/__pycache__/model_run_locally.cpython-311.pyc +0 -0
  215. clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc +0 -0
  216. clarifai/runners/models/__pycache__/model_runner.cpython-311.pyc +0 -0
  217. clarifai/runners/models/__pycache__/model_upload.cpython-310.pyc +0 -0
  218. clarifai/runners/models/base_typed_model.py +0 -238
  219. clarifai/runners/models/model_class_refract.py +0 -80
  220. clarifai/runners/models/model_upload.py +0 -607
  221. clarifai/runners/models/temp.py +0 -25
  222. clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  223. clarifai/runners/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  224. clarifai/runners/utils/__pycache__/__init__.cpython-38.pyc +0 -0
  225. clarifai/runners/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  226. clarifai/runners/utils/__pycache__/buffered_stream.cpython-310.pyc +0 -0
  227. clarifai/runners/utils/__pycache__/buffered_stream.cpython-38.pyc +0 -0
  228. clarifai/runners/utils/__pycache__/buffered_stream.cpython-39.pyc +0 -0
  229. clarifai/runners/utils/__pycache__/const.cpython-310.pyc +0 -0
  230. clarifai/runners/utils/__pycache__/const.cpython-311.pyc +0 -0
  231. clarifai/runners/utils/__pycache__/constants.cpython-310.pyc +0 -0
  232. clarifai/runners/utils/__pycache__/constants.cpython-38.pyc +0 -0
  233. clarifai/runners/utils/__pycache__/constants.cpython-39.pyc +0 -0
  234. clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc +0 -0
  235. clarifai/runners/utils/__pycache__/data_handler.cpython-311.pyc +0 -0
  236. clarifai/runners/utils/__pycache__/data_handler.cpython-38.pyc +0 -0
  237. clarifai/runners/utils/__pycache__/data_handler.cpython-39.pyc +0 -0
  238. clarifai/runners/utils/__pycache__/data_utils.cpython-310.pyc +0 -0
  239. clarifai/runners/utils/__pycache__/data_utils.cpython-311.pyc +0 -0
  240. clarifai/runners/utils/__pycache__/data_utils.cpython-38.pyc +0 -0
  241. clarifai/runners/utils/__pycache__/data_utils.cpython-39.pyc +0 -0
  242. clarifai/runners/utils/__pycache__/grpc_server.cpython-310.pyc +0 -0
  243. clarifai/runners/utils/__pycache__/grpc_server.cpython-38.pyc +0 -0
  244. clarifai/runners/utils/__pycache__/grpc_server.cpython-39.pyc +0 -0
  245. clarifai/runners/utils/__pycache__/health.cpython-310.pyc +0 -0
  246. clarifai/runners/utils/__pycache__/health.cpython-38.pyc +0 -0
  247. clarifai/runners/utils/__pycache__/health.cpython-39.pyc +0 -0
  248. clarifai/runners/utils/__pycache__/loader.cpython-310.pyc +0 -0
  249. clarifai/runners/utils/__pycache__/loader.cpython-311.pyc +0 -0
  250. clarifai/runners/utils/__pycache__/logging.cpython-310.pyc +0 -0
  251. clarifai/runners/utils/__pycache__/logging.cpython-38.pyc +0 -0
  252. clarifai/runners/utils/__pycache__/logging.cpython-39.pyc +0 -0
  253. clarifai/runners/utils/__pycache__/stream_source.cpython-310.pyc +0 -0
  254. clarifai/runners/utils/__pycache__/stream_source.cpython-39.pyc +0 -0
  255. clarifai/runners/utils/__pycache__/url_fetcher.cpython-310.pyc +0 -0
  256. clarifai/runners/utils/__pycache__/url_fetcher.cpython-311.pyc +0 -0
  257. clarifai/runners/utils/__pycache__/url_fetcher.cpython-38.pyc +0 -0
  258. clarifai/runners/utils/__pycache__/url_fetcher.cpython-39.pyc +0 -0
  259. clarifai/runners/utils/data_handler.py +0 -231
  260. clarifai/runners/utils/data_handler_refract.py +0 -213
  261. clarifai/runners/utils/data_types.py +0 -469
  262. clarifai/runners/utils/logger.py +0 -0
  263. clarifai/runners/utils/openai_format.py +0 -87
  264. clarifai/schema/__pycache__/search.cpython-310.pyc +0 -0
  265. clarifai/schema/__pycache__/search.cpython-311.pyc +0 -0
  266. clarifai/urls/__pycache__/helper.cpython-310.pyc +0 -0
  267. clarifai/urls/__pycache__/helper.cpython-311.pyc +0 -0
  268. clarifai/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  269. clarifai/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  270. clarifai/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  271. clarifai/utils/__pycache__/cli.cpython-310.pyc +0 -0
  272. clarifai/utils/__pycache__/cli.cpython-311.pyc +0 -0
  273. clarifai/utils/__pycache__/config.cpython-311.pyc +0 -0
  274. clarifai/utils/__pycache__/constants.cpython-310.pyc +0 -0
  275. clarifai/utils/__pycache__/constants.cpython-311.pyc +0 -0
  276. clarifai/utils/__pycache__/logging.cpython-310.pyc +0 -0
  277. clarifai/utils/__pycache__/logging.cpython-311.pyc +0 -0
  278. clarifai/utils/__pycache__/misc.cpython-310.pyc +0 -0
  279. clarifai/utils/__pycache__/misc.cpython-311.pyc +0 -0
  280. clarifai/utils/__pycache__/model_train.cpython-310.pyc +0 -0
  281. clarifai/utils/__pycache__/model_train.cpython-311.pyc +0 -0
  282. clarifai/utils/__pycache__/protobuf.cpython-311.pyc +0 -0
  283. clarifai/utils/evaluation/__pycache__/__init__.cpython-311.pyc +0 -0
  284. clarifai/utils/evaluation/__pycache__/__init__.cpython-39.pyc +0 -0
  285. clarifai/utils/evaluation/__pycache__/helpers.cpython-311.pyc +0 -0
  286. clarifai/utils/evaluation/__pycache__/main.cpython-311.pyc +0 -0
  287. clarifai/utils/evaluation/__pycache__/main.cpython-39.pyc +0 -0
  288. clarifai/workflows/__pycache__/__init__.cpython-310.pyc +0 -0
  289. clarifai/workflows/__pycache__/__init__.cpython-311.pyc +0 -0
  290. clarifai/workflows/__pycache__/__init__.cpython-39.pyc +0 -0
  291. clarifai/workflows/__pycache__/export.cpython-310.pyc +0 -0
  292. clarifai/workflows/__pycache__/export.cpython-311.pyc +0 -0
  293. clarifai/workflows/__pycache__/utils.cpython-310.pyc +0 -0
  294. clarifai/workflows/__pycache__/utils.cpython-311.pyc +0 -0
  295. clarifai/workflows/__pycache__/validate.cpython-310.pyc +0 -0
  296. clarifai/workflows/__pycache__/validate.cpython-311.pyc +0 -0
  297. clarifai-11.3.0rc2.dist-info/RECORD +0 -322
  298. {clarifai-11.3.0rc2.dist-info → clarifai-11.4.0.dist-info}/entry_points.txt +0 -0
  299. {clarifai-11.3.0rc2.dist-info → clarifai-11.4.0.dist-info/licenses}/LICENSE +0 -0
  300. {clarifai-11.3.0rc2.dist-info → clarifai-11.4.0.dist-info}/top_level.txt +0 -0
clarifai/rag/rag.py CHANGED
@@ -12,8 +12,12 @@ from clarifai.client.user import User
12
12
  from clarifai.client.workflow import Workflow
13
13
  from clarifai.constants.rag import MAX_UPLOAD_BATCH_SIZE
14
14
  from clarifai.errors import UserError
15
- from clarifai.rag.utils import (convert_messages_to_str, format_assistant_message, load_documents,
16
- split_document)
15
+ from clarifai.rag.utils import (
16
+ convert_messages_to_str,
17
+ format_assistant_message,
18
+ load_documents,
19
+ split_document,
20
+ )
17
21
  from clarifai.utils.constants import CLARIFAI_USER_ID_ENV_VAR
18
22
  from clarifai.utils.logging import logger
19
23
  from clarifai.utils.misc import get_from_dict_or_env
@@ -22,7 +26,7 @@ DEFAULT_RAG_PROMPT_TEMPLATE = "Context information is below:\n{data.hits}\nGiven
22
26
 
23
27
 
24
28
  class RAG:
25
- """
29
+ """
26
30
  RAG is a class for Retrieval Augmented Generation.
27
31
 
28
32
  Example:
@@ -30,290 +34,310 @@ class RAG:
30
34
  >>> rag_agent = RAG(workflow_url=YOUR_WORKFLOW_URL)
31
35
  >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
32
36
  """
33
- chat_state_id = None
34
-
35
- def __init__(self,
36
- workflow_url: str = None,
37
- workflow: Workflow = None,
38
- base_url: str = "https://api.clarifai.com",
39
- pat: str = None,
40
- **kwargs):
41
- """Initialize an empty or existing RAG.
42
- """
43
- self.logger = logger
44
- if workflow_url is not None and workflow is None:
45
- self.logger.info("workflow_url:%s", workflow_url)
46
- w = Workflow(workflow_url, base_url=base_url, pat=pat)
47
- self._prompt_workflow = w
48
- self._app = App(app_id=w.app_id, user_id=w.user_id, base_url=w.base, pat=w.pat)
49
- elif workflow_url is None and workflow is not None:
50
- self._prompt_workflow = workflow
51
- self._app = App(
52
- app_id=workflow.app_id,
53
- user_id=workflow.user_id,
54
- base_url=workflow.base,
55
- pat=workflow.pat)
56
-
57
- @classmethod
58
- def setup(cls,
59
- user_id: str = None,
60
- app_url: str = None,
61
- llm_url: str = "https://clarifai.com/mistralai/completion/models/mistral-7B-Instruct",
62
- base_workflow: str = "Text",
63
- workflow_yaml_filename: str = 'prompter_wf.yaml',
64
- workflow_id: str = None,
65
- base_url: str = "https://api.clarifai.com",
66
- pat: str = None,
67
- **kwargs):
68
- """Creates an app with `Text` as base workflow, create prompt model, create prompt workflow.
69
-
70
- **kwargs: Additional keyword arguments to be passed to rag-promter model.
71
- - min_score (float): The minimum score for search hits.
72
- - max_results (float): The maximum number of search hits.
73
- - prompt_template (str): The prompt template used. Must contain {data.hits} for the search hits and {data.text.raw} for the query string.
74
37
 
75
- Example:
76
- >>> from clarifai.rag import RAG
77
- >>> rag_agent = RAG.setup(user_id=YOUR_USER_ID)
78
- >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
79
-
80
- Or if you already have an existing app with ingested data:
81
- >>> rag_agent = RAG.setup(app_url=YOUR_APP_URL)
82
- >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
83
- """
84
- if not app_url:
85
- try:
86
- user_id = get_from_dict_or_env(key="user_id", env_key=CLARIFAI_USER_ID_ENV_VAR, **kwargs)
87
- except Exception:
88
- pass
89
-
90
- now_ts = uuid.uuid4().hex[:10]
91
- if user_id and not app_url:
92
- user = User(user_id=user_id, base_url=base_url, pat=pat)
93
- ## Create an App
94
- app_id = f"rag_app_{now_ts}"
95
- app = user.create_app(app_id=app_id, base_workflow=base_workflow)
96
-
97
- if not user_id and app_url:
98
- app = App(url=app_url, pat=pat)
99
- uid = app_url.split(".com/")[1].split("/")[0]
100
- user = User(user_id=uid, base_url=base_url, pat=pat)
101
-
102
- if user_id and app_url:
103
- raise UserError("Must provide one of user_id or app_url, not both.")
104
-
105
- if not user_id and not app_url:
106
- raise UserError(
107
- "user_id or app_url must be provided. The user_id can be found at https://clarifai.com/settings."
108
- )
109
-
110
- llm = Model(url=llm_url, pat=pat)
111
-
112
- min_score = kwargs.get("min_score", 0.95)
113
- max_results = kwargs.get("max_results", 5)
114
- prompt_template = kwargs.get("prompt_template", DEFAULT_RAG_PROMPT_TEMPLATE)
115
- params = Struct()
116
- params.update({
117
- "min_score": min_score,
118
- "max_results": max_results,
119
- "prompt_template": prompt_template
120
- })
121
- prompter_model_params = {"params": params}
122
-
123
- ## Create rag-prompter model and version
124
- model_id = f"prompter-{workflow_id}-{now_ts}" if workflow_id is not None else f"rag-prompter-{now_ts}"
125
- prompter_model = app.create_model(model_id=model_id, model_type_id="rag-prompter")
126
- prompter_model = prompter_model.create_version(output_info=prompter_model_params)
127
-
128
- ## Generate a tmp yaml file for workflow creation
129
- workflow_id = f"rag-wf-{now_ts}" if workflow_id is None else workflow_id
130
- workflow_dict = {
131
- "workflow": {
132
- "id":
133
- workflow_id,
134
- "nodes": [{
135
- "id": "rag-prompter",
136
- "model": {
137
- "model_id": prompter_model.id,
138
- "model_version_id": prompter_model.model_version.id
139
- }
140
- }, {
141
- "id": "llm",
142
- "model": {
143
- "model_id": llm.id,
144
- "user_id": llm.user_id,
145
- "app_id": llm.app_id
146
- },
147
- "node_inputs": [{
148
- "node_id": "rag-prompter"
149
- }]
150
- }]
38
+ chat_state_id = None
39
+
40
+ def __init__(
41
+ self,
42
+ workflow_url: str = None,
43
+ workflow: Workflow = None,
44
+ base_url: str = "https://api.clarifai.com",
45
+ pat: str = None,
46
+ **kwargs,
47
+ ):
48
+ """Initialize an empty or existing RAG."""
49
+ self.logger = logger
50
+ if workflow_url is not None and workflow is None:
51
+ self.logger.info("workflow_url:%s", workflow_url)
52
+ w = Workflow(workflow_url, base_url=base_url, pat=pat)
53
+ self._prompt_workflow = w
54
+ self._app = App(app_id=w.app_id, user_id=w.user_id, base_url=w.base, pat=w.pat)
55
+ elif workflow_url is None and workflow is not None:
56
+ self._prompt_workflow = workflow
57
+ self._app = App(
58
+ app_id=workflow.app_id,
59
+ user_id=workflow.user_id,
60
+ base_url=workflow.base,
61
+ pat=workflow.pat,
62
+ )
63
+
64
+ @classmethod
65
+ def setup(
66
+ cls,
67
+ user_id: str = None,
68
+ app_url: str = None,
69
+ llm_url: str = "https://clarifai.com/mistralai/completion/models/mistral-7B-Instruct",
70
+ base_workflow: str = "Text",
71
+ workflow_yaml_filename: str = 'prompter_wf.yaml',
72
+ workflow_id: str = None,
73
+ base_url: str = "https://api.clarifai.com",
74
+ pat: str = None,
75
+ **kwargs,
76
+ ):
77
+ """Creates an app with `Text` as base workflow, create prompt model, create prompt workflow.
78
+
79
+ **kwargs: Additional keyword arguments to be passed to rag-promter model.
80
+ - min_score (float): The minimum score for search hits.
81
+ - max_results (float): The maximum number of search hits.
82
+ - prompt_template (str): The prompt template used. Must contain {data.hits} for the search hits and {data.text.raw} for the query string.
83
+
84
+ Example:
85
+ >>> from clarifai.rag import RAG
86
+ >>> rag_agent = RAG.setup(user_id=YOUR_USER_ID)
87
+ >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
88
+
89
+ Or if you already have an existing app with ingested data:
90
+ >>> rag_agent = RAG.setup(app_url=YOUR_APP_URL)
91
+ >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
92
+ """
93
+ if not app_url:
94
+ try:
95
+ user_id = get_from_dict_or_env(
96
+ key="user_id", env_key=CLARIFAI_USER_ID_ENV_VAR, **kwargs
97
+ )
98
+ except Exception:
99
+ pass
100
+
101
+ now_ts = uuid.uuid4().hex[:10]
102
+ if user_id and not app_url:
103
+ user = User(user_id=user_id, base_url=base_url, pat=pat)
104
+ ## Create an App
105
+ app_id = f"rag_app_{now_ts}"
106
+ app = user.create_app(app_id=app_id, base_workflow=base_workflow)
107
+
108
+ if not user_id and app_url:
109
+ app = App(url=app_url, pat=pat)
110
+ uid = app_url.split(".com/")[1].split("/")[0]
111
+ user = User(user_id=uid, base_url=base_url, pat=pat)
112
+
113
+ if user_id and app_url:
114
+ raise UserError("Must provide one of user_id or app_url, not both.")
115
+
116
+ if not user_id and not app_url:
117
+ raise UserError(
118
+ "user_id or app_url must be provided. The user_id can be found at https://clarifai.com/settings."
119
+ )
120
+
121
+ llm = Model(url=llm_url, pat=pat)
122
+
123
+ min_score = kwargs.get("min_score", 0.95)
124
+ max_results = kwargs.get("max_results", 5)
125
+ prompt_template = kwargs.get("prompt_template", DEFAULT_RAG_PROMPT_TEMPLATE)
126
+ params = Struct()
127
+ params.update(
128
+ {
129
+ "min_score": min_score,
130
+ "max_results": max_results,
131
+ "prompt_template": prompt_template,
132
+ }
133
+ )
134
+ prompter_model_params = {"params": params}
135
+
136
+ ## Create rag-prompter model and version
137
+ model_id = (
138
+ f"prompter-{workflow_id}-{now_ts}"
139
+ if workflow_id is not None
140
+ else f"rag-prompter-{now_ts}"
141
+ )
142
+ prompter_model = app.create_model(model_id=model_id, model_type_id="rag-prompter")
143
+ prompter_model = prompter_model.create_version(output_info=prompter_model_params)
144
+
145
+ ## Generate a tmp yaml file for workflow creation
146
+ workflow_id = f"rag-wf-{now_ts}" if workflow_id is None else workflow_id
147
+ workflow_dict = {
148
+ "workflow": {
149
+ "id": workflow_id,
150
+ "nodes": [
151
+ {
152
+ "id": "rag-prompter",
153
+ "model": {
154
+ "model_id": prompter_model.id,
155
+ "model_version_id": prompter_model.model_version.id,
156
+ },
157
+ },
158
+ {
159
+ "id": "llm",
160
+ "model": {
161
+ "model_id": llm.id,
162
+ "user_id": llm.user_id,
163
+ "app_id": llm.app_id,
164
+ },
165
+ "node_inputs": [{"node_id": "rag-prompter"}],
166
+ },
167
+ ],
168
+ }
151
169
  }
152
- }
153
- with open(workflow_yaml_filename, 'w') as out_file:
154
- yaml.dump(workflow_dict, out_file, default_flow_style=False)
155
-
156
- ## Create prompt workflow
157
- wf = app.create_workflow(config_filepath=workflow_yaml_filename)
158
- del user, llm, prompter_model, prompter_model_params
159
- return cls(workflow=wf)
160
-
161
- def upload(self,
162
- file_path: str = None,
163
- folder_path: str = None,
164
- url: str = None,
165
- batch_size: int = 128,
166
- chunk_size: int = 1024,
167
- chunk_overlap: int = 200,
168
- dataset_id: str = None,
169
- metadata: dict = None,
170
- **kwargs) -> None:
171
- """Uploads documents to the app.
172
- - Read from a local directory or public url or local filename.
173
- - Parse the document(s) into chunks.
174
- - Ingest chunks into the app with metadata.
175
-
176
- Args:
177
- file_path str: File path to the document.
178
- folder_path str: Folder path to the documents.
179
- url str: Public url to the document.
180
- batch_size int: Batch size for uploading.
181
- chunk_size int: Chunk size for splitting the document.
182
- chunk_overlap int: The token overlap of each chunk when splitting.
183
- **kwargs: Additional arguments for the SentenceSplitter. Refer https://docs.llamaindex.ai/en/stable/api/llama_index.node_parser.SentenceSplitter.html
184
-
185
- Example:
186
- >>> from clarifai.rag import RAG
187
- >>> rag_agent = RAG.setup(user_id=YOUR_USER_ID)
188
- >>> rag_agent.upload(folder_path = "~/work/docs")
189
- >>> rag_agent.upload(file_path = "~/work/docs/manual.pdf")
190
- >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
191
- """
192
- #set batch size
193
- if batch_size > MAX_UPLOAD_BATCH_SIZE:
194
- raise ValueError(f"batch_size cannot be greater than {MAX_UPLOAD_BATCH_SIZE}")
195
-
196
- #check if only one of file_path, folder_path, or url is specified
197
- if file_path and (folder_path or url):
198
- raise ValueError("Only one of file_path, folder_path, or url can be specified.")
199
- if folder_path and (file_path or url):
200
- raise ValueError("Only one of file_path, folder_path, or url can be specified.")
201
- if url and (file_path or folder_path):
202
- raise ValueError("Only one of file_path, folder_path, or url can be specified.")
203
-
204
- #loading documents
205
- documents = load_documents(file_path=file_path, folder_path=folder_path, url=url)
206
-
207
- #splitting documents into chunks
208
- text_chunks = []
209
- metadata_list = []
210
-
211
- #iterate through documents
212
- for doc in documents:
213
- doc_i = 0
214
- cur_text_chunks = split_document(
215
- text=doc.text, chunk_size=chunk_size, chunk_overlap=chunk_overlap, **kwargs)
216
- text_chunks.extend(cur_text_chunks)
217
- metadata_list.extend([doc.metadata for _ in range(len(cur_text_chunks))])
218
- #if batch size is reached, upload the batch
219
- if len(text_chunks) > batch_size:
220
- for idx in range(0, len(text_chunks), batch_size):
221
- if idx + batch_size > len(text_chunks):
222
- continue
223
- batch_texts = text_chunks[0:batch_size]
224
- batch_ids = [uuid.uuid4().hex for _ in range(batch_size)]
225
- #metadata
226
- batch_metadatas = metadata_list[0:batch_size]
227
- meta_list = []
228
- for meta in batch_metadatas:
229
- meta_struct = Struct()
230
- meta_struct.update(meta)
231
- meta_struct.update({"doc_chunk_no": doc_i})
232
- if metadata and isinstance(metadata, dict):
233
- meta_struct.update(metadata)
234
- meta_list.append(meta_struct)
235
- doc_i += 1
236
- del batch_metadatas
237
- #creating input proto
238
- input_batch = [
239
- self._app.inputs().get_text_input(
240
- input_id=batch_ids[i],
241
- raw_text=text,
242
- dataset_id=dataset_id,
243
- metadata=meta_list[i],
244
- ) for i, text in enumerate(batch_texts)
245
- ]
246
- #uploading input with metadata
247
- self._app.inputs().upload_inputs(inputs=input_batch)
248
- #delete uploaded chunks
249
- del text_chunks[0:batch_size]
250
- del metadata_list[0:batch_size]
251
-
252
- #uploading the remaining chunks
253
- if len(text_chunks) > 0:
254
- batch_size = len(text_chunks)
255
- batch_ids = [uuid.uuid4().hex for _ in range(batch_size)]
256
- #metadata
257
- batch_metadatas = metadata_list[0:batch_size]
258
- meta_list = []
259
- for meta in batch_metadatas:
260
- meta_struct = Struct()
261
- meta_struct.update(meta)
262
- meta_struct.update({"doc_chunk_no": doc_i})
263
- if metadata and isinstance(metadata, dict):
264
- meta_struct.update(metadata)
265
- meta_list.append(meta_struct)
266
- doc_i += 1
267
- del batch_metadatas
268
- #creating input proto
269
- input_batch = [
270
- self._app.inputs().get_text_input(
271
- input_id=batch_ids[i],
272
- raw_text=text,
273
- dataset_id=dataset_id,
274
- metadata=meta_list[i],
275
- ) for i, text in enumerate(text_chunks)
276
- ]
277
- #uploading input with metadata
278
- self._app.inputs().upload_inputs(inputs=input_batch)
279
- del text_chunks
280
- del metadata_list
281
-
282
- def chat(self, messages: List[dict], client_manage_state: bool = False) -> List[dict]:
283
- """Chat interface in OpenAI API format.
284
-
285
- Args:
286
- messages List[dict]: A list of dictionary in the following format:
287
- ```
288
- [
289
- {"role": "user", "content": "Hello there."},
290
- {"role": "assistant", "content": "Hi, I'm Claude. How can I help you?"},
291
- {"role": "user", "content": "Can you explain LLMs in plain English?"},
292
- ]
293
- ```
294
- client_manage_state (bool): Whether the client will handle chat state management. Default is false.
295
-
296
- This will pass back the workflow state ID for the server to store chat state.
297
- """
298
- if client_manage_state:
299
- single_prompt = convert_messages_to_str(messages)
300
- input_proto = Inputs._get_proto("", "", text_pb=resources_pb2.Text(raw=single_prompt))
301
- response = self._prompt_workflow.predict([input_proto])
302
- messages.append(format_assistant_message(response.results[0].outputs[-1].data.text.raw))
303
- return messages
304
-
305
- # server-side state management
306
- message = messages[-1].get("content", "")
307
- if len(message) == 0:
308
- raise UserError("Empty message supplied.")
309
-
310
- # get chat state id
311
- chat_state_id = "init" if self.chat_state_id is None else self.chat_state_id
312
-
313
- # call predict
314
- input_proto = Inputs._get_proto("", "", text_pb=resources_pb2.Text(raw=message))
315
- response = self._prompt_workflow.predict([input_proto], workflow_state_id=chat_state_id)
316
-
317
- # store chat state id
318
- self.chat_state_id = response.workflow_state.id
319
- return [format_assistant_message(response.results[0].outputs[-1].data.text.raw)]
170
+ with open(workflow_yaml_filename, 'w') as out_file:
171
+ yaml.dump(workflow_dict, out_file, default_flow_style=False)
172
+
173
+ ## Create prompt workflow
174
+ wf = app.create_workflow(config_filepath=workflow_yaml_filename)
175
+ del user, llm, prompter_model, prompter_model_params
176
+ return cls(workflow=wf)
177
+
178
+ def upload(
179
+ self,
180
+ file_path: str = None,
181
+ folder_path: str = None,
182
+ url: str = None,
183
+ batch_size: int = 128,
184
+ chunk_size: int = 1024,
185
+ chunk_overlap: int = 200,
186
+ dataset_id: str = None,
187
+ metadata: dict = None,
188
+ **kwargs,
189
+ ) -> None:
190
+ """Uploads documents to the app.
191
+ - Read from a local directory or public url or local filename.
192
+ - Parse the document(s) into chunks.
193
+ - Ingest chunks into the app with metadata.
194
+
195
+ Args:
196
+ file_path str: File path to the document.
197
+ folder_path str: Folder path to the documents.
198
+ url str: Public url to the document.
199
+ batch_size int: Batch size for uploading.
200
+ chunk_size int: Chunk size for splitting the document.
201
+ chunk_overlap int: The token overlap of each chunk when splitting.
202
+ **kwargs: Additional arguments for the SentenceSplitter. Refer https://docs.llamaindex.ai/en/stable/api/llama_index.node_parser.SentenceSplitter.html
203
+
204
+ Example:
205
+ >>> from clarifai.rag import RAG
206
+ >>> rag_agent = RAG.setup(user_id=YOUR_USER_ID)
207
+ >>> rag_agent.upload(folder_path = "~/work/docs")
208
+ >>> rag_agent.upload(file_path = "~/work/docs/manual.pdf")
209
+ >>> rag_agent.chat(messages=[{"role":"human", "content":"What is Clarifai"}])
210
+ """
211
+ # set batch size
212
+ if batch_size > MAX_UPLOAD_BATCH_SIZE:
213
+ raise ValueError(f"batch_size cannot be greater than {MAX_UPLOAD_BATCH_SIZE}")
214
+
215
+ # check if only one of file_path, folder_path, or url is specified
216
+ if file_path and (folder_path or url):
217
+ raise ValueError("Only one of file_path, folder_path, or url can be specified.")
218
+ if folder_path and (file_path or url):
219
+ raise ValueError("Only one of file_path, folder_path, or url can be specified.")
220
+ if url and (file_path or folder_path):
221
+ raise ValueError("Only one of file_path, folder_path, or url can be specified.")
222
+
223
+ # loading documents
224
+ documents = load_documents(file_path=file_path, folder_path=folder_path, url=url)
225
+
226
+ # splitting documents into chunks
227
+ text_chunks = []
228
+ metadata_list = []
229
+
230
+ # iterate through documents
231
+ for doc in documents:
232
+ doc_i = 0
233
+ cur_text_chunks = split_document(
234
+ text=doc.text, chunk_size=chunk_size, chunk_overlap=chunk_overlap, **kwargs
235
+ )
236
+ text_chunks.extend(cur_text_chunks)
237
+ metadata_list.extend([doc.metadata for _ in range(len(cur_text_chunks))])
238
+ # if batch size is reached, upload the batch
239
+ if len(text_chunks) > batch_size:
240
+ for idx in range(0, len(text_chunks), batch_size):
241
+ if idx + batch_size > len(text_chunks):
242
+ continue
243
+ batch_texts = text_chunks[0:batch_size]
244
+ batch_ids = [uuid.uuid4().hex for _ in range(batch_size)]
245
+ # metadata
246
+ batch_metadatas = metadata_list[0:batch_size]
247
+ meta_list = []
248
+ for meta in batch_metadatas:
249
+ meta_struct = Struct()
250
+ meta_struct.update(meta)
251
+ meta_struct.update({"doc_chunk_no": doc_i})
252
+ if metadata and isinstance(metadata, dict):
253
+ meta_struct.update(metadata)
254
+ meta_list.append(meta_struct)
255
+ doc_i += 1
256
+ del batch_metadatas
257
+ # creating input proto
258
+ input_batch = [
259
+ self._app.inputs().get_text_input(
260
+ input_id=batch_ids[i],
261
+ raw_text=text,
262
+ dataset_id=dataset_id,
263
+ metadata=meta_list[i],
264
+ )
265
+ for i, text in enumerate(batch_texts)
266
+ ]
267
+ # uploading input with metadata
268
+ self._app.inputs().upload_inputs(inputs=input_batch)
269
+ # delete uploaded chunks
270
+ del text_chunks[0:batch_size]
271
+ del metadata_list[0:batch_size]
272
+
273
+ # uploading the remaining chunks
274
+ if len(text_chunks) > 0:
275
+ batch_size = len(text_chunks)
276
+ batch_ids = [uuid.uuid4().hex for _ in range(batch_size)]
277
+ # metadata
278
+ batch_metadatas = metadata_list[0:batch_size]
279
+ meta_list = []
280
+ for meta in batch_metadatas:
281
+ meta_struct = Struct()
282
+ meta_struct.update(meta)
283
+ meta_struct.update({"doc_chunk_no": doc_i})
284
+ if metadata and isinstance(metadata, dict):
285
+ meta_struct.update(metadata)
286
+ meta_list.append(meta_struct)
287
+ doc_i += 1
288
+ del batch_metadatas
289
+ # creating input proto
290
+ input_batch = [
291
+ self._app.inputs().get_text_input(
292
+ input_id=batch_ids[i],
293
+ raw_text=text,
294
+ dataset_id=dataset_id,
295
+ metadata=meta_list[i],
296
+ )
297
+ for i, text in enumerate(text_chunks)
298
+ ]
299
+ # uploading input with metadata
300
+ self._app.inputs().upload_inputs(inputs=input_batch)
301
+ del text_chunks
302
+ del metadata_list
303
+
304
+ def chat(self, messages: List[dict], client_manage_state: bool = False) -> List[dict]:
305
+ """Chat interface in OpenAI API format.
306
+
307
+ Args:
308
+ messages List[dict]: A list of dictionary in the following format:
309
+ ```
310
+ [
311
+ {"role": "user", "content": "Hello there."},
312
+ {"role": "assistant", "content": "Hi, I'm Claude. How can I help you?"},
313
+ {"role": "user", "content": "Can you explain LLMs in plain English?"},
314
+ ]
315
+ ```
316
+ client_manage_state (bool): Whether the client will handle chat state management. Default is false.
317
+
318
+ This will pass back the workflow state ID for the server to store chat state.
319
+ """
320
+ if client_manage_state:
321
+ single_prompt = convert_messages_to_str(messages)
322
+ input_proto = Inputs._get_proto("", "", text_pb=resources_pb2.Text(raw=single_prompt))
323
+ response = self._prompt_workflow.predict([input_proto])
324
+ messages.append(
325
+ format_assistant_message(response.results[0].outputs[-1].data.text.raw)
326
+ )
327
+ return messages
328
+
329
+ # server-side state management
330
+ message = messages[-1].get("content", "")
331
+ if len(message) == 0:
332
+ raise UserError("Empty message supplied.")
333
+
334
+ # get chat state id
335
+ chat_state_id = "init" if self.chat_state_id is None else self.chat_state_id
336
+
337
+ # call predict
338
+ input_proto = Inputs._get_proto("", "", text_pb=resources_pb2.Text(raw=message))
339
+ response = self._prompt_workflow.predict([input_proto], workflow_state_id=chat_state_id)
340
+
341
+ # store chat state id
342
+ self.chat_state_id = response.workflow_state.id
343
+ return [format_assistant_message(response.results[0].outputs[-1].data.text.raw)]