danidanidani commited on
Commit
1d3caec
·
1 Parent(s): 31692d5

Update src/backend/chatbot.py

Browse files
Files changed (1) hide show
  1. src/backend/chatbot.py +241 -119
src/backend/chatbot.py CHANGED
@@ -20,36 +20,70 @@ from llama_index.llms.llama_utils import (
20
  )
21
 
22
 
23
- # set model
24
- # model = 'openai'
25
- model = 'Llama2-7B_CPP'
26
-
27
  # set version
28
- st.session_state.demo_lite = True
29
-
30
- # initialize model
31
- if st.session_state.demo_lite == False:
32
- if model == 'Llama2-7B_CPP':
33
- model_path = "/Users/dheym/Library/CloudStorage/OneDrive-Personal/Documents/side_projects/GRDN/src/models/llama-2-7b-chat.Q4_K_M.gguf"
34
- llm = LlamaCPP(
35
- # You can pass in the URL to a GGML model to download it automatically
36
- #model_url=model_url,
37
- # optionally, you can set the path to a pre-downloaded model instead of model_url
38
- model_path=model_path,
39
- temperature=0.1,
40
- max_new_tokens=1000,
41
- # llama2 has a context window of 4096 tokens, but we set it lower to allow for some wiggle room
42
- context_window=3000,
43
- # kwargs to pass to __call__()
44
- generate_kwargs={},
45
- # kwargs to pass to __init__()
46
- # set to at least 1 to use GPU
47
- model_kwargs={"n_gpu_layers": 1},
48
- # transform inputs into Llama2 format
49
- messages_to_prompt=messages_to_prompt,
50
- completion_to_prompt=completion_to_prompt,
51
- verbose=True,
52
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  def parse_and_evaluate_text(text):
55
  # Find the indices of the opening and closing brackets
@@ -58,113 +92,161 @@ def parse_and_evaluate_text(text):
58
 
59
  if opening_bracket_index != -1 and closing_bracket_index != -1:
60
  # Extract the text within the brackets
61
- extracted_list = "[" + text[opening_bracket_index + 1: closing_bracket_index] + "]"
 
 
62
  # Return the evaluated text list
63
  return eval(extracted_list)
64
-
65
 
66
  else:
67
  print("Error with parsing plant list")
68
  return None
69
-
70
- def chat_response(template, prompt_text, model):
71
- if model == 'openai':
72
- chat = ChatOpenAI(temperature=.1)
 
73
  system_message_prompt = SystemMessagePromptTemplate.from_template(template)
74
- human_template="{text}"
75
  human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
76
- chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
77
- response = chat(chat_prompt.format_prompt(text= prompt_text).to_messages())
 
 
78
  return response
79
  # return response.content
80
- # elif model == 'Llama2-7B':
81
- # llm = Replicate(
82
- # model="a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5",
83
- # temperature=0.1,
84
- # #context_window=32,
85
- # top_p=0.9,
86
- # repetition_penalty=1.0,
87
- # max_tokens=2000,
88
- # #stop_sequences=["\n\n"],
89
- # )
90
- # input_prompt = template + prompt_text
91
- # print(input_prompt)
92
- # resp = llm.complete(input_prompt)
93
- # print(resp)
94
- # return resp
95
- elif model == 'Llama2-7B_CPP':
96
  response = llm.complete(template + prompt_text)
97
  return response.text
98
  else:
99
  print("Error with chatbot model")
100
  return None
101
 
102
- # get the plant list from user input
103
- def get_plant_list(input_plant_text):
104
- template="You are a helpful assistant that knows all about gardening and plants and python data structures."
105
- text = 'which of the elements of this list can be grown in a garden, [' + input_plant_text + ']? Return JUST a python list object containing the elements that can be grown in a garden. Do not include any other text or explanation.'
106
- plant_list_text = chat_response(template, text, model)
107
- plant_list = parse_and_evaluate_text(plant_list_text.content)
108
- print(plant_list)
109
- return plant_list
 
 
110
 
111
  # get plant care tips based on plant list
112
- def get_plant_care_tips(plant_list):
113
  plant_care_tips = ""
114
- template="You are a helpful assistant that knows all about gardening, plants, and companion planting."
115
- text = 'from this list of plants, [' + str(st.session_state.input_plants_raw) + '], generate a list of up to 10 plant care tips or interesting stories of plant compatibility for the plants in the list- maybe 1-2 per plant depending on what you know. Return just the plant care tips in HTML markdown format. Make sure to use ### for headers. Do not include any other text or explanation before or after the markdown. It must be in HTML markdown format.'
116
- plant_care_tips = chat_response(template, text, model)
117
- # check to see if response contains ### for headers
118
- if "###" not in plant_care_tips:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  print("Error with parsing plant care tips")
120
  # try again up to 5 times
121
  for i in range(5):
122
- print("Error with parsing plant care tips. Trying for attempt #" + str(i+1))
123
- plant_care_tips = chat_response(template, text, model)
 
 
124
  # check to see if response contains ### for headers
125
- if "###" not in plant_care_tips:
126
  continue
127
  else:
128
  break
129
- # remove any text before the first ### in the response
130
- plant_care_tips = "\n\n" + plant_care_tips[plant_care_tips.find("###"):]
131
-
 
 
 
 
 
 
 
132
  print(plant_care_tips)
133
  return plant_care_tips
134
 
 
135
  # get compatability matrix for companion planting
136
- def get_compatibility_matrix(plant_list):
137
  # Convert the compatibility matrix to a string
138
- with open('data/compatibilities_text.txt', 'r') as file:
139
  # Read the contents of the file
140
  compatibility_text = file.read()
141
  plant_comp_context = compatibility_text
142
- template="You are a helpful assistant that knows all about gardening, companion planting, and python data structures- specifically compatibility matrices."
143
- text = 'from this list of plants, [' + str(plant_list) + '], Return JUST a python array (with values separated by commas like this: [[0,1],[1,0]]\n\n ) for companion plant compatibility. Each row and column should represent plants, and the element of the array will contain a -1, 0, or 1 depending on if the relationship between plants is antagonists, neutral, or companions, respectively. You must refer to this knowledge base of information on plant compatibility: \n\n, ' + plant_comp_context + '\n\n A plant\'s compatibility with itself is always 0. Do not include any other text or explanation.'
144
- compatibility_mat = chat_response(template, text)
145
-
146
-
147
-
 
 
 
148
 
149
  # Find the indices of the opening and closing brackets
150
  opening_bracket_index = compatibility_mat.content.find("[[")
151
  closing_bracket_index = compatibility_mat.content.find("]]")
152
  if opening_bracket_index != -1 and closing_bracket_index != -1:
153
  # Extract the text within the brackets
154
- extracted_mat = "[" + compatibility_mat.content[opening_bracket_index + 1: closing_bracket_index] + "]]"
 
 
 
 
 
 
155
  # Return the evaluated mat
156
  # check to see if compatiblity matrix only contains values of -1, 0, or 1
157
- if eval(extracted_mat).count('0') + eval(extracted_mat).count('1') == len(eval(extracted_mat)):
 
 
158
  # continue
159
  pass
160
  else:
161
  # try again up to 5 times
162
  for i in range(5):
163
- print("Error with parsing plant compatibility matrix. Trying for attempt #" + str(i+1))
 
 
 
164
  print(extracted_mat)
165
- extracted_mat = chat_response(template + "remember, it MUST ONLY CONTAIN -1s, 0s, and 1s, like this structure: [[0,1],[1,0]]", text)
 
 
 
 
 
 
166
  # Extract the text within the brackets
167
- extracted_mat = "[" + compatibility_mat.content[opening_bracket_index + 1: closing_bracket_index] + "]]"
 
 
 
 
 
 
168
  print(extracted_mat)
169
  total_count = 0
170
  count_0 = extracted_mat.count("0")
@@ -172,22 +254,36 @@ def get_compatibility_matrix(plant_list):
172
  total_count = count_0 + count_1
173
  print("matrix count of -1, 0, 1: ", total_count)
174
  # if count euals the number of plants squared, then we have a valid matrix
175
- print("plant_list_len: ", len(plant_list)**2)
176
- if total_count == (len(plant_list))**2:
177
- #if count == eval(extracted_mat):
178
  print("success")
179
  return eval(extracted_mat)
180
  break
181
 
182
-
183
  else:
184
  print("Error with parsing plant compatibility matrix")
185
  # try again up to 5 times
186
  for i in range(5):
187
- print("Error with parsing plant compatibility matrix. Trying for attempt #" + str(i+1))
188
- extracted_mat = chat_response(template + "remember, it MUST ONLY CONTAIN -1s, 0s, and 1s, like this structure: [[0,1],[1,0]]", text)
 
 
 
 
 
 
 
 
 
189
  # Extract the text within the brackets
190
- extracted_mat = "[" + compatibility_mat.content[opening_bracket_index + 1: closing_bracket_index] + "]]"
 
 
 
 
 
 
191
  print(extracted_mat)
192
  total_count = 0
193
  count_0 = extracted_mat.count("0")
@@ -195,23 +291,26 @@ def get_compatibility_matrix(plant_list):
195
  total_count = count_0 + count_1
196
  print("matrix count of -1, 0, 1: ", total_count)
197
  # if count euals the number of plants squared, then we have a valid matrix
198
- print("plant_list_len: ", len(plant_list)**2)
199
- if total_count == (len(plant_list))**2:
200
- #if count == eval(extracted_mat):
201
  print("success")
202
  return eval(extracted_mat)
203
  break
204
 
205
  return None
206
-
 
207
  # get compatability matrix for companion planting via subsetting a hardcoded matrix
208
  # make plant_compatibility.csv into a matrix. it currently has indexes as rows and columns for plant names and then compatibility values as the values
209
- plant_compatibility = pd.read_csv('src/data/plant_compatibility.csv', index_col=0)
210
 
211
- def get_compatibility_matrix_2(plant_list):
212
 
 
213
  # Subset the matrix to only include the plants in the user's list
214
- plant_compatibility = st.session_state.raw_plant_compatibility.loc[plant_list, plant_list]
 
 
215
 
216
  # full matrix
217
  full_mat = st.session_state.raw_plant_compatibility.to_numpy()
@@ -221,27 +320,41 @@ def get_compatibility_matrix_2(plant_list):
221
 
222
  # Get the list of original indices (from the DataFrame)
223
  original_indices = plant_compatibility.index.tolist()
224
-
225
  # Create a dictionary to map plant names to their original indices
226
  plant_index_mapping = {plant: index for index, plant in enumerate(original_indices)}
227
 
228
  # Return the matrix and the plant-index mapping
229
  return plant_compatibility_matrix, full_mat, plant_index_mapping
230
 
 
231
  # get plant groupings from LLM
232
- def get_seed_groupings_from_LLM():
233
  plant_groupings_evaluated = "no response yet"
234
- if st.session_state.demo_lite:
235
  # just return "no response yet" for now
236
  return plant_groupings_evaluated
237
- template="You are a helpful assistant that only outputs python lists of lists of lists of plants."
238
  # make sure output is strictly and only a list of lists for one grouping
239
- text ='''I am working on a gardening project and need to optimally group a set of plants based on their compatibility. Below is the compatibility matrix for the plants, where each value represents how well two plants grow together (positive values indicate good compatibility, negative values indicate poor compatibility). I also have specific constraints for planting: there are a certain number of plant beds (n_plant_beds), each bed can have a minimum of min_species species and a maximum of max_species species. Given these constraints, please suggest several groupings of these plants into n_plant_beds beds, optimizing for overall compatibility.
 
240
 
241
- Number of Plant Beds: ''' + str(st.session_state.n_plant_beds) + '''
242
- Minimum Species per Bed: ''' + str(st.session_state.min_species) + '''
243
- Maximum Species per Bed: ''' + str(st.session_state.max_species) + '''
244
- Plants and Compatibility Matrix:'''+ str(st.session_state.raw_plant_compatibility.loc[st.session_state.input_plants_raw, st.session_state.input_plants_raw]) + '''
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
  Please provide a grouping that maximize positive interactions within each bed and minimize negative interactions, adhering to the specified bed constraints. Return a list of lists where each list represents an iteration of plant groupings. Each list within the list represents a bed, and each list within the bed represents the plants in that bed.
247
  sample output: [['plant1', 'plant2'] #bed1, ['plant3', 'plant4'] #bed2, ['plant1', 'plant3'] #bed3]
@@ -249,11 +362,11 @@ def get_seed_groupings_from_LLM():
249
  Note: the number of beds, the number of plants per bed, and the number of plants in the list may vary.
250
  Note: only output ONE python list of lists of plants. Do not include any other text or explanation.
251
 
252
- '''
 
253
 
254
-
255
- plant_groupings = chat_response(template, text, model)
256
- print('response about LLMs choice on groupings', plant_groupings)
257
 
258
  # try to eval the string to a list of lists
259
  try:
@@ -265,13 +378,15 @@ def get_seed_groupings_from_LLM():
265
  print("Error with parsing plant groupings")
266
  # try again up to 5 times
267
  for i in range(5):
268
- print("Error with parsing plant groupings. Trying for attempt #" + str(i+1))
269
- plant_groupings = chat_response(template, text, model)
 
 
270
  print(plant_groupings)
271
  # try to eval the string to a list of lists
272
  try:
273
  # make sure plant1 is not in the output
274
- if 'plant1' in plant_groupings:
275
  print("plant1 is in the output")
276
  continue
277
  else:
@@ -284,9 +399,15 @@ def get_seed_groupings_from_LLM():
284
  closing_bracket_index = plant_groupings.find("]]")
285
  if opening_bracket_index != -1 and closing_bracket_index != -1:
286
  # Extract the text within the brackets
287
- extracted_list = "[" + plant_groupings[opening_bracket_index + 1: closing_bracket_index] + "]]"
 
 
 
 
 
 
288
  # Return the evaluated text list
289
- if 'plant1' in extracted_list:
290
  print("plant1 is in the output")
291
  continue
292
  else:
@@ -298,3 +419,4 @@ def get_seed_groupings_from_LLM():
298
  continue
299
 
300
  return plant_groupings_evaluated
 
 
20
  )
21
 
22
 
 
 
 
 
23
  # set version
24
+ # st.session_state.demo_lite = False
25
+
26
+ # initialize model
27
+ # llm = "tbd"
28
+
29
+ print("BP 4 ")
30
+
31
+
32
+ # initialize model- get 11m depending on st.session_state.demo_lite, and model
33
+ def init_llm(model, demo_lite):
34
+ # st.write("BP 4.1: model: ", model)
35
+ if demo_lite == False:
36
+ print("BP 5 : running full demo")
37
+ if model == "Llama2-7b_CPP":
38
+ model_path = "/Users/dheym/Library/CloudStorage/OneDrive-Personal/Documents/side_projects/GRDN/src/models/llama-2-7b-chat.Q4_K_M.gguf"
39
+ print("model path: ", model_path)
40
+ llm = LlamaCPP(
41
+ # You can pass in the URL to a GGML model to download it automatically
42
+ # model_url=model_url,
43
+ # optionally, you can set the path to a pre-downloaded model instead of model_url
44
+ model_path=model_path,
45
+ temperature=0.1,
46
+ max_new_tokens=1000,
47
+ # llama2 has a context window of 4096 tokens, but we set it lower to allow for some wiggle room
48
+ context_window=3000,
49
+ # kwargs to pass to __call__()
50
+ generate_kwargs={},
51
+ # kwargs to pass to __init__()
52
+ # set to at least 1 to use GPU
53
+ model_kwargs={"n_gpu_layers": 1},
54
+ # transform inputs into Llama2 format
55
+ messages_to_prompt=messages_to_prompt,
56
+ completion_to_prompt=completion_to_prompt,
57
+ verbose=True,
58
+ )
59
+ elif model == "deci-7b_CPP":
60
+ model_path = "/Users/dheym/Library/CloudStorage/OneDrive-Personal/Documents/side_projects/GRDN/src/models/decilm-7b-uniform-gqa-q8_0.gguf"
61
+ print("model path: ", model_path)
62
+ llm = LlamaCPP(
63
+ # You can pass in the URL to a GGML model to download it automatically
64
+ # model_url=model_url,
65
+ # optionally, you can set the path to a pre-downloaded model instead of model_url
66
+ model_path=model_path,
67
+ # model_url = "https://huggingface.co/Deci/DeciLM-7B-instruct-GGUF/resolve/main/decilm-7b-uniform-gqa-q8_0.gguf",
68
+ temperature=0.1,
69
+ max_new_tokens=1000,
70
+ # llama2 has a context window of 4096 tokens, but we set it lower to allow for some wiggle room
71
+ context_window=3000,
72
+ # kwargs to pass to __call__()
73
+ generate_kwargs={},
74
+ # kwargs to pass to __init__()
75
+ # set to at least 1 to use GPU
76
+ model_kwargs={"n_gpu_layers": 1},
77
+ # transform inputs into Llama2 format
78
+ # messages_to_prompt=messages_to_prompt,
79
+ # completion_to_prompt=completion_to_prompt,
80
+ verbose=True,
81
+ )
82
+ else:
83
+ print("Error with chatbot model")
84
+ return None
85
+ return llm
86
+
87
 
88
  def parse_and_evaluate_text(text):
89
  # Find the indices of the opening and closing brackets
 
92
 
93
  if opening_bracket_index != -1 and closing_bracket_index != -1:
94
  # Extract the text within the brackets
95
+ extracted_list = (
96
+ "[" + text[opening_bracket_index + 1 : closing_bracket_index] + "]"
97
+ )
98
  # Return the evaluated text list
99
  return eval(extracted_list)
 
100
 
101
  else:
102
  print("Error with parsing plant list")
103
  return None
104
+
105
+
106
+ def chat_response(template, prompt_text, model, demo_lite):
107
+ if model == "openai-gpt35turbo":
108
+ chat = ChatOpenAI(temperature=0.1)
109
  system_message_prompt = SystemMessagePromptTemplate.from_template(template)
110
+ human_template = "{text}"
111
  human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
112
+ chat_prompt = ChatPromptTemplate.from_messages(
113
+ [system_message_prompt, human_message_prompt]
114
+ )
115
+ response = chat(chat_prompt.format_prompt(text=prompt_text).to_messages())
116
  return response
117
  # return response.content
118
+ elif model == "Llama2-7b_CPP" or model == "deci-7b_CPP":
119
+ print("BP 5.1: running full demo, model: ", model)
120
+ llm = init_llm(model, demo_lite)
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  response = llm.complete(template + prompt_text)
122
  return response.text
123
  else:
124
  print("Error with chatbot model")
125
  return None
126
 
127
+
128
+ # # get the plant list from user input
129
+ # def get_plant_list(input_plant_text, model):
130
+ # template="You are a helpful assistant that knows all about gardening and plants and python data structures."
131
+ # text = 'which of the elements of this list can be grown in a garden, [' + input_plant_text + ']? Return JUST a python list object containing the elements that can be grown in a garden. Do not include any other text or explanation.'
132
+ # plant_list_text = chat_response(template, text, model)
133
+ # plant_list = parse_and_evaluate_text(plant_list_text.content)
134
+ # print(plant_list)
135
+ # return plant_list
136
+
137
 
138
  # get plant care tips based on plant list
139
+ def get_plant_care_tips(plant_list, model, demo_lite):
140
  plant_care_tips = ""
141
+ template = "You are a helpful assistant that knows all about gardening, plants, and companion planting."
142
+ text = (
143
+ "from this list of plants, ["
144
+ + str(st.session_state.input_plants_raw)
145
+ + "], generate 1-2 plant care tips for each plant based on what you know. Return just the plant care tips in HTML markdown format. Make sure to use ### for headers. Do not include any other text or explanation before or after the markdown. It must be in HTML markdown format."
146
+ )
147
+
148
+ if model == "deci-7b_CPP":
149
+ template = (
150
+ "### System: \n\n You are a helpful assistant that knows all about gardening, plants, and companion planting."
151
+ + "\n\n ### User: Generate gardening tips. Return just the plant care tips in HTML markdown format. Make sure to use ### for headers. Do not include any other text or explanation before or after the markdown. It must be in HTML markdown format. \n\n"
152
+ )
153
+ text = "### Assistant: \n\n"
154
+ print("deci-7b_CPP")
155
+ plant_care_tips = chat_response(template, text, model, demo_lite)
156
+ # check to see if response contains ### or < for headers
157
+ print("BP6", plant_care_tips)
158
+ # st.write(plant_care_tips)
159
+ if (
160
+ "###" not in plant_care_tips
161
+ and "<" not in plant_care_tips
162
+ and model != "deci-7b_CPP"
163
+ ): # deci-7b_CPP has more general plant care tips
164
+ st.write(plant_care_tips)
165
  print("Error with parsing plant care tips")
166
  # try again up to 5 times
167
  for i in range(5):
168
+ print(
169
+ "Error with parsing plant care tips. Trying for attempt #" + str(i + 1)
170
+ )
171
+ plant_care_tips = chat_response(template, text, model, demo_lite)
172
  # check to see if response contains ### for headers
173
+ if "###" not in plant_care_tips and "<" not in plant_care_tips:
174
  continue
175
  else:
176
  break
177
+ # remove any text before the first ### or < in the response
178
+ print(plant_care_tips)
179
+ # look for either # or < for headers
180
+ if "###" in plant_care_tips:
181
+ plant_care_tips = "\n\n" + plant_care_tips[plant_care_tips.find("###") :]
182
+ elif "<" in plant_care_tips:
183
+ plant_care_tips = "\n\n" + plant_care_tips[plant_care_tips.find("<") :]
184
+ else:
185
+ print("funky formatting")
186
+ plant_care_tips = plant_care_tips
187
  print(plant_care_tips)
188
  return plant_care_tips
189
 
190
+
191
  # get compatability matrix for companion planting
192
+ def get_compatibility_matrix(plant_list, model, demo_lite):
193
  # Convert the compatibility matrix to a string
194
+ with open("data/compatibilities_text.txt", "r") as file:
195
  # Read the contents of the file
196
  compatibility_text = file.read()
197
  plant_comp_context = compatibility_text
198
+ template = "You are a helpful assistant that knows all about gardening, companion planting, and python data structures- specifically compatibility matrices."
199
+ text = (
200
+ "from this list of plants, ["
201
+ + str(plant_list)
202
+ + "], Return JUST a python array (with values separated by commas like this: [[0,1],[1,0]]\n\n ) for companion plant compatibility. Each row and column should represent plants, and the element of the array will contain a -1, 0, or 1 depending on if the relationship between plants is antagonists, neutral, or companions, respectively. You must refer to this knowledge base of information on plant compatibility: \n\n, "
203
+ + plant_comp_context
204
+ + "\n\n A plant's compatibility with itself is always 0. Do not include any other text or explanation."
205
+ )
206
+ compatibility_mat = chat_response(template, text, model, demo_lite)
207
 
208
  # Find the indices of the opening and closing brackets
209
  opening_bracket_index = compatibility_mat.content.find("[[")
210
  closing_bracket_index = compatibility_mat.content.find("]]")
211
  if opening_bracket_index != -1 and closing_bracket_index != -1:
212
  # Extract the text within the brackets
213
+ extracted_mat = (
214
+ "["
215
+ + compatibility_mat.content[
216
+ opening_bracket_index + 1 : closing_bracket_index
217
+ ]
218
+ + "]]"
219
+ )
220
  # Return the evaluated mat
221
  # check to see if compatiblity matrix only contains values of -1, 0, or 1
222
+ if eval(extracted_mat).count("0") + eval(extracted_mat).count("1") == len(
223
+ eval(extracted_mat)
224
+ ):
225
  # continue
226
  pass
227
  else:
228
  # try again up to 5 times
229
  for i in range(5):
230
+ print(
231
+ "Error with parsing plant compatibility matrix. Trying for attempt #"
232
+ + str(i + 1)
233
+ )
234
  print(extracted_mat)
235
+ extracted_mat = chat_response(
236
+ template
237
+ + "remember, it MUST ONLY CONTAIN -1s, 0s, and 1s, like this structure: [[0,1],[1,0]]",
238
+ text,
239
+ model,
240
+ demo_lite,
241
+ )
242
  # Extract the text within the brackets
243
+ extracted_mat = (
244
+ "["
245
+ + compatibility_mat.content[
246
+ opening_bracket_index + 1 : closing_bracket_index
247
+ ]
248
+ + "]]"
249
+ )
250
  print(extracted_mat)
251
  total_count = 0
252
  count_0 = extracted_mat.count("0")
 
254
  total_count = count_0 + count_1
255
  print("matrix count of -1, 0, 1: ", total_count)
256
  # if count euals the number of plants squared, then we have a valid matrix
257
+ print("plant_list_len: ", len(plant_list) ** 2)
258
+ if total_count == (len(plant_list)) ** 2:
259
+ # if count == eval(extracted_mat):
260
  print("success")
261
  return eval(extracted_mat)
262
  break
263
 
 
264
  else:
265
  print("Error with parsing plant compatibility matrix")
266
  # try again up to 5 times
267
  for i in range(5):
268
+ print(
269
+ "Error with parsing plant compatibility matrix. Trying for attempt #"
270
+ + str(i + 1)
271
+ )
272
+ extracted_mat = chat_response(
273
+ template
274
+ + "remember, it MUST ONLY CONTAIN -1s, 0s, and 1s, like this structure: [[0,1],[1,0]]",
275
+ text,
276
+ model,
277
+ demo_lite,
278
+ )
279
  # Extract the text within the brackets
280
+ extracted_mat = (
281
+ "["
282
+ + compatibility_mat.content[
283
+ opening_bracket_index + 1 : closing_bracket_index
284
+ ]
285
+ + "]]"
286
+ )
287
  print(extracted_mat)
288
  total_count = 0
289
  count_0 = extracted_mat.count("0")
 
291
  total_count = count_0 + count_1
292
  print("matrix count of -1, 0, 1: ", total_count)
293
  # if count euals the number of plants squared, then we have a valid matrix
294
+ print("plant_list_len: ", len(plant_list) ** 2)
295
+ if total_count == (len(plant_list)) ** 2:
296
+ # if count == eval(extracted_mat):
297
  print("success")
298
  return eval(extracted_mat)
299
  break
300
 
301
  return None
302
+
303
+
304
  # get compatability matrix for companion planting via subsetting a hardcoded matrix
305
  # make plant_compatibility.csv into a matrix. it currently has indexes as rows and columns for plant names and then compatibility values as the values
306
+ plant_compatibility = pd.read_csv("src/data/plant_compatibility.csv", index_col=0)
307
 
 
308
 
309
+ def get_compatibility_matrix_2(plant_list):
310
  # Subset the matrix to only include the plants in the user's list
311
+ plant_compatibility = st.session_state.raw_plant_compatibility.loc[
312
+ plant_list, plant_list
313
+ ]
314
 
315
  # full matrix
316
  full_mat = st.session_state.raw_plant_compatibility.to_numpy()
 
320
 
321
  # Get the list of original indices (from the DataFrame)
322
  original_indices = plant_compatibility.index.tolist()
323
+
324
  # Create a dictionary to map plant names to their original indices
325
  plant_index_mapping = {plant: index for index, plant in enumerate(original_indices)}
326
 
327
  # Return the matrix and the plant-index mapping
328
  return plant_compatibility_matrix, full_mat, plant_index_mapping
329
 
330
+
331
  # get plant groupings from LLM
332
+ def get_seed_groupings_from_LLM(model, demo_lite):
333
  plant_groupings_evaluated = "no response yet"
334
+ if demo_lite:
335
  # just return "no response yet" for now
336
  return plant_groupings_evaluated
337
+ template = "You are a helpful assistant that only outputs python lists of lists of lists of plants."
338
  # make sure output is strictly and only a list of lists for one grouping
339
+ text = (
340
+ """I am working on a gardening project and need to optimally group a set of plants based on their compatibility. Below is the compatibility matrix for the plants, where each value represents how well two plants grow together (positive values indicate good compatibility, negative values indicate poor compatibility). I also have specific constraints for planting: there are a certain number of plant beds (n_plant_beds), each bed can have a minimum of min_species species and a maximum of max_species species. Given these constraints, please suggest several groupings of these plants into n_plant_beds beds, optimizing for overall compatibility.
341
 
342
+ Number of Plant Beds: """
343
+ + str(st.session_state.n_plant_beds)
344
+ + """
345
+ Minimum Species per Bed: """
346
+ + str(st.session_state.min_species)
347
+ + """
348
+ Maximum Species per Bed: """
349
+ + str(st.session_state.max_species)
350
+ + """
351
+ Plants and Compatibility Matrix:"""
352
+ + str(
353
+ st.session_state.raw_plant_compatibility.loc[
354
+ st.session_state.input_plants_raw, st.session_state.input_plants_raw
355
+ ]
356
+ )
357
+ + """
358
 
359
  Please provide a grouping that maximize positive interactions within each bed and minimize negative interactions, adhering to the specified bed constraints. Return a list of lists where each list represents an iteration of plant groupings. Each list within the list represents a bed, and each list within the bed represents the plants in that bed.
360
  sample output: [['plant1', 'plant2'] #bed1, ['plant3', 'plant4'] #bed2, ['plant1', 'plant3'] #bed3]
 
362
  Note: the number of beds, the number of plants per bed, and the number of plants in the list may vary.
363
  Note: only output ONE python list of lists of plants. Do not include any other text or explanation.
364
 
365
+ """
366
+ )
367
 
368
+ plant_groupings = chat_response(template, text, model, demo_lite)
369
+ print("response about LLMs choice on groupings", plant_groupings)
 
370
 
371
  # try to eval the string to a list of lists
372
  try:
 
378
  print("Error with parsing plant groupings")
379
  # try again up to 5 times
380
  for i in range(5):
381
+ print(
382
+ "Error with parsing plant groupings. Trying for attempt #" + str(i + 1)
383
+ )
384
+ plant_groupings = chat_response(template, text, model, demo_lite)
385
  print(plant_groupings)
386
  # try to eval the string to a list of lists
387
  try:
388
  # make sure plant1 is not in the output
389
+ if "plant1" in plant_groupings.lower():
390
  print("plant1 is in the output")
391
  continue
392
  else:
 
399
  closing_bracket_index = plant_groupings.find("]]")
400
  if opening_bracket_index != -1 and closing_bracket_index != -1:
401
  # Extract the text within the brackets
402
+ extracted_list = (
403
+ "["
404
+ + plant_groupings[
405
+ opening_bracket_index + 1 : closing_bracket_index
406
+ ]
407
+ + "]]"
408
+ )
409
  # Return the evaluated text list
410
+ if "plant1" in extracted_list.lower():
411
  print("plant1 is in the output")
412
  continue
413
  else:
 
419
  continue
420
 
421
  return plant_groupings_evaluated
422
+