prompty 0.1.10__py3-none-any.whl → 0.1.34__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- prompty/__init__.py +312 -117
- prompty/azure/__init__.py +10 -0
- prompty/azure/executor.py +218 -0
- prompty/azure/processor.py +142 -0
- prompty/cli.py +74 -28
- prompty/core.py +112 -225
- prompty/invoker.py +297 -0
- prompty/openai/__init__.py +10 -0
- prompty/openai/executor.py +114 -0
- prompty/{processors.py → openai/processor.py} +25 -15
- prompty/parsers.py +18 -1
- prompty/renderers.py +19 -2
- prompty/serverless/__init__.py +8 -0
- prompty/serverless/executor.py +240 -0
- prompty/serverless/processor.py +113 -0
- prompty/tracer.py +164 -30
- prompty/utils.py +105 -0
- prompty-0.1.34.dist-info/METADATA +219 -0
- prompty-0.1.34.dist-info/RECORD +22 -0
- {prompty-0.1.10.dist-info → prompty-0.1.34.dist-info}/WHEEL +1 -1
- prompty-0.1.34.dist-info/entry_points.txt +5 -0
- prompty/executors.py +0 -94
- prompty-0.1.10.dist-info/METADATA +0 -136
- prompty-0.1.10.dist-info/RECORD +0 -12
- {prompty-0.1.10.dist-info → prompty-0.1.34.dist-info}/licenses/LICENSE +0 -0
prompty/core.py
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import os
|
4
|
-
import re
|
5
|
-
import yaml
|
6
|
-
import json
|
7
|
-
import abc
|
8
4
|
from pathlib import Path
|
9
|
-
|
5
|
+
|
6
|
+
from .tracer import Tracer, to_dict
|
10
7
|
from pydantic import BaseModel, Field, FilePath
|
11
|
-
from typing import AsyncIterator, Iterator, List, Literal, Dict, Callable, Set
|
8
|
+
from typing import AsyncIterator, Iterator, List, Literal, Dict, Callable, Set, Tuple
|
9
|
+
|
10
|
+
from .utils import load_json, load_json_async
|
11
|
+
|
12
|
+
|
13
|
+
class ToolCall(BaseModel):
|
14
|
+
id: str
|
15
|
+
name: str
|
16
|
+
arguments: str
|
12
17
|
|
13
18
|
|
14
19
|
class PropertySettings(BaseModel):
|
@@ -188,33 +193,74 @@ class Prompty(BaseModel):
|
|
188
193
|
d[k] = v
|
189
194
|
return d
|
190
195
|
|
196
|
+
@staticmethod
|
197
|
+
def hoist_base_prompty(top: Prompty, base: Prompty) -> Prompty:
|
198
|
+
top.name = base.name if top.name == "" else top.name
|
199
|
+
top.description = base.description if top.description == "" else top.description
|
200
|
+
top.authors = list(set(base.authors + top.authors))
|
201
|
+
top.tags = list(set(base.tags + top.tags))
|
202
|
+
top.version = base.version if top.version == "" else top.version
|
203
|
+
|
204
|
+
top.model.api = base.model.api if top.model.api == "" else top.model.api
|
205
|
+
top.model.configuration = param_hoisting(
|
206
|
+
top.model.configuration, base.model.configuration
|
207
|
+
)
|
208
|
+
top.model.parameters = param_hoisting(
|
209
|
+
top.model.parameters, base.model.parameters
|
210
|
+
)
|
211
|
+
top.model.response = param_hoisting(top.model.response, base.model.response)
|
212
|
+
|
213
|
+
top.sample = param_hoisting(top.sample, base.sample)
|
214
|
+
|
215
|
+
top.basePrompty = base
|
216
|
+
|
217
|
+
return top
|
218
|
+
|
191
219
|
@staticmethod
|
192
220
|
def _process_file(file: str, parent: Path) -> any:
|
193
221
|
file = Path(parent / Path(file)).resolve().absolute()
|
194
222
|
if file.exists():
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
223
|
+
items = load_json(file)
|
224
|
+
if isinstance(items, list):
|
225
|
+
return [Prompty.normalize(value, parent) for value in items]
|
226
|
+
elif isinstance(items, dict):
|
227
|
+
return {
|
228
|
+
key: Prompty.normalize(value, parent)
|
229
|
+
for key, value in items.items()
|
230
|
+
}
|
231
|
+
else:
|
232
|
+
return items
|
233
|
+
else:
|
234
|
+
raise FileNotFoundError(f"File {file} not found")
|
235
|
+
|
236
|
+
@staticmethod
|
237
|
+
async def _process_file_async(file: str, parent: Path) -> any:
|
238
|
+
file = Path(parent / Path(file)).resolve().absolute()
|
239
|
+
if file.exists():
|
240
|
+
items = await load_json_async(file)
|
241
|
+
if isinstance(items, list):
|
242
|
+
return [Prompty.normalize(value, parent) for value in items]
|
243
|
+
elif isinstance(items, dict):
|
244
|
+
return {
|
245
|
+
key: Prompty.normalize(value, parent)
|
246
|
+
for key, value in items.items()
|
247
|
+
}
|
248
|
+
else:
|
249
|
+
return items
|
206
250
|
else:
|
207
251
|
raise FileNotFoundError(f"File {file} not found")
|
208
252
|
|
209
253
|
@staticmethod
|
210
|
-
def _process_env(variable: str, env_error=True) -> any:
|
254
|
+
def _process_env(variable: str, env_error=True, default: str = None) -> any:
|
211
255
|
if variable in os.environ.keys():
|
212
256
|
return os.environ[variable]
|
213
257
|
else:
|
258
|
+
if default:
|
259
|
+
return default
|
214
260
|
if env_error:
|
215
261
|
raise ValueError(f"Variable {variable} not found in environment")
|
216
|
-
|
217
|
-
|
262
|
+
|
263
|
+
return ""
|
218
264
|
|
219
265
|
@staticmethod
|
220
266
|
def normalize(attribute: any, parent: Path, env_error=True) -> any:
|
@@ -224,30 +270,15 @@ class Prompty(BaseModel):
|
|
224
270
|
# check if env or file
|
225
271
|
variable = attribute[2:-1].split(":")
|
226
272
|
if variable[0] == "env" and len(variable) > 1:
|
227
|
-
return Prompty._process_env(
|
273
|
+
return Prompty._process_env(
|
274
|
+
variable[1],
|
275
|
+
env_error,
|
276
|
+
variable[2] if len(variable) > 2 else None,
|
277
|
+
)
|
228
278
|
elif variable[0] == "file" and len(variable) > 1:
|
229
279
|
return Prompty._process_file(variable[1], parent)
|
230
280
|
else:
|
231
|
-
|
232
|
-
v = Prompty._process_env(variable[0], False)
|
233
|
-
if len(v) == 0:
|
234
|
-
if len(variable) > 1:
|
235
|
-
return variable[1]
|
236
|
-
else:
|
237
|
-
if env_error:
|
238
|
-
raise ValueError(
|
239
|
-
f"Variable {variable[0]} not found in environment"
|
240
|
-
)
|
241
|
-
else:
|
242
|
-
return v
|
243
|
-
else:
|
244
|
-
return v
|
245
|
-
elif (
|
246
|
-
attribute.startswith("file:")
|
247
|
-
and Path(parent / attribute.split(":")[1]).exists()
|
248
|
-
):
|
249
|
-
# old way of doing things for back compatibility
|
250
|
-
return Prompty._process_file(attribute.split(":")[1], parent)
|
281
|
+
raise ValueError(f"Invalid attribute format ({attribute})")
|
251
282
|
else:
|
252
283
|
return attribute
|
253
284
|
elif isinstance(attribute, list):
|
@@ -260,6 +291,35 @@ class Prompty(BaseModel):
|
|
260
291
|
else:
|
261
292
|
return attribute
|
262
293
|
|
294
|
+
@staticmethod
|
295
|
+
async def normalize_async(attribute: any, parent: Path, env_error=True) -> any:
|
296
|
+
if isinstance(attribute, str):
|
297
|
+
attribute = attribute.strip()
|
298
|
+
if attribute.startswith("${") and attribute.endswith("}"):
|
299
|
+
# check if env or file
|
300
|
+
variable = attribute[2:-1].split(":")
|
301
|
+
if variable[0] == "env" and len(variable) > 1:
|
302
|
+
return Prompty._process_env(
|
303
|
+
variable[1],
|
304
|
+
env_error,
|
305
|
+
variable[2] if len(variable) > 2 else None,
|
306
|
+
)
|
307
|
+
elif variable[0] == "file" and len(variable) > 1:
|
308
|
+
return await Prompty._process_file_async(variable[1], parent)
|
309
|
+
else:
|
310
|
+
raise ValueError(f"Invalid attribute format ({attribute})")
|
311
|
+
else:
|
312
|
+
return attribute
|
313
|
+
elif isinstance(attribute, list):
|
314
|
+
return [await Prompty.normalize_async(value, parent) for value in attribute]
|
315
|
+
elif isinstance(attribute, dict):
|
316
|
+
return {
|
317
|
+
key: await Prompty.normalize_async(value, parent)
|
318
|
+
for key, value in attribute.items()
|
319
|
+
}
|
320
|
+
else:
|
321
|
+
return attribute
|
322
|
+
|
263
323
|
|
264
324
|
def param_hoisting(
|
265
325
|
top: Dict[str, any], bottom: Dict[str, any], top_key: str = None
|
@@ -274,183 +334,6 @@ def param_hoisting(
|
|
274
334
|
return new_dict
|
275
335
|
|
276
336
|
|
277
|
-
class Invoker(abc.ABC):
|
278
|
-
"""Abstract class for Invoker
|
279
|
-
|
280
|
-
Attributes
|
281
|
-
----------
|
282
|
-
prompty : Prompty
|
283
|
-
The prompty object
|
284
|
-
name : str
|
285
|
-
The name of the invoker
|
286
|
-
|
287
|
-
"""
|
288
|
-
|
289
|
-
def __init__(self, prompty: Prompty) -> None:
|
290
|
-
self.prompty = prompty
|
291
|
-
self.name = self.__class__.__name__
|
292
|
-
|
293
|
-
@abc.abstractmethod
|
294
|
-
def invoke(self, data: any) -> any:
|
295
|
-
"""Abstract method to invoke the invoker
|
296
|
-
|
297
|
-
Parameters
|
298
|
-
----------
|
299
|
-
data : any
|
300
|
-
The data to be invoked
|
301
|
-
|
302
|
-
Returns
|
303
|
-
-------
|
304
|
-
any
|
305
|
-
The invoked
|
306
|
-
"""
|
307
|
-
pass
|
308
|
-
|
309
|
-
@trace
|
310
|
-
def __call__(self, data: any) -> any:
|
311
|
-
"""Method to call the invoker
|
312
|
-
|
313
|
-
Parameters
|
314
|
-
----------
|
315
|
-
data : any
|
316
|
-
The data to be invoked
|
317
|
-
|
318
|
-
Returns
|
319
|
-
-------
|
320
|
-
any
|
321
|
-
The invoked
|
322
|
-
"""
|
323
|
-
return self.invoke(data)
|
324
|
-
|
325
|
-
|
326
|
-
class InvokerFactory:
|
327
|
-
"""Factory class for Invoker"""
|
328
|
-
|
329
|
-
_renderers: Dict[str, Invoker] = {}
|
330
|
-
_parsers: Dict[str, Invoker] = {}
|
331
|
-
_executors: Dict[str, Invoker] = {}
|
332
|
-
_processors: Dict[str, Invoker] = {}
|
333
|
-
|
334
|
-
@classmethod
|
335
|
-
def register_renderer(cls, name: str) -> Callable:
|
336
|
-
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
337
|
-
cls._renderers[name] = wrapped_class
|
338
|
-
return wrapped_class
|
339
|
-
|
340
|
-
return inner_wrapper
|
341
|
-
|
342
|
-
@classmethod
|
343
|
-
def register_parser(cls, name: str) -> Callable:
|
344
|
-
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
345
|
-
cls._parsers[name] = wrapped_class
|
346
|
-
return wrapped_class
|
347
|
-
|
348
|
-
return inner_wrapper
|
349
|
-
|
350
|
-
@classmethod
|
351
|
-
def register_executor(cls, name: str) -> Callable:
|
352
|
-
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
353
|
-
cls._executors[name] = wrapped_class
|
354
|
-
return wrapped_class
|
355
|
-
|
356
|
-
return inner_wrapper
|
357
|
-
|
358
|
-
@classmethod
|
359
|
-
def register_processor(cls, name: str) -> Callable:
|
360
|
-
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
361
|
-
cls._processors[name] = wrapped_class
|
362
|
-
return wrapped_class
|
363
|
-
|
364
|
-
return inner_wrapper
|
365
|
-
|
366
|
-
@classmethod
|
367
|
-
def create_renderer(cls, name: str, prompty: Prompty) -> Invoker:
|
368
|
-
if name not in cls._renderers:
|
369
|
-
raise ValueError(f"Renderer {name} not found")
|
370
|
-
return cls._renderers[name](prompty)
|
371
|
-
|
372
|
-
@classmethod
|
373
|
-
def create_parser(cls, name: str, prompty: Prompty) -> Invoker:
|
374
|
-
if name not in cls._parsers:
|
375
|
-
raise ValueError(f"Parser {name} not found")
|
376
|
-
return cls._parsers[name](prompty)
|
377
|
-
|
378
|
-
@classmethod
|
379
|
-
def create_executor(cls, name: str, prompty: Prompty) -> Invoker:
|
380
|
-
if name not in cls._executors:
|
381
|
-
raise ValueError(f"Executor {name} not found")
|
382
|
-
return cls._executors[name](prompty)
|
383
|
-
|
384
|
-
@classmethod
|
385
|
-
def create_processor(cls, name: str, prompty: Prompty) -> Invoker:
|
386
|
-
if name not in cls._processors:
|
387
|
-
raise ValueError(f"Processor {name} not found")
|
388
|
-
return cls._processors[name](prompty)
|
389
|
-
|
390
|
-
|
391
|
-
@InvokerFactory.register_renderer("NOOP")
|
392
|
-
@InvokerFactory.register_parser("NOOP")
|
393
|
-
@InvokerFactory.register_executor("NOOP")
|
394
|
-
@InvokerFactory.register_processor("NOOP")
|
395
|
-
@InvokerFactory.register_parser("prompty.embedding")
|
396
|
-
@InvokerFactory.register_parser("prompty.image")
|
397
|
-
@InvokerFactory.register_parser("prompty.completion")
|
398
|
-
class NoOp(Invoker):
|
399
|
-
def invoke(self, data: any) -> any:
|
400
|
-
return data
|
401
|
-
|
402
|
-
|
403
|
-
class Frontmatter:
|
404
|
-
"""Frontmatter class to extract frontmatter from string."""
|
405
|
-
|
406
|
-
_yaml_delim = r"(?:---|\+\+\+)"
|
407
|
-
_yaml = r"(.*?)"
|
408
|
-
_content = r"\s*(.+)$"
|
409
|
-
_re_pattern = r"^\s*" + _yaml_delim + _yaml + _yaml_delim + _content
|
410
|
-
_regex = re.compile(_re_pattern, re.S | re.M)
|
411
|
-
|
412
|
-
@classmethod
|
413
|
-
def read_file(cls, path):
|
414
|
-
"""Returns dict with separated frontmatter from file.
|
415
|
-
|
416
|
-
Parameters
|
417
|
-
----------
|
418
|
-
path : str
|
419
|
-
The path to the file
|
420
|
-
"""
|
421
|
-
with open(path, encoding="utf-8") as file:
|
422
|
-
file_contents = file.read()
|
423
|
-
return cls.read(file_contents)
|
424
|
-
|
425
|
-
@classmethod
|
426
|
-
def read(cls, string):
|
427
|
-
"""Returns dict with separated frontmatter from string.
|
428
|
-
|
429
|
-
Parameters
|
430
|
-
----------
|
431
|
-
string : str
|
432
|
-
The string to extract frontmatter from
|
433
|
-
|
434
|
-
|
435
|
-
Returns
|
436
|
-
-------
|
437
|
-
dict
|
438
|
-
The separated frontmatter
|
439
|
-
"""
|
440
|
-
fmatter = ""
|
441
|
-
body = ""
|
442
|
-
result = cls._regex.search(string)
|
443
|
-
|
444
|
-
if result:
|
445
|
-
fmatter = result.group(1)
|
446
|
-
body = result.group(2)
|
447
|
-
return {
|
448
|
-
"attributes": yaml.load(fmatter, Loader=yaml.FullLoader),
|
449
|
-
"body": body,
|
450
|
-
"frontmatter": fmatter,
|
451
|
-
}
|
452
|
-
|
453
|
-
|
454
337
|
class PromptyStream(Iterator):
|
455
338
|
"""PromptyStream class to iterate over LLM stream.
|
456
339
|
Necessary for Prompty to handle streaming data when tracing."""
|
@@ -474,9 +357,11 @@ class PromptyStream(Iterator):
|
|
474
357
|
except StopIteration:
|
475
358
|
# StopIteration is raised
|
476
359
|
# contents are exhausted
|
477
|
-
if len(self.items) > 0:
|
478
|
-
with Tracer.start(
|
479
|
-
trace("
|
360
|
+
if len(self.items) > 0:
|
361
|
+
with Tracer.start("PromptyStream") as trace:
|
362
|
+
trace("signature", f"{self.name}.PromptyStream")
|
363
|
+
trace("inputs", "None")
|
364
|
+
trace("result", [to_dict(s) for s in self.items])
|
480
365
|
|
481
366
|
raise StopIteration
|
482
367
|
|
@@ -501,11 +386,13 @@ class AsyncPromptyStream(AsyncIterator):
|
|
501
386
|
self.items.append(o)
|
502
387
|
return o
|
503
388
|
|
504
|
-
except
|
389
|
+
except StopAsyncIteration:
|
505
390
|
# StopIteration is raised
|
506
391
|
# contents are exhausted
|
507
392
|
if len(self.items) > 0:
|
508
|
-
with Tracer.start(
|
509
|
-
trace("
|
393
|
+
with Tracer.start("AsyncPromptyStream") as trace:
|
394
|
+
trace("signature", f"{self.name}.AsyncPromptyStream")
|
395
|
+
trace("inputs", "None")
|
396
|
+
trace("result", [to_dict(s) for s in self.items])
|
510
397
|
|
511
|
-
raise
|
398
|
+
raise StopAsyncIteration
|
prompty/invoker.py
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
import abc
|
2
|
+
from .tracer import trace
|
3
|
+
from .core import Prompty
|
4
|
+
from typing import Callable, Dict, Literal
|
5
|
+
|
6
|
+
|
7
|
+
class Invoker(abc.ABC):
|
8
|
+
"""Abstract class for Invoker
|
9
|
+
|
10
|
+
Attributes
|
11
|
+
----------
|
12
|
+
prompty : Prompty
|
13
|
+
The prompty object
|
14
|
+
name : str
|
15
|
+
The name of the invoker
|
16
|
+
|
17
|
+
"""
|
18
|
+
|
19
|
+
def __init__(self, prompty: Prompty) -> None:
|
20
|
+
self.prompty = prompty
|
21
|
+
self.name = self.__class__.__name__
|
22
|
+
|
23
|
+
@abc.abstractmethod
|
24
|
+
def invoke(self, data: any) -> any:
|
25
|
+
"""Abstract method to invoke the invoker
|
26
|
+
|
27
|
+
Parameters
|
28
|
+
----------
|
29
|
+
data : any
|
30
|
+
The data to be invoked
|
31
|
+
|
32
|
+
Returns
|
33
|
+
-------
|
34
|
+
any
|
35
|
+
The invoked
|
36
|
+
"""
|
37
|
+
pass
|
38
|
+
|
39
|
+
@abc.abstractmethod
|
40
|
+
async def invoke_async(self, data: any) -> any:
|
41
|
+
"""Abstract method to invoke the invoker asynchronously
|
42
|
+
|
43
|
+
Parameters
|
44
|
+
----------
|
45
|
+
data : any
|
46
|
+
The data to be invoked
|
47
|
+
|
48
|
+
Returns
|
49
|
+
-------
|
50
|
+
any
|
51
|
+
The invoked
|
52
|
+
"""
|
53
|
+
pass
|
54
|
+
|
55
|
+
@trace
|
56
|
+
def run(self, data: any) -> any:
|
57
|
+
"""Method to run the invoker
|
58
|
+
|
59
|
+
Parameters
|
60
|
+
----------
|
61
|
+
data : any
|
62
|
+
The data to be invoked
|
63
|
+
|
64
|
+
Returns
|
65
|
+
-------
|
66
|
+
any
|
67
|
+
The invoked
|
68
|
+
"""
|
69
|
+
return self.invoke(data)
|
70
|
+
|
71
|
+
@trace
|
72
|
+
async def run_async(self, data: any) -> any:
|
73
|
+
"""Method to run the invoker asynchronously
|
74
|
+
|
75
|
+
Parameters
|
76
|
+
----------
|
77
|
+
data : any
|
78
|
+
The data to be invoked
|
79
|
+
|
80
|
+
Returns
|
81
|
+
-------
|
82
|
+
any
|
83
|
+
The invoked
|
84
|
+
"""
|
85
|
+
return await self.invoke_async(data)
|
86
|
+
|
87
|
+
|
88
|
+
class InvokerFactory:
|
89
|
+
"""Factory class for Invoker"""
|
90
|
+
|
91
|
+
_renderers: Dict[str, Invoker] = {}
|
92
|
+
_parsers: Dict[str, Invoker] = {}
|
93
|
+
_executors: Dict[str, Invoker] = {}
|
94
|
+
_processors: Dict[str, Invoker] = {}
|
95
|
+
|
96
|
+
@classmethod
|
97
|
+
def add_renderer(cls, name: str, invoker: Invoker) -> None:
|
98
|
+
cls._renderers[name] = invoker
|
99
|
+
|
100
|
+
@classmethod
|
101
|
+
def add_parser(cls, name: str, invoker: Invoker) -> None:
|
102
|
+
cls._parsers[name] = invoker
|
103
|
+
|
104
|
+
@classmethod
|
105
|
+
def add_executor(cls, name: str, invoker: Invoker) -> None:
|
106
|
+
cls._executors[name] = invoker
|
107
|
+
|
108
|
+
@classmethod
|
109
|
+
def add_processor(cls, name: str, invoker: Invoker) -> None:
|
110
|
+
cls._processors[name] = invoker
|
111
|
+
|
112
|
+
@classmethod
|
113
|
+
def register_renderer(cls, name: str) -> Callable:
|
114
|
+
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
115
|
+
cls._renderers[name] = wrapped_class
|
116
|
+
return wrapped_class
|
117
|
+
|
118
|
+
return inner_wrapper
|
119
|
+
|
120
|
+
@classmethod
|
121
|
+
def register_parser(cls, name: str) -> Callable:
|
122
|
+
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
123
|
+
cls._parsers[name] = wrapped_class
|
124
|
+
return wrapped_class
|
125
|
+
|
126
|
+
return inner_wrapper
|
127
|
+
|
128
|
+
@classmethod
|
129
|
+
def register_executor(cls, name: str) -> Callable:
|
130
|
+
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
131
|
+
cls._executors[name] = wrapped_class
|
132
|
+
return wrapped_class
|
133
|
+
|
134
|
+
return inner_wrapper
|
135
|
+
|
136
|
+
@classmethod
|
137
|
+
def register_processor(cls, name: str) -> Callable:
|
138
|
+
def inner_wrapper(wrapped_class: Invoker) -> Callable:
|
139
|
+
cls._processors[name] = wrapped_class
|
140
|
+
return wrapped_class
|
141
|
+
|
142
|
+
return inner_wrapper
|
143
|
+
|
144
|
+
@classmethod
|
145
|
+
def _get_name(
|
146
|
+
cls,
|
147
|
+
type: Literal["renderer", "parser", "executor", "processor"],
|
148
|
+
prompty: Prompty,
|
149
|
+
) -> str:
|
150
|
+
if type == "renderer":
|
151
|
+
return prompty.template.type
|
152
|
+
elif type == "parser":
|
153
|
+
return f"{prompty.template.parser}.{prompty.model.api}"
|
154
|
+
elif type == "executor":
|
155
|
+
return prompty.model.configuration["type"]
|
156
|
+
elif type == "processor":
|
157
|
+
return prompty.model.configuration["type"]
|
158
|
+
else:
|
159
|
+
raise ValueError(f"Type {type} not found")
|
160
|
+
|
161
|
+
@classmethod
|
162
|
+
def _get_invoker(
|
163
|
+
cls,
|
164
|
+
type: Literal["renderer", "parser", "executor", "processor"],
|
165
|
+
prompty: Prompty,
|
166
|
+
) -> Invoker:
|
167
|
+
if type == "renderer":
|
168
|
+
name = prompty.template.type
|
169
|
+
if name not in cls._renderers:
|
170
|
+
raise ValueError(f"Renderer {name} not found")
|
171
|
+
|
172
|
+
return cls._renderers[name](prompty)
|
173
|
+
|
174
|
+
elif type == "parser":
|
175
|
+
name = f"{prompty.template.parser}.{prompty.model.api}"
|
176
|
+
if name not in cls._parsers:
|
177
|
+
raise ValueError(f"Parser {name} not found")
|
178
|
+
|
179
|
+
return cls._parsers[name](prompty)
|
180
|
+
|
181
|
+
elif type == "executor":
|
182
|
+
name = prompty.model.configuration["type"]
|
183
|
+
if name not in cls._executors:
|
184
|
+
raise ValueError(f"Executor {name} not found")
|
185
|
+
|
186
|
+
return cls._executors[name](prompty)
|
187
|
+
|
188
|
+
elif type == "processor":
|
189
|
+
name = prompty.model.configuration["type"]
|
190
|
+
if name not in cls._processors:
|
191
|
+
raise ValueError(f"Processor {name} not found")
|
192
|
+
|
193
|
+
return cls._processors[name](prompty)
|
194
|
+
|
195
|
+
else:
|
196
|
+
raise ValueError(f"Type {type} not found")
|
197
|
+
|
198
|
+
@classmethod
|
199
|
+
def run(
|
200
|
+
cls,
|
201
|
+
type: Literal["renderer", "parser", "executor", "processor"],
|
202
|
+
prompty: Prompty,
|
203
|
+
data: any,
|
204
|
+
default: any = None,
|
205
|
+
):
|
206
|
+
name = cls._get_name(type, prompty)
|
207
|
+
if name.startswith("NOOP") and default != None:
|
208
|
+
return default
|
209
|
+
elif name.startswith("NOOP"):
|
210
|
+
return data
|
211
|
+
|
212
|
+
invoker = cls._get_invoker(type, prompty)
|
213
|
+
value = invoker.run(data)
|
214
|
+
return value
|
215
|
+
|
216
|
+
@classmethod
|
217
|
+
async def run_async(
|
218
|
+
cls,
|
219
|
+
type: Literal["renderer", "parser", "executor", "processor"],
|
220
|
+
prompty: Prompty,
|
221
|
+
data: any,
|
222
|
+
default: any = None,
|
223
|
+
):
|
224
|
+
name = cls._get_name(type, prompty)
|
225
|
+
if name.startswith("NOOP") and default != None:
|
226
|
+
return default
|
227
|
+
elif name.startswith("NOOP"):
|
228
|
+
return data
|
229
|
+
invoker = cls._get_invoker(type, prompty)
|
230
|
+
value = await invoker.run_async(data)
|
231
|
+
return value
|
232
|
+
|
233
|
+
@classmethod
|
234
|
+
def run_renderer(cls, prompty: Prompty, data: any, default: any = None) -> any:
|
235
|
+
return cls.run("renderer", prompty, data, default)
|
236
|
+
|
237
|
+
@classmethod
|
238
|
+
async def run_renderer_async(
|
239
|
+
cls, prompty: Prompty, data: any, default: any = None
|
240
|
+
) -> any:
|
241
|
+
return await cls.run_async("renderer", prompty, data, default)
|
242
|
+
|
243
|
+
@classmethod
|
244
|
+
def run_parser(cls, prompty: Prompty, data: any, default: any = None) -> any:
|
245
|
+
return cls.run("parser", prompty, data, default)
|
246
|
+
|
247
|
+
@classmethod
|
248
|
+
async def run_parser_async(
|
249
|
+
cls, prompty: Prompty, data: any, default: any = None
|
250
|
+
) -> any:
|
251
|
+
return await cls.run_async("parser", prompty, data, default)
|
252
|
+
|
253
|
+
@classmethod
|
254
|
+
def run_executor(cls, prompty: Prompty, data: any, default: any = None) -> any:
|
255
|
+
return cls.run("executor", prompty, data, default)
|
256
|
+
|
257
|
+
@classmethod
|
258
|
+
async def run_executor_async(
|
259
|
+
cls, prompty: Prompty, data: any, default: any = None
|
260
|
+
) -> any:
|
261
|
+
return await cls.run_async("executor", prompty, data, default)
|
262
|
+
|
263
|
+
@classmethod
|
264
|
+
def run_processor(cls, prompty: Prompty, data: any, default: any = None) -> any:
|
265
|
+
return cls.run("processor", prompty, data, default)
|
266
|
+
|
267
|
+
@classmethod
|
268
|
+
async def run_processor_async(
|
269
|
+
cls, prompty: Prompty, data: any, default: any = None
|
270
|
+
) -> any:
|
271
|
+
return await cls.run_async("processor", prompty, data, default)
|
272
|
+
|
273
|
+
|
274
|
+
class InvokerException(Exception):
|
275
|
+
"""Exception class for Invoker"""
|
276
|
+
|
277
|
+
def __init__(self, message: str, type: str) -> None:
|
278
|
+
super().__init__(message)
|
279
|
+
self.type = type
|
280
|
+
|
281
|
+
def __str__(self) -> str:
|
282
|
+
return f"{super().__str__()}. Make sure to pip install any necessary package extras (i.e. could be something like `pip install prompty[{self.type}]`) for {self.type} as well as import the appropriate invokers (i.e. could be something like `import prompty.{self.type}`)."
|
283
|
+
|
284
|
+
|
285
|
+
@InvokerFactory.register_renderer("NOOP")
|
286
|
+
@InvokerFactory.register_parser("NOOP")
|
287
|
+
@InvokerFactory.register_executor("NOOP")
|
288
|
+
@InvokerFactory.register_processor("NOOP")
|
289
|
+
@InvokerFactory.register_parser("prompty.embedding")
|
290
|
+
@InvokerFactory.register_parser("prompty.image")
|
291
|
+
@InvokerFactory.register_parser("prompty.completion")
|
292
|
+
class NoOp(Invoker):
|
293
|
+
def invoke(self, data: any) -> any:
|
294
|
+
return data
|
295
|
+
|
296
|
+
async def invoke_async(self, data: str) -> str:
|
297
|
+
return self.invoke(data)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# __init__.py
|
2
|
+
from prompty.invoker import InvokerException
|
3
|
+
|
4
|
+
try:
|
5
|
+
from .executor import OpenAIExecutor
|
6
|
+
from .processor import OpenAIProcessor
|
7
|
+
except ImportError:
|
8
|
+
raise InvokerException(
|
9
|
+
"Error registering OpenAIExecutor and OpenAIProcessor", "openai"
|
10
|
+
)
|