opik-optimizer 0.8.1__py3-none-any.whl → 0.9.0__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.
- opik_optimizer/__init__.py +15 -26
- opik_optimizer/base_optimizer.py +28 -44
- opik_optimizer/datasets/__init__.py +6 -7
- opik_optimizer/evolutionary_optimizer/evolutionary_optimizer.py +742 -726
- opik_optimizer/evolutionary_optimizer/reporting.py +246 -0
- opik_optimizer/few_shot_bayesian_optimizer/few_shot_bayesian_optimizer.py +297 -193
- opik_optimizer/few_shot_bayesian_optimizer/reporting.py +119 -0
- opik_optimizer/meta_prompt_optimizer/__init__.py +5 -0
- opik_optimizer/meta_prompt_optimizer/meta_prompt_optimizer.py +816 -0
- opik_optimizer/meta_prompt_optimizer/reporting.py +140 -0
- opik_optimizer/mipro_optimizer/__init__.py +1 -1
- opik_optimizer/mipro_optimizer/_mipro_optimizer_v2.py +12 -20
- opik_optimizer/mipro_optimizer/mipro_optimizer.py +32 -52
- opik_optimizer/mipro_optimizer/utils.py +1 -23
- opik_optimizer/optimization_config/chat_prompt.py +106 -0
- opik_optimizer/optimization_config/configs.py +2 -21
- opik_optimizer/optimization_config/mappers.py +1 -1
- opik_optimizer/optimization_result.py +57 -85
- opik_optimizer/reporting_utils.py +180 -0
- opik_optimizer/task_evaluator.py +41 -26
- opik_optimizer/utils.py +187 -3
- {opik_optimizer-0.8.1.dist-info → opik_optimizer-0.9.0.dist-info}/METADATA +15 -31
- opik_optimizer-0.9.0.dist-info/RECORD +48 -0
- {opik_optimizer-0.8.1.dist-info → opik_optimizer-0.9.0.dist-info}/WHEEL +1 -1
- opik_optimizer/few_shot_bayesian_optimizer/prompt_parameter.py +0 -91
- opik_optimizer/few_shot_bayesian_optimizer/prompt_templates.py +0 -80
- opik_optimizer/integrations/__init__.py +0 -0
- opik_optimizer/meta_prompt_optimizer.py +0 -1151
- opik_optimizer-0.8.1.dist-info/RECORD +0 -45
- {opik_optimizer-0.8.1.dist-info → opik_optimizer-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {opik_optimizer-0.8.1.dist-info → opik_optimizer-0.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
from contextlib import contextmanager
|
2
|
+
from io import StringIO
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
import rich
|
6
|
+
from rich.console import Console
|
7
|
+
from rich.panel import Panel
|
8
|
+
from rich.text import Text
|
9
|
+
|
10
|
+
from ..optimization_config import chat_prompt
|
11
|
+
from ..reporting_utils import (
|
12
|
+
convert_tqdm_to_rich,
|
13
|
+
display_configuration, # noqa: F401
|
14
|
+
display_header, # noqa: F401
|
15
|
+
display_messages, # noqa: F401
|
16
|
+
display_result, # noqa: F401
|
17
|
+
get_console,
|
18
|
+
suppress_opik_logs,
|
19
|
+
)
|
20
|
+
|
21
|
+
PANEL_WIDTH = 70
|
22
|
+
console = get_console()
|
23
|
+
|
24
|
+
|
25
|
+
@contextmanager
|
26
|
+
def infer_output_style(verbose: int = 1):
|
27
|
+
class Reporter:
|
28
|
+
def start_style_inference(self, output_style_prompt):
|
29
|
+
if verbose >= 1:
|
30
|
+
console.print("> Infering the output style using the prompt:")
|
31
|
+
console.print("│")
|
32
|
+
|
33
|
+
def error(self, error_message):
|
34
|
+
if verbose >= 1:
|
35
|
+
console.print(Text("│ ").append(Text(f"Failed to infer output style: {error_message}", style="red")))
|
36
|
+
console.print(Text("│ ").append(Text("Continuing with default style", style="dim")))
|
37
|
+
|
38
|
+
def display_style_inference_prompt(self, output_style_prompt):
|
39
|
+
if verbose >= 1:
|
40
|
+
panel = Panel(
|
41
|
+
Text(output_style_prompt),
|
42
|
+
title="Output style inference prompt",
|
43
|
+
title_align="left",
|
44
|
+
border_style="dim",
|
45
|
+
width=PANEL_WIDTH,
|
46
|
+
padding=(1, 2),
|
47
|
+
)
|
48
|
+
|
49
|
+
# Use a temporary buffer to render the panel
|
50
|
+
buffer = StringIO()
|
51
|
+
temp_console = get_console(file=buffer, width=console.width)
|
52
|
+
temp_console.print(panel)
|
53
|
+
|
54
|
+
# Add prefix to each line
|
55
|
+
panel_output = buffer.getvalue()
|
56
|
+
prefixed = "\n".join(f"│ {line}" for line in panel_output.splitlines())
|
57
|
+
|
58
|
+
# Print the final result
|
59
|
+
console.print(prefixed)
|
60
|
+
console.print(Text("│"))
|
61
|
+
|
62
|
+
def success(self, output_style_prompt):
|
63
|
+
if verbose >= 1:
|
64
|
+
panel = Panel(
|
65
|
+
Text(output_style_prompt),
|
66
|
+
title="Successfully inferred output style",
|
67
|
+
title_align="left",
|
68
|
+
border_style="green",
|
69
|
+
width=PANEL_WIDTH,
|
70
|
+
padding=(1, 2),
|
71
|
+
)
|
72
|
+
|
73
|
+
# Capture the panel as rendered text with ANSI styles
|
74
|
+
with console.capture() as capture:
|
75
|
+
console.print(panel)
|
76
|
+
|
77
|
+
# Retrieve the rendered string (with ANSI)
|
78
|
+
rendered_panel = capture.get()
|
79
|
+
|
80
|
+
# Prefix each line with '│ ', preserving ANSI styles
|
81
|
+
prefixed_output = "\n".join(f"│ {line}" for line in rendered_panel.splitlines())
|
82
|
+
|
83
|
+
# Print the prefixed output (will include colors)
|
84
|
+
console.print(prefixed_output, highlight=False)
|
85
|
+
console.print(Text(""))
|
86
|
+
|
87
|
+
try:
|
88
|
+
yield Reporter()
|
89
|
+
finally:
|
90
|
+
pass
|
91
|
+
|
92
|
+
@contextmanager
|
93
|
+
def initializing_population(verbose: int = 1):
|
94
|
+
class Reporter:
|
95
|
+
def start(self, population_size):
|
96
|
+
if verbose >= 1:
|
97
|
+
console.print(f"> Creating {population_size - 1} variations of the initial prompt")
|
98
|
+
console.print("│")
|
99
|
+
|
100
|
+
def start_fresh_prompts(self, num_fresh_starts):
|
101
|
+
if verbose >= 1:
|
102
|
+
console.print(f"│ Generating {num_fresh_starts} fresh prompts based on the task description.")
|
103
|
+
|
104
|
+
def success_fresh_prompts(self, num_fresh_starts):
|
105
|
+
if verbose >= 1:
|
106
|
+
console.print(Text("│ ").append(Text(f"Successfully generated {num_fresh_starts} fresh prompts based on the task description.", style="dim green")))
|
107
|
+
console.print("│")
|
108
|
+
|
109
|
+
def failed_fresh_prompts(self, num_fresh_starts, error):
|
110
|
+
if verbose >= 1:
|
111
|
+
console.print(Text("│ ").append(Text(f"Failed to generate fresh prompts from LLM: {error}", style="dim red")))
|
112
|
+
console.print("│")
|
113
|
+
|
114
|
+
def start_variations(self, num_variations):
|
115
|
+
if verbose >= 1:
|
116
|
+
console.print(f"│ Generating {num_variations} variations of the initial prompt.")
|
117
|
+
|
118
|
+
def success_variations(self, num_variations):
|
119
|
+
if verbose >= 1:
|
120
|
+
console.print(Text(f"│ Successfully generated {num_variations - 1} variations of the initial prompt).", style="dim green"))
|
121
|
+
console.print("│")
|
122
|
+
|
123
|
+
def failed_variations(self, num_variations, error):
|
124
|
+
if verbose >= 1:
|
125
|
+
console.print(Text(f"│ Failed to generate {num_variations - 1} variations of the initial prompt: {error}", style="dim red"))
|
126
|
+
console.print("│")
|
127
|
+
|
128
|
+
def end(self, population_prompts: List[chat_prompt.ChatPrompt]):
|
129
|
+
if verbose >= 1:
|
130
|
+
console.print(f"│ Successfully initialized population with {len(population_prompts)} prompts.")
|
131
|
+
console.print("")
|
132
|
+
|
133
|
+
|
134
|
+
try:
|
135
|
+
yield Reporter()
|
136
|
+
finally:
|
137
|
+
pass
|
138
|
+
|
139
|
+
@contextmanager
|
140
|
+
def baseline_performance(verbose: int = 1):
|
141
|
+
"""Context manager to display messages during an evaluation phase."""
|
142
|
+
# Entry point
|
143
|
+
if verbose >= 1:
|
144
|
+
console.print(Text("> First we will establish the baseline performance."))
|
145
|
+
|
146
|
+
# Create a simple object with a method to set the score
|
147
|
+
class Reporter:
|
148
|
+
def set_score(self, s):
|
149
|
+
if verbose >= 1:
|
150
|
+
console.print(Text(f"\r Baseline score was: {s:.4f}.\n", style="green"))
|
151
|
+
|
152
|
+
# Use our log suppression context manager and yield the reporter
|
153
|
+
with suppress_opik_logs():
|
154
|
+
with convert_tqdm_to_rich(" Evaluation", verbose=verbose):
|
155
|
+
try:
|
156
|
+
yield Reporter()
|
157
|
+
finally:
|
158
|
+
pass
|
159
|
+
|
160
|
+
@contextmanager
|
161
|
+
def evaluate_initial_population(verbose: int = 1):
|
162
|
+
"""Context manager to display messages during an evaluation phase."""
|
163
|
+
# Entry point
|
164
|
+
if verbose >= 1:
|
165
|
+
console.print(Text("> Let's now evaluate the initial population"))
|
166
|
+
|
167
|
+
# Create a simple object with a method to set the score
|
168
|
+
class Reporter:
|
169
|
+
def set_score(self, index, score, baseline_score):
|
170
|
+
if verbose >= 1:
|
171
|
+
if score >= baseline_score:
|
172
|
+
console.print(Text(f"\r Prompt {index+1} score was: {score}.", style="green"))
|
173
|
+
else:
|
174
|
+
console.print(Text(f"\r Prompt {index+1} score was: {score}.", style="dim"))
|
175
|
+
|
176
|
+
# Use our log suppression context manager and yield the reporter
|
177
|
+
with suppress_opik_logs():
|
178
|
+
with convert_tqdm_to_rich("│ Evaluation", verbose=verbose):
|
179
|
+
try:
|
180
|
+
yield Reporter()
|
181
|
+
finally:
|
182
|
+
if verbose >= 1:
|
183
|
+
console.print("")
|
184
|
+
|
185
|
+
@contextmanager
|
186
|
+
def start_evolutionary_algo(verbose: int = 1):
|
187
|
+
"""Context manager to display messages during an evolutionary algorithm phase."""
|
188
|
+
# Entry point
|
189
|
+
if verbose >= 1:
|
190
|
+
console.print(Text("> Starting evolutionary algorithm optimization"))
|
191
|
+
|
192
|
+
# Create a simple object with a method to set the score
|
193
|
+
class Reporter:
|
194
|
+
def start_gen(self, gen, num_gens):
|
195
|
+
if verbose >= 1:
|
196
|
+
console.print(Text(f"│ Starting generation {gen} of {num_gens}"))
|
197
|
+
|
198
|
+
def restart_population(self, restart_generation_nb):
|
199
|
+
if verbose >= 1:
|
200
|
+
console.print(Text(f"│ Re-creating the population as we have not made progress in {restart_generation_nb} generations."))
|
201
|
+
|
202
|
+
def performing_crossover(self):
|
203
|
+
if verbose >= 1:
|
204
|
+
console.print(Text("│ Performing crossover - Combining multiple prompts into a new one."))
|
205
|
+
|
206
|
+
def performing_mutation(self):
|
207
|
+
if verbose >= 1:
|
208
|
+
console.print(Text("│ Performing mutation - Altering prompts to improve their performance."))
|
209
|
+
|
210
|
+
def performing_evaluation(self, num_prompts: int):
|
211
|
+
if verbose >= 1:
|
212
|
+
console.print(Text(f"│ Performing evaluation - Assessing {num_prompts} prompts' performance."))
|
213
|
+
|
214
|
+
def performed_evaluation(self, prompt_idx: int, score: float):
|
215
|
+
if verbose >= 1:
|
216
|
+
console.print(Text(f"│ Performed evaluation for prompt {prompt_idx} - Score: {score:.4f}.", style="dim"))
|
217
|
+
|
218
|
+
# Use our log suppression context manager and yield the reporter
|
219
|
+
with suppress_opik_logs():
|
220
|
+
with convert_tqdm_to_rich("│ Evaluation", verbose=verbose):
|
221
|
+
try:
|
222
|
+
yield Reporter()
|
223
|
+
finally:
|
224
|
+
if verbose >= 1:
|
225
|
+
console.print("")
|
226
|
+
|
227
|
+
def display_error(error_message, verbose: int = 1):
|
228
|
+
if verbose >= 1:
|
229
|
+
console.print(Text("│ ").append(Text(error_message, style="dim red")))
|
230
|
+
|
231
|
+
def display_success(message, verbose: int = 1):
|
232
|
+
if verbose >= 1:
|
233
|
+
console.print(Text("│ ").append(Text(message, style="dim green")))
|
234
|
+
|
235
|
+
def display_message(message, verbose: int = 1):
|
236
|
+
if verbose >= 1:
|
237
|
+
console.print(Text("│ ").append(Text(message, style="dim")))
|
238
|
+
|
239
|
+
def end_gen(generation_idx, best_gen_score, initial_primary_score, verbose: int = 1):
|
240
|
+
if verbose >= 1:
|
241
|
+
if best_gen_score >= initial_primary_score:
|
242
|
+
console.print(Text(f"│ Generation {generation_idx} completed. Found a new prompt with a score of {best_gen_score:.4f}.", style="green"))
|
243
|
+
else:
|
244
|
+
console.print(Text(f"│ Generation {generation_idx} completed. No improvement in this generation."))
|
245
|
+
|
246
|
+
console.print("│")
|