polyapi-python 0.3.19.dev4__py3-none-any.whl → 0.3.20.dev1__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.
- polyapi/ai_function.py +96 -0
- polyapi/generate.py +12 -1
- polyapi/typedefs.py +1 -1
- polyapi/utils.py +22 -4
- {polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/METADATA +1 -1
- {polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/RECORD +9 -8
- {polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/WHEEL +1 -1
- {polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/licenses/LICENSE +0 -0
- {polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/top_level.txt +0 -0
polyapi/ai_function.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Tuple, cast
|
|
2
|
+
|
|
3
|
+
from polyapi.typedefs import PropertySpecification, PropertyType
|
|
4
|
+
from polyapi.utils import add_type_import_path, parse_arguments, get_type_and_def, return_type_already_defined_in_args, rewrite_arg_name
|
|
5
|
+
|
|
6
|
+
AI_DEFS_TEMPLATE = """
|
|
7
|
+
from typing import List, Dict, Any, TypedDict, Callable
|
|
8
|
+
{args_def}
|
|
9
|
+
{return_type_def}
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
AI_FUNCTION_TEMPLATE = """
|
|
13
|
+
def {function_name}(
|
|
14
|
+
{args}
|
|
15
|
+
) -> {return_type_name}:
|
|
16
|
+
\"""{function_description}
|
|
17
|
+
|
|
18
|
+
Function ID: {function_id}
|
|
19
|
+
\"""
|
|
20
|
+
resp = execute("{function_type}", "{function_id}", {data})
|
|
21
|
+
try:
|
|
22
|
+
return {return_action}
|
|
23
|
+
except:
|
|
24
|
+
return resp.text # type: ignore # fallback for debugging
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def {function_name}_async(
|
|
28
|
+
{args}
|
|
29
|
+
) -> {return_type_name}:
|
|
30
|
+
\"""{function_description}
|
|
31
|
+
|
|
32
|
+
Function ID: {function_id}
|
|
33
|
+
\"""
|
|
34
|
+
resp = await execute_async("{function_type}", "{function_id}", {data})
|
|
35
|
+
try:
|
|
36
|
+
return {return_action}
|
|
37
|
+
except:
|
|
38
|
+
return resp.text # type: ignore # fallback for debugging
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def render_ai_function(
|
|
45
|
+
function_type: str,
|
|
46
|
+
function_name: str,
|
|
47
|
+
function_id: str,
|
|
48
|
+
function_description: str,
|
|
49
|
+
arguments: List[PropertySpecification],
|
|
50
|
+
return_type: Dict[str, Any],
|
|
51
|
+
) -> Tuple[str, str]:
|
|
52
|
+
arg_names = [a["name"] for a in arguments]
|
|
53
|
+
args, args_def = parse_arguments(function_name, arguments)
|
|
54
|
+
return_type_name, return_type_def = get_type_and_def(cast(PropertyType, return_type), "ReturnType")
|
|
55
|
+
|
|
56
|
+
if return_type_def and return_type_already_defined_in_args(return_type_name, args_def):
|
|
57
|
+
return_type_def = ""
|
|
58
|
+
|
|
59
|
+
data = "{" + ", ".join([f"'{arg}': {rewrite_arg_name(arg)}" for arg in arg_names]) + "}"
|
|
60
|
+
func_type_defs = AI_DEFS_TEMPLATE.format(
|
|
61
|
+
args_def=args_def,
|
|
62
|
+
return_type_def=return_type_def,
|
|
63
|
+
)
|
|
64
|
+
func_str = AI_FUNCTION_TEMPLATE.format(
|
|
65
|
+
return_type_name=_normalize_return_type_for_annotation(function_name, return_type_name),
|
|
66
|
+
function_type="ai",
|
|
67
|
+
function_name=function_name,
|
|
68
|
+
function_id=function_id,
|
|
69
|
+
function_description=function_description.replace('"', "'"),
|
|
70
|
+
args=args,
|
|
71
|
+
return_action=_get_ai_return_action(return_type_name),
|
|
72
|
+
data=data,
|
|
73
|
+
)
|
|
74
|
+
return func_str, func_type_defs
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _normalize_return_type_for_annotation(function_name: str, return_type_name: str) -> str:
|
|
78
|
+
if return_type_name == "ReturnType":
|
|
79
|
+
return "ReturnType"
|
|
80
|
+
return add_type_import_path(function_name, return_type_name)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _get_ai_return_action(return_type_name: str) -> str:
|
|
84
|
+
normalized_type = return_type_name.replace(" ", "")
|
|
85
|
+
|
|
86
|
+
if normalized_type in {"str", "Optional[str]"}:
|
|
87
|
+
return_action = "resp.text"
|
|
88
|
+
elif "|" in normalized_type:
|
|
89
|
+
union_parts = {part for part in normalized_type.split("|") if part}
|
|
90
|
+
if union_parts == {"str", "None"}:
|
|
91
|
+
return_action = "resp.text"
|
|
92
|
+
else:
|
|
93
|
+
return_action = "resp.json()"
|
|
94
|
+
else:
|
|
95
|
+
return_action = "resp.json()"
|
|
96
|
+
return return_action
|
polyapi/generate.py
CHANGED
|
@@ -17,6 +17,7 @@ from .webhook import render_webhook_handle
|
|
|
17
17
|
from .typedefs import PropertySpecification, SchemaSpecDto, SpecificationDto, VariableSpecDto, TableSpecDto
|
|
18
18
|
from .api import render_api_function
|
|
19
19
|
from .server import render_server_function
|
|
20
|
+
from .ai_function import render_ai_function
|
|
20
21
|
from .utils import add_import_to_init, get_auth_headers, init_the_init, print_green, to_func_namespace, to_type_module_alias
|
|
21
22
|
from .variables import generate_variables
|
|
22
23
|
from .poly_tables import generate_tables
|
|
@@ -29,6 +30,7 @@ SUPPORTED_FUNCTION_TYPES = {
|
|
|
29
30
|
"customFunction", # client function - this is badly named in /specs atm
|
|
30
31
|
"serverFunction",
|
|
31
32
|
"webhookHandle",
|
|
33
|
+
"aiFunction",
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
SUPPORTED_TYPES = SUPPORTED_FUNCTION_TYPES | {"serverVariable", "schema", "snippet", "table"}
|
|
@@ -98,7 +100,7 @@ def resolve_poly_refs(obj, schema_index):
|
|
|
98
100
|
def replace_poly_refs_in_functions(specs: List[SpecificationDto], schema_index):
|
|
99
101
|
spec_idxs_to_remove = []
|
|
100
102
|
for idx, spec in enumerate(specs):
|
|
101
|
-
if spec.get("type") in ("apiFunction", "customFunction", "serverFunction"):
|
|
103
|
+
if spec.get("type") in ("apiFunction", "customFunction", "serverFunction", "aiFunction"):
|
|
102
104
|
func = spec.get("function")
|
|
103
105
|
if func:
|
|
104
106
|
try:
|
|
@@ -501,6 +503,15 @@ def render_spec(spec: SpecificationDto) -> Tuple[str, str]:
|
|
|
501
503
|
arguments,
|
|
502
504
|
return_type,
|
|
503
505
|
)
|
|
506
|
+
elif function_type == "aiFunction":
|
|
507
|
+
func_str, func_type_defs = render_ai_function(
|
|
508
|
+
function_type,
|
|
509
|
+
function_name,
|
|
510
|
+
function_id,
|
|
511
|
+
function_description,
|
|
512
|
+
arguments,
|
|
513
|
+
return_type,
|
|
514
|
+
)
|
|
504
515
|
|
|
505
516
|
if X_POLY_REF_WARNING in func_type_defs:
|
|
506
517
|
# this indicates that jsonschema_gentypes has detected an x-poly-ref
|
polyapi/typedefs.py
CHANGED
|
@@ -35,7 +35,7 @@ class SpecificationDto(TypedDict):
|
|
|
35
35
|
description: str
|
|
36
36
|
# function is none (or function key not present) if this is actually VariableSpecDto
|
|
37
37
|
function: NotRequired[FunctionSpecification | None]
|
|
38
|
-
type: Literal['apiFunction', 'customFunction', 'serverFunction', 'authFunction', 'webhookHandle', 'serverVariable', 'table']
|
|
38
|
+
type: Literal['apiFunction', 'customFunction', 'serverFunction', 'authFunction', 'webhookHandle', 'serverVariable', 'table', 'aiFunction']
|
|
39
39
|
code: NotRequired[str]
|
|
40
40
|
language: str
|
|
41
41
|
|
polyapi/utils.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import keyword
|
|
2
2
|
import re
|
|
3
3
|
import os
|
|
4
|
-
from urllib.parse import urlparse
|
|
4
|
+
from urllib.parse import unquote, urlparse
|
|
5
5
|
from typing import Tuple, List, Optional, cast
|
|
6
6
|
from colorama import Fore, Style
|
|
7
7
|
from polyapi.constants import BASIC_PYTHON_TYPES
|
|
@@ -299,11 +299,29 @@ def _maybe_add_fallback_schema_name(a: PropertySpecification):
|
|
|
299
299
|
# Handle cases where type might be missing
|
|
300
300
|
if not a.get("type"):
|
|
301
301
|
return
|
|
302
|
-
|
|
302
|
+
|
|
303
303
|
if a["type"].get("kind") == "object" and a["type"].get("schema"):
|
|
304
304
|
schema = a["type"].get("schema", {})
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
title = schema.get("title") or schema.get("name")
|
|
306
|
+
if not title and a.get("name"):
|
|
307
|
+
title = a["name"].title()
|
|
308
|
+
schema["title"] = title
|
|
309
|
+
|
|
310
|
+
reference = schema.get("$ref")
|
|
311
|
+
definitions = schema.get("definitions")
|
|
312
|
+
reference_prefix = "#/definitions/"
|
|
313
|
+
if not isinstance(title, str):
|
|
314
|
+
return
|
|
315
|
+
if not isinstance(reference, str) or not reference.startswith(reference_prefix):
|
|
316
|
+
return
|
|
317
|
+
if not isinstance(definitions, dict):
|
|
318
|
+
return
|
|
319
|
+
|
|
320
|
+
definition_name = unquote(reference[len(reference_prefix):])
|
|
321
|
+
definition_name = definition_name.replace("~1", "/").replace("~0", "~")
|
|
322
|
+
definition = definitions.get(definition_name)
|
|
323
|
+
if isinstance(definition, dict):
|
|
324
|
+
definition.setdefault("title", title)
|
|
307
325
|
|
|
308
326
|
|
|
309
327
|
def _clean_description(text: str) -> str:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
polyapi/__init__.py,sha256=vV1N9xtIMtpi4o-2jAI3775LkzRbC9JUo87MAnW9zgo,5201
|
|
2
2
|
polyapi/__main__.py,sha256=V4zhAh_YGxno5f_KSrlkELxcuDh9bR3WSd0n-2r-qQQ,93
|
|
3
|
+
polyapi/ai_function.py,sha256=GvJKpBZFbI11y9JAKTHXMkztbMHZxNTfL37LLbGKmwI,3017
|
|
3
4
|
polyapi/api.py,sha256=CzqX99GekhQJVqAAWlL03hUenIi_5iTln9cWgQzz6Ko,2784
|
|
4
5
|
polyapi/auth.py,sha256=l0pGAoYvEWqa2TMsrM9GS8imXu3GsWvpn4eFPy1vksI,6195
|
|
5
6
|
polyapi/cli.py,sha256=V3586ElV1927u2AhQZAo_4UYKoJPqE8lz6b3_gJfMj0,11918
|
|
@@ -12,7 +13,7 @@ polyapi/error_handler.py,sha256=I_e0iz6VM23FLVQWJljxs2NGcl_OODbi43OcbnqBlp8,2398
|
|
|
12
13
|
polyapi/exceptions.py,sha256=Zh7i7eCUhDuXEdUYjatkLFTeZkrx1BJ1P5ePgbJ9eIY,89
|
|
13
14
|
polyapi/execute.py,sha256=4jLkQely6cM7pNN9pYpGZTbEis-DfwENi5Fl07xSiig,8966
|
|
14
15
|
polyapi/function_cli.py,sha256=gJE72lRvuWnGl6CG9GpqL78TOnUzxVe4kJMvg0PQixw,4493
|
|
15
|
-
polyapi/generate.py,sha256=
|
|
16
|
+
polyapi/generate.py,sha256=QLljL5dT7kyPrIPuOxEhqSE2ASm1XzLV7tAGrQOF8eI,22393
|
|
16
17
|
polyapi/http_client.py,sha256=TcoFsIvRcNB9wWJT4YePPWFFY6lX90cdqi7C4jKbqqk,2259
|
|
17
18
|
polyapi/parser.py,sha256=t3jJI6g5F7Qg_tirPOzSkQ02VLkSVhnqs9YGapyHx2k,21901
|
|
18
19
|
polyapi/poly_schemas.py,sha256=JGMQbELPFw4V_0nA0o71WJKFTdxjCGoKqJvIid_Y-a4,10759
|
|
@@ -23,12 +24,12 @@ polyapi/rendered_spec.py,sha256=J2Num7MXnW_mKAe2MSVIL1coWopNYZ-6nNNwQRfseV0,2262
|
|
|
23
24
|
polyapi/schema.py,sha256=SPO5GDvIE1BjRfJR89vJMEGCXERfEbhNXQm2A05UAOc,6959
|
|
24
25
|
polyapi/server.py,sha256=_14lP4_BmRYMBXwaqXVWmiSTHH3h7ecCHxSalM9UiSc,3049
|
|
25
26
|
polyapi/sync.py,sha256=t0Khh8B5GylxB7KWRP_xvkrvkuyVarSLCOvtmaz7lcc,6766
|
|
26
|
-
polyapi/typedefs.py,sha256=
|
|
27
|
-
polyapi/utils.py,sha256=
|
|
27
|
+
polyapi/typedefs.py,sha256=UeAdyYrgqxrvBRkjisK_xgzQmuTePPvOM74HKf1y0II,5656
|
|
28
|
+
polyapi/utils.py,sha256=LUqTkbb0b7y3gjsOU-WO1LVYaTMyExTGpYjKY8wVKg8,16300
|
|
28
29
|
polyapi/variables.py,sha256=hfSDPGQK6YphNCa9MqE0W88WIFfqCQWgpBDWkExMq-A,7582
|
|
29
30
|
polyapi/webhook.py,sha256=0ceLwHNjNd2Yx_8MX5jOIxiQ5Lwhy2pe81ProAuKon0,5108
|
|
30
|
-
polyapi_python-0.3.
|
|
31
|
-
polyapi_python-0.3.
|
|
32
|
-
polyapi_python-0.3.
|
|
33
|
-
polyapi_python-0.3.
|
|
34
|
-
polyapi_python-0.3.
|
|
31
|
+
polyapi_python-0.3.20.dev1.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
|
|
32
|
+
polyapi_python-0.3.20.dev1.dist-info/METADATA,sha256=uQkx5Ut9vT6cP2Gt3rsw3yB1uSWGB9_Q85rel0BlzFg,5898
|
|
33
|
+
polyapi_python-0.3.20.dev1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
34
|
+
polyapi_python-0.3.20.dev1.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
|
|
35
|
+
polyapi_python-0.3.20.dev1.dist-info/RECORD,,
|
{polyapi_python-0.3.19.dev4.dist-info → polyapi_python-0.3.20.dev1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|