|
45 | 45 | import anyio |
46 | 46 |
|
47 | 47 | from dotpromptz.helpers import register_all_helpers |
48 | | -from dotpromptz.parse import parse_document |
| 48 | +from dotpromptz.parse import parse_document, to_messages |
49 | 49 | from dotpromptz.picoschema import picoschema_to_json_schema |
50 | 50 | from dotpromptz.resolvers import resolve_json_schema, resolve_partial, resolve_tool |
51 | 51 | from dotpromptz.typing import ( |
| 52 | + DataArgument, |
52 | 53 | JsonSchema, |
53 | 54 | ModelConfigT, |
54 | 55 | ParsedPrompt, |
55 | 56 | PartialResolver, |
| 57 | + PromptFunction, |
56 | 58 | PromptMetadata, |
57 | 59 | PromptStore, |
| 60 | + RenderedPrompt, |
58 | 61 | SchemaResolver, |
59 | 62 | ToolDefinition, |
60 | 63 | ToolResolver, |
| 64 | + VariablesT, |
61 | 65 | ) |
62 | 66 | from dotpromptz.util import remove_undefined_fields |
63 | 67 | from handlebarrz import EscapeFunction, Handlebars, HelperFn |
@@ -113,6 +117,45 @@ def _identify_partials(template: str) -> set[str]: |
113 | 117 | return set(_PARTIAL_PATTERN.findall(template)) |
114 | 118 |
|
115 | 119 |
|
| 120 | +class CompiledRenderer(PromptFunction[ModelConfigT]): |
| 121 | + """A compiled prompt function with the prompt as a property. |
| 122 | +
|
| 123 | + This is the Python equivalent of the renderFunc nested function |
| 124 | + within the compile method of the Dotprompt class in TypeScript. |
| 125 | +
|
| 126 | + It exposes the prompt property to the user. |
| 127 | + """ |
| 128 | + |
| 129 | + def __init__(self, dotprompt: Dotprompt, handlebars: Handlebars, prompt: ParsedPrompt[ModelConfigT]): |
| 130 | + """Initialize the renderer. |
| 131 | +
|
| 132 | + Args: |
| 133 | + dotprompt: The Dotprompt instance. |
| 134 | + handlebars: The Handlebars instance. |
| 135 | + prompt: The parsed prompt. |
| 136 | + """ |
| 137 | + self._dotprompt = dotprompt |
| 138 | + self._handlebars = handlebars |
| 139 | + |
| 140 | + self.prompt = prompt |
| 141 | + |
| 142 | + async def __call__( |
| 143 | + self, data: DataArgument[VariablesT], options: PromptMetadata[ModelConfigT] | None = None |
| 144 | + ) -> RenderedPrompt[ModelConfigT]: |
| 145 | + """Render the prompt. |
| 146 | +
|
| 147 | + Args: |
| 148 | + data: The data to be used to render the prompt. |
| 149 | + options: Additional options for the prompt. |
| 150 | +
|
| 151 | + Returns: |
| 152 | + The rendered prompt. |
| 153 | + """ |
| 154 | + # Construct and return the final RenderedPrompt. |
| 155 | + # TODO: Stub |
| 156 | + return RenderedPrompt[ModelConfigT](messages=[]) |
| 157 | + |
| 158 | + |
116 | 159 | class Dotprompt: |
117 | 160 | """Dotprompt extends a Handlebars template for use with Gen AI prompts.""" |
118 | 161 |
|
@@ -222,6 +265,45 @@ def parse(self, source: str) -> ParsedPrompt[Any]: |
222 | 265 | """ |
223 | 266 | return parse_document(source) |
224 | 267 |
|
| 268 | + async def render( |
| 269 | + self, source: str, data: DataArgument[VariablesT], options: PromptMetadata[ModelConfigT] | None = None |
| 270 | + ) -> RenderedPrompt[ModelConfigT]: |
| 271 | + """Render a prompt. |
| 272 | +
|
| 273 | + Args: |
| 274 | + source: The source code for the prompt. |
| 275 | + data: The data to be used to render the prompt. |
| 276 | + options: Additional options for the prompt. |
| 277 | +
|
| 278 | + Returns: |
| 279 | + The rendered prompt. |
| 280 | + """ |
| 281 | + renderer: PromptFunction[ModelConfigT] = await self.compile(source) |
| 282 | + return await renderer(data, options) |
| 283 | + |
| 284 | + async def compile( |
| 285 | + self, source: str, additional_metadata: PromptMetadata[ModelConfigT] | None = None |
| 286 | + ) -> PromptFunction[ModelConfigT]: |
| 287 | + """Compile a prompt. |
| 288 | +
|
| 289 | + Args: |
| 290 | + source: The source code for the prompt. |
| 291 | + additional_metadata: Additional metadata to be used to render the prompt. |
| 292 | +
|
| 293 | + Returns: |
| 294 | + A function that can be used to render the prompt. |
| 295 | + """ |
| 296 | + prompt = self.parse(source) if isinstance(source, str) else source |
| 297 | + if additional_metadata is not None: |
| 298 | + prompt = prompt.model_copy( |
| 299 | + deep=True, |
| 300 | + update=additional_metadata.model_dump(exclude_none=True, by_alias=True), |
| 301 | + ) |
| 302 | + |
| 303 | + # Resolve partials before compiling. |
| 304 | + await self._resolve_partials(prompt.template) |
| 305 | + return CompiledRenderer(self, self._handlebars, prompt) |
| 306 | + |
225 | 307 | async def render_metadata( |
226 | 308 | self, |
227 | 309 | source: str | ParsedPrompt[ModelConfigT], |
|
0 commit comments