prompty 0.1.39__py3-none-any.whl → 0.1.44__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- prompty/__init__.py +35 -31
- prompty/azure/__init__.py +2 -2
- prompty/azure/executor.py +23 -19
- prompty/azure/processor.py +18 -7
- prompty/azure_beta/__init__.py +2 -2
- prompty/azure_beta/executor.py +26 -17
- prompty/cli.py +47 -13
- prompty/core.py +45 -40
- prompty/invoker.py +51 -37
- prompty/openai/__init__.py +4 -4
- prompty/openai/executor.py +9 -5
- prompty/openai/processor.py +9 -6
- prompty/parsers.py +21 -17
- prompty/renderers.py +18 -7
- prompty/serverless/__init__.py +2 -2
- prompty/serverless/executor.py +32 -16
- prompty/serverless/processor.py +11 -7
- prompty/tracer.py +41 -32
- prompty/utils.py +20 -15
- {prompty-0.1.39.dist-info → prompty-0.1.44.dist-info}/METADATA +1 -1
- prompty-0.1.44.dist-info/RECORD +24 -0
- prompty-0.1.39.dist-info/RECORD +0 -24
- {prompty-0.1.39.dist-info → prompty-0.1.44.dist-info}/WHEEL +0 -0
- {prompty-0.1.39.dist-info → prompty-0.1.44.dist-info}/entry_points.txt +0 -0
- {prompty-0.1.39.dist-info → prompty-0.1.44.dist-info}/licenses/LICENSE +0 -0
prompty/core.py
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
1
|
import os
|
2
|
+
import typing
|
3
|
+
from collections.abc import AsyncIterator, Iterator
|
4
4
|
from pathlib import Path
|
5
|
+
from typing import Literal, Union
|
5
6
|
|
6
|
-
from .tracer import Tracer, to_dict, sanitize
|
7
7
|
from pydantic import BaseModel, Field, FilePath
|
8
|
-
from
|
8
|
+
from pydantic.main import IncEx
|
9
9
|
|
10
|
+
from .tracer import Tracer, sanitize, to_dict
|
10
11
|
from .utils import load_json, load_json_async
|
11
12
|
|
12
13
|
|
@@ -30,7 +31,7 @@ class PropertySettings(BaseModel):
|
|
30
31
|
"""
|
31
32
|
|
32
33
|
type: Literal["string", "number", "array", "object", "boolean"]
|
33
|
-
default: str
|
34
|
+
default: Union[str, int, float, list, dict, bool, None] = Field(default=None)
|
34
35
|
description: str = Field(default="")
|
35
36
|
|
36
37
|
|
@@ -58,21 +59,19 @@ class ModelSettings(BaseModel):
|
|
58
59
|
self,
|
59
60
|
*,
|
60
61
|
mode: str = "python",
|
61
|
-
include:
|
62
|
-
|
63
|
-
|
64
|
-
exclude: (
|
65
|
-
Set[int] | Set[str] | Dict[int, os.Any] | Dict[str, os.Any] | None
|
66
|
-
) = None,
|
67
|
-
context: os.Any | None = None,
|
62
|
+
include: Union[IncEx, None] = None,
|
63
|
+
exclude: Union[IncEx, None] = None,
|
64
|
+
context: Union[typing.Any, None] = None,
|
68
65
|
by_alias: bool = False,
|
69
66
|
exclude_unset: bool = False,
|
70
67
|
exclude_defaults: bool = False,
|
71
68
|
exclude_none: bool = False,
|
72
69
|
round_trip: bool = False,
|
73
|
-
warnings:
|
70
|
+
warnings: Union[
|
71
|
+
bool, Literal["none"], Literal["warn"], Literal["error"]
|
72
|
+
] = True,
|
74
73
|
serialize_as_any: bool = False,
|
75
|
-
) ->
|
74
|
+
) -> dict[str, typing.Any]:
|
76
75
|
"""Method to dump the model in a safe way"""
|
77
76
|
d = super().model_dump(
|
78
77
|
mode=mode,
|
@@ -145,11 +144,11 @@ class Prompty(BaseModel):
|
|
145
144
|
# metadata
|
146
145
|
name: str = Field(default="")
|
147
146
|
description: str = Field(default="")
|
148
|
-
authors:
|
149
|
-
tags:
|
147
|
+
authors: list[str] = Field(default=[])
|
148
|
+
tags: list[str] = Field(default=[])
|
150
149
|
version: str = Field(default="")
|
151
150
|
base: str = Field(default="")
|
152
|
-
basePrompty: Prompty
|
151
|
+
basePrompty: Union["Prompty", None] = Field(default=None)
|
153
152
|
# model
|
154
153
|
model: ModelSettings = Field(default_factory=ModelSettings)
|
155
154
|
|
@@ -157,19 +156,19 @@ class Prompty(BaseModel):
|
|
157
156
|
sample: dict = Field(default={})
|
158
157
|
|
159
158
|
# input / output
|
160
|
-
inputs:
|
161
|
-
outputs:
|
159
|
+
inputs: dict[str, PropertySettings] = Field(default={})
|
160
|
+
outputs: dict[str, PropertySettings] = Field(default={})
|
162
161
|
|
163
162
|
# template
|
164
163
|
template: TemplateSettings
|
165
164
|
|
166
|
-
file: FilePath = Field(default="")
|
167
|
-
content: str
|
165
|
+
file: Union[str, FilePath] = Field(default="")
|
166
|
+
content: Union[str, list[str], dict] = Field(default="")
|
168
167
|
|
169
|
-
def to_safe_dict(self) ->
|
168
|
+
def to_safe_dict(self) -> dict[str, typing.Any]:
|
170
169
|
d = {}
|
171
170
|
for k, v in self:
|
172
|
-
if v != "" and v != {} and v != [] and v
|
171
|
+
if v != "" and v != {} and v != [] and v is not None:
|
173
172
|
if k == "model":
|
174
173
|
d[k] = v.model_dump()
|
175
174
|
elif k == "template":
|
@@ -191,7 +190,7 @@ class Prompty(BaseModel):
|
|
191
190
|
return d
|
192
191
|
|
193
192
|
@staticmethod
|
194
|
-
def hoist_base_prompty(top: Prompty, base: Prompty) -> Prompty:
|
193
|
+
def hoist_base_prompty(top: "Prompty", base: "Prompty") -> "Prompty":
|
195
194
|
top.name = base.name if top.name == "" else top.name
|
196
195
|
top.description = base.description if top.description == "" else top.description
|
197
196
|
top.authors = list(set(base.authors + top.authors))
|
@@ -214,10 +213,10 @@ class Prompty(BaseModel):
|
|
214
213
|
return top
|
215
214
|
|
216
215
|
@staticmethod
|
217
|
-
def _process_file(file: str, parent: Path) ->
|
218
|
-
|
219
|
-
if
|
220
|
-
items = load_json(
|
216
|
+
def _process_file(file: str, parent: Path) -> typing.Any:
|
217
|
+
f = Path(parent / Path(file)).resolve().absolute()
|
218
|
+
if f.exists():
|
219
|
+
items = load_json(f)
|
221
220
|
if isinstance(items, list):
|
222
221
|
return [Prompty.normalize(value, parent) for value in items]
|
223
222
|
elif isinstance(items, dict):
|
@@ -231,10 +230,10 @@ class Prompty(BaseModel):
|
|
231
230
|
raise FileNotFoundError(f"File {file} not found")
|
232
231
|
|
233
232
|
@staticmethod
|
234
|
-
async def _process_file_async(file: str, parent: Path) ->
|
235
|
-
|
236
|
-
if
|
237
|
-
items = await load_json_async(
|
233
|
+
async def _process_file_async(file: str, parent: Path) -> typing.Any:
|
234
|
+
f = Path(parent / Path(file)).resolve().absolute()
|
235
|
+
if f.exists():
|
236
|
+
items = await load_json_async(f)
|
238
237
|
if isinstance(items, list):
|
239
238
|
return [Prompty.normalize(value, parent) for value in items]
|
240
239
|
elif isinstance(items, dict):
|
@@ -248,7 +247,9 @@ class Prompty(BaseModel):
|
|
248
247
|
raise FileNotFoundError(f"File {file} not found")
|
249
248
|
|
250
249
|
@staticmethod
|
251
|
-
def _process_env(
|
250
|
+
def _process_env(
|
251
|
+
variable: str, env_error=True, default: Union[str, None] = None
|
252
|
+
) -> typing.Any:
|
252
253
|
if variable in os.environ.keys():
|
253
254
|
return os.environ[variable]
|
254
255
|
else:
|
@@ -260,7 +261,7 @@ class Prompty(BaseModel):
|
|
260
261
|
return ""
|
261
262
|
|
262
263
|
@staticmethod
|
263
|
-
def normalize(attribute:
|
264
|
+
def normalize(attribute: typing.Any, parent: Path, env_error=True) -> typing.Any:
|
264
265
|
if isinstance(attribute, str):
|
265
266
|
attribute = attribute.strip()
|
266
267
|
if attribute.startswith("${") and attribute.endswith("}"):
|
@@ -289,7 +290,9 @@ class Prompty(BaseModel):
|
|
289
290
|
return attribute
|
290
291
|
|
291
292
|
@staticmethod
|
292
|
-
async def normalize_async(
|
293
|
+
async def normalize_async(
|
294
|
+
attribute: typing.Any, parent: Path, env_error=True
|
295
|
+
) -> typing.Any:
|
293
296
|
if isinstance(attribute, str):
|
294
297
|
attribute = attribute.strip()
|
295
298
|
if attribute.startswith("${") and attribute.endswith("}"):
|
@@ -319,14 +322,16 @@ class Prompty(BaseModel):
|
|
319
322
|
|
320
323
|
|
321
324
|
def param_hoisting(
|
322
|
-
top:
|
323
|
-
|
325
|
+
top: dict[str, typing.Any],
|
326
|
+
bottom: dict[str, typing.Any],
|
327
|
+
top_key: Union[str, None] = None,
|
328
|
+
) -> dict[str, typing.Any]:
|
324
329
|
if top_key:
|
325
330
|
new_dict = {**top[top_key]} if top_key in top else {}
|
326
331
|
else:
|
327
332
|
new_dict = {**top}
|
328
333
|
for key, value in bottom.items():
|
329
|
-
if not
|
334
|
+
if key not in new_dict:
|
330
335
|
new_dict[key] = value
|
331
336
|
return new_dict
|
332
337
|
|
@@ -338,7 +343,7 @@ class PromptyStream(Iterator):
|
|
338
343
|
def __init__(self, name: str, iterator: Iterator):
|
339
344
|
self.name = name
|
340
345
|
self.iterator = iterator
|
341
|
-
self.items:
|
346
|
+
self.items: list[typing.Any] = []
|
342
347
|
self.__name__ = "PromptyStream"
|
343
348
|
|
344
349
|
def __iter__(self):
|
@@ -370,7 +375,7 @@ class AsyncPromptyStream(AsyncIterator):
|
|
370
375
|
def __init__(self, name: str, iterator: AsyncIterator):
|
371
376
|
self.name = name
|
372
377
|
self.iterator = iterator
|
373
|
-
self.items:
|
378
|
+
self.items: list[typing.Any] = []
|
374
379
|
self.__name__ = "AsyncPromptyStream"
|
375
380
|
|
376
381
|
def __aiter__(self):
|
prompty/invoker.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
import abc
|
2
|
-
|
2
|
+
import typing
|
3
|
+
from typing import Callable, Literal
|
4
|
+
|
3
5
|
from .core import Prompty
|
4
|
-
from
|
6
|
+
from .tracer import trace
|
5
7
|
|
6
8
|
|
7
9
|
class Invoker(abc.ABC):
|
@@ -21,7 +23,7 @@ class Invoker(abc.ABC):
|
|
21
23
|
self.name = self.__class__.__name__
|
22
24
|
|
23
25
|
@abc.abstractmethod
|
24
|
-
def invoke(self, data:
|
26
|
+
def invoke(self, data: typing.Any) -> typing.Any:
|
25
27
|
"""Abstract method to invoke the invoker
|
26
28
|
|
27
29
|
Parameters
|
@@ -37,7 +39,7 @@ class Invoker(abc.ABC):
|
|
37
39
|
pass
|
38
40
|
|
39
41
|
@abc.abstractmethod
|
40
|
-
async def invoke_async(self, data:
|
42
|
+
async def invoke_async(self, data: typing.Any) -> typing.Any:
|
41
43
|
"""Abstract method to invoke the invoker asynchronously
|
42
44
|
|
43
45
|
Parameters
|
@@ -53,7 +55,7 @@ class Invoker(abc.ABC):
|
|
53
55
|
pass
|
54
56
|
|
55
57
|
@trace
|
56
|
-
def run(self, data:
|
58
|
+
def run(self, data: typing.Any) -> typing.Any:
|
57
59
|
"""Method to run the invoker
|
58
60
|
|
59
61
|
Parameters
|
@@ -69,7 +71,7 @@ class Invoker(abc.ABC):
|
|
69
71
|
return self.invoke(data)
|
70
72
|
|
71
73
|
@trace
|
72
|
-
async def run_async(self, data:
|
74
|
+
async def run_async(self, data: typing.Any) -> typing.Any:
|
73
75
|
"""Method to run the invoker asynchronously
|
74
76
|
|
75
77
|
Parameters
|
@@ -88,30 +90,31 @@ class Invoker(abc.ABC):
|
|
88
90
|
class InvokerFactory:
|
89
91
|
"""Factory class for Invoker"""
|
90
92
|
|
91
|
-
_renderers:
|
92
|
-
_parsers:
|
93
|
-
_executors:
|
94
|
-
_processors:
|
93
|
+
_renderers: dict[str, type[Invoker]] = {}
|
94
|
+
_parsers: dict[str, type[Invoker]] = {}
|
95
|
+
_executors: dict[str, type[Invoker]] = {}
|
96
|
+
_processors: dict[str, type[Invoker]] = {}
|
95
97
|
|
96
98
|
@classmethod
|
97
|
-
def add_renderer(cls, name: str, invoker: Invoker) -> None:
|
99
|
+
def add_renderer(cls, name: str, invoker: type[Invoker]) -> None:
|
98
100
|
cls._renderers[name] = invoker
|
99
101
|
|
100
102
|
@classmethod
|
101
|
-
def add_parser(cls, name: str, invoker: Invoker) -> None:
|
103
|
+
def add_parser(cls, name: str, invoker: type[Invoker]) -> None:
|
102
104
|
cls._parsers[name] = invoker
|
103
105
|
|
104
106
|
@classmethod
|
105
|
-
def add_executor(cls, name: str, invoker: Invoker) -> None:
|
107
|
+
def add_executor(cls, name: str, invoker: type[Invoker]) -> None:
|
106
108
|
cls._executors[name] = invoker
|
107
109
|
|
108
110
|
@classmethod
|
109
|
-
def add_processor(cls, name: str, invoker: Invoker) -> None:
|
111
|
+
def add_processor(cls, name: str, invoker: type[Invoker]) -> None:
|
110
112
|
cls._processors[name] = invoker
|
111
113
|
|
112
114
|
@classmethod
|
113
115
|
def register_renderer(cls, name: str) -> Callable:
|
114
|
-
|
116
|
+
|
117
|
+
def inner_wrapper(wrapped_class: type[Invoker]) -> type[Invoker]:
|
115
118
|
cls._renderers[name] = wrapped_class
|
116
119
|
return wrapped_class
|
117
120
|
|
@@ -119,7 +122,8 @@ class InvokerFactory:
|
|
119
122
|
|
120
123
|
@classmethod
|
121
124
|
def register_parser(cls, name: str) -> Callable:
|
122
|
-
|
125
|
+
|
126
|
+
def inner_wrapper(wrapped_class: type[Invoker]) -> type[Invoker]:
|
123
127
|
cls._parsers[name] = wrapped_class
|
124
128
|
return wrapped_class
|
125
129
|
|
@@ -127,7 +131,8 @@ class InvokerFactory:
|
|
127
131
|
|
128
132
|
@classmethod
|
129
133
|
def register_executor(cls, name: str) -> Callable:
|
130
|
-
|
134
|
+
|
135
|
+
def inner_wrapper(wrapped_class: type[Invoker]) -> type[Invoker]:
|
131
136
|
cls._executors[name] = wrapped_class
|
132
137
|
return wrapped_class
|
133
138
|
|
@@ -135,7 +140,8 @@ class InvokerFactory:
|
|
135
140
|
|
136
141
|
@classmethod
|
137
142
|
def register_processor(cls, name: str) -> Callable:
|
138
|
-
|
143
|
+
|
144
|
+
def inner_wrapper(wrapped_class: type[Invoker]) -> type[Invoker]:
|
139
145
|
cls._processors[name] = wrapped_class
|
140
146
|
return wrapped_class
|
141
147
|
|
@@ -200,11 +206,11 @@ class InvokerFactory:
|
|
200
206
|
cls,
|
201
207
|
type: Literal["renderer", "parser", "executor", "processor"],
|
202
208
|
prompty: Prompty,
|
203
|
-
data:
|
204
|
-
default:
|
209
|
+
data: typing.Any,
|
210
|
+
default: typing.Any = None,
|
205
211
|
):
|
206
212
|
name = cls._get_name(type, prompty)
|
207
|
-
if name.startswith("NOOP") and default
|
213
|
+
if name.startswith("NOOP") and default is not None:
|
208
214
|
return default
|
209
215
|
elif name.startswith("NOOP"):
|
210
216
|
return data
|
@@ -218,11 +224,11 @@ class InvokerFactory:
|
|
218
224
|
cls,
|
219
225
|
type: Literal["renderer", "parser", "executor", "processor"],
|
220
226
|
prompty: Prompty,
|
221
|
-
data:
|
222
|
-
default:
|
227
|
+
data: typing.Any,
|
228
|
+
default: typing.Any = None,
|
223
229
|
):
|
224
230
|
name = cls._get_name(type, prompty)
|
225
|
-
if name.startswith("NOOP") and default
|
231
|
+
if name.startswith("NOOP") and default is not None:
|
226
232
|
return default
|
227
233
|
elif name.startswith("NOOP"):
|
228
234
|
return data
|
@@ -231,43 +237,51 @@ class InvokerFactory:
|
|
231
237
|
return value
|
232
238
|
|
233
239
|
@classmethod
|
234
|
-
def run_renderer(
|
240
|
+
def run_renderer(
|
241
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
242
|
+
) -> typing.Any:
|
235
243
|
return cls.run("renderer", prompty, data, default)
|
236
244
|
|
237
245
|
@classmethod
|
238
246
|
async def run_renderer_async(
|
239
|
-
cls, prompty: Prompty, data:
|
240
|
-
) ->
|
247
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
248
|
+
) -> typing.Any:
|
241
249
|
return await cls.run_async("renderer", prompty, data, default)
|
242
250
|
|
243
251
|
@classmethod
|
244
|
-
def run_parser(
|
252
|
+
def run_parser(
|
253
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
254
|
+
) -> typing.Any:
|
245
255
|
return cls.run("parser", prompty, data, default)
|
246
256
|
|
247
257
|
@classmethod
|
248
258
|
async def run_parser_async(
|
249
|
-
cls, prompty: Prompty, data:
|
250
|
-
) ->
|
259
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
260
|
+
) -> typing.Any:
|
251
261
|
return await cls.run_async("parser", prompty, data, default)
|
252
262
|
|
253
263
|
@classmethod
|
254
|
-
def run_executor(
|
264
|
+
def run_executor(
|
265
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
266
|
+
) -> typing.Any:
|
255
267
|
return cls.run("executor", prompty, data, default)
|
256
268
|
|
257
269
|
@classmethod
|
258
270
|
async def run_executor_async(
|
259
|
-
cls, prompty: Prompty, data:
|
260
|
-
) ->
|
271
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
272
|
+
) -> typing.Any:
|
261
273
|
return await cls.run_async("executor", prompty, data, default)
|
262
274
|
|
263
275
|
@classmethod
|
264
|
-
def run_processor(
|
276
|
+
def run_processor(
|
277
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
278
|
+
) -> typing.Any:
|
265
279
|
return cls.run("processor", prompty, data, default)
|
266
280
|
|
267
281
|
@classmethod
|
268
282
|
async def run_processor_async(
|
269
|
-
cls, prompty: Prompty, data:
|
270
|
-
) ->
|
283
|
+
cls, prompty: Prompty, data: typing.Any, default: typing.Any = None
|
284
|
+
) -> typing.Any:
|
271
285
|
return await cls.run_async("processor", prompty, data, default)
|
272
286
|
|
273
287
|
|
@@ -290,7 +304,7 @@ class InvokerException(Exception):
|
|
290
304
|
@InvokerFactory.register_parser("prompty.image")
|
291
305
|
@InvokerFactory.register_parser("prompty.completion")
|
292
306
|
class NoOp(Invoker):
|
293
|
-
def invoke(self, data:
|
307
|
+
def invoke(self, data: typing.Any) -> typing.Any:
|
294
308
|
return data
|
295
309
|
|
296
310
|
async def invoke_async(self, data: str) -> str:
|
prompty/openai/__init__.py
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
from prompty.invoker import InvokerException
|
3
3
|
|
4
4
|
try:
|
5
|
-
from .executor import OpenAIExecutor
|
6
|
-
from .processor import OpenAIProcessor
|
7
|
-
except ImportError:
|
5
|
+
from .executor import OpenAIExecutor # noqa
|
6
|
+
from .processor import OpenAIProcessor # noqa
|
7
|
+
except ImportError as e:
|
8
8
|
raise InvokerException(
|
9
|
-
"Error registering OpenAIExecutor and OpenAIProcessor", "openai"
|
9
|
+
f"Error registering OpenAIExecutor and OpenAIProcessor: {e}", "openai"
|
10
10
|
)
|
prompty/openai/executor.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
import importlib.metadata
|
2
|
+
import typing
|
3
|
+
from collections.abc import Iterator
|
4
|
+
|
2
5
|
from openai import OpenAI
|
3
|
-
from typing import Iterator
|
4
6
|
|
5
7
|
from prompty.tracer import Tracer
|
8
|
+
|
6
9
|
from ..core import Prompty, PromptyStream
|
7
10
|
from ..invoker import Invoker, InvokerFactory
|
8
11
|
|
@@ -18,14 +21,15 @@ class OpenAIExecutor(Invoker):
|
|
18
21
|
self.kwargs = {
|
19
22
|
key: value
|
20
23
|
for key, value in self.prompty.model.configuration.items()
|
21
|
-
if key != "type"
|
24
|
+
if key != "type" and key != "name"
|
22
25
|
}
|
23
26
|
|
24
27
|
self.api = self.prompty.model.api
|
25
|
-
self.deployment = self.prompty.model.configuration["azure_deployment"]
|
26
28
|
self.parameters = self.prompty.model.parameters
|
29
|
+
self.model = self.prompty.model.configuration["name"]
|
30
|
+
self.deployment = self.prompty.model.configuration["deployment"]
|
27
31
|
|
28
|
-
def invoke(self, data:
|
32
|
+
def invoke(self, data: typing.Any) -> typing.Any:
|
29
33
|
"""Invoke the OpenAI API
|
30
34
|
|
31
35
|
Parameters
|
@@ -59,7 +63,7 @@ class OpenAIExecutor(Invoker):
|
|
59
63
|
if self.api == "chat":
|
60
64
|
trace("signature", "OpenAI.chat.completions.create")
|
61
65
|
args = {
|
62
|
-
"model": self.
|
66
|
+
"model": self.model,
|
63
67
|
"messages": data if isinstance(data, list) else [data],
|
64
68
|
**self.parameters,
|
65
69
|
}
|
prompty/openai/processor.py
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
|
2
|
-
from
|
1
|
+
import typing
|
2
|
+
from collections.abc import Iterator
|
3
|
+
|
3
4
|
from openai.types.chat.chat_completion import ChatCompletion
|
4
|
-
from
|
5
|
-
from ..core import Prompty, PromptyStream, ToolCall
|
5
|
+
from openai.types.completion import Completion
|
6
6
|
from openai.types.create_embedding_response import CreateEmbeddingResponse
|
7
7
|
|
8
|
+
from ..core import Prompty, PromptyStream, ToolCall
|
9
|
+
from ..invoker import Invoker, InvokerFactory
|
10
|
+
|
8
11
|
|
9
12
|
@InvokerFactory.register_processor("openai")
|
10
13
|
class OpenAIProcessor(Invoker):
|
@@ -13,7 +16,7 @@ class OpenAIProcessor(Invoker):
|
|
13
16
|
def __init__(self, prompty: Prompty) -> None:
|
14
17
|
super().__init__(prompty)
|
15
18
|
|
16
|
-
def invoke(self, data:
|
19
|
+
def invoke(self, data: typing.Any) -> typing.Any:
|
17
20
|
"""Invoke the OpenAI API
|
18
21
|
|
19
22
|
Parameters
|
@@ -56,7 +59,7 @@ class OpenAIProcessor(Invoker):
|
|
56
59
|
for chunk in data:
|
57
60
|
if (
|
58
61
|
len(chunk.choices) == 1
|
59
|
-
and chunk.choices[0].delta.content
|
62
|
+
and chunk.choices[0].delta.content is not None
|
60
63
|
):
|
61
64
|
content = chunk.choices[0].delta.content
|
62
65
|
yield content
|
prompty/parsers.py
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
-
import re
|
2
1
|
import base64
|
2
|
+
import re
|
3
|
+
from pathlib import Path
|
4
|
+
|
3
5
|
from .core import Prompty
|
4
|
-
from .invoker import Invoker
|
6
|
+
from .invoker import Invoker
|
5
7
|
|
6
8
|
|
7
|
-
@InvokerFactory.register_parser("prompty.chat")
|
8
9
|
class PromptyChatParser(Invoker):
|
9
|
-
"""
|
10
|
+
"""Prompty Chat Parser"""
|
11
|
+
|
10
12
|
def __init__(self, prompty: Prompty) -> None:
|
11
13
|
super().__init__(prompty)
|
12
14
|
self.roles = ["assistant", "function", "system", "user"]
|
15
|
+
if isinstance(self.prompty.file, str):
|
16
|
+
self.prompty.file = Path(self.prompty.file).resolve().absolute()
|
17
|
+
|
13
18
|
self.path = self.prompty.file.parent
|
14
19
|
|
15
20
|
def inline_image(self, image_item: str) -> str:
|
16
|
-
"""
|
21
|
+
"""Inline Image
|
17
22
|
|
18
23
|
Parameters
|
19
24
|
----------
|
20
25
|
image_item : str
|
21
26
|
The image item to inline
|
22
|
-
|
27
|
+
|
23
28
|
Returns
|
24
29
|
-------
|
25
30
|
str
|
@@ -46,13 +51,13 @@ class PromptyChatParser(Invoker):
|
|
46
51
|
)
|
47
52
|
|
48
53
|
def parse_content(self, content: str):
|
49
|
-
"""
|
50
|
-
|
54
|
+
"""for parsing inline images
|
55
|
+
|
51
56
|
Parameters
|
52
57
|
----------
|
53
58
|
content : str
|
54
59
|
The content to parse
|
55
|
-
|
60
|
+
|
56
61
|
Returns
|
57
62
|
-------
|
58
63
|
any
|
@@ -97,14 +102,14 @@ class PromptyChatParser(Invoker):
|
|
97
102
|
else:
|
98
103
|
return content
|
99
104
|
|
100
|
-
def invoke(self, data: str) -> str:
|
101
|
-
"""
|
105
|
+
def invoke(self, data: str) -> list[dict[str, str]]:
|
106
|
+
"""Invoke the Prompty Chat Parser
|
102
107
|
|
103
108
|
Parameters
|
104
109
|
----------
|
105
110
|
data : str
|
106
111
|
The data to parse
|
107
|
-
|
112
|
+
|
108
113
|
Returns
|
109
114
|
-------
|
110
115
|
str
|
@@ -121,7 +126,7 @@ class PromptyChatParser(Invoker):
|
|
121
126
|
]
|
122
127
|
|
123
128
|
# if no starter role, then inject system role
|
124
|
-
if
|
129
|
+
if chunks[0].strip().lower() not in self.roles:
|
125
130
|
chunks.insert(0, "system")
|
126
131
|
|
127
132
|
# if last chunk is role entry, then remove (no content?)
|
@@ -138,16 +143,15 @@ class PromptyChatParser(Invoker):
|
|
138
143
|
messages.append({"role": role, "content": self.parse_content(content)})
|
139
144
|
|
140
145
|
return messages
|
141
|
-
|
142
146
|
|
143
|
-
async def invoke_async(self, data: str) -> str:
|
144
|
-
"""
|
147
|
+
async def invoke_async(self, data: str) -> list[dict[str, str]]:
|
148
|
+
"""Invoke the Prompty Chat Parser (Async)
|
145
149
|
|
146
150
|
Parameters
|
147
151
|
----------
|
148
152
|
data : str
|
149
153
|
The data to parse
|
150
|
-
|
154
|
+
|
151
155
|
Returns
|
152
156
|
-------
|
153
157
|
str
|
prompty/renderers.py
CHANGED
@@ -1,24 +1,35 @@
|
|
1
|
-
|
1
|
+
import typing
|
2
|
+
from pathlib import Path
|
3
|
+
|
2
4
|
from jinja2 import DictLoader, Environment
|
3
|
-
|
5
|
+
|
6
|
+
from .core import Prompty
|
7
|
+
from .invoker import Invoker
|
4
8
|
|
5
9
|
|
6
|
-
@InvokerFactory.register_renderer("jinja2")
|
7
10
|
class Jinja2Renderer(Invoker):
|
8
11
|
"""Jinja2 Renderer"""
|
9
12
|
|
10
13
|
def __init__(self, prompty: Prompty) -> None:
|
11
14
|
super().__init__(prompty)
|
12
|
-
self.templates = {}
|
15
|
+
self.templates: dict[str, str] = {}
|
13
16
|
# generate template dictionary
|
14
|
-
cur_prompt = self.prompty
|
17
|
+
cur_prompt: typing.Union[Prompty, None] = self.prompty
|
15
18
|
while cur_prompt:
|
16
|
-
|
19
|
+
if isinstance(cur_prompt.file, str):
|
20
|
+
cur_prompt.file = Path(cur_prompt.file).resolve().absolute()
|
21
|
+
|
22
|
+
if isinstance(cur_prompt.content, str):
|
23
|
+
self.templates[cur_prompt.file.name] = cur_prompt.content
|
24
|
+
|
17
25
|
cur_prompt = cur_prompt.basePrompty
|
18
26
|
|
27
|
+
if isinstance(self.prompty.file, str):
|
28
|
+
self.prompty.file = Path(self.prompty.file).resolve().absolute()
|
29
|
+
|
19
30
|
self.name = self.prompty.file.name
|
20
31
|
|
21
|
-
def invoke(self, data:
|
32
|
+
def invoke(self, data: typing.Any) -> typing.Any:
|
22
33
|
env = Environment(loader=DictLoader(self.templates))
|
23
34
|
t = env.get_template(self.name)
|
24
35
|
generated = t.render(**data)
|
prompty/serverless/__init__.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
from prompty.invoker import InvokerException
|
3
3
|
|
4
4
|
try:
|
5
|
-
from .executor import ServerlessExecutor
|
6
|
-
from .processor import ServerlessProcessor
|
5
|
+
from .executor import ServerlessExecutor # noqa
|
6
|
+
from .processor import ServerlessProcessor # noqa
|
7
7
|
except ImportError:
|
8
8
|
raise InvokerException("Error registering ServerlessExecutor and ServerlessProcessor", "serverless")
|