qtype 0.0.9__py3-none-any.whl → 0.0.11__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.
- qtype/application/__init__.py +12 -0
- qtype/application/commons/__init__.py +7 -0
- qtype/{converters → application/converters}/tools_from_module.py +2 -2
- qtype/{converters → application/converters}/types.py +0 -33
- qtype/{dsl/document.py → application/documentation.py} +2 -0
- qtype/application/facade.py +160 -0
- qtype/base/__init__.py +14 -0
- qtype/base/exceptions.py +49 -0
- qtype/base/logging.py +39 -0
- qtype/base/types.py +29 -0
- qtype/commands/convert.py +64 -49
- qtype/commands/generate.py +59 -4
- qtype/commands/run.py +109 -72
- qtype/commands/serve.py +42 -28
- qtype/commands/validate.py +25 -42
- qtype/commands/visualize.py +51 -37
- qtype/dsl/__init__.py +9 -0
- qtype/dsl/base_types.py +8 -0
- qtype/dsl/custom_types.py +6 -4
- qtype/dsl/model.py +185 -50
- qtype/dsl/validator.py +9 -4
- qtype/interpreter/api.py +96 -40
- qtype/interpreter/auth/__init__.py +3 -0
- qtype/interpreter/auth/aws.py +234 -0
- qtype/interpreter/auth/cache.py +67 -0
- qtype/interpreter/auth/generic.py +103 -0
- qtype/interpreter/batch/flow.py +95 -0
- qtype/interpreter/batch/sql_source.py +95 -0
- qtype/interpreter/batch/step.py +63 -0
- qtype/interpreter/batch/types.py +41 -0
- qtype/interpreter/batch/utils.py +179 -0
- qtype/interpreter/conversions.py +21 -10
- qtype/interpreter/resource_cache.py +4 -2
- qtype/interpreter/steps/decoder.py +13 -9
- qtype/interpreter/steps/llm_inference.py +7 -9
- qtype/interpreter/steps/prompt_template.py +1 -1
- qtype/interpreter/streaming_helpers.py +3 -3
- qtype/interpreter/typing.py +47 -11
- qtype/interpreter/ui/404/index.html +1 -1
- qtype/interpreter/ui/404.html +1 -1
- qtype/interpreter/ui/index.html +1 -1
- qtype/interpreter/ui/index.txt +1 -1
- qtype/loader.py +9 -15
- qtype/semantic/generate.py +91 -39
- qtype/semantic/model.py +183 -52
- qtype/semantic/resolver.py +4 -4
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/METADATA +5 -1
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/RECORD +58 -44
- qtype/commons/generate.py +0 -93
- qtype/semantic/errors.py +0 -4
- /qtype/{commons → application/commons}/tools.py +0 -0
- /qtype/{commons → application/converters}/__init__.py +0 -0
- /qtype/{converters → application/converters}/tools_from_api.py +0 -0
- /qtype/{converters → interpreter/batch}/__init__.py +0 -0
- /qtype/interpreter/ui/_next/static/{uMm4B0RSTGhXxgH3rTfwc → OT8QJQW3J70VbDWWfrEMT}/_buildManifest.js +0 -0
- /qtype/interpreter/ui/_next/static/{uMm4B0RSTGhXxgH3rTfwc → OT8QJQW3J70VbDWWfrEMT}/_ssgManifest.js +0 -0
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/WHEEL +0 -0
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/entry_points.txt +0 -0
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/licenses/LICENSE +0 -0
- {qtype-0.0.9.dist-info → qtype-0.0.11.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ from typing import Any, Type, Union, get_args, get_origin
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from qtype.converters.types import PYTHON_TYPE_TO_PRIMITIVE_TYPE
|
|
7
|
+
from qtype.application.converters.types import PYTHON_TYPE_TO_PRIMITIVE_TYPE
|
|
8
8
|
from qtype.dsl.base_types import PrimitiveTypeEnum
|
|
9
9
|
from qtype.dsl.model import (
|
|
10
10
|
CustomType,
|
|
@@ -239,7 +239,7 @@ def _map_python_type_to_variable_type(
|
|
|
239
239
|
return PYTHON_TYPE_TO_PRIMITIVE_TYPE[python_type]
|
|
240
240
|
elif python_type in get_args(VariableType):
|
|
241
241
|
# If it's a domain type, return its name
|
|
242
|
-
return python_type
|
|
242
|
+
return python_type # type: ignore[no-any-return]
|
|
243
243
|
elif inspect.isclass(python_type) and issubclass(python_type, BaseModel):
|
|
244
244
|
# If it's a Pydantic model, create or retrieve its CustomType definition
|
|
245
245
|
return _pydantic_to_custom_types(python_type, custom_types)
|
|
@@ -31,36 +31,3 @@ PYTHON_TYPE_TO_PRIMITIVE_TYPE = {
|
|
|
31
31
|
time: PrimitiveTypeEnum.time,
|
|
32
32
|
# TODO: decide on internal representation for images, video, and audio, or use annotation/hinting
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
# def create_custom_type(model_cls: Type[BaseModel],) -> CustomType:
|
|
36
|
-
# """
|
|
37
|
-
# Create a CustomType from a Pydantic BaseModel.
|
|
38
|
-
|
|
39
|
-
# Args:
|
|
40
|
-
# type: The Pydantic BaseModel class.
|
|
41
|
-
|
|
42
|
-
# Returns:
|
|
43
|
-
# A CustomType instance representing the model.
|
|
44
|
-
# """
|
|
45
|
-
|
|
46
|
-
# properties = {}
|
|
47
|
-
# for field_name, field_info in model_cls.model_fields.items():
|
|
48
|
-
# # Use the annotation (the type hint) for the field
|
|
49
|
-
# field_type = field_info.annotation
|
|
50
|
-
# if field_type is None:
|
|
51
|
-
# raise TypeError(
|
|
52
|
-
# f"Field '{field_name}' in '{model_name}' must have a type hint."
|
|
53
|
-
# )
|
|
54
|
-
# origin = get_origin(field_type)
|
|
55
|
-
|
|
56
|
-
# if origin is Union:
|
|
57
|
-
# # Assume the union means it's optional
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# return CustomType(
|
|
61
|
-
# id=type.__name__,
|
|
62
|
-
# properties={
|
|
63
|
-
# name: python_type_to_variable_type(field.type_)
|
|
64
|
-
# for name, field in type.__fields__.items()
|
|
65
|
-
# },
|
|
66
|
-
# )
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Main facade for qtype operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from qtype.base.logging import get_logger
|
|
12
|
+
from qtype.base.types import CustomTypeRegistry, DocumentRootType, PathLike
|
|
13
|
+
from qtype.dsl.base_types import StepCardinality
|
|
14
|
+
from qtype.dsl.model import Application as DSLApplication
|
|
15
|
+
from qtype.dsl.model import DocumentType
|
|
16
|
+
from qtype.interpreter.batch.types import BatchConfig
|
|
17
|
+
from qtype.semantic.model import Application as SemanticApplication
|
|
18
|
+
from qtype.semantic.model import Variable
|
|
19
|
+
|
|
20
|
+
logger = get_logger("application.facade")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class QTypeFacade:
|
|
24
|
+
"""
|
|
25
|
+
Simplified interface for all qtype operations.
|
|
26
|
+
|
|
27
|
+
This facade hides the complexity of coordinating between DSL, semantic,
|
|
28
|
+
and interpreter layers, providing a clean API for common operations.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def load_dsl_document(
|
|
32
|
+
self, path: PathLike
|
|
33
|
+
) -> tuple[DocumentRootType, CustomTypeRegistry]:
|
|
34
|
+
from qtype.loader import load_document
|
|
35
|
+
|
|
36
|
+
return load_document(Path(path).read_text(encoding="utf-8"))
|
|
37
|
+
|
|
38
|
+
def load_and_validate(self, path: PathLike) -> DocumentRootType:
|
|
39
|
+
"""Load and validate a document."""
|
|
40
|
+
logger.info("Document loaded, proceeding to validation")
|
|
41
|
+
root, _ = self.load_dsl_document(path)
|
|
42
|
+
return root
|
|
43
|
+
|
|
44
|
+
def load_semantic_model(
|
|
45
|
+
self, path: PathLike
|
|
46
|
+
) -> tuple[SemanticApplication, CustomTypeRegistry]:
|
|
47
|
+
"""Load a document and return the resolved semantic model."""
|
|
48
|
+
from qtype.loader import load
|
|
49
|
+
|
|
50
|
+
content = Path(path).read_text(encoding="utf-8")
|
|
51
|
+
return load(content)
|
|
52
|
+
|
|
53
|
+
def execute_workflow(
|
|
54
|
+
self,
|
|
55
|
+
path: PathLike,
|
|
56
|
+
inputs: dict | pd.DataFrame,
|
|
57
|
+
flow_name: str | None = None,
|
|
58
|
+
batch_config: BatchConfig | None = None,
|
|
59
|
+
**kwargs: Any,
|
|
60
|
+
) -> pd.DataFrame | list[Variable]:
|
|
61
|
+
"""Execute a complete workflow from document to results."""
|
|
62
|
+
logger.info(f"Executing workflow from {path}")
|
|
63
|
+
|
|
64
|
+
# Load the semantic application
|
|
65
|
+
semantic_model, type_registry = self.load_semantic_model(path)
|
|
66
|
+
|
|
67
|
+
# Find the flow to execute (inlined from _find_flow)
|
|
68
|
+
if flow_name:
|
|
69
|
+
target_flow = None
|
|
70
|
+
for flow in semantic_model.flows:
|
|
71
|
+
if flow.id == flow_name:
|
|
72
|
+
target_flow = flow
|
|
73
|
+
break
|
|
74
|
+
if target_flow is None:
|
|
75
|
+
raise ValueError(f"Flow '{flow_name}' not found")
|
|
76
|
+
else:
|
|
77
|
+
if semantic_model.flows:
|
|
78
|
+
target_flow = semantic_model.flows[0]
|
|
79
|
+
else:
|
|
80
|
+
raise ValueError("No flows found in application")
|
|
81
|
+
if target_flow.cardinality == StepCardinality.many:
|
|
82
|
+
if isinstance(inputs, dict):
|
|
83
|
+
inputs = pd.DataFrame([inputs])
|
|
84
|
+
if not isinstance(inputs, pd.DataFrame):
|
|
85
|
+
raise ValueError(
|
|
86
|
+
"Input must be a DataFrame for flows with 'many' cardinality"
|
|
87
|
+
)
|
|
88
|
+
from qtype.interpreter.batch.flow import batch_execute_flow
|
|
89
|
+
|
|
90
|
+
batch_config = batch_config or BatchConfig()
|
|
91
|
+
results, errors = batch_execute_flow(
|
|
92
|
+
target_flow, inputs, batch_config, **kwargs
|
|
93
|
+
) # type: ignore
|
|
94
|
+
return results
|
|
95
|
+
else:
|
|
96
|
+
from qtype.interpreter.flow import execute_flow
|
|
97
|
+
|
|
98
|
+
args = {**kwargs, **inputs}
|
|
99
|
+
return execute_flow(target_flow, **args)
|
|
100
|
+
|
|
101
|
+
def visualize_application(self, path: PathLike) -> str:
|
|
102
|
+
"""Visualize an application as Mermaid diagram."""
|
|
103
|
+
from qtype.semantic.visualize import visualize_application
|
|
104
|
+
|
|
105
|
+
semantic_model, _ = self.load_semantic_model(path)
|
|
106
|
+
return visualize_application(semantic_model)
|
|
107
|
+
|
|
108
|
+
def convert_document(self, document: DocumentType) -> str:
|
|
109
|
+
"""Convert a document to YAML format."""
|
|
110
|
+
# Wrap DSLApplication in Document if needed
|
|
111
|
+
wrapped_document: BaseModel = document
|
|
112
|
+
if isinstance(document, DSLApplication):
|
|
113
|
+
from qtype.dsl.model import Document
|
|
114
|
+
|
|
115
|
+
wrapped_document = Document(root=document)
|
|
116
|
+
|
|
117
|
+
# Try to use pydantic_yaml first
|
|
118
|
+
try:
|
|
119
|
+
from pydantic_yaml import to_yaml_str
|
|
120
|
+
|
|
121
|
+
return to_yaml_str(
|
|
122
|
+
wrapped_document, exclude_unset=True, exclude_none=True
|
|
123
|
+
)
|
|
124
|
+
except ImportError:
|
|
125
|
+
# Fallback to basic YAML if pydantic_yaml is not available
|
|
126
|
+
import yaml
|
|
127
|
+
|
|
128
|
+
document_dict = wrapped_document.model_dump(
|
|
129
|
+
exclude_unset=True, exclude_none=True
|
|
130
|
+
)
|
|
131
|
+
return yaml.dump(document_dict, default_flow_style=False)
|
|
132
|
+
|
|
133
|
+
def generate_aws_bedrock_models(self) -> list[dict[str, Any]]:
|
|
134
|
+
"""
|
|
135
|
+
Generate AWS Bedrock model definitions.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
List of model definitions for AWS Bedrock models.
|
|
139
|
+
|
|
140
|
+
Raises:
|
|
141
|
+
ImportError: If boto3 is not installed.
|
|
142
|
+
Exception: If AWS API call fails.
|
|
143
|
+
"""
|
|
144
|
+
import boto3 # type: ignore[import-untyped]
|
|
145
|
+
|
|
146
|
+
logger.info("Discovering AWS Bedrock models...")
|
|
147
|
+
client = boto3.client("bedrock")
|
|
148
|
+
models = client.list_foundation_models()
|
|
149
|
+
|
|
150
|
+
model_definitions = []
|
|
151
|
+
for model_summary in models.get("modelSummaries", []):
|
|
152
|
+
model_definitions.append(
|
|
153
|
+
{
|
|
154
|
+
"id": model_summary["modelId"],
|
|
155
|
+
"provider": "aws-bedrock",
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
logger.info(f"Discovered {len(model_definitions)} AWS Bedrock models")
|
|
160
|
+
return model_definitions
|
qtype/base/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Base utilities and types for qtype."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .exceptions import QTypeError, ValidationError
|
|
6
|
+
from .logging import get_logger
|
|
7
|
+
from .types import JSONValue
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"QTypeError",
|
|
11
|
+
"ValidationError",
|
|
12
|
+
"get_logger",
|
|
13
|
+
"JSONValue",
|
|
14
|
+
]
|
qtype/base/exceptions.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Base exceptions for qtype."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QTypeError(Exception):
|
|
9
|
+
"""Base exception for all qtype errors."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self, message: str, details: dict[str, Any] | None = None
|
|
13
|
+
) -> None:
|
|
14
|
+
"""Initialize the exception with message and optional details."""
|
|
15
|
+
super().__init__(message)
|
|
16
|
+
self.message = message
|
|
17
|
+
self.details = details or {}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ValidationError(QTypeError):
|
|
21
|
+
"""Exception raised when validation fails."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
message: str,
|
|
26
|
+
errors: list[str] | None = None,
|
|
27
|
+
details: dict[str, Any] | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize validation error with list of error messages."""
|
|
30
|
+
super().__init__(message, details)
|
|
31
|
+
self.errors = errors or []
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LoadError(QTypeError):
|
|
35
|
+
"""Exception raised when loading documents fails."""
|
|
36
|
+
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class SemanticError(QTypeError):
|
|
41
|
+
"""Exception raised when semantic processing fails."""
|
|
42
|
+
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class InterpreterError(QTypeError):
|
|
47
|
+
"""Exception raised when interpretation/execution fails."""
|
|
48
|
+
|
|
49
|
+
pass
|
qtype/base/logging.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Logging utilities for qtype."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_logger(name: str) -> logging.Logger:
|
|
9
|
+
"""Get a logger with the given name and consistent formatting."""
|
|
10
|
+
logger = logging.getLogger(f"qtype.{name}")
|
|
11
|
+
|
|
12
|
+
# Only configure if not already configured
|
|
13
|
+
if not logger.handlers:
|
|
14
|
+
handler = logging.StreamHandler()
|
|
15
|
+
formatter = logging.Formatter(
|
|
16
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
17
|
+
)
|
|
18
|
+
handler.setFormatter(formatter)
|
|
19
|
+
logger.addHandler(handler)
|
|
20
|
+
logger.setLevel(logging.INFO)
|
|
21
|
+
|
|
22
|
+
return logger
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def configure_logging(
|
|
26
|
+
level: str = "INFO", format_string: str | None = None
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Configure root logging for qtype."""
|
|
29
|
+
numeric_level = getattr(logging, level.upper(), logging.INFO)
|
|
30
|
+
|
|
31
|
+
format_str = (
|
|
32
|
+
format_string or "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
logging.basicConfig(
|
|
36
|
+
level=numeric_level,
|
|
37
|
+
format=format_str,
|
|
38
|
+
force=True, # Override any existing configuration
|
|
39
|
+
)
|
qtype/base/types.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Common type definitions for qtype."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pathlib
|
|
6
|
+
from typing import Any, Type, Union
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from qtype.dsl import model as dsl
|
|
11
|
+
|
|
12
|
+
# JSON-serializable value types
|
|
13
|
+
JSONValue = Union[
|
|
14
|
+
str,
|
|
15
|
+
int,
|
|
16
|
+
float,
|
|
17
|
+
bool,
|
|
18
|
+
None,
|
|
19
|
+
dict[str, "JSONValue"],
|
|
20
|
+
list["JSONValue"],
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
# Configuration dictionary type
|
|
24
|
+
ConfigDict = dict[str, Any]
|
|
25
|
+
|
|
26
|
+
# Path-like type (string or Path object)
|
|
27
|
+
PathLike = Union[str, pathlib.Path]
|
|
28
|
+
CustomTypeRegistry = dict[str, Type[BaseModel]]
|
|
29
|
+
DocumentRootType = dsl.Agent | dsl.Application | dsl.Flow | list
|
qtype/commands/convert.py
CHANGED
|
@@ -1,46 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for converting tools and APIs to qtype format.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
1
7
|
import argparse
|
|
2
8
|
import logging
|
|
9
|
+
from pathlib import Path
|
|
3
10
|
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
from qtype.dsl.model import Application
|
|
11
|
+
from qtype.application.facade import QTypeFacade
|
|
7
12
|
|
|
8
13
|
logger = logging.getLogger(__name__)
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
def convert_api(args: argparse.Namespace) -> None:
|
|
17
|
+
"""Convert API specification to qtype format."""
|
|
12
18
|
raise NotImplementedError("API conversion is not implemented yet.")
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
def convert_module(args: argparse.Namespace) -> None:
|
|
16
22
|
"""Convert Python module tools to qtype format."""
|
|
23
|
+
from qtype.application.converters.tools_from_module import (
|
|
24
|
+
tools_from_module,
|
|
25
|
+
)
|
|
26
|
+
from qtype.dsl.model import Application, ToolList
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
tools, types = tools_from_module(args.module_path)
|
|
30
|
+
if not tools:
|
|
31
|
+
raise ValueError(
|
|
32
|
+
f"No tools found in the module: {args.module_path}"
|
|
33
|
+
)
|
|
17
34
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
# Create application document
|
|
36
|
+
if types:
|
|
37
|
+
doc: Application | ToolList = Application(
|
|
38
|
+
id=args.module_path,
|
|
39
|
+
description=f"Tools created from Python module {args.module_path}",
|
|
40
|
+
tools=list(tools),
|
|
41
|
+
types=types,
|
|
42
|
+
)
|
|
43
|
+
else:
|
|
44
|
+
doc = ToolList(
|
|
45
|
+
root=list(tools),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Use facade to convert to YAML format
|
|
49
|
+
facade = QTypeFacade()
|
|
50
|
+
content = facade.convert_document(doc)
|
|
51
|
+
|
|
52
|
+
# Write to file or stdout
|
|
53
|
+
if args.output:
|
|
54
|
+
output_path = Path(args.output)
|
|
55
|
+
output_path.write_text(content, encoding="utf-8")
|
|
56
|
+
logger.info(f"✅ Converted tools saved to {output_path}")
|
|
57
|
+
else:
|
|
58
|
+
print(content)
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f"❌ Conversion failed: {e}")
|
|
62
|
+
raise
|
|
44
63
|
|
|
45
64
|
|
|
46
65
|
def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
@@ -54,36 +73,32 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
54
73
|
dest="convert_command", required=True
|
|
55
74
|
)
|
|
56
75
|
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
# Convert from Python module
|
|
77
|
+
module_parser = convert_subparsers.add_parser(
|
|
78
|
+
"module", help="Convert a Python module to qtype tools format."
|
|
59
79
|
)
|
|
60
|
-
|
|
61
|
-
"module_path",
|
|
62
|
-
type=str,
|
|
63
|
-
help="Path to the Python module to convert.",
|
|
80
|
+
module_parser.add_argument(
|
|
81
|
+
"module_path", type=str, help="Path to the Python module to convert."
|
|
64
82
|
)
|
|
65
|
-
|
|
83
|
+
module_parser.add_argument(
|
|
66
84
|
"-o",
|
|
67
85
|
"--output",
|
|
68
86
|
type=str,
|
|
69
|
-
|
|
70
|
-
help="Where to save the converted YAML file. If not specified, it is just printed to stdout.",
|
|
87
|
+
help="Output file path. If not specified, prints to stdout.",
|
|
71
88
|
)
|
|
72
|
-
|
|
89
|
+
module_parser.set_defaults(func=convert_module)
|
|
73
90
|
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
# Convert from API specification
|
|
92
|
+
api_parser = convert_subparsers.add_parser(
|
|
93
|
+
"api", help="Convert an API specification to qtype format."
|
|
76
94
|
)
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
type=str,
|
|
80
|
-
help="URL of the OpenAPI specification.",
|
|
95
|
+
api_parser.add_argument(
|
|
96
|
+
"api_spec", type=str, help="Path to the API specification file."
|
|
81
97
|
)
|
|
82
|
-
|
|
98
|
+
api_parser.add_argument(
|
|
83
99
|
"-o",
|
|
84
100
|
"--output",
|
|
85
101
|
type=str,
|
|
86
|
-
|
|
87
|
-
help="Where to save the converted YAML file. If not specified, it is just printed to stdout.",
|
|
102
|
+
help="Output file path. If not specified, prints to stdout.",
|
|
88
103
|
)
|
|
89
|
-
|
|
104
|
+
api_parser.set_defaults(func=convert_api)
|
qtype/commands/generate.py
CHANGED
|
@@ -10,13 +10,68 @@ logger = logging.getLogger(__name__)
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def run_dump_commons_library(args: argparse.Namespace) -> None:
|
|
13
|
-
|
|
13
|
+
"""Generate commons library tools and AWS Bedrock models."""
|
|
14
|
+
import logging
|
|
15
|
+
from pathlib import Path
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
from qtype.application.facade import QTypeFacade
|
|
18
|
+
from qtype.dsl.model import Model, ModelList
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
facade = QTypeFacade()
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
# Generate common tools using convert module functionality
|
|
25
|
+
logger.info("Generating common tools...")
|
|
26
|
+
|
|
27
|
+
# Create a mock args object for convert_module
|
|
28
|
+
import argparse
|
|
29
|
+
|
|
30
|
+
from qtype.commands.convert import convert_module
|
|
31
|
+
|
|
32
|
+
convert_args = argparse.Namespace(
|
|
33
|
+
module_path="qtype.application.commons.tools",
|
|
34
|
+
output=f"{args.prefix}/tools.qtype.yaml",
|
|
35
|
+
)
|
|
36
|
+
convert_module(convert_args)
|
|
37
|
+
|
|
38
|
+
# Generate AWS Bedrock models
|
|
39
|
+
logger.info("Generating AWS Bedrock models...")
|
|
40
|
+
try:
|
|
41
|
+
model_definitions = facade.generate_aws_bedrock_models()
|
|
42
|
+
|
|
43
|
+
model_list = ModelList(
|
|
44
|
+
root=[
|
|
45
|
+
Model(
|
|
46
|
+
id=model_def["id"],
|
|
47
|
+
provider=model_def["provider"],
|
|
48
|
+
)
|
|
49
|
+
for model_def in model_definitions
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Convert to YAML and save
|
|
54
|
+
content = facade.convert_document(model_list)
|
|
55
|
+
output_path = Path(f"{args.prefix}/aws.bedrock.models.qtype.yaml")
|
|
56
|
+
output_path.write_text(content, encoding="utf-8")
|
|
57
|
+
logger.info(f"AWS Bedrock models exported to {output_path}")
|
|
58
|
+
|
|
59
|
+
except ImportError:
|
|
60
|
+
logger.warning(
|
|
61
|
+
"boto3 not available. Skipping AWS Bedrock model generation."
|
|
62
|
+
)
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"Failed to generate AWS Bedrock models: {e}")
|
|
65
|
+
|
|
66
|
+
logger.info("Commons library generation complete.")
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Failed to generate commons library: {e}")
|
|
70
|
+
raise
|
|
16
71
|
|
|
17
72
|
|
|
18
73
|
def run_generate_documentation(args: argparse.Namespace) -> None:
|
|
19
|
-
from qtype.
|
|
74
|
+
from qtype.application.documentation import generate_documentation
|
|
20
75
|
|
|
21
76
|
generate_documentation(Path(args.output))
|
|
22
77
|
|
|
@@ -93,7 +148,7 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
93
148
|
# only add this if networkx and ruff are installed
|
|
94
149
|
try:
|
|
95
150
|
import networkx # noqa: F401
|
|
96
|
-
import ruff # noqa: F401
|
|
151
|
+
import ruff # type: ignore[import-untyped] # noqa: F401
|
|
97
152
|
|
|
98
153
|
from qtype.semantic.generate import generate_semantic_model
|
|
99
154
|
|