MilanM commited on
Commit
2acc39f
·
verified ·
1 Parent(s): 0485f71

Upload table_processor_v3.py

Browse files
Files changed (1) hide show
  1. table_processor_v3.py +1839 -0
table_processor_v3.py ADDED
@@ -0,0 +1,1839 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /// script
2
+ # [tool.marimo.display]
3
+ # custom_css = ["./custom_header_font.css"]
4
+ # ///
5
+
6
+ import marimo
7
+
8
+ __generated_with = "0.13.14"
9
+ app = marimo.App(width="full", app_title="watsonx-SheetProcessor-9000")
10
+
11
+ with app.setup:
12
+ # Initialization code that runs before all other cells
13
+ import marimo as mo
14
+ from typing import Dict, Optional, List, Union, Any
15
+ from ibm_watsonx_ai import APIClient, Credentials
16
+ from pathlib import Path
17
+ import pandas as pd
18
+ import mimetypes
19
+ import requests
20
+ import zipfile
21
+ import tempfile
22
+ import certifi
23
+ import base64
24
+ import polars
25
+ import nltk
26
+ import time
27
+ import json
28
+ import glob
29
+ import ast
30
+ import os
31
+ import io
32
+ import re
33
+
34
+ from dotenv import load_dotenv
35
+ load_dotenv()
36
+
37
+ def get_iam_token(api_key):
38
+ return requests.post(
39
+ "https://iam.cloud.ibm.com/identity/token",
40
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
41
+ data={
42
+ "grant_type": "urn:ibm:params:oauth:grant-type:apikey",
43
+ "apikey": api_key,
44
+ },
45
+ verify=certifi.where(),
46
+ ).json()["access_token"]
47
+
48
+ def setup_task_credentials(client):
49
+ # Get existing task credentials
50
+ existing_credentials = client.task_credentials.get_details()
51
+
52
+ # Delete existing credentials if any
53
+ if "resources" in existing_credentials and existing_credentials["resources"]:
54
+ for cred in existing_credentials["resources"]:
55
+ cred_id = client.task_credentials.get_id(cred)
56
+ client.task_credentials.delete(cred_id)
57
+
58
+ # Store new credentials
59
+ return client.task_credentials.store()
60
+
61
+
62
+ @app.cell
63
+ def _():
64
+ ### Loads baked in credentials if present
65
+ from baked_in_credentials.creds import credentials
66
+ from base_variables import wx_regions, wx_platform_url
67
+
68
+ ### Loads helper functions
69
+ from helper_functions.helper_functions import (
70
+ get_cred_value,
71
+ get_model_selection_table,
72
+ filter_models_by_function,
73
+ _enforce_model_selection,
74
+ update_max_tokens_limit,
75
+ get_key_by_value,
76
+ markdown_spacing,
77
+ load_file_dataframe,
78
+ create_parameter_table,
79
+ convert_table_to_json_docs,
80
+ get_cell_values,
81
+ wrap_with_spaces,
82
+ load_templates,
83
+ )
84
+
85
+ ### Table Related Helper Functions
86
+ from helper_functions.table_helper_functions import (
87
+ append_llm_results_to_dataframe,
88
+ display_answers_as_markdown,
89
+ display_answers_stacked,
90
+ process_with_llm,
91
+ process_prompt_lineage
92
+ )
93
+
94
+ return (
95
+ append_llm_results_to_dataframe,
96
+ convert_table_to_json_docs,
97
+ create_parameter_table,
98
+ credentials,
99
+ get_cell_values,
100
+ get_cred_value,
101
+ get_key_by_value,
102
+ get_model_selection_table,
103
+ load_file_dataframe,
104
+ load_templates,
105
+ process_prompt_lineage,
106
+ process_with_llm,
107
+ wrap_with_spaces,
108
+ wx_regions,
109
+ )
110
+
111
+
112
+ @app.cell
113
+ def _(credentials, get_cred_value, wx_regions):
114
+ # Create a form with multiple elements
115
+ baked_in_creds = credentials
116
+ client_instantiation_form = (
117
+ mo.md(
118
+ """
119
+ ###**watsonx.ai credentials:**
120
+
121
+ {wx_region}
122
+
123
+ {wx_api_key}
124
+
125
+ {project_id}
126
+
127
+ {space_id}
128
+ """
129
+ )
130
+ .batch(
131
+ wx_region=mo.ui.dropdown(
132
+ wx_regions,
133
+ label="Select your watsonx.ai region:",
134
+ value=get_cred_value("region", creds_var_name="baked_in_creds"),
135
+ searchable=True,
136
+ ),
137
+ wx_api_key=mo.ui.text(
138
+ placeholder="Add your IBM Cloud api-key...",
139
+ label="IBM Cloud Api-key:",
140
+ kind="password",
141
+ value=get_cred_value("api_key", creds_var_name="baked_in_creds"),
142
+ ),
143
+ project_id=mo.ui.text(
144
+ placeholder="Add your watsonx.ai project_id...",
145
+ label="Project_ID:",
146
+ kind="text",
147
+ value=get_cred_value("project_id", creds_var_name="baked_in_creds"),
148
+ ),
149
+ space_id=mo.ui.text(
150
+ placeholder="Add your watsonx.ai space_id...",
151
+ label="Space_ID:",
152
+ kind="text",
153
+ value=get_cred_value("space_id", creds_var_name="baked_in_creds"),
154
+ ),
155
+ )
156
+ .form(show_clear_button=True, bordered=False)
157
+ )
158
+
159
+ return (client_instantiation_form,)
160
+
161
+
162
+ @app.cell
163
+ def _(activate_prompt_lineage):
164
+ if activate_prompt_lineage.value:
165
+ switch_between_lineage_modes = mo.ui.switch(
166
+ label="**Switch** between placeholder input variables and row data"
167
+ )
168
+ include_input_column_names = mo.ui.checkbox()
169
+ include_llm_parameters = mo.ui.checkbox()
170
+ else:
171
+ switch_between_lineage_modes = mo.ui.switch(
172
+ label="**Switch** between placeholder input variables and row data",
173
+ disabled=True,
174
+ )
175
+ include_input_column_names = mo.ui.checkbox(disabled=True, label="*Inactive*")
176
+ include_llm_parameters = mo.ui.checkbox(disabled=True, label="*Inactive*")
177
+ return (
178
+ include_input_column_names,
179
+ include_llm_parameters,
180
+ switch_between_lineage_modes,
181
+ )
182
+
183
+
184
+ @app.cell
185
+ def _(activate_prompt_lineage, switch_between_lineage_modes):
186
+ if switch_between_lineage_modes.value:
187
+ current_mode = mo.md(">**Current Mode:** Saves Prompts with data used")
188
+ elif activate_prompt_lineage.value == False:
189
+ current_mode = mo.md(">**Current Mode:** Inactive")
190
+ else:
191
+ current_mode = mo.md(
192
+ ">**Current Mode:** Saves Prompts with input variable placeholders"
193
+ )
194
+ return (current_mode,)
195
+
196
+
197
+ @app.cell
198
+ def _():
199
+ activate_prompt_lineage = mo.ui.checkbox()
200
+ return (activate_prompt_lineage,)
201
+
202
+
203
+ @app.cell
204
+ def _(
205
+ activate_prompt_lineage,
206
+ current_mode,
207
+ include_input_column_names,
208
+ include_llm_parameters,
209
+ switch_between_lineage_modes,
210
+ ):
211
+ prompt_lineage_form = mo.md(
212
+ f"""
213
+ ###**Prompt Lineage**
214
+
215
+ **Activate Prompt Lineage:** {activate_prompt_lineage}
216
+
217
+ > If you activate prompt lineage, based on the selected options alongisde your results column a second column with the suffix *"___prompt_lineage"* with the prompt data will be included.
218
+
219
+ {switch_between_lineage_modes}
220
+
221
+ {current_mode}
222
+
223
+ **Include LLM parameters:** {include_llm_parameters}
224
+
225
+ **Include Input Variable Names:** {include_input_column_names}
226
+ """
227
+ )
228
+ return (prompt_lineage_form,)
229
+
230
+
231
+ @app.cell
232
+ def _(
233
+ activate_prompt_lineage,
234
+ include_input_column_names,
235
+ include_llm_parameters,
236
+ switch_between_lineage_modes,
237
+ ):
238
+ lineage_options = {
239
+ "activate_prompt_lineage": activate_prompt_lineage.value,
240
+ "switch_between_lineage_modes": (
241
+ switch_between_lineage_modes.value
242
+ if activate_prompt_lineage.value
243
+ else None
244
+ ),
245
+ "include_llm_parameters": include_llm_parameters.value,
246
+ "include_input_column_names": include_input_column_names.value,
247
+ }
248
+ return (lineage_options,)
249
+
250
+
251
+ @app.cell
252
+ def _():
253
+ mo.md(
254
+ r"""
255
+ #watsonx.ai LLM Table Processor - Marimo Notebook
256
+
257
+ #### This marimo notebook can be used to process tabular data by running a prompt on each selected row with specified columns and input variables. Each row will be prompted with the data within its columns and the outputs will be added as a new column to the end of the table. Optionally one can also toggle on prompt lineage which allows you to save data about the LLM used, input prompts with or without data baked in, etc.
258
+
259
+ #### This tool can be used for an unlimited number of use-cases, in practice it has found popularity as a way to perform grammar/tone/requirements validation for RFP requirements tables, but also to generate synthetic data based on scenario/requirements specifications and many other uses.
260
+
261
+ >>> Keep in mind that all data and states are stored in memory, refreashing the page or restarting the application will loose all progress unless you have downloaded/cloned this repository and made the adjustments to create a backend to store it.
262
+ <br>
263
+ /// attention | Warning!
264
+ While I have been asked whether it can be used to generate responses like in the case of RFP requirements tables, i do not recommend **EVER** using an LLM for generating text in such a way for any task that requires factual validity or cannot accomodate the risk of faulty text sneaking past. Most individuals state that they will evaluate all of the outputs, but the very motivation behind this kind of LLM use is to avoid doing this type of work. <br><br>The likelihood of an individual manually evaluating and correcting hundreds of rows of data without an error sneaking past is very low, not to mention that it would most likely take more time than to write the text yourself. <br>**Large Language Models do not understand the context, interpretation, background information or intent in the way that humans expect that they do.**
265
+ ///
266
+ <br>
267
+
268
+ /// admonition
269
+ Created by ***Milan Mrdenovic*** [[email protected]] for IBM Ecosystem Client Engineering, NCEE - ***version 3.1*** - *01.06.2025* <br>
270
+ Initial concept co-created with ***Inga Tomasdottir*** [[email protected]].
271
+ ///
272
+
273
+
274
+ >Licensed under apache 2.0, users hold full accountability for any use or modification of the code or application.
275
+ ><br>This asset is part of a set meant to support IBMers, IBM Partners, Clients in developing understanding of how to better utilize various watsonx features and generative AI as a subject matter.
276
+
277
+ <br>
278
+ """
279
+ )
280
+ return
281
+
282
+
283
+ @app.cell
284
+ def _():
285
+ mo.md(
286
+ r"""
287
+ <br>
288
+ ###Part 1 - Client Setup, File Upload, Column and Row Selection
289
+ """
290
+ )
291
+ return
292
+
293
+
294
+ @app.cell
295
+ def _(client_section):
296
+ ui_accordion_section_1 = mo.accordion(
297
+ {"Section 1: **watsonx.ai Credentials**": client_section}
298
+ )
299
+ ui_accordion_section_1
300
+ return
301
+
302
+
303
+ @app.cell
304
+ def _(why_important):
305
+ # Markdown Documentation
306
+ file_loader_md="""
307
+ /// admonition
308
+ **Drag and Drop or Click to Load in a file *(supported formats .csv, .xlsx or .json)*.**<br>
309
+ If you load an excel file with multiple sheets you will see a dropdown menu to select your active sheet.<br><br>
310
+ The checkbox **activate header adjustment** lets you move *(downwards)* which row will be used for the headers, be very careful with this and only use it in cases where the column names row is not the first one in the file.<br><br> When this is active the number selector - **Header Row index** controls which one it is with 0 being the first one.
311
+ ///
312
+ """
313
+
314
+ column_and_row_selector_md="""
315
+ /// admonition
316
+ **In this section you need to select the rows which you want to process with an LLM, alongside the columns that will become input variables.**
317
+ The columns that are detected based on the header of the table *(or in the case of JSON the key names)* are turned into a multi-select list, **if you don't select any, all are made available to you**.<br><br>
318
+ If you want **to select every row** in the document, **click the selection button in the header of the table**, that selects all rows in the visible table then scroll down to the end of the table page, in the bottom left you will see a **blue Select all <number of rows> button**, clicking it will select all rows in the loaded document.<br><br>
319
+ The buttons to the right of this text control the look of the table - namely column text wrapping and the justification of the text. **Bare in mind - Changing it WILL reset your selections**, so do it in the beginning if you plan on changing it. The table has additional features, so feel free to check the other buttons built into the widget.
320
+ ///
321
+ """
322
+
323
+ llm_setup_md="""
324
+ /// admonition
325
+ **Select an LLM from the list of available models in your watsonx.ai instance/region and set up the parameters.**<br>
326
+ **Unless you are very used to working with LLMs and prompt engineering, it's best to only adjust the maximum and minimum output tokens.**<br>
327
+ If you switch the decoding to sampling you will get additional input widgets for temperature, top_p, top_k and seed definition.<br>
328
+ **Stopping sequences** should either be:<br>
329
+ **1)** The default EOS token for your model *(most models have their tokenizers listed on huggingface [https://huggingface.co])*<br>
330
+ **2)** A custom word/trigger you want to use *(e.g. stopping when a specific word is generated)*<br>
331
+ **3)** Or just leave the default ones provided here *(the default ones are the EoS tokens for llama3 and mistral models)*<br><br>
332
+ **Section 5 - Prompt Lineage** Allows you to save an additional column with the prompt setup, llm parameters, etc. and has its own simple instruction set so it does not have a detailed description area like this one.<br><br>
333
+ *p.s. ***EOS token*** stands for "End of String" and is used during training to nudge the model into knowing when to stop generating outputs.*
334
+ ///
335
+ """
336
+
337
+ prompt_and_variable_setup_md=f"""
338
+ /// admonition
339
+ **Use the scroll bar to choose how many prompts you want to have *(max. 5)* each will be available to you to prompt with the same model and parameters but different prompt setups.**<br>
340
+ If you duplicate the repository you will be able to set up different baked in starter templates, the templates are to be stored as .txt files in a folder called *```prompt_templates```* in the directory. Each folder and the files inside it will be loaded into the dropdown selectors. This way you can customize it with pre-made tasks or added llm syntax.
341
+
342
+ {why_important}
343
+
344
+ On a practical note, most providers publish guides on the tags that comprise their templates, like these:<br>
345
+ [https://www.llama.com/docs/model-cards-and-prompt-formats/llama3_3/]<br>
346
+ [https://www.ibm.com/granite/docs/models/granite/]<br>
347
+ [https://docs.mistral.ai/guides/tokenization/]
348
+ ///
349
+ """
350
+
351
+ additional_variables_setup_md="""
352
+ /// admonition
353
+ **In this section you can create up to 5 custom variables that will be appended to all rows in the table when prompting.**<br>
354
+ Use it in the case of needing to add large sections of text that doesn't change that you'd like to reuse in different prompts, for example:<br>**1)** system prompts<br>**2)** guardrail definitions<br>**3)** rules or directives<br> or other data elements that do not change between prompts.<br><br>
355
+ Don't forget to **turn on the checkbox** in the tab if you want to use it, otherwise they won't be applied.
356
+ ///
357
+ """
358
+
359
+
360
+ prompt_stack_md="""
361
+ /// admonition
362
+ **The app will generate a column_name input and prompt editor box for the number of prompts you selected int he previous steps.**<br><br>
363
+ Add an appropriate column name into the widget, as this will be the name of the column with the generated responses and edit your prompt with the appropriate syntax and instructions.
364
+ To define where your column data goes, add the column name with {} surrounding them, for example *```{description}```* will paste in the value of the cell in the column description for each row that is being prompted.
365
+
366
+ You don't need to include all of the rows, nor all of the rows you provided before, but unless you specify them like this they will not be used. The same goes for any additional variables you defined, just specify their name.
367
+ > If any input variables had malformed names the app will automatically rename them to all lowercase letters with any spaces replaced by _. If you are unsure of any of the names, you can click the box at the bottom of the app to show the input variable sidebar. This will close all of the app sections, but it does not loose you progress. It's just a minor glitch from how marimo handles states but does not affect your progress.
368
+ ///
369
+ """
370
+
371
+ results_stack_md="""
372
+ /// admonition
373
+ **Pressing each button will batch prompt *(10 rows per call)* the LLM and prompt in that slot. Then it will append it with the column name defined in the prompt setup tab to the end of the table.**<br><br>
374
+ If you have turned on the prompt lineage feature another column will be added to the right with the prompt lineage outputs that you selected.<br>
375
+ If you make changes to the prompt template, but do not change the column name in that slot it will overwrite the column. Changing the column name will generate a new prompt.<br>
376
+ > Once you have finished with your work and want to save your results, do the same as in the beginning to **select all the rows by clicking the header checkbox and then selecting all rows in the bottom left.<br>After that click the download button on the right side to export as a json, csv or parquet file**.
377
+ ///
378
+ """
379
+ return (
380
+ additional_variables_setup_md,
381
+ column_and_row_selector_md,
382
+ file_loader_md,
383
+ llm_setup_md,
384
+ prompt_and_variable_setup_md,
385
+ prompt_stack_md,
386
+ results_stack_md,
387
+ )
388
+
389
+
390
+ @app.cell
391
+ def _():
392
+
393
+ why_important_md = mo.md("""/// attention |
394
+ Unless one uses a chatapi *(which this app does not to provide the most flexibility)* you have to provide correct syntax for different LLMs. <br>These tags are used in training *(alongside the previously mentioned EOS token)* to nudge the model into understanding what part of the input is a user instruction, system prompt, function call, etc. LLMs are by their very nature volatile, there is no way actual to build in features like *"tool calling"* or *"safety guardrails"*, all that we can do is introduce these artificial tags into the fine-tuning data, provide tens/hundreds of thousands of tailored examples of the desired result and then hope that the model *"picks up the hint"* if you will. If you've seen tags like *<|image_start|>* or *[INST]* in documentation or prompt templates, that's what they are.
395
+
396
+ This is not properly communicated in the public discourse, because a lot of people would not feel comfortable with using these technologies if they did not feel like the rigid and safe mechanistic rules of software logic that they are used to since the dawn of computer science. It also doesn't bode well for people who benefit from both the hype and fear surrounding ideas of AGI and living machines, which by very definition of how the technology works... LLMs cannot be. So they don't mention it. But that's a topic for another time, maybe over some coffee.
397
+
398
+ Without these tags, models will at best peform subpar and at worst completely break, generating loops of sentences, garbage text or in some cases hallucinating so bad that they might output some rather creepy nonsense. All that LLM chat api's do is programatically enclose your text with the tags before delivering it to the LLM as a system of messages.
399
+ ///""")
400
+
401
+ why_important_accordion = mo.accordion(
402
+ {"### Why is this important?": why_important_md}
403
+ )
404
+
405
+ why_important = mo.callout(why_important_accordion, kind="warn")
406
+ return (why_important,)
407
+
408
+
409
+ @app.cell
410
+ def _(file_loader_md, file_uploader):
411
+ ui_accordion_section_2 = mo.accordion(
412
+ {"Section 2: **File Loading**": mo.hstack([mo.md(file_loader_md),file_uploader], justify="space-around", align="center", widths=[0.55,0.4])}
413
+ )
414
+ ui_accordion_section_2
415
+ return
416
+
417
+
418
+ @app.cell
419
+ def _(column_and_rows_sector):
420
+ ui_accordion_section_3 = mo.accordion(
421
+ {"Section 3: **Column and Row Selection**": column_and_rows_sector}
422
+ )
423
+ ui_accordion_section_3
424
+ return
425
+
426
+
427
+ @app.cell
428
+ def _():
429
+ mo.md(
430
+ r"""
431
+ <br>
432
+ ###Part 2 - Model and Prompt Lineage Setup
433
+ """
434
+ )
435
+ return
436
+
437
+
438
+ @app.cell
439
+ def _(llm_setup_with_docs):
440
+ ui_accordion_section_4 = mo.accordion({"Section 4: **Model Setup**": llm_setup_with_docs})
441
+ ui_accordion_section_4
442
+ return
443
+
444
+
445
+ @app.cell
446
+ def _(prompt_lineage_form):
447
+ ui_accordion_section_5 = mo.accordion({"Section 5: **Prompt Lineage** - *[Optional]*": prompt_lineage_form})
448
+ ui_accordion_section_5
449
+ return
450
+
451
+
452
+ @app.cell
453
+ def _():
454
+ mo.md(
455
+ r"""
456
+ <br>
457
+ ###Part 3 - Prompt Templates and Results Table
458
+ """
459
+ )
460
+ return
461
+
462
+
463
+ @app.cell
464
+ def _(prompt_setup_stack):
465
+ ui_accordion_section_6 = mo.accordion(
466
+ {
467
+ "Section 6: **Choose the Number of Prompts and Templates**": prompt_setup_stack
468
+ }
469
+ )
470
+ ui_accordion_section_6
471
+ return
472
+
473
+
474
+ @app.cell
475
+ def _(additional_variables_stack):
476
+ ui_accordion_section_6_1 = mo.accordion(
477
+ {"Section 6.1: **Additional Variables** *(Optional)*": additional_variables_stack}
478
+ )
479
+ ui_accordion_section_6_1
480
+ return
481
+
482
+
483
+ @app.cell
484
+ def _(prompt_stack):
485
+ ui_accordion_section_7 = mo.accordion({"Section 7: **Prompt Setup**": prompt_stack})
486
+ ui_accordion_section_7
487
+ return
488
+
489
+
490
+ @app.cell
491
+ def _(client_instantiation_form):
492
+ client_setup = client_instantiation_form.value or None
493
+
494
+ ### Extract Credential Variables:
495
+ if client_setup:
496
+ wx_url = client_setup["wx_region"] if client_setup["wx_region"] else "EU"
497
+ wx_api_key = (
498
+ client_setup["wx_api_key"].strip() if client_setup["wx_api_key"] else None
499
+ )
500
+ os.environ["WATSONX_APIKEY"] = wx_api_key or ""
501
+
502
+ project_id = (
503
+ client_setup["project_id"].strip() if client_setup["project_id"] else None
504
+ )
505
+ space_id = (
506
+ client_setup["space_id"].strip() if client_setup["space_id"] else None
507
+ )
508
+ else:
509
+ os.environ["WATSONX_APIKEY"] = ""
510
+ project_id = space_id = wx_api_key = wx_url = None
511
+ return client_setup, project_id, space_id, wx_api_key, wx_url
512
+
513
+
514
+ @app.cell
515
+ def client_instantiation(
516
+ client_setup,
517
+ project_id,
518
+ space_id,
519
+ wx_api_key,
520
+ wx_url,
521
+ ):
522
+ ### Instantiate the watsonx.ai client
523
+ if client_setup:
524
+ try:
525
+ wx_credentials = Credentials(url=wx_url, api_key=wx_api_key)
526
+ project_client = (
527
+ APIClient(credentials=wx_credentials, project_id=project_id)
528
+ if project_id
529
+ else None
530
+ )
531
+ deployment_client = (
532
+ APIClient(credentials=wx_credentials, space_id=space_id)
533
+ if space_id
534
+ else None
535
+ )
536
+ instantiation_success = True
537
+ instantiation_error = None
538
+ except Exception as e:
539
+ instantiation_success = False
540
+ instantiation_error = str(e)
541
+ wx_credentials = project_client = deployment_client = None
542
+ else:
543
+ wx_credentials = project_client = deployment_client = None
544
+ instantiation_success = None
545
+ instantiation_error = None
546
+
547
+ return (
548
+ deployment_client,
549
+ instantiation_error,
550
+ instantiation_success,
551
+ project_client,
552
+ )
553
+
554
+
555
+ @app.cell
556
+ def _(client_callout_kind, client_instantiation_form, client_status):
557
+ client_callout = mo.callout(client_status, kind=client_callout_kind)
558
+
559
+ client_section = mo.hstack(
560
+ [client_instantiation_form, client_callout],
561
+ align="center",
562
+ justify="space-around",
563
+ )
564
+ return (client_section,)
565
+
566
+
567
+ @app.cell
568
+ def _(
569
+ client_key,
570
+ client_options,
571
+ client_selector,
572
+ client_setup,
573
+ get_key_by_value,
574
+ instantiation_error,
575
+ instantiation_success,
576
+ wrap_with_spaces,
577
+ ):
578
+ active_client_name = (
579
+ get_key_by_value(client_options, client_key)
580
+ if client_key
581
+ else "No Client" or "Project Client"
582
+ )
583
+
584
+ if client_setup:
585
+ if instantiation_success:
586
+ client_status = mo.md(
587
+ f"### ✅ Client Instantiation Successful ✅\n\n"
588
+ f"{client_selector}\n\n"
589
+ f"**Active Client:**{wrap_with_spaces(active_client_name, prefix_spaces=5)}"
590
+ )
591
+ client_callout_kind = "success"
592
+ else:
593
+ client_status = mo.md(
594
+ f"### ❌ Client Instantiation Failed\n**Error:** {instantiation_error}\n\nCheck your region selection and credentials"
595
+ )
596
+ client_callout_kind = "danger"
597
+ else:
598
+ client_status = mo.md(
599
+ f"### Client Instantiation Status will turn Green When Ready\n\n"
600
+ f"{client_selector}\n\n"
601
+ f"**Active Client:**{wrap_with_spaces(active_client_name, prefix_spaces=5)}"
602
+ )
603
+ client_callout_kind = "neutral"
604
+
605
+ return client_callout_kind, client_status
606
+
607
+
608
+ @app.cell
609
+ def _(deployment_client, project_client):
610
+ if project_client is not None and deployment_client is not None:
611
+ client_options = {
612
+ "Project Client": project_client,
613
+ "Deployment Client": deployment_client,
614
+ }
615
+
616
+ elif project_client is not None:
617
+ client_options = {"Project Client": project_client}
618
+
619
+ elif deployment_client is not None:
620
+ client_options = {"Deployment Client": deployment_client}
621
+
622
+ else:
623
+ client_options = {"No Client": "Instantiate a Client"}
624
+
625
+ default_client = next(iter(client_options))
626
+ client_selector = mo.ui.dropdown(
627
+ client_options, value=default_client, label="**Switch your active client:**"
628
+ )
629
+ return client_options, client_selector
630
+
631
+
632
+ @app.cell
633
+ def _(client_selector):
634
+ client_key = client_selector.value
635
+ if client_key == "Instantiate a Client":
636
+ client = None
637
+ else:
638
+ client = client_key
639
+ return client, client_key
640
+
641
+
642
+ @app.cell
643
+ def _():
644
+ file = mo.ui.file(
645
+ kind="area",
646
+ filetypes=[".xlsx", ".xls", ".csv", ".json"],
647
+ label="Upload a file (CSV, Excel, or JSON)",
648
+ )
649
+ return (file,)
650
+
651
+
652
+ @app.cell
653
+ def _(file):
654
+ def get_file_extension(filename):
655
+ """Get the file extension from a filename."""
656
+ if not filename:
657
+ return None
658
+ return os.path.splitext(filename)[1].lower()
659
+
660
+ # Initialize variables
661
+ sheet_names = []
662
+ file_extension = None
663
+ excel_data = None
664
+
665
+ if file.contents():
666
+ file_extension = get_file_extension(file.name())
667
+
668
+ # Handle Excel files to get sheet names
669
+ if file_extension in [".xlsx", ".xls"]:
670
+ # For Excel files
671
+ excel_data = io.BytesIO(file.contents())
672
+ # Get sheet names without loading the data yet
673
+ sheet_names = pd.ExcelFile(excel_data).sheet_names
674
+
675
+ # Create sheet selector for Excel files
676
+ if file_extension in [".xlsx", ".xls"] and sheet_names:
677
+ sheet_selector = mo.ui.dropdown(
678
+ options=sheet_names,
679
+ value=sheet_names[0],
680
+ label="Select Sheet:",
681
+ full_width=False,
682
+ searchable=True,
683
+ )
684
+ else:
685
+ sheet_selector = None
686
+ return excel_data, file_extension, sheet_selector
687
+
688
+
689
+ @app.cell
690
+ def _(table_dataframe_raw):
691
+ if not table_dataframe_raw.empty:
692
+ apply_header_readjustment = mo.ui.checkbox(label="Activate Header Adjustment")
693
+ else:
694
+ apply_header_readjustment = None
695
+ return (apply_header_readjustment,)
696
+
697
+
698
+ @app.cell
699
+ def _():
700
+ show_variable_sidebar = mo.ui.checkbox(
701
+ label="Show Sidebar with Input Variables", value=False
702
+ )
703
+ return (show_variable_sidebar,)
704
+
705
+
706
+ @app.cell
707
+ def _(apply_header_readjustment, sheet_selector, table_dataframe_raw):
708
+ if not table_dataframe_raw.empty:
709
+ if apply_header_readjustment.value:
710
+ header_row = mo.ui.number(
711
+ label="Header Row index:",
712
+ value=0,
713
+ start=0,
714
+ stop=len(table_dataframe_raw) + 1,
715
+ )
716
+ else:
717
+ header_row = mo.ui.number(
718
+ label="Header Row index:", value=0, start=0, stop=0
719
+ )
720
+ else:
721
+ header_row = None
722
+
723
+ sheet_and_column_controls = mo.hstack(
724
+ [sheet_selector, apply_header_readjustment, header_row],
725
+ gap=2,
726
+ justify="space-around",
727
+ )
728
+ return header_row, sheet_and_column_controls
729
+
730
+
731
+ @app.cell
732
+ def _(file, sheet_and_column_controls):
733
+ if file.name():
734
+ name_printout = mo.md(f"**{file.name()}**")
735
+ else:
736
+ name_printout = mo.md(f"No File Uploaded")
737
+
738
+ file_uploader = mo.vstack(
739
+ [file, name_printout, sheet_and_column_controls],
740
+ justify="space-around",
741
+ align="center",
742
+ )
743
+ return (file_uploader,)
744
+
745
+
746
+ @app.cell
747
+ def _():
748
+ wrap_columns = mo.ui.switch(label="**Wrap column text in table**")
749
+ return (wrap_columns,)
750
+
751
+
752
+ @app.cell
753
+ def _():
754
+ justify_options = ["left","center","right"]
755
+ justify_columns = mo.ui.dropdown(label="**Justify column text to:**", options=justify_options, value="left")
756
+ return (justify_columns,)
757
+
758
+
759
+ @app.cell
760
+ def _(column_and_row_selector_md, justify_columns, wrap_columns):
761
+ table_controls_stack = mo.vstack([wrap_columns, justify_columns], justify="start", gap=1)
762
+ table_controls_stack_and_docs = mo.hstack([mo.md(column_and_row_selector_md),table_controls_stack], justify="space-around", align="center", widths=[0.55,0.25])
763
+ return (table_controls_stack_and_docs,)
764
+
765
+
766
+ @app.cell
767
+ def _(
768
+ justify_columns,
769
+ set_column_justify_state,
770
+ table_column_names,
771
+ table_dataframe,
772
+ ):
773
+ if not table_dataframe.empty:
774
+ justify_column_value = justify_columns.value
775
+ center_column_text = {col: justify_column_value for col in table_column_names}
776
+ set_column_justify_state(center_column_text)
777
+ else:
778
+ center_column_text = None
779
+ set_column_justify_state(center_column_text)
780
+ return
781
+
782
+
783
+ @app.cell
784
+ def _(
785
+ set_column_wrapping_state,
786
+ table_column_names,
787
+ table_dataframe,
788
+ wrap_columns,
789
+ ):
790
+ if not table_dataframe.empty and wrap_columns.value:
791
+ set_column_wrapping_state(table_column_names)
792
+ else:
793
+ set_column_wrapping_state(None)
794
+ return
795
+
796
+
797
+ @app.cell
798
+ def _():
799
+ get_column_justify_state, set_column_justify_state = mo.state(None)
800
+ return get_column_justify_state, set_column_justify_state
801
+
802
+
803
+ @app.cell
804
+ def _():
805
+ get_column_wrapping_state, set_column_wrapping_state = mo.state(None)
806
+ return get_column_wrapping_state, set_column_wrapping_state
807
+
808
+
809
+ @app.function
810
+ def apply_header_row(table_dataframe, header_row_value):
811
+ """
812
+ Set a specific row as the header for a dataframe.
813
+
814
+ Parameters:
815
+ -----------
816
+ table_dataframe : pd.DataFrame
817
+ The dataframe to modify
818
+ header_row_value : int
819
+ Row index to use as header (0-based)
820
+
821
+ Returns:
822
+ --------
823
+ tuple : (pd.DataFrame, list)
824
+ Modified dataframe with new headers and list of column names
825
+ """
826
+ if not table_dataframe.empty:
827
+ # Convert header row to column names
828
+ new_header = table_dataframe.iloc[header_row_value]
829
+ # Create new dataframe without the header row
830
+ new_df = table_dataframe.iloc[header_row_value + 1 :]
831
+ # Set the new header
832
+ new_df.columns = new_header
833
+ # Get list of column names
834
+ column_names = list(new_df.columns)
835
+ return new_df, column_names
836
+ return table_dataframe, []
837
+
838
+
839
+ @app.cell
840
+ def _(excel_data, file, file_extension, load_file_dataframe, sheet_selector):
841
+ table_dataframe_raw, table_column_names_raw = load_file_dataframe(
842
+ file=file,
843
+ file_extension=file_extension,
844
+ sheet_selector=sheet_selector,
845
+ excel_data=excel_data,
846
+ )
847
+ return table_column_names_raw, table_dataframe_raw
848
+
849
+
850
+ @app.cell
851
+ def _(
852
+ apply_header_readjustment,
853
+ header_row,
854
+ table_column_names_raw,
855
+ table_dataframe_raw,
856
+ ):
857
+ if apply_header_readjustment is not None and apply_header_readjustment.value:
858
+ table_dataframe, table_column_names = apply_header_row(
859
+ table_dataframe_raw,
860
+ header_row_value=header_row.value if header_row is not None else 0,
861
+ )
862
+ else:
863
+ table_dataframe, table_column_names = (
864
+ table_dataframe_raw,
865
+ table_column_names_raw,
866
+ )
867
+ return table_column_names, table_dataframe
868
+
869
+
870
+ @app.cell
871
+ def _(get_column_justify_state, get_column_wrapping_state, table_dataframe):
872
+ if not table_dataframe.empty:
873
+ # center_column_text = {col: "left" for col in table_column_names}
874
+ table = mo.ui.table(
875
+ table_dataframe,
876
+ show_column_summaries=False,
877
+ initial_selection=[0],
878
+ wrapped_columns=get_column_wrapping_state(),
879
+ text_justify_columns=get_column_justify_state(),
880
+ label="**Select the Rows to Process**",
881
+ )
882
+ else:
883
+ table = mo.md("""###**No data available in the uploaded file**""").batch(
884
+ upload_a_file=mo.ui.table(
885
+ data=pd.DataFrame({"Upload File": "No File"}, index=[0])
886
+ )
887
+ )
888
+ return (table,)
889
+
890
+
891
+ @app.cell
892
+ def _(create_parameter_table, table_column_names, table_dataframe):
893
+ if not table_dataframe.empty:
894
+ column_selector = create_parameter_table(
895
+ label="Select the Columns to Process",
896
+ input_list=table_column_names,
897
+ column_name="Column Options",
898
+ selection_type="multi-cell",
899
+ text_justify="center",
900
+ )
901
+ else:
902
+ column_selector = create_parameter_table(
903
+ label="Select the Columns to Process",
904
+ input_list=[],
905
+ column_name="Column Options",
906
+ selection_type="multi-cell",
907
+ text_justify="center",
908
+ )
909
+
910
+ return (column_selector,)
911
+
912
+
913
+ @app.cell
914
+ def _(column_selector, get_cell_values):
915
+ columns_to_use = get_cell_values(column_selector)
916
+ return (columns_to_use,)
917
+
918
+
919
+ @app.cell
920
+ def _(column_selector, table, table_controls_stack_and_docs):
921
+ column_and_rows_sector = mo.vstack(
922
+ [table_controls_stack_and_docs, column_selector, table], align="stretch", justify="start"
923
+ )
924
+ return (column_and_rows_sector,)
925
+
926
+
927
+ @app.cell
928
+ def _(
929
+ columns_to_use,
930
+ convert_table_to_json_docs,
931
+ set_additional_variable_state,
932
+ table,
933
+ ):
934
+ if table.value is not None:
935
+ selected_rows = table.value
936
+ fields_to_process_raw = convert_table_to_json_docs(
937
+ selected_rows, selected_columns=columns_to_use
938
+ )
939
+ set_additional_variable_state(fields_to_process_raw)
940
+ else:
941
+ selected_rows = pd.DataFrame([])
942
+ fields_to_process_raw = []
943
+ return fields_to_process_raw, selected_rows
944
+
945
+
946
+ @app.cell
947
+ def _(client, get_model_selection_table):
948
+ if client is not None:
949
+ model_selector, resources, model_id_list = get_model_selection_table(
950
+ client=client,
951
+ model_type="chat",
952
+ filter_functionality=None,
953
+ selection_mode="single-cell",
954
+ )
955
+ else:
956
+ model_selector = get_model_selection_table(
957
+ client=None, selection_mode="single-cell"
958
+ )
959
+ resources = model_id_list = None
960
+ return (model_selector,)
961
+
962
+
963
+ @app.cell
964
+ def _():
965
+ from ibm_watsonx_ai.foundation_models import ModelInference
966
+ from ibm_watsonx_ai.metanames import GenTextParamsMetaNames as GenParams
967
+
968
+ # Create a form with multiple elements
969
+ llm_parameters = mo.md(
970
+ """
971
+ ###**LLM parameters:**
972
+
973
+ {decoding_method}
974
+
975
+ {repetition_penalty}
976
+
977
+ {min_tokens}
978
+
979
+ {max_tokens}
980
+
981
+ {stop_sequences}
982
+ """
983
+ ).batch(
984
+ ### Preset Options
985
+ decoding_method=mo.ui.dropdown(
986
+ options=["greedy", "sample"], value="greedy", label="Decoding Method:"
987
+ ),
988
+ min_tokens=mo.ui.number(start=1, stop=1, label="Minimum Output Tokens:"),
989
+ max_tokens=mo.ui.number(
990
+ start=1, stop=8096, value=500, label="Maximum Output Tokens:"
991
+ ),
992
+ repetition_penalty=mo.ui.number(
993
+ start=1.0, stop=2.0, step=0.01, label="Repetition Penalty:"
994
+ ),
995
+ stop_sequences=mo.ui.text(
996
+ label="Stopping Sequences:",
997
+ value="['<|end_of_text|>','</s>']",
998
+ placeholder="List of Strings, e.g. ['<|end_of_text|>','</s>']",
999
+ full_width=False,
1000
+ ),
1001
+ )
1002
+ return GenParams, ModelInference, llm_parameters
1003
+
1004
+
1005
+ @app.cell
1006
+ def _(llm_setup_md):
1007
+ llm_setup_docs = mo.hstack([mo.md(llm_setup_md)], justify="start", widths=[1.0])
1008
+ return (llm_setup_docs,)
1009
+
1010
+
1011
+ @app.cell
1012
+ def _(llm_setup, llm_setup_docs):
1013
+ llm_setup_with_docs = mo.vstack([llm_setup_docs,llm_setup], gap=1)
1014
+ return (llm_setup_with_docs,)
1015
+
1016
+
1017
+ @app.cell
1018
+ def _(llm_param_stack, model_selector):
1019
+ llm_setup = mo.hstack(
1020
+ [model_selector, llm_param_stack], align="center", justify="space-around", widths=[0.4,0.3]
1021
+ )
1022
+ return (llm_setup,)
1023
+
1024
+
1025
+ @app.cell
1026
+ def _(llm_parameters, llm_sampling_parameters):
1027
+ llm_param_stack = mo.vstack([llm_parameters, llm_sampling_parameters], gap=2)
1028
+ return (llm_param_stack,)
1029
+
1030
+
1031
+ @app.cell
1032
+ def _(llm_parameters):
1033
+ if llm_parameters.value and llm_parameters.value["decoding_method"] == "sample":
1034
+ llm_sampling_parameters = (
1035
+ mo.md('''
1036
+ **Sampling parameters:**
1037
+
1038
+ {temperature}
1039
+
1040
+ {top_p}
1041
+ {top_k}
1042
+
1043
+ {seed}
1044
+ ''')
1045
+ .batch(
1046
+ ### Preset Options
1047
+ temperature = mo.ui.number(start=0, stop=2, step=0.01, value=0.7, label="Temperature:"),
1048
+ top_p = mo.ui.number(start=0, stop=1, value=1, label="Top P:"),
1049
+ top_k = mo.ui.number(start=1, stop=100, step=1, label="Top K:"),
1050
+ seed = mo.ui.number(start=0 , label="Seed:"),
1051
+ )
1052
+ )
1053
+ else:
1054
+ llm_sampling_parameters = (
1055
+ mo.md('''
1056
+ ''')
1057
+ .batch(
1058
+ )
1059
+ )
1060
+ return (llm_sampling_parameters,)
1061
+
1062
+
1063
+ @app.cell
1064
+ def _(model_selector):
1065
+ if model_selector.value:
1066
+ selected_model = model_selector.value[0]["value"]
1067
+ else:
1068
+ selected_model = "mistralai/mistral-large"
1069
+ return (selected_model,)
1070
+
1071
+
1072
+ @app.cell
1073
+ def _(
1074
+ GenParams,
1075
+ ModelInference,
1076
+ client,
1077
+ llm_parameters,
1078
+ llm_sampling_parameters,
1079
+ selected_model,
1080
+ ):
1081
+ if llm_parameters.value:
1082
+ params = {
1083
+ GenParams.DECODING_METHOD: llm_parameters.value["decoding_method"],
1084
+ GenParams.MAX_NEW_TOKENS: llm_parameters.value["max_tokens"],
1085
+ GenParams.MIN_NEW_TOKENS: llm_parameters.value["min_tokens"],
1086
+ GenParams.REPETITION_PENALTY: llm_parameters.value["repetition_penalty"],
1087
+ GenParams.STOP_SEQUENCES: ast.literal_eval(
1088
+ llm_parameters.value["stop_sequences"]
1089
+ ),
1090
+ GenParams.RETURN_OPTIONS: {
1091
+ "input_text": False,
1092
+ "generated_tokens": False,
1093
+ "input_tokens": True,
1094
+ "token_logprobs": False,
1095
+ },
1096
+ }
1097
+ if llm_sampling_parameters.value:
1098
+ if 'temperature' in llm_sampling_parameters.value:
1099
+ params["temperature"] = llm_sampling_parameters.value['temperature']
1100
+ if 'top_p' in llm_sampling_parameters.value:
1101
+ params["top_p"] = llm_sampling_parameters.value['top_p']
1102
+ if 'top_k' in llm_sampling_parameters.value:
1103
+ params["top_k"] = llm_sampling_parameters.value['top_k']
1104
+ if 'seed' in llm_sampling_parameters.value and llm_sampling_parameters.value['seed'] != 0:
1105
+ params["random_seed"] = llm_sampling_parameters.value['seed']
1106
+ else:
1107
+ params = {}
1108
+
1109
+ if client:
1110
+ inf_model = ModelInference(
1111
+ api_client=client, model_id=selected_model, params=params
1112
+ )
1113
+ else:
1114
+ inf_model = None
1115
+ return inf_model, params
1116
+
1117
+
1118
+ @app.cell
1119
+ def _():
1120
+ prompt_template_folders = get_subfolder_paths("./prompt_templates", depth=1)
1121
+ prompt_template_model_paths = mo.ui.dropdown(
1122
+ options=prompt_template_folders,
1123
+ label="Prompt Template Variants *(Select Based on your Model)*",
1124
+ )
1125
+ return (prompt_template_model_paths,)
1126
+
1127
+
1128
+ @app.cell
1129
+ def _(load_templates, prompt_template_model_paths):
1130
+ template_folder = str(prompt_template_model_paths.value)
1131
+ templates = load_templates(template_folder)
1132
+ return (templates,)
1133
+
1134
+
1135
+ @app.cell
1136
+ def _():
1137
+ prompt_number_slider = mo.ui.slider(
1138
+ start=1, stop=5, value=1, step=1, label="Prompt Templates", show_value=True
1139
+ )
1140
+ return (prompt_number_slider,)
1141
+
1142
+
1143
+ @app.cell
1144
+ def _(prompt_number_slider, prompt_template_model_paths):
1145
+ prompt_mechanics_stack = mo.vstack(
1146
+ [prompt_number_slider, prompt_template_model_paths], align="start"
1147
+ )
1148
+ return (prompt_mechanics_stack,)
1149
+
1150
+
1151
+ @app.cell
1152
+ def _(prompt_and_variable_setup_md):
1153
+ prompt_setup_docs = mo.hstack([mo.md(prompt_and_variable_setup_md)], justify="start", widths=[1.0])
1154
+ return (prompt_setup_docs,)
1155
+
1156
+
1157
+ @app.cell
1158
+ def _(prompt_mechanics_stack, template_selector_stack):
1159
+ prompt_setup_stack_widgets = mo.hstack(
1160
+ [prompt_mechanics_stack, template_selector_stack], justify="space-around"
1161
+ )
1162
+ return (prompt_setup_stack_widgets,)
1163
+
1164
+
1165
+ @app.cell
1166
+ def _(prompt_setup_docs, prompt_setup_stack_widgets):
1167
+ prompt_setup_stack = mo.vstack(
1168
+ [prompt_setup_docs, prompt_setup_stack_widgets], gap=1
1169
+ )
1170
+ return (prompt_setup_stack,)
1171
+
1172
+
1173
+ @app.cell
1174
+ def _():
1175
+ get_pt_state, set_pt_state = mo.state(None)
1176
+ return get_pt_state, set_pt_state
1177
+
1178
+
1179
+ @app.function
1180
+ def get_subfolder_paths(base_path, depth=1):
1181
+ """Lists subfolder paths up to specified depth.
1182
+
1183
+ Args:
1184
+ base_path: Directory to search in
1185
+ depth: Subdirectory levels to traverse (default: 1)
1186
+
1187
+ Returns:
1188
+ Dict with folder names as keys and paths as values
1189
+ """
1190
+ import os
1191
+
1192
+ result = {}
1193
+ if depth <= 0 or not os.path.isdir(base_path):
1194
+ return result
1195
+
1196
+ for entry in os.scandir(base_path):
1197
+ if entry.is_dir():
1198
+ result[entry.name] = entry.path
1199
+ if depth > 1:
1200
+ # Recursively get subdirectories
1201
+ subfolders = get_subfolder_paths(entry.path, depth - 1)
1202
+ # Update result with subfolders
1203
+ result.update(subfolders)
1204
+
1205
+ return result
1206
+
1207
+
1208
+ @app.cell
1209
+ def _(prompt_number_slider, set_pt_state, templates):
1210
+ def update_state_from_templates(value):
1211
+ # Get current values from all template selectors
1212
+ template_values = [selector.value for selector in template_selectors]
1213
+
1214
+ # Update the state with the list of values
1215
+ set_pt_state(template_values)
1216
+
1217
+ # Return the list of values
1218
+ return template_values
1219
+
1220
+ def create_template_dropdowns(num=1):
1221
+ return mo.ui.dropdown(
1222
+ options=templates,
1223
+ label=f"**Select Prompt {num} Template with Syntax:**",
1224
+ value="empty",
1225
+ on_change=update_state_from_templates,
1226
+ )
1227
+
1228
+ template_selectors = [
1229
+ create_template_dropdowns(i) for i in range(1, prompt_number_slider.value + 1)
1230
+ ]
1231
+ template_selector_stack = mo.vstack(template_selectors, align="start")
1232
+ return (template_selector_stack,)
1233
+
1234
+
1235
+ @app.cell
1236
+ def _(fields_to_process):
1237
+ if fields_to_process:
1238
+ variable_names = [
1239
+ key
1240
+ for key in fields_to_process[0].keys()
1241
+ if key != "_marimo_row_id" and key != "upload_a_file"
1242
+ ]
1243
+ else:
1244
+ variable_names = []
1245
+ return (variable_names,)
1246
+
1247
+
1248
+ @app.cell
1249
+ def _(prompt_number_slider):
1250
+ def is_disabled(button_num):
1251
+ return prompt_number_slider.value < button_num
1252
+
1253
+ return (is_disabled,)
1254
+
1255
+
1256
+ @app.function
1257
+ def create_stats_from_variables(variable_names):
1258
+ """
1259
+ Creates mo.stat objects for each variable name in the list.
1260
+ Labels are formatted as "Column Variable Tag: {index+1}"
1261
+ Values display the variable name itself.
1262
+ """
1263
+ stats = []
1264
+
1265
+ for i, var_name in enumerate(variable_names):
1266
+ stat = mo.stat(
1267
+ value=f"{{{var_name}}}",
1268
+ label=f"Column Variable Tag {i+1}",
1269
+ bordered=True,
1270
+ )
1271
+ stats.append(stat)
1272
+
1273
+ return mo.sidebar(stats, width="375")
1274
+
1275
+
1276
+ @app.cell
1277
+ def _(additional_variables_setup_md):
1278
+ additional_variable_docs = mo.hstack([mo.md(additional_variables_setup_md)], justify="start", widths=[1.0])
1279
+ return (additional_variable_docs,)
1280
+
1281
+
1282
+ @app.cell
1283
+ def _():
1284
+ get_additional_variable_state, set_additional_variable_state = mo.state(None)
1285
+ return get_additional_variable_state, set_additional_variable_state
1286
+
1287
+
1288
+ @app.cell
1289
+ def _(
1290
+ add_vars_stack,
1291
+ additional_variable_docs,
1292
+ additional_variable_mechanics_stack,
1293
+ ):
1294
+ additional_variables_stack = mo.vstack([additional_variable_docs, additional_variable_mechanics_stack, add_vars_stack], justify="start")
1295
+ return (additional_variables_stack,)
1296
+
1297
+
1298
+ @app.cell
1299
+ def _(additional_variables_raw):
1300
+ add_vars = [mo.vstack([add_var[0], add_var[1]]) for add_var in additional_variables_raw]
1301
+ add_vars_stack = mo.vstack(add_vars, heights="equal", align="stretch", justify="space-around", gap=3)
1302
+ return (add_vars_stack,)
1303
+
1304
+
1305
+ @app.cell
1306
+ def _():
1307
+ use_additional_variables = mo.ui.checkbox(label="**Use additional variable boxes** *(E.g. adding large chunks of text to all prompts, etc.)*", value=True)
1308
+ return (use_additional_variables,)
1309
+
1310
+
1311
+ @app.cell
1312
+ def _(additional_variable_slider, use_additional_variables):
1313
+ additional_variable_mechanics_stack = mo.hstack([additional_variable_slider, use_additional_variables], align="start")
1314
+ return (additional_variable_mechanics_stack,)
1315
+
1316
+
1317
+ @app.cell
1318
+ def _():
1319
+ additional_variable_slider = mo.ui.slider(start=1, stop=5, value=1, step=1, label="Additional Variables", show_value=True)
1320
+ return (additional_variable_slider,)
1321
+
1322
+
1323
+ @app.function
1324
+ def add_additional_variables(fields_to_process, use_additional_variables, additional_variables_raw, create_copy=True):
1325
+ """
1326
+ Add additional variables to each dict in fields_to_process if conditions are met.
1327
+
1328
+ Args:
1329
+ fields_to_process: List of dictionaries to process
1330
+ use_additional_variables: Object with boolean value property
1331
+ additional_variables_raw: List of [key, value] pairs
1332
+ create_copy: If True, creates a new copy instead of modifying the original
1333
+
1334
+ Returns:
1335
+ Updated fields_to_process or a new copy with updates
1336
+ """
1337
+ if not fields_to_process:
1338
+ return fields_to_process
1339
+ if not (use_additional_variables.value and additional_variables_raw):
1340
+ return fields_to_process
1341
+
1342
+ result = [field.copy() for field in fields_to_process] if create_copy else fields_to_process
1343
+
1344
+ additional_vars = {item[0].value: item[1].value for item in additional_variables_raw
1345
+ if item[0].value and item[1].value != ""}
1346
+ if additional_vars:
1347
+ for field in result:
1348
+ field.update(additional_vars)
1349
+
1350
+ return result
1351
+
1352
+
1353
+ @app.cell
1354
+ def _(additional_variable_slider, get_additional_variable_state):
1355
+ def create_additional_variable_input(num=1):
1356
+ # Wrap in a function to create reactive dependency on state
1357
+ def get_template_content(num=1):
1358
+ content = get_additional_variable_state()[num-1] if get_additional_variable_state() and num-1 < len(get_additional_variable_state()) else "empty"
1359
+ return content
1360
+ additional_variable_column_label = mo.ui.text(label=f"**Additional Variable {num}:**", value=f"additional_var_{num}")
1361
+ additional_variable_editor = mo.ui.code_editor(language="python", min_height=300, theme="dark")
1362
+ return [
1363
+ additional_variable_column_label,
1364
+ additional_variable_editor
1365
+ ]
1366
+ additional_variables_raw = [create_additional_variable_input(i) for i in range(1, additional_variable_slider.value+1)]
1367
+ return (additional_variables_raw,)
1368
+
1369
+
1370
+ @app.cell
1371
+ def _(
1372
+ additional_variables_raw,
1373
+ fields_to_process_raw,
1374
+ use_additional_variables,
1375
+ ):
1376
+ if fields_to_process_raw and use_additional_variables.value and additional_variables_raw:
1377
+ fields_to_process = add_additional_variables(fields_to_process_raw, use_additional_variables, additional_variables_raw)
1378
+ else:
1379
+ fields_to_process = fields_to_process_raw
1380
+ return (fields_to_process,)
1381
+
1382
+
1383
+ @app.cell
1384
+ def _(variable_names):
1385
+ if variable_names:
1386
+ prompt_input_variables_sidebar = create_stats_from_variables(variable_names)
1387
+ else:
1388
+ prompt_input_variables_sidebar = None
1389
+ return (prompt_input_variables_sidebar,)
1390
+
1391
+
1392
+ @app.cell
1393
+ def _(get_pt_state, prompt_number_slider):
1394
+ def create_prompt(num=1):
1395
+ # Wrap in a function to create reactive dependency on state
1396
+ def get_template_content(num=1):
1397
+ content = (
1398
+ get_pt_state()[num - 1]
1399
+ if get_pt_state() and num - 1 < len(get_pt_state())
1400
+ else "empty"
1401
+ )
1402
+ return content
1403
+
1404
+ prompt_column_label = mo.ui.text(
1405
+ label=f"**Add output column name for Prompt {num}:**",
1406
+ value=f"Added Column {num}",
1407
+ )
1408
+ prompt_editor = mo.ui.code_editor(
1409
+ value=get_template_content(num),
1410
+ language="python",
1411
+ min_height=300,
1412
+ theme="dark",
1413
+ )
1414
+
1415
+ return [prompt_column_label, prompt_editor]
1416
+
1417
+ prompts_raw = [create_prompt(i) for i in range(1, prompt_number_slider.value + 1)]
1418
+ return (prompts_raw,)
1419
+
1420
+
1421
+ @app.cell
1422
+ def _(is_disabled):
1423
+ run_prompt_button_1 = mo.ui.run_button(
1424
+ label="Run Prompt 1", disabled=is_disabled(1)
1425
+ )
1426
+ return (run_prompt_button_1,)
1427
+
1428
+
1429
+ @app.cell
1430
+ def _(is_disabled):
1431
+ run_prompt_button_2 = mo.ui.run_button(
1432
+ label="Run Prompt 2", disabled=is_disabled(2)
1433
+ )
1434
+ return (run_prompt_button_2,)
1435
+
1436
+
1437
+ @app.cell
1438
+ def _(is_disabled):
1439
+ run_prompt_button_3 = mo.ui.run_button(
1440
+ label="Run Prompt 3", disabled=is_disabled(3)
1441
+ )
1442
+ return (run_prompt_button_3,)
1443
+
1444
+
1445
+ @app.cell
1446
+ def _(is_disabled):
1447
+ run_prompt_button_4 = mo.ui.run_button(
1448
+ label="Run Prompt 4", disabled=is_disabled(4)
1449
+ )
1450
+ return (run_prompt_button_4,)
1451
+
1452
+
1453
+ @app.cell
1454
+ def _(is_disabled):
1455
+ run_prompt_button_5 = mo.ui.run_button(
1456
+ label="Run Prompt 5", disabled=is_disabled(5)
1457
+ )
1458
+ return (run_prompt_button_5,)
1459
+
1460
+
1461
+ @app.cell
1462
+ def _(
1463
+ activate_prompt_lineage,
1464
+ append_llm_results_to_dataframe,
1465
+ fields_to_process,
1466
+ inf_model,
1467
+ lineage_options,
1468
+ params,
1469
+ process_prompt_lineage,
1470
+ process_with_llm,
1471
+ prompts_raw,
1472
+ results_table,
1473
+ run_prompt_button_1,
1474
+ selected_model,
1475
+ selected_rows,
1476
+ ):
1477
+ if run_prompt_button_1.value:
1478
+ pt_1_prompt = prompts_raw[0][1].value
1479
+ pt_1_column = prompts_raw[0][0].value
1480
+ prompt_answers_1 = process_with_llm(
1481
+ fields_to_process=fields_to_process,
1482
+ prompt_template=pt_1_prompt,
1483
+ inf_model=inf_model,
1484
+ params=params,
1485
+ batch_size=10,
1486
+ )
1487
+ append_llm_results_to_dataframe(
1488
+ target_dataframe=results_table,
1489
+ llm_results=prompt_answers_1,
1490
+ selection_table=selected_rows,
1491
+ column_name=pt_1_column,
1492
+ )
1493
+ if activate_prompt_lineage.value:
1494
+ prompt_lineage_1 = process_prompt_lineage(
1495
+ lineage_options=lineage_options,
1496
+ selected_model=selected_model,
1497
+ params=params,
1498
+ fields_to_process=fields_to_process,
1499
+ prompt_template=pt_1_prompt
1500
+ )
1501
+ append_llm_results_to_dataframe(
1502
+ target_dataframe=results_table,
1503
+ llm_results=prompt_lineage_1,
1504
+ selection_table=selected_rows,
1505
+ column_name=f"{pt_1_column}___prompt_lineage",
1506
+ )
1507
+ else:
1508
+ pt_1_prompt = pt_1_column = prompt_lineage_1 = None
1509
+ prompt_answers_1 = []
1510
+ return
1511
+
1512
+
1513
+ @app.cell
1514
+ def _(
1515
+ activate_prompt_lineage,
1516
+ append_llm_results_to_dataframe,
1517
+ fields_to_process,
1518
+ inf_model,
1519
+ lineage_options,
1520
+ params,
1521
+ process_prompt_lineage,
1522
+ process_with_llm,
1523
+ prompts_raw,
1524
+ results_table,
1525
+ run_prompt_button_2,
1526
+ selected_model,
1527
+ selected_rows,
1528
+ ):
1529
+ if run_prompt_button_2.value:
1530
+ pt_2_prompt = prompts_raw[1][1].value
1531
+ pt_2_column = prompts_raw[1][0].value
1532
+ prompt_answers_2 = process_with_llm(
1533
+ fields_to_process=fields_to_process,
1534
+ prompt_template=pt_2_prompt,
1535
+ inf_model=inf_model,
1536
+ params=params,
1537
+ batch_size=10,
1538
+ )
1539
+ append_llm_results_to_dataframe(
1540
+ target_dataframe=results_table,
1541
+ llm_results=prompt_answers_2,
1542
+ selection_table=selected_rows,
1543
+ column_name=pt_2_column,
1544
+ )
1545
+ if activate_prompt_lineage.value:
1546
+ prompt_lineage_2 = process_prompt_lineage(
1547
+ lineage_options=lineage_options,
1548
+ selected_model=selected_model,
1549
+ params=params,
1550
+ fields_to_process=fields_to_process,
1551
+ prompt_template=pt_2_prompt
1552
+ )
1553
+ append_llm_results_to_dataframe(
1554
+ target_dataframe=results_table,
1555
+ llm_results=prompt_lineage_2,
1556
+ selection_table=selected_rows,
1557
+ column_name=f"{pt_2_column}___prompt_lineage",
1558
+ )
1559
+ else:
1560
+ pt_2_prompt = pt_2_column = prompt_lineage_2 = None
1561
+ prompt_answers_2 = []
1562
+ return
1563
+
1564
+
1565
+ @app.cell
1566
+ def _(
1567
+ activate_prompt_lineage,
1568
+ append_llm_results_to_dataframe,
1569
+ fields_to_process,
1570
+ inf_model,
1571
+ lineage_options,
1572
+ params,
1573
+ process_prompt_lineage,
1574
+ process_with_llm,
1575
+ prompts_raw,
1576
+ results_table,
1577
+ run_prompt_button_3,
1578
+ selected_model,
1579
+ selected_rows,
1580
+ ):
1581
+ if run_prompt_button_3.value:
1582
+ pt_3_prompt = prompts_raw[2][1].value
1583
+ pt_3_column = prompts_raw[2][0].value
1584
+ prompt_answers_3 = process_with_llm(
1585
+ fields_to_process=fields_to_process,
1586
+ prompt_template=pt_3_prompt,
1587
+ inf_model=inf_model,
1588
+ params=params,
1589
+ batch_size=10,
1590
+ )
1591
+ append_llm_results_to_dataframe(
1592
+ target_dataframe=results_table,
1593
+ llm_results=prompt_answers_3,
1594
+ selection_table=selected_rows,
1595
+ column_name=pt_3_column,
1596
+ )
1597
+ if activate_prompt_lineage.value:
1598
+ prompt_lineage_3 = process_prompt_lineage(
1599
+ lineage_options=lineage_options,
1600
+ selected_model=selected_model,
1601
+ params=params,
1602
+ fields_to_process=fields_to_process,
1603
+ prompt_template=pt_3_prompt
1604
+ )
1605
+ append_llm_results_to_dataframe(
1606
+ target_dataframe=results_table,
1607
+ llm_results=prompt_lineage_3,
1608
+ selection_table=selected_rows,
1609
+ column_name=f"{pt_3_column}___prompt_lineage",
1610
+ )
1611
+ else:
1612
+ pt_3_prompt = pt_3_column = prompt_lineage_3 = None
1613
+ prompt_answers_3 = []
1614
+ return
1615
+
1616
+
1617
+ @app.cell
1618
+ def _(
1619
+ activate_prompt_lineage,
1620
+ append_llm_results_to_dataframe,
1621
+ fields_to_process,
1622
+ inf_model,
1623
+ lineage_options,
1624
+ params,
1625
+ process_prompt_lineage,
1626
+ process_with_llm,
1627
+ prompts_raw,
1628
+ results_table,
1629
+ run_prompt_button_4,
1630
+ selected_model,
1631
+ selected_rows,
1632
+ ):
1633
+ if run_prompt_button_4.value:
1634
+ pt_4_prompt = prompts_raw[3][1].value
1635
+ pt_4_column = prompts_raw[3][0].value
1636
+ prompt_answers_4 = process_with_llm(
1637
+ fields_to_process=fields_to_process,
1638
+ prompt_template=pt_4_prompt,
1639
+ inf_model=inf_model,
1640
+ params=params,
1641
+ batch_size=10,
1642
+ )
1643
+ append_llm_results_to_dataframe(
1644
+ target_dataframe=results_table,
1645
+ llm_results=prompt_answers_4,
1646
+ selection_table=selected_rows,
1647
+ column_name=pt_4_column,
1648
+ )
1649
+ if activate_prompt_lineage.value:
1650
+ prompt_lineage_4 = process_prompt_lineage(
1651
+ lineage_options=lineage_options,
1652
+ selected_model=selected_model,
1653
+ params=params,
1654
+ fields_to_process=fields_to_process,
1655
+ prompt_template=pt_4_prompt
1656
+ )
1657
+ append_llm_results_to_dataframe(
1658
+ target_dataframe=results_table,
1659
+ llm_results=prompt_lineage_4,
1660
+ selection_table=selected_rows,
1661
+ column_name=f"{pt_4_column}___prompt_lineage",
1662
+ )
1663
+ else:
1664
+ pt_4_prompt = pt_4_column = prompt_lineage_4 = None
1665
+ prompt_answers_4 = []
1666
+ return
1667
+
1668
+
1669
+ @app.cell
1670
+ def _(
1671
+ activate_prompt_lineage,
1672
+ append_llm_results_to_dataframe,
1673
+ fields_to_process,
1674
+ inf_model,
1675
+ lineage_options,
1676
+ params,
1677
+ process_prompt_lineage,
1678
+ process_with_llm,
1679
+ prompts_raw,
1680
+ results_table,
1681
+ run_prompt_button_5,
1682
+ selected_model,
1683
+ selected_rows,
1684
+ ):
1685
+ if run_prompt_button_5.value:
1686
+ pt_5_prompt = prompts_raw[4][1].value
1687
+ pt_5_column = prompts_raw[4][0].value
1688
+ prompt_answers_5 = process_with_llm(
1689
+ fields_to_process=fields_to_process,
1690
+ prompt_template=pt_5_prompt,
1691
+ inf_model=inf_model,
1692
+ params=params,
1693
+ batch_size=10,
1694
+ )
1695
+ append_llm_results_to_dataframe(
1696
+ target_dataframe=results_table,
1697
+ llm_results=prompt_answers_5,
1698
+ selection_table=selected_rows,
1699
+ column_name=pt_5_column,
1700
+ )
1701
+ if activate_prompt_lineage.value:
1702
+ prompt_lineage_5 = process_prompt_lineage(
1703
+ lineage_options=lineage_options,
1704
+ selected_model=selected_model,
1705
+ params=params,
1706
+ fields_to_process=fields_to_process,
1707
+ prompt_template=pt_5_prompt
1708
+ )
1709
+ append_llm_results_to_dataframe(
1710
+ target_dataframe=results_table,
1711
+ llm_results=prompt_lineage_5,
1712
+ selection_table=selected_rows,
1713
+ column_name=f"{pt_5_column}___prompt_lineage",
1714
+ )
1715
+ else:
1716
+ pt_5_prompt = pt_5_column = prompt_lineage_5 = None
1717
+ prompt_answers_5 = []
1718
+ return
1719
+
1720
+
1721
+ @app.cell
1722
+ def _(results_stack):
1723
+ ui_accordion_section_8 = mo.accordion(
1724
+ {"Section 8: **Run and View Results**": results_stack}
1725
+ )
1726
+ ui_accordion_section_8
1727
+ return
1728
+
1729
+
1730
+ @app.cell
1731
+ def _(show_variable_sidebar):
1732
+ show_variable_sidebar.right()
1733
+ return
1734
+
1735
+
1736
+ @app.cell
1737
+ def _(prompt_input_variables_sidebar, show_variable_sidebar):
1738
+ show_sidebar = show_variable_sidebar.value
1739
+ mo.vstack([show_sidebar is not False and prompt_input_variables_sidebar]).right()
1740
+ return
1741
+
1742
+
1743
+ @app.cell
1744
+ def _(table_dataframe):
1745
+ if not table_dataframe.empty:
1746
+ results_table = table_dataframe.copy()
1747
+ else:
1748
+ results_table = []
1749
+ return (results_table,)
1750
+
1751
+
1752
+ @app.cell
1753
+ def _(
1754
+ results_table,
1755
+ run_prompt_button_1,
1756
+ run_prompt_button_2,
1757
+ run_prompt_button_3,
1758
+ run_prompt_button_4,
1759
+ run_prompt_button_5,
1760
+ ):
1761
+ if (
1762
+ run_prompt_button_1.value
1763
+ or run_prompt_button_2.value
1764
+ or run_prompt_button_3.value
1765
+ or run_prompt_button_4.value
1766
+ or run_prompt_button_5.value
1767
+ ):
1768
+ results_table_view = mo.ui.table(results_table, show_column_summaries=False)
1769
+ else:
1770
+ results_table_view = mo.ui.table(results_table, show_column_summaries=False)
1771
+ return (results_table_view,)
1772
+
1773
+
1774
+ @app.cell
1775
+ def _(prompt_stack_md):
1776
+ prompt_stack_docs = mo.hstack([mo.md(prompt_stack_md)], justify="start", widths=[1.0])
1777
+ return (prompt_stack_docs,)
1778
+
1779
+
1780
+ @app.cell
1781
+ def _(results_stack_md):
1782
+ result_stack_docs = mo.hstack([mo.md(results_stack_md)], justify="start", widths=[1.0])
1783
+ return (result_stack_docs,)
1784
+
1785
+
1786
+ @app.cell
1787
+ def _(prompt_stack_docs, prompts_raw):
1788
+ prompts = [prompt_stack_docs]+[mo.vstack([prompt[0], prompt[1]]) for prompt in prompts_raw]
1789
+ prompt_stack = mo.vstack(
1790
+ prompts, heights="equal", align="stretch", justify="space-around", gap=3
1791
+ )
1792
+ return (prompt_stack,)
1793
+
1794
+
1795
+ @app.cell
1796
+ def _(
1797
+ result_stack_docs,
1798
+ results_table_view,
1799
+ run_prompt_button_1,
1800
+ run_prompt_button_2,
1801
+ run_prompt_button_3,
1802
+ run_prompt_button_4,
1803
+ run_prompt_button_5,
1804
+ ):
1805
+ run_button_stack = mo.hstack(
1806
+ [
1807
+ run_prompt_button_1,
1808
+ run_prompt_button_2,
1809
+ run_prompt_button_3,
1810
+ run_prompt_button_4,
1811
+ run_prompt_button_5,
1812
+ ]
1813
+ )
1814
+ results_stack = mo.vstack([result_stack_docs, run_button_stack, results_table_view])
1815
+ return (results_stack,)
1816
+
1817
+
1818
+ @app.cell
1819
+ def _():
1820
+ return
1821
+
1822
+
1823
+ @app.cell
1824
+ def _():
1825
+ return
1826
+
1827
+
1828
+ @app.cell
1829
+ def _():
1830
+ return
1831
+
1832
+
1833
+ @app.cell
1834
+ def _():
1835
+ return
1836
+
1837
+
1838
+ if __name__ == "__main__":
1839
+ app.run()