cat-llm 0.0.39__tar.gz → 0.0.40__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cat_llm-0.0.39 → cat_llm-0.0.40}/PKG-INFO +1 -1
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/CERAD_functions.py +68 -41
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/__about__.py +1 -1
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/image_functions.py +74 -27
- {cat_llm-0.0.39 → cat_llm-0.0.40}/.gitignore +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/LICENSE +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/README.md +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/pyproject.toml +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/__init__.py +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/images/circle.png +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/images/cube.png +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/images/diamond.png +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/images/overlapping_pentagons.png +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/images/rectangles.png +0 -0
- {cat_llm-0.0.39 → cat_llm-0.0.40}/src/catllm/text_functions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cat-llm
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.40
|
|
4
4
|
Summary: A tool for categorizing text data and images using LLMs and vision models
|
|
5
5
|
Project-URL: Documentation, https://github.com/chrissoria/cat-llm#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/chrissoria/cat-llm/issues
|
|
@@ -67,8 +67,8 @@ def cerad_drawn_score(
|
|
|
67
67
|
categories = ["The image contains a drawing that clearly represents overlapping rectangles",
|
|
68
68
|
"The image does NOT contain any drawing that resembles overlapping rectangles",
|
|
69
69
|
"The image contains a drawing that resembles overlapping rectangles",
|
|
70
|
-
"If rectangle 1 is present it has 4 sides",
|
|
71
|
-
"If
|
|
70
|
+
"If rectangle 1 is present and it has 4 sides",
|
|
71
|
+
"If rectangle 2 is present and it has 4 sides",
|
|
72
72
|
"The drawn rectangles are overlapping",
|
|
73
73
|
"The drawn rectangles overlap to form a longer vertical rectangle with top and bottom sticking out",
|
|
74
74
|
"None of the above descriptions apply"]
|
|
@@ -131,19 +131,30 @@ def cerad_drawn_score(
|
|
|
131
131
|
continue # Skip the rest of the loop iteration
|
|
132
132
|
|
|
133
133
|
# Only open the file if path is valid
|
|
134
|
-
|
|
135
|
-
encoded =
|
|
136
|
-
|
|
134
|
+
if os.path.isdir(img_path):
|
|
135
|
+
encoded = "Not a Valid Image, contains file path"
|
|
136
|
+
else:
|
|
137
|
+
try:
|
|
138
|
+
with open(img_path, "rb") as f:
|
|
139
|
+
encoded = base64.b64encode(f.read()).decode("utf-8")
|
|
140
|
+
except Exception as e:
|
|
141
|
+
encoded = f"Error: {str(e)}"
|
|
137
142
|
# Handle extension safely
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
if encoded.startswith("Error:") or encoded == "Not a Valid Image, contains file path":
|
|
144
|
+
encoded_image = encoded
|
|
145
|
+
valid_image = False
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
ext = Path(img_path).suffix.lstrip(".").lower()
|
|
149
|
+
encoded_image = f"data:image/{ext};base64,{encoded}"
|
|
150
|
+
valid_image = True
|
|
140
151
|
|
|
141
152
|
if reference_in_image:
|
|
142
153
|
reference_text = f"This image contains a perfect reference image of a {shape}. Next to is a drawing that is meant to be similar to the reference {shape}.\n\n"
|
|
143
154
|
else:
|
|
144
155
|
reference_text = f"Image is expected to show within it a drawing of a {shape}.\n\n"
|
|
145
156
|
|
|
146
|
-
if model_source == "OpenAI":
|
|
157
|
+
if model_source == "OpenAI" and valid_image:
|
|
147
158
|
prompt = [
|
|
148
159
|
{
|
|
149
160
|
"type": "text",
|
|
@@ -154,8 +165,8 @@ def cerad_drawn_score(
|
|
|
154
165
|
f"{reference_text}"
|
|
155
166
|
f"Categories:\n{categories_str}\n\n"
|
|
156
167
|
f"Output format ► Respond with **only** a JSON object whose keys are the "
|
|
157
|
-
f"quoted category numbers ('1', '2', …) and whose values are 1 or 0. "
|
|
158
|
-
f"No additional keys, comments, or text.\n\n"
|
|
168
|
+
f"quoted category numbers ('1', '2', …) and whose values are 1 if present or 0 if not present. "
|
|
169
|
+
f"No additional keys, comments, numbers beyond 0 or 1, or text.\n\n"
|
|
159
170
|
f"Example:\n"
|
|
160
171
|
f"{example_JSON}"
|
|
161
172
|
)
|
|
@@ -173,7 +184,7 @@ def cerad_drawn_score(
|
|
|
173
184
|
"image_url": {"url": encoded_image, "detail": "high"}
|
|
174
185
|
})
|
|
175
186
|
|
|
176
|
-
elif model_source == "Anthropic":
|
|
187
|
+
elif model_source == "Anthropic" and valid_image:
|
|
177
188
|
prompt = [
|
|
178
189
|
{
|
|
179
190
|
"type": "text",
|
|
@@ -184,8 +195,8 @@ def cerad_drawn_score(
|
|
|
184
195
|
f"{reference_text}"
|
|
185
196
|
f"Categories:\n{categories_str}\n\n"
|
|
186
197
|
f"Output format ► Respond with **only** a JSON object whose keys are the "
|
|
187
|
-
f"quoted category numbers ('1', '2', …) and whose values are 1 or 0. "
|
|
188
|
-
f"No additional keys, comments, or text.\n\n"
|
|
198
|
+
f"quoted category numbers ('1', '2', …) and whose values are 1 if present or 0 if not present. "
|
|
199
|
+
f"No additional keys, comments, numbers beyond 0 or 1, or text.\n\n"
|
|
189
200
|
f"Example:\n"
|
|
190
201
|
f"{example_JSON}"
|
|
191
202
|
),
|
|
@@ -213,7 +224,7 @@ def cerad_drawn_score(
|
|
|
213
224
|
}
|
|
214
225
|
)
|
|
215
226
|
|
|
216
|
-
elif model_source == "Mistral":
|
|
227
|
+
elif model_source == "Mistral" and valid_image:
|
|
217
228
|
prompt = [
|
|
218
229
|
{
|
|
219
230
|
"type": "text",
|
|
@@ -224,8 +235,8 @@ def cerad_drawn_score(
|
|
|
224
235
|
f"{reference_text}"
|
|
225
236
|
f"Categories:\n{categories_str}\n\n"
|
|
226
237
|
f"Output format ► Respond with **only** a JSON object whose keys are the "
|
|
227
|
-
f"quoted category numbers ('1', '2', …) and whose values are 1 or 0. "
|
|
228
|
-
f"No additional keys, comments, or text.\n\n"
|
|
238
|
+
f"quoted category numbers ('1', '2', …) and whose values are 1 if present or 0 if not present. "
|
|
239
|
+
f"No additional keys, comments, numbers beyond 0 or 1, or text.\n\n"
|
|
229
240
|
f"Example:\n"
|
|
230
241
|
f"{example_JSON}"
|
|
231
242
|
),
|
|
@@ -241,8 +252,8 @@ def cerad_drawn_score(
|
|
|
241
252
|
"type": "image_url",
|
|
242
253
|
"image_url": f"data:image/{ext};base64,{encoded_image}"
|
|
243
254
|
})
|
|
244
|
-
|
|
245
|
-
if model_source == "OpenAI":
|
|
255
|
+
|
|
256
|
+
if model_source == "OpenAI" and valid_image:
|
|
246
257
|
from openai import OpenAI
|
|
247
258
|
client = OpenAI(api_key=api_key)
|
|
248
259
|
try:
|
|
@@ -254,10 +265,10 @@ def cerad_drawn_score(
|
|
|
254
265
|
reply = response_obj.choices[0].message.content
|
|
255
266
|
link1.append(reply)
|
|
256
267
|
except Exception as e:
|
|
257
|
-
print(
|
|
258
|
-
link1.append(
|
|
268
|
+
print("An error occurred: {e}")
|
|
269
|
+
link1.append("Error processing input: {e}")
|
|
259
270
|
|
|
260
|
-
elif model_source == "Anthropic":
|
|
271
|
+
elif model_source == "Anthropic" and valid_image:
|
|
261
272
|
import anthropic
|
|
262
273
|
client = anthropic.Anthropic(api_key=api_key)
|
|
263
274
|
try:
|
|
@@ -270,10 +281,10 @@ def cerad_drawn_score(
|
|
|
270
281
|
reply = message.content[0].text # Anthropic returns content as list
|
|
271
282
|
link1.append(reply)
|
|
272
283
|
except Exception as e:
|
|
273
|
-
print(
|
|
274
|
-
link1.append(
|
|
284
|
+
print("An error occurred: {e}")
|
|
285
|
+
link1.append("Error processing input: {e}")
|
|
275
286
|
|
|
276
|
-
elif model_source == "Mistral":
|
|
287
|
+
elif model_source == "Mistral" and valid_image:
|
|
277
288
|
from mistralai import Mistral
|
|
278
289
|
reply = None
|
|
279
290
|
client = Mistral(api_key=api_key)
|
|
@@ -288,25 +299,34 @@ def cerad_drawn_score(
|
|
|
288
299
|
reply = response.choices[0].message.content
|
|
289
300
|
link1.append(reply)
|
|
290
301
|
except Exception as e:
|
|
291
|
-
|
|
292
|
-
|
|
302
|
+
reply = None
|
|
303
|
+
print("An error occurred: {e}")
|
|
304
|
+
link1.append("Error processing input: {e}")
|
|
305
|
+
#if no valid image path is provided
|
|
306
|
+
elif valid_image == False:
|
|
307
|
+
reply = "invalid image path"
|
|
308
|
+
print("Skipped NaN input or invalid path")
|
|
309
|
+
#extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
310
|
+
link1.append("Error processing input: {e}")
|
|
293
311
|
else:
|
|
294
312
|
raise ValueError("Unknown source! Choose from OpenAI, Perplexity, or Mistral")
|
|
295
313
|
# in situation that no JSON is found
|
|
296
314
|
if reply is not None:
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
300
|
-
extracted_jsons.append(cleaned_json)
|
|
301
|
-
#print(cleaned_json)
|
|
315
|
+
if reply == "invalid image path":
|
|
316
|
+
extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
302
317
|
else:
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
318
|
+
extracted_json = regex.findall(r'\{(?:[^{}]|(?R))*\}', reply, regex.DOTALL)
|
|
319
|
+
if extracted_json:
|
|
320
|
+
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
321
|
+
extracted_jsons.append(cleaned_json)
|
|
322
|
+
else:
|
|
323
|
+
error_message = """{"1":"e"}"""
|
|
324
|
+
extracted_jsons.append(error_message)
|
|
325
|
+
print(error_message)
|
|
306
326
|
else:
|
|
307
327
|
error_message = """{"1":"e"}"""
|
|
308
328
|
extracted_jsons.append(error_message)
|
|
309
|
-
|
|
329
|
+
print(error_message)
|
|
310
330
|
|
|
311
331
|
# --- Safety Save ---
|
|
312
332
|
if safety:
|
|
@@ -369,6 +389,8 @@ def cerad_drawn_score(
|
|
|
369
389
|
categorized_data['score'] = categorized_data['cir_almost_closed'] + categorized_data['cir_closed'] + categorized_data['cir_round'] + categorized_data['cir_almost_round']
|
|
370
390
|
categorized_data.loc[categorized_data['none'] == 1, 'score'] = 0
|
|
371
391
|
categorized_data.loc[(categorized_data['drawing_present'] == 0) & (categorized_data['score'] == 0), 'score'] = 0
|
|
392
|
+
#this score should never be greater than 2
|
|
393
|
+
categorized_data.loc[categorized_data['score'] > 2, 'score'] = 2
|
|
372
394
|
|
|
373
395
|
elif shape == "diamond":
|
|
374
396
|
|
|
@@ -382,11 +404,12 @@ def cerad_drawn_score(
|
|
|
382
404
|
"7": "complex_diamond",
|
|
383
405
|
"8": "none"
|
|
384
406
|
})
|
|
385
|
-
|
|
386
|
-
categorized_data['score'] = categorized_data['diamond_4_sides'] + categorized_data['diamond_equal_sides'] + categorized_data['similar']
|
|
407
|
+
categorized_data['diamond_4_sides'] = np.where(categorized_data['diamond_4_sides'] > 1, 1, categorized_data['diamond_4_sides'])
|
|
408
|
+
categorized_data['score'] = categorized_data['diamond_4_sides'] + categorized_data['diamond_equal_sides'] + categorized_data['similar'] + categorized_data['diamond_square']
|
|
387
409
|
|
|
388
410
|
categorized_data.loc[categorized_data['none'] == 1, 'score'] = 0
|
|
389
|
-
#
|
|
411
|
+
#this score should never be greater than 3
|
|
412
|
+
categorized_data.loc[categorized_data['score'] > 3, 'score'] = 3
|
|
390
413
|
|
|
391
414
|
elif shape == "rectangles" or shape == "overlapping rectangles":
|
|
392
415
|
|
|
@@ -401,11 +424,13 @@ def cerad_drawn_score(
|
|
|
401
424
|
"8": "none"
|
|
402
425
|
})
|
|
403
426
|
|
|
404
|
-
|
|
405
|
-
categorized_data
|
|
406
|
-
categorized_data.loc[(categorized_data['rectangles_overlap'] == 1) & (categorized_data['rectangles_cross'] == 1), 'score'] += 1
|
|
427
|
+
#TODO: check to this logic, it might be skewing scores to be more often 2 than should be
|
|
428
|
+
categorized_data['score'] = categorized_data['rectangles_overlap'] + categorized_data['similar'] + categorized_data['rectangles_cross']
|
|
407
429
|
categorized_data.loc[categorized_data['none'] == 1, 'score'] = 0
|
|
408
430
|
|
|
431
|
+
#this score should never be greater than 2
|
|
432
|
+
categorized_data.loc[categorized_data['score'] > 2, 'score'] = 2
|
|
433
|
+
|
|
409
434
|
elif shape == "cube":
|
|
410
435
|
|
|
411
436
|
categorized_data = categorized_data.rename(columns={
|
|
@@ -424,12 +449,14 @@ def cerad_drawn_score(
|
|
|
424
449
|
categorized_data.loc[categorized_data['none'] == 1, 'score'] = 0
|
|
425
450
|
categorized_data.loc[(categorized_data['drawing_present'] == 0) & (categorized_data['score'] == 0), 'score'] = 0
|
|
426
451
|
categorized_data.loc[(categorized_data['not_similar'] == 1) & (categorized_data['score'] == 0), 'score'] = 0
|
|
452
|
+
#this score should never be greater than 4
|
|
427
453
|
categorized_data.loc[categorized_data['score'] > 4, 'score'] = 4
|
|
428
454
|
|
|
429
455
|
else:
|
|
430
456
|
raise ValueError("Invalid shape! Choose from 'circle', 'diamond', 'rectangles', or 'cube'.")
|
|
431
457
|
|
|
432
458
|
categorized_data.loc[categorized_data['no_valid_image'] == 1, 'score'] = None
|
|
459
|
+
categorized_data['image_file'] = categorized_data['image_input'].apply(lambda x: Path(x).name)
|
|
433
460
|
|
|
434
461
|
if filename is not None:
|
|
435
462
|
categorized_data.to_csv(filename, index=False)
|
|
@@ -66,8 +66,23 @@ def image_multi_class(
|
|
|
66
66
|
continue # Skip the rest of the loop iteration
|
|
67
67
|
|
|
68
68
|
# Only open the file if path is valid
|
|
69
|
-
|
|
70
|
-
encoded =
|
|
69
|
+
if os.path.isdir(img_path):
|
|
70
|
+
encoded = "Not a Valid Image, contains file path"
|
|
71
|
+
else:
|
|
72
|
+
try:
|
|
73
|
+
with open(img_path, "rb") as f:
|
|
74
|
+
encoded = base64.b64encode(f.read()).decode("utf-8")
|
|
75
|
+
except Exception as e:
|
|
76
|
+
encoded = f"Error: {str(e)}"
|
|
77
|
+
# Handle extension safely
|
|
78
|
+
if encoded.startswith("Error:") or encoded == "Not a Valid Image, contains file path":
|
|
79
|
+
encoded_image = encoded
|
|
80
|
+
valid_image = False
|
|
81
|
+
extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
82
|
+
else:
|
|
83
|
+
ext = Path(img_path).suffix.lstrip(".").lower()
|
|
84
|
+
encoded_image = f"data:image/{ext};base64,{encoded}"
|
|
85
|
+
valid_image = True
|
|
71
86
|
|
|
72
87
|
# Handle extension safely
|
|
73
88
|
ext = Path(img_path).suffix.lstrip(".").lower()
|
|
@@ -169,23 +184,31 @@ def image_multi_class(
|
|
|
169
184
|
except Exception as e:
|
|
170
185
|
print(f"An error occurred: {e}")
|
|
171
186
|
link1.append(f"Error processing input: {e}")
|
|
187
|
+
#if no valid image path is provided
|
|
188
|
+
elif valid_image == False:
|
|
189
|
+
reply = "invalid image path"
|
|
190
|
+
print("Skipped NaN input or invalid path")
|
|
191
|
+
#extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
192
|
+
link1.append("Error processing input: {e}")
|
|
172
193
|
else:
|
|
173
|
-
raise ValueError("Unknown source! Choose from OpenAI,
|
|
194
|
+
raise ValueError("Unknown source! Choose from OpenAI, Perplexity, or Mistral")
|
|
174
195
|
# in situation that no JSON is found
|
|
175
196
|
if reply is not None:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
179
|
-
extracted_jsons.append(cleaned_json)
|
|
180
|
-
#print(cleaned_json)
|
|
197
|
+
if reply == "invalid image path":
|
|
198
|
+
extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
181
199
|
else:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
extracted_json = regex.findall(r'\{(?:[^{}]|(?R))*\}', reply, regex.DOTALL)
|
|
201
|
+
if extracted_json:
|
|
202
|
+
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
203
|
+
extracted_jsons.append(cleaned_json)
|
|
204
|
+
else:
|
|
205
|
+
error_message = """{"1":"e"}"""
|
|
206
|
+
extracted_jsons.append(error_message)
|
|
207
|
+
print(error_message)
|
|
185
208
|
else:
|
|
186
209
|
error_message = """{"1":"e"}"""
|
|
187
210
|
extracted_jsons.append(error_message)
|
|
188
|
-
|
|
211
|
+
print(error_message)
|
|
189
212
|
|
|
190
213
|
# --- Safety Save ---
|
|
191
214
|
if safety:
|
|
@@ -227,9 +250,6 @@ def image_multi_class(
|
|
|
227
250
|
'json': pd.Series(extracted_jsons).reset_index(drop=True)
|
|
228
251
|
})
|
|
229
252
|
categorized_data = pd.concat([categorized_data, normalized_data], axis=1)
|
|
230
|
-
|
|
231
|
-
if columns != "numbered": #if user wants text columns
|
|
232
|
-
categorized_data.columns = list(categorized_data.columns[:3]) + categories[:len(categorized_data.columns) - 3]
|
|
233
253
|
|
|
234
254
|
if to_csv:
|
|
235
255
|
if save_directory is None:
|
|
@@ -301,8 +321,23 @@ def image_score_drawing(
|
|
|
301
321
|
continue # Skip the rest of the loop iteration
|
|
302
322
|
|
|
303
323
|
# Only open the file if path is valid
|
|
304
|
-
|
|
305
|
-
encoded =
|
|
324
|
+
if os.path.isdir(img_path):
|
|
325
|
+
encoded = "Not a Valid Image, contains file path"
|
|
326
|
+
else:
|
|
327
|
+
try:
|
|
328
|
+
with open(img_path, "rb") as f:
|
|
329
|
+
encoded = base64.b64encode(f.read()).decode("utf-8")
|
|
330
|
+
except Exception as e:
|
|
331
|
+
encoded = f"Error: {str(e)}"
|
|
332
|
+
# Handle extension safely
|
|
333
|
+
if encoded.startswith("Error:") or encoded == "Not a Valid Image, contains file path":
|
|
334
|
+
encoded_image = encoded
|
|
335
|
+
valid_image = False
|
|
336
|
+
|
|
337
|
+
else:
|
|
338
|
+
ext = Path(img_path).suffix.lstrip(".").lower()
|
|
339
|
+
encoded_image = f"data:image/{ext};base64,{encoded}"
|
|
340
|
+
valid_image = True
|
|
306
341
|
|
|
307
342
|
# Handle extension safely
|
|
308
343
|
ext = Path(img_path).suffix.lstrip(".").lower()
|
|
@@ -436,23 +471,31 @@ def image_score_drawing(
|
|
|
436
471
|
except Exception as e:
|
|
437
472
|
print(f"An error occurred: {e}")
|
|
438
473
|
link1.append(f"Error processing input: {e}")
|
|
474
|
+
#if no valid image path is provided
|
|
475
|
+
elif valid_image == False:
|
|
476
|
+
reply = "invalid image path"
|
|
477
|
+
print("Skipped NaN input or invalid path")
|
|
478
|
+
#extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
479
|
+
link1.append("Error processing input: {e}")
|
|
439
480
|
else:
|
|
440
|
-
raise ValueError("Unknown source! Choose from OpenAI,
|
|
481
|
+
raise ValueError("Unknown source! Choose from OpenAI, Perplexity, or Mistral")
|
|
441
482
|
# in situation that no JSON is found
|
|
442
483
|
if reply is not None:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
446
|
-
extracted_jsons.append(cleaned_json)
|
|
447
|
-
#print(cleaned_json)
|
|
484
|
+
if reply == "invalid image path":
|
|
485
|
+
extracted_jsons.append("""{"no_valid_path": 1}""")
|
|
448
486
|
else:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
487
|
+
extracted_json = regex.findall(r'\{(?:[^{}]|(?R))*\}', reply, regex.DOTALL)
|
|
488
|
+
if extracted_json:
|
|
489
|
+
cleaned_json = extracted_json[0].replace('[', '').replace(']', '').replace('\n', '').replace(" ", '').replace(" ", '')
|
|
490
|
+
extracted_jsons.append(cleaned_json)
|
|
491
|
+
else:
|
|
492
|
+
error_message = """{"1":"e"}"""
|
|
493
|
+
extracted_jsons.append(error_message)
|
|
494
|
+
print(error_message)
|
|
452
495
|
else:
|
|
453
496
|
error_message = """{"1":"e"}"""
|
|
454
497
|
extracted_jsons.append(error_message)
|
|
455
|
-
|
|
498
|
+
print(error_message)
|
|
456
499
|
|
|
457
500
|
# --- Safety Save ---
|
|
458
501
|
if safety:
|
|
@@ -697,6 +740,10 @@ def image_features(
|
|
|
697
740
|
except Exception as e:
|
|
698
741
|
print(f"An error occurred: {e}")
|
|
699
742
|
link1.append(f"Error processing input: {e}")
|
|
743
|
+
elif valid_image == False:
|
|
744
|
+
print("Skipped NaN input or invalid path")
|
|
745
|
+
reply = None
|
|
746
|
+
link1.append("Error processing input: {e}")
|
|
700
747
|
else:
|
|
701
748
|
raise ValueError("Unknown source! Choose from OpenAI, Anthropic, Perplexity, or Mistral")
|
|
702
749
|
# in situation that no JSON is found
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|