qtype 0.1.2__tar.gz → 0.1.4__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 (142) hide show
  1. {qtype-0.1.2/qtype.egg-info → qtype-0.1.4}/PKG-INFO +1 -1
  2. {qtype-0.1.2 → qtype-0.1.4}/pyproject.toml +1 -1
  3. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/model.py +2 -1
  4. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/parser.py +3 -3
  5. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/base_step_executor.py +1 -1
  6. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/conversions.py +25 -3
  7. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/document_embedder_executor.py +1 -1
  8. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/document_splitter_executor.py +1 -1
  9. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/invoke_embedding_executor.py +3 -1
  10. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/flow.py +12 -1
  11. qtype-0.1.4/qtype/interpreter/logging_progress.py +61 -0
  12. {qtype-0.1.2 → qtype-0.1.4/qtype.egg-info}/PKG-INFO +1 -1
  13. {qtype-0.1.2 → qtype-0.1.4}/qtype.egg-info/SOURCES.txt +1 -0
  14. {qtype-0.1.2 → qtype-0.1.4}/LICENSE +0 -0
  15. {qtype-0.1.2 → qtype-0.1.4}/README.md +0 -0
  16. {qtype-0.1.2 → qtype-0.1.4}/qtype/__init__.py +0 -0
  17. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/__init__.py +0 -0
  18. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/commons/__init__.py +0 -0
  19. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/commons/tools.py +0 -0
  20. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/converters/__init__.py +0 -0
  21. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/converters/tools_from_api.py +0 -0
  22. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/converters/tools_from_module.py +0 -0
  23. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/converters/types.py +0 -0
  24. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/documentation.py +0 -0
  25. {qtype-0.1.2 → qtype-0.1.4}/qtype/application/facade.py +0 -0
  26. {qtype-0.1.2 → qtype-0.1.4}/qtype/base/__init__.py +0 -0
  27. {qtype-0.1.2 → qtype-0.1.4}/qtype/base/exceptions.py +0 -0
  28. {qtype-0.1.2 → qtype-0.1.4}/qtype/base/logging.py +0 -0
  29. {qtype-0.1.2 → qtype-0.1.4}/qtype/base/types.py +0 -0
  30. {qtype-0.1.2 → qtype-0.1.4}/qtype/cli.py +0 -0
  31. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/__init__.py +0 -0
  32. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/convert.py +0 -0
  33. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/generate.py +0 -0
  34. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/run.py +0 -0
  35. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/serve.py +0 -0
  36. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/validate.py +0 -0
  37. {qtype-0.1.2 → qtype-0.1.4}/qtype/commands/visualize.py +0 -0
  38. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/__init__.py +0 -0
  39. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/custom_types.py +0 -0
  40. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/domain_types.py +0 -0
  41. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/linker.py +0 -0
  42. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/loader.py +0 -0
  43. {qtype-0.1.2 → qtype-0.1.4}/qtype/dsl/types.py +0 -0
  44. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/__init__.py +0 -0
  45. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/api.py +0 -0
  46. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/auth/__init__.py +0 -0
  47. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/auth/aws.py +0 -0
  48. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/auth/cache.py +0 -0
  49. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/auth/generic.py +0 -0
  50. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/batch_step_executor.py +0 -0
  51. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/exceptions.py +0 -0
  52. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/executor_context.py +0 -0
  53. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/factory.py +0 -0
  54. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/progress_tracker.py +0 -0
  55. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/secrets.py +0 -0
  56. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/step_cache.py +0 -0
  57. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/base/stream_emitter.py +0 -0
  58. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/converters.py +0 -0
  59. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/endpoints.py +0 -0
  60. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/agent_executor.py +0 -0
  61. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/aggregate_executor.py +0 -0
  62. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/bedrock_reranker_executor.py +0 -0
  63. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/decoder_executor.py +0 -0
  64. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/doc_to_text_executor.py +0 -0
  65. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/document_search_executor.py +0 -0
  66. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/document_source_executor.py +0 -0
  67. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/echo_executor.py +0 -0
  68. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/field_extractor_executor.py +0 -0
  69. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/file_source_executor.py +0 -0
  70. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/file_writer_executor.py +0 -0
  71. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/index_upsert_executor.py +0 -0
  72. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/invoke_flow_executor.py +0 -0
  73. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/invoke_tool_executor.py +0 -0
  74. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/llm_inference_executor.py +0 -0
  75. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/prompt_template_executor.py +0 -0
  76. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/sql_source_executor.py +0 -0
  77. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/executors/vector_search_executor.py +0 -0
  78. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/metadata_api.py +0 -0
  79. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/resource_cache.py +0 -0
  80. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/rich_progress.py +0 -0
  81. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/chat/__init__.py +0 -0
  82. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/chat/converter.py +0 -0
  83. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/chat/file_conversions.py +0 -0
  84. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/chat/ui_request_to_domain_type.py +0 -0
  85. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/chat/vercel.py +0 -0
  86. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/__init__.py +0 -0
  87. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/build_vercel_ai_formatter.py +0 -0
  88. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/callback_to_stream.py +0 -0
  89. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/create_streaming_response.py +0 -0
  90. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/default_chat_extract_text.py +0 -0
  91. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/stream/utils/error_streaming_response.py +0 -0
  92. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/telemetry.py +0 -0
  93. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/tools/__init__.py +0 -0
  94. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/tools/function_tool_helper.py +0 -0
  95. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/types.py +0 -0
  96. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/typing.py +0 -0
  97. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/404/index.html +0 -0
  98. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/404.html +0 -0
  99. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_buildManifest.js +0 -0
  100. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_ssgManifest.js +0 -0
  101. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/434-b2112d19f25c44ff.js +0 -0
  102. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -0
  103. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/964-2b041321a01cbf56.js +0 -0
  104. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +0 -0
  105. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/app/layout-a05273ead5de2c41.js +0 -0
  106. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/app/page-8c67d16ac90d23cb.js +0 -0
  107. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/ba12c10f-546f2714ff8abc66.js +0 -0
  108. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +0 -0
  109. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +0 -0
  110. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/main-e26b9cb206da2cac.js +0 -0
  111. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -0
  112. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +0 -0
  113. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  114. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/chunks/webpack-08642e441b39b6c2.js +0 -0
  115. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/css/8a8d1269e362fef7.css +0 -0
  116. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  117. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  118. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  119. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  120. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  121. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  122. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/file.svg +0 -0
  123. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/globe.svg +0 -0
  124. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/icon.png +0 -0
  125. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/index.html +0 -0
  126. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/index.txt +0 -0
  127. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/next.svg +0 -0
  128. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/vercel.svg +0 -0
  129. {qtype-0.1.2 → qtype-0.1.4}/qtype/interpreter/ui/window.svg +0 -0
  130. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/__init__.py +0 -0
  131. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/base_types.py +0 -0
  132. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/checker.py +0 -0
  133. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/generate.py +0 -0
  134. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/loader.py +0 -0
  135. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/model.py +0 -0
  136. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/resolver.py +0 -0
  137. {qtype-0.1.2 → qtype-0.1.4}/qtype/semantic/visualize.py +0 -0
  138. {qtype-0.1.2 → qtype-0.1.4}/qtype.egg-info/dependency_links.txt +0 -0
  139. {qtype-0.1.2 → qtype-0.1.4}/qtype.egg-info/entry_points.txt +0 -0
  140. {qtype-0.1.2 → qtype-0.1.4}/qtype.egg-info/requires.txt +0 -0
  141. {qtype-0.1.2 → qtype-0.1.4}/qtype.egg-info/top_level.txt +0 -0
  142. {qtype-0.1.2 → qtype-0.1.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: DSL for Generative AI Prototyping
5
5
  Author-email: Lou Kratz <lou.kratz+qtype@bazaarvoice.com>
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qtype"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  description = "DSL for Generative AI Prototyping"
5
5
  authors = [{ name="Lou Kratz", email="lou.kratz+qtype@bazaarvoice.com" }]
6
6
  readme = "README.md"
@@ -765,8 +765,9 @@ class AWSAuthProvider(AuthorizationProvider):
765
765
  has_keys = self.access_key_id and self.secret_access_key
766
766
  has_profile = self.profile_name
767
767
  has_role = self.role_arn
768
+ has_region = self.region
768
769
 
769
- if not (has_keys or has_profile or has_role):
770
+ if not (has_keys or has_profile or has_role or has_region):
770
771
  raise ValueError(
771
772
  "AWSAuthProvider must specify at least one authentication method: "
772
773
  "access keys, profile name, or role ARN."
@@ -153,12 +153,12 @@ def _format_validation_errors(
153
153
  error_msg = "Validation failed (see details above)"
154
154
  else:
155
155
  error_msg = "Validation failed:\n"
156
- for error in relevant_errors[:5]: # Show max 5 errors
156
+ for error in relevant_errors[:30]: # Show max 5 errors
157
157
  loc_path = _simplify_field_path(error["loc"])
158
158
  error_msg += f" {loc_path}: {error['msg']}\n"
159
159
 
160
- if len(relevant_errors) > 5:
161
- error_msg += f" ... and {len(relevant_errors) - 5} more errors\n"
160
+ if len(relevant_errors) > 30:
161
+ error_msg += f" ... and {len(relevant_errors) - 30} more errors\n"
162
162
 
163
163
  if source_name:
164
164
  error_msg = f"In {source_name}:\n{error_msg}"
@@ -241,7 +241,7 @@ class StepExecutor(ABC):
241
241
 
242
242
  # Track message counts for telemetry
243
243
  message_count = 0
244
- error_count = len(failed_messages)
244
+ error_count = 0
245
245
 
246
246
  # Stream results and track progress
247
247
  async with all_results.stream() as streamer:
@@ -34,6 +34,7 @@ from qtype.interpreter.base.secrets import SecretManagerBase
34
34
  from qtype.interpreter.types import InterpreterError
35
35
  from qtype.semantic.model import (
36
36
  APIKeyAuthProvider,
37
+ AWSAuthProvider,
37
38
  DocumentIndex,
38
39
  DocumentSplitter,
39
40
  Model,
@@ -302,7 +303,9 @@ def to_vector_store(
302
303
 
303
304
 
304
305
  @cached_resource
305
- def to_embedding_model(model: Model) -> BaseEmbedding:
306
+ def to_embedding_model(
307
+ model: Model, secret_manager: SecretManagerBase
308
+ ) -> BaseEmbedding:
306
309
  """Convert a qtype Model to a LlamaIndex embedding model."""
307
310
 
308
311
  if model.provider == "aws-bedrock":
@@ -310,7 +313,14 @@ def to_embedding_model(model: Model) -> BaseEmbedding:
310
313
  BedrockEmbedding,
311
314
  )
312
315
 
316
+ session = None
317
+ if model.auth is not None:
318
+ assert isinstance(model.auth, AWSAuthProvider)
319
+ with aws(model.auth, secret_manager) as session:
320
+ session = session._session
321
+
313
322
  bedrock_embedding: BaseEmbedding = BedrockEmbedding(
323
+ botocore_session=session,
314
324
  model_name=model.model_id if model.model_id else model.id,
315
325
  max_retries=100,
316
326
  )
@@ -320,8 +330,20 @@ def to_embedding_model(model: Model) -> BaseEmbedding:
320
330
  OpenAIEmbedding,
321
331
  )
322
332
 
333
+ api_key = None
334
+ if model.auth:
335
+ with auth(model.auth, secret_manager) as provider:
336
+ if not isinstance(provider, APIKeyAuthProvider):
337
+ raise InterpreterError(
338
+ f"OpenAI provider requires APIKeyAuthProvider, "
339
+ f"got {type(provider).__name__}"
340
+ )
341
+ # api_key is guaranteed to be str after auth() resolves it
342
+ api_key = provider.api_key # type: ignore[assignment]
343
+
323
344
  openai_embedding: BaseEmbedding = OpenAIEmbedding(
324
- model_name=model.model_id if model.model_id else model.id
345
+ api_key=api_key,
346
+ model_name=model.model_id if model.model_id else model.id,
325
347
  )
326
348
  return openai_embedding
327
349
  else:
@@ -566,7 +588,7 @@ def to_llama_vector_store_and_retriever(
566
588
  vector_store = to_vector_store(index, secret_manager)
567
589
 
568
590
  # Get the embedding model
569
- embedding_model = to_embedding_model(index.embedding_model)
591
+ embedding_model = to_embedding_model(index.embedding_model, secret_manager)
570
592
 
571
593
  # Create a VectorStoreIndex with the vector store and embedding model
572
594
  vector_index = VectorStoreIndex.from_vector_store(
@@ -41,7 +41,7 @@ class DocumentEmbedderExecutor(StepExecutor):
41
41
  self.step: DocumentEmbedder = step
42
42
  # Initialize the embedding model once for the executor
43
43
  self.embedding_model: BaseEmbedding = to_embedding_model(
44
- self.step.model
44
+ self.step.model, context.secret_manager
45
45
  )
46
46
 
47
47
  # TODO: properly abstract this into a mixin
@@ -71,7 +71,7 @@ class DocumentSplitterExecutor(StepExecutor):
71
71
  # Convert to LlamaIndex Document for splitting
72
72
  llama_doc = LlamaDocument(
73
73
  text=content_text,
74
- metadata=document.metadata or {},
74
+ metadata={}, # ommit metadata here as it's added back later and we don't want the chunk size checks
75
75
  doc_id=document.file_id,
76
76
  )
77
77
 
@@ -30,7 +30,9 @@ class InvokeEmbeddingExecutor(StepExecutor):
30
30
  )
31
31
  self.step: InvokeEmbedding = step
32
32
  # Initialize the embedding model once for the executor
33
- self.embedding_model = to_embedding_model(self.step.model)
33
+ self.embedding_model = to_embedding_model(
34
+ self.step.model, context.secret_manager
35
+ )
34
36
 
35
37
  async def process_message(
36
38
  self,
@@ -11,9 +11,12 @@ from openinference.semconv.trace import (
11
11
  from opentelemetry import context as otel_context
12
12
  from opentelemetry import trace
13
13
  from opentelemetry.trace import Status, StatusCode
14
+ from rich.console import Console
15
+ from transformers import ProgressCallback
14
16
 
15
17
  from qtype.interpreter.base import factory
16
18
  from qtype.interpreter.base.executor_context import ExecutorContext
19
+ from qtype.interpreter.logging_progress import LoggingProgressCallback
17
20
  from qtype.interpreter.rich_progress import RichProgressCallback
18
21
  from qtype.interpreter.types import FlowMessage
19
22
  from qtype.semantic.model import Flow
@@ -42,9 +45,17 @@ async def run_flow(
42
45
  """
43
46
  from qtype.interpreter.base.secrets import NoOpSecretManager
44
47
 
48
+ # Wire up progress callback if requested
49
+ progress_callback: ProgressCallback | None = None
50
+ if show_progress:
51
+ console = Console()
52
+ if console.is_terminal:
53
+ progress_callback = RichProgressCallback()
54
+ else:
55
+ progress_callback = LoggingProgressCallback(log_every_seconds=120)
56
+
45
57
  # Extract or create ExecutorContext
46
58
  exec_context = kwargs.pop("context", None)
47
- progress_callback = RichProgressCallback() if show_progress else None
48
59
  if exec_context is None:
49
60
  exec_context = ExecutorContext(
50
61
  secret_manager=NoOpSecretManager(),
@@ -0,0 +1,61 @@
1
+ import logging
2
+ import time
3
+
4
+ from qtype.interpreter.types import ProgressCallback
5
+
6
+
7
+ class LoggingProgressCallback(ProgressCallback):
8
+ def __init__(self, log_every_seconds: float = 120.0) -> None:
9
+ super().__init__()
10
+ self.log_every_seconds = log_every_seconds
11
+ self._last_log: dict[str, float] = {}
12
+ self._totals: dict[str, int | None] = {}
13
+
14
+ def __call__(
15
+ self,
16
+ step_id: str,
17
+ items_processed: int,
18
+ items_in_error: int,
19
+ items_succeeded: int,
20
+ total_items: int | None,
21
+ cache_hits: int | None,
22
+ cache_misses: int | None,
23
+ ) -> None:
24
+ logger = logging.getLogger(__name__)
25
+ now = time.monotonic()
26
+ last = self._last_log.get(step_id, 0.0)
27
+
28
+ self._totals[step_id] = total_items
29
+
30
+ if now - last < self.log_every_seconds:
31
+ return
32
+
33
+ self._last_log[step_id] = now
34
+ total_str = (
35
+ f"{items_processed}/{total_items}"
36
+ if total_items is not None
37
+ else f"{items_processed}"
38
+ )
39
+ if cache_hits is not None or cache_misses is not None:
40
+ logger.info(
41
+ "Step %s: processed=%s, succeeded=%s, errors=%s, "
42
+ "cache_hits=%s, cache_misses=%s",
43
+ step_id,
44
+ total_str,
45
+ items_succeeded,
46
+ items_in_error,
47
+ cache_hits if cache_hits is not None else "-",
48
+ cache_misses if cache_misses is not None else "-",
49
+ )
50
+ else:
51
+ logger.info(
52
+ "Step %s: processed=%s, succeeded=%s, errors=%s",
53
+ step_id,
54
+ total_str,
55
+ items_succeeded,
56
+ items_in_error,
57
+ )
58
+
59
+ def close(self) -> None:
60
+ # optional: final summary logging
61
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: DSL for Generative AI Prototyping
5
5
  Author-email: Lou Kratz <lou.kratz+qtype@bazaarvoice.com>
6
6
  License-Expression: Apache-2.0
@@ -43,6 +43,7 @@ qtype/interpreter/conversions.py
43
43
  qtype/interpreter/converters.py
44
44
  qtype/interpreter/endpoints.py
45
45
  qtype/interpreter/flow.py
46
+ qtype/interpreter/logging_progress.py
46
47
  qtype/interpreter/metadata_api.py
47
48
  qtype/interpreter/resource_cache.py
48
49
  qtype/interpreter/rich_progress.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes