cat-stack 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,622 @@
1
+ # openai stepback prompt
2
+
3
+ import requests
4
+
5
+
6
+ def get_stepback_insight_openai(
7
+ stepback,
8
+ api_key,
9
+ user_model,
10
+ model_source="openai",
11
+ creativity=None
12
+ ):
13
+ """
14
+ Get stepback insight from OpenAI-compatible APIs.
15
+ Uses direct HTTP requests instead of OpenAI SDK for lighter dependencies.
16
+ """
17
+ # Determine the base URL based on model source
18
+ if model_source == "huggingface":
19
+ from cat_stack._providers import _detect_huggingface_endpoint
20
+ base_url = _detect_huggingface_endpoint(api_key, user_model)
21
+ elif model_source == "huggingface-together":
22
+ base_url = "https://router.huggingface.co/together/v1"
23
+ elif model_source == "perplexity":
24
+ base_url = "https://api.perplexity.ai"
25
+ elif model_source == "xai":
26
+ base_url = "https://api.x.ai/v1"
27
+ else:
28
+ base_url = "https://api.openai.com/v1"
29
+
30
+ endpoint = f"{base_url}/chat/completions"
31
+
32
+ headers = {
33
+ "Content-Type": "application/json",
34
+ "Authorization": f"Bearer {api_key}"
35
+ }
36
+
37
+ payload = {
38
+ "model": user_model,
39
+ "messages": [{"role": "user", "content": stepback}],
40
+ }
41
+
42
+ if creativity is not None:
43
+ payload["temperature"] = creativity
44
+
45
+ try:
46
+ response = requests.post(endpoint, headers=headers, json=payload, timeout=120)
47
+ response.raise_for_status()
48
+ result = response.json()
49
+ stepback_insight = result["choices"][0]["message"]["content"]
50
+
51
+ return stepback_insight, True
52
+
53
+ except Exception as e:
54
+ print(f"An error occurred during step-back prompting: {e}")
55
+ return None, False
56
+
57
+
58
+ # claude stepback prompt
59
+
60
+ def get_stepback_insight_anthropic(
61
+ stepback,
62
+ api_key,
63
+ user_model,
64
+ model_source="anthropic",
65
+ creativity=None
66
+ ):
67
+ """
68
+ Get stepback insight from Anthropic Claude.
69
+
70
+ Uses direct HTTP requests instead of Anthropic SDK for lighter dependencies.
71
+ """
72
+ import requests
73
+
74
+ endpoint = "https://api.anthropic.com/v1/messages"
75
+
76
+ headers = {
77
+ "Content-Type": "application/json",
78
+ "x-api-key": api_key,
79
+ "anthropic-version": "2023-06-01"
80
+ }
81
+
82
+ payload = {
83
+ "model": user_model,
84
+ "max_tokens": 4096,
85
+ "messages": [{"role": "user", "content": stepback}],
86
+ }
87
+
88
+ if creativity is not None:
89
+ payload["temperature"] = creativity
90
+
91
+ try:
92
+ response = requests.post(endpoint, headers=headers, json=payload, timeout=120)
93
+ response.raise_for_status()
94
+ result = response.json()
95
+
96
+ # Parse response - Anthropic returns content as a list
97
+ content = result.get("content", [])
98
+ if content and content[0].get("type") == "text":
99
+ stepback_insight = content[0].get("text", "")
100
+ return stepback_insight, True
101
+
102
+ return None, False
103
+
104
+ except Exception as e:
105
+ print(f"An error occurred during step-back prompting: {e}")
106
+ return None, False
107
+
108
+ # google stepback prompt
109
+
110
+ def get_stepback_insight_google(
111
+ stepback,
112
+ api_key,
113
+ user_model,
114
+ model_source="google",
115
+ creativity=None
116
+ ):
117
+
118
+ import requests
119
+
120
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/{user_model}:generateContent?key={api_key}"
121
+
122
+ headers = {
123
+ "Content-Type": "application/json"
124
+ }
125
+
126
+ payload = {
127
+ "contents": [{
128
+ "parts": [{"text": stepback}],
129
+
130
+ **({"generationConfig": {"temperature": creativity}} if creativity is not None else {})
131
+ }]
132
+ }
133
+
134
+ try:
135
+ response = requests.post(url, headers=headers, json=payload)
136
+ response.raise_for_status() # Raise error for bad status codes
137
+
138
+ result = response.json()
139
+ stepback_insight = result['candidates'][0]['content']['parts'][0]['text']
140
+
141
+ return stepback_insight, True
142
+
143
+ except Exception as e:
144
+ print(f"An error occurred during step-back prompting: {e}")
145
+ return None, False
146
+
147
+ # mistral stepback prompt
148
+
149
+ def get_stepback_insight_mistral(
150
+ stepback,
151
+ api_key,
152
+ user_model,
153
+ model_source="mistral",
154
+ creativity=None
155
+ ):
156
+ import requests
157
+
158
+ endpoint = "https://api.mistral.ai/v1/chat/completions"
159
+ headers = {
160
+ "Content-Type": "application/json",
161
+ "Authorization": f"Bearer {api_key}"
162
+ }
163
+
164
+ payload = {
165
+ "model": user_model,
166
+ "messages": [{'role': 'user', 'content': stepback}],
167
+ }
168
+ if creativity is not None:
169
+ payload["temperature"] = creativity
170
+
171
+ try:
172
+ response = requests.post(endpoint, headers=headers, json=payload, timeout=120)
173
+ response.raise_for_status()
174
+ result = response.json()
175
+ stepback_insight = result["choices"][0]["message"]["content"]
176
+
177
+ return stepback_insight, True
178
+
179
+ except Exception as e:
180
+ print(f"An error occurred during step-back prompting: {e}")
181
+ return None, False
182
+
183
+ # openai chain of verification calls
184
+
185
+ def chain_of_verification_openai(
186
+ initial_reply,
187
+ step2_prompt,
188
+ step3_prompt,
189
+ step4_prompt,
190
+ client,
191
+ user_model,
192
+ creativity,
193
+ remove_numbering
194
+ ):
195
+ """
196
+ Execute Chain of Verification (CoVe) process.
197
+ Returns the verified reply or initial reply if error occurs.
198
+ """
199
+ try:
200
+ # STEP 2: Generate verification questions
201
+ step2_filled = step2_prompt.replace('<<INITIAL_REPLY>>', initial_reply)
202
+
203
+ verification_response = client.chat.completions.create(
204
+ model=user_model,
205
+ messages=[{'role': 'user', 'content': step2_filled}],
206
+ **({"temperature": creativity} if creativity is not None else {})
207
+ )
208
+
209
+ verification_questions = verification_response.choices[0].message.content
210
+
211
+ # STEP 3: Answer verification questions
212
+ questions_list = [
213
+ remove_numbering(q)
214
+ for q in verification_questions.split('\n')
215
+ if q.strip()
216
+ ]
217
+ verification_qa = []
218
+
219
+ # Prompting each question individually
220
+ for question in questions_list:
221
+ step3_filled = step3_prompt.replace('<<QUESTION>>', question)
222
+
223
+ answer_response = client.chat.completions.create(
224
+ model=user_model,
225
+ messages=[{'role': 'user', 'content': step3_filled}],
226
+ **({"temperature": creativity} if creativity is not None else {})
227
+ )
228
+
229
+ answer = answer_response.choices[0].message.content
230
+ verification_qa.append(f"Q: {question}\nA: {answer}")
231
+
232
+ # STEP 4: Final corrected categorization
233
+ verification_qa_text = "\n\n".join(verification_qa)
234
+
235
+ step4_filled = (step4_prompt
236
+ .replace('<<INITIAL_REPLY>>', initial_reply)
237
+ .replace('<<VERIFICATION_QA>>', verification_qa_text))
238
+
239
+ print(f"Final prompt:\n{step4_filled}\n")
240
+
241
+ final_response = client.chat.completions.create(
242
+ model=user_model,
243
+ messages=[{'role': 'user', 'content': step4_filled}],
244
+ response_format={"type": "json_object"},
245
+ **({"temperature": creativity} if creativity is not None else {})
246
+ )
247
+
248
+ verified_reply = final_response.choices[0].message.content
249
+ print("Chain of verification completed. Final response generated.\n")
250
+
251
+ return verified_reply
252
+
253
+ except Exception as e:
254
+ print(f"ERROR in Chain of Verification: {str(e)}")
255
+ print("Falling back to initial response.\n")
256
+ return initial_reply
257
+
258
+ # anthropic chain of verification calls
259
+
260
+ def chain_of_verification_anthropic(
261
+ initial_reply,
262
+ step2_prompt,
263
+ step3_prompt,
264
+ step4_prompt,
265
+ client,
266
+ user_model,
267
+ creativity,
268
+ remove_numbering
269
+ ):
270
+ """
271
+ Execute Chain of Verification (CoVe) process for Anthropic Claude.
272
+ Returns the verified reply or initial reply if error occurs.
273
+ """
274
+ try:
275
+ # STEP 2: Generate verification questions
276
+ step2_filled = step2_prompt.replace('<<INITIAL_REPLY>>', initial_reply)
277
+
278
+ verification_response = client.messages.create(
279
+ model=user_model,
280
+ messages=[{'role': 'user', 'content': step2_filled}],
281
+ max_tokens=4096,
282
+ **({"temperature": creativity} if creativity is not None else {})
283
+ )
284
+
285
+ verification_questions = verification_response.content[0].text
286
+
287
+ # STEP 3: Answer verification questions
288
+ questions_list = [
289
+ remove_numbering(q)
290
+ for q in verification_questions.split('\n')
291
+ if q.strip()
292
+ ]
293
+ print(f"Verification questions:\n{questions_list}\n")
294
+ verification_qa = []
295
+
296
+ # Prompting each question individually
297
+ for question in questions_list:
298
+ step3_filled = step3_prompt.replace('<<QUESTION>>', question)
299
+
300
+ answer_response = client.messages.create(
301
+ model=user_model,
302
+ messages=[{'role': 'user', 'content': step3_filled}],
303
+ max_tokens=4096,
304
+ **({"temperature": creativity} if creativity is not None else {})
305
+ )
306
+
307
+ answer = answer_response.content[0].text
308
+ verification_qa.append(f"Q: {question}\nA: {answer}")
309
+
310
+ # STEP 4: Final corrected categorization
311
+ verification_qa_text = "\n\n".join(verification_qa)
312
+
313
+ step4_filled = (step4_prompt
314
+ .replace('<<INITIAL_REPLY>>', initial_reply)
315
+ .replace('<<VERIFICATION_QA>>', verification_qa_text))
316
+
317
+ print(f"Final prompt:\n{step4_filled}\n")
318
+
319
+ tools = [{
320
+ "name": "return_categories",
321
+ "description": "Return categorization results as 0 (not present) or 1 (present) for each category",
322
+ "input_schema": {
323
+ "type": "object",
324
+ "properties": properties,
325
+ "required": list(properties.keys()) # All categories required
326
+ }
327
+ }]
328
+
329
+ final_response = client.messages.create(
330
+ model=user_model,
331
+ messages=[{'role': 'user', 'content': step4_filled}],
332
+ max_tokens=4096,
333
+ tools=tools,
334
+ tool_choice={"type": "tool", "name": "return_categories"},
335
+ **({"temperature": creativity} if creativity is not None else {})
336
+ )
337
+
338
+ result_dict = final_response.content[0].input
339
+
340
+ verified_reply = json.dumps(result_dict)
341
+ print("Chain of verification completed. Final response generated.\n")
342
+
343
+ return verified_reply
344
+
345
+ except Exception as e:
346
+ print(f"ERROR in Chain of Verification: {str(e)}")
347
+ print("Falling back to initial response.\n")
348
+ return initial_reply
349
+
350
+ # google chain of verification calls
351
+ def chain_of_verification_google(
352
+ initial_reply,
353
+ prompt,
354
+ step2_prompt,
355
+ step3_prompt,
356
+ step4_prompt,
357
+ url,
358
+ headers,
359
+ creativity,
360
+ remove_numbering,
361
+ make_google_request
362
+ ):
363
+ import time
364
+ """
365
+ Execute Chain of Verification (CoVe) process for Google Gemini.
366
+ Returns the verified reply or initial reply if error occurs.
367
+ """
368
+ try:
369
+ # STEP 2: Generate verification questions
370
+ step2_filled = step2_prompt.replace('<<INITIAL_REPLY>>', initial_reply)
371
+
372
+ payload_step2 = {
373
+ "contents": [{
374
+ "parts": [{"text": step2_filled}]
375
+ }],
376
+ **({"generationConfig": {"temperature": creativity}} if creativity is not None else {}),
377
+ **({"thinkingConfig": {"thinkingBudget": thinking_budget}} if thinking_budget is not None else {})
378
+ }
379
+
380
+ result_step2 = make_google_request(url, headers, payload_step2)
381
+ verification_questions = result_step2["candidates"][0]["content"]["parts"][0]["text"]
382
+
383
+ # STEP 3: Answer verification questions
384
+ questions_list = [
385
+ remove_numbering(q)
386
+ for q in verification_questions.split('\n')
387
+ if q.strip()
388
+ ]
389
+ verification_qa = []
390
+
391
+ for question in questions_list:
392
+ time.sleep(2) # temporary rate limit handling
393
+ step3_filled = step3_prompt.replace('<<QUESTION>>', question)
394
+
395
+ payload_step3 = {
396
+ "contents": [{
397
+ "parts": [{"text": step3_filled}]
398
+ }],
399
+ **({"generationConfig": {"temperature": creativity}} if creativity is not None else {}),
400
+ **({"thinkingConfig": {"thinkingBudget": thinking_budget}} if thinking_budget is not None else {})
401
+ }
402
+
403
+ result_step3 = make_google_request(url, headers, payload_step3)
404
+ answer = result_step3["candidates"][0]["content"]["parts"][0]["text"]
405
+ verification_qa.append(f"Q: {question}\nA: {answer}")
406
+
407
+ # STEP 4: Final corrected categorization
408
+ verification_qa_text = "\n\n".join(verification_qa)
409
+
410
+ step4_filled = (step4_prompt
411
+ .replace('<<PROMPT>>', prompt)
412
+ .replace('<<INITIAL_REPLY>>', initial_reply)
413
+ .replace('<<VERIFICATION_QA>>', verification_qa_text))
414
+
415
+ payload_step4 = {
416
+ "contents": [{
417
+ "parts": [{"text": step4_filled}]
418
+ }],
419
+ "generationConfig": {
420
+ "responseMimeType": "application/json",
421
+ **({"temperature": creativity} if creativity is not None else {}),
422
+ **({"thinkingConfig": {"thinkingBudget": thinking_budget}} if thinking_budget is not None else {})
423
+ }
424
+ }
425
+
426
+ result_step4 = make_google_request(url, headers, payload_step4)
427
+ verified_reply = result_step4["candidates"][0]["content"]["parts"][0]["text"]
428
+
429
+ print("Chain of verification completed. Final response generated.\n")
430
+ return verified_reply
431
+
432
+ except Exception as e:
433
+ print(f"ERROR in Chain of Verification: {str(e)}")
434
+ print("Falling back to initial response.\n")
435
+ return initial_reply
436
+
437
+ # mistral chain of verification calls
438
+
439
+ def chain_of_verification_mistral(
440
+ initial_reply,
441
+ step2_prompt,
442
+ step3_prompt,
443
+ step4_prompt,
444
+ client,
445
+ user_model,
446
+ creativity,
447
+ remove_numbering
448
+ ):
449
+ """
450
+ Execute Chain of Verification (CoVe) process for Mistral AI.
451
+ Returns the verified reply or initial reply if error occurs.
452
+ """
453
+ try:
454
+ # STEP 2: Generate verification questions
455
+ step2_filled = step2_prompt.replace('<<INITIAL_REPLY>>', initial_reply)
456
+
457
+ verification_response = client.chat.complete(
458
+ model=user_model,
459
+ messages=[{'role': 'user', 'content': step2_filled}],
460
+ **({"temperature": creativity} if creativity is not None else {})
461
+ )
462
+
463
+ verification_questions = verification_response.choices[0].message.content
464
+
465
+ # STEP 3: Answer verification questions
466
+ questions_list = [
467
+ remove_numbering(q)
468
+ for q in verification_questions.split('\n')
469
+ if q.strip()
470
+ ]
471
+ verification_qa = []
472
+
473
+ # Prompting each question individually
474
+ for question in questions_list:
475
+ step3_filled = step3_prompt.replace('<<QUESTION>>', question)
476
+
477
+ answer_response = client.chat.complete(
478
+ model=user_model,
479
+ messages=[{'role': 'user', 'content': step3_filled}],
480
+ **({"temperature": creativity} if creativity is not None else {})
481
+ )
482
+
483
+ answer = answer_response.choices[0].message.content
484
+ verification_qa.append(f"Q: {question}\nA: {answer}")
485
+
486
+ # STEP 4: Final corrected categorization
487
+ verification_qa_text = "\n\n".join(verification_qa)
488
+
489
+ step4_filled = (step4_prompt
490
+ .replace('<<INITIAL_REPLY>>', initial_reply)
491
+ .replace('<<VERIFICATION_QA>>', verification_qa_text))
492
+
493
+ final_response = client.chat.complete(
494
+ model=user_model,
495
+ messages=[{'role': 'user', 'content': step4_filled}],
496
+ response_format={"type": "json_object"},
497
+ **({"temperature": creativity} if creativity is not None else {})
498
+ )
499
+
500
+ verified_reply = final_response.choices[0].message.content
501
+ print("Chain of verification completed. Final response generated.\n")
502
+
503
+ return verified_reply
504
+
505
+ except Exception as e:
506
+ print(f"ERROR in Chain of Verification: {str(e)}")
507
+ print("Falling back to initial response.\n")
508
+ return initial_reply
509
+
510
+ # openai explore corpus call
511
+ def get_openai_top_n(
512
+ prompt,
513
+ user_model,
514
+ specificity,
515
+ model_source,
516
+ api_key,
517
+ research_question,
518
+ creativity
519
+ ):
520
+ """
521
+ Get response from OpenAI API with system message.
522
+ Uses direct HTTP requests instead of OpenAI SDK for lighter dependencies.
523
+ """
524
+ # Determine the base URL based on model source
525
+ if model_source == "huggingface":
526
+ from cat_stack._providers import _detect_huggingface_endpoint
527
+ base_url = _detect_huggingface_endpoint(api_key, user_model)
528
+ elif model_source == "huggingface-together":
529
+ base_url = "https://router.huggingface.co/together/v1"
530
+ elif model_source == "perplexity":
531
+ base_url = "https://api.perplexity.ai"
532
+ elif model_source == "xai":
533
+ base_url = "https://api.x.ai/v1"
534
+ else:
535
+ base_url = "https://api.openai.com/v1"
536
+
537
+ endpoint = f"{base_url}/chat/completions"
538
+
539
+ headers = {
540
+ "Content-Type": "application/json",
541
+ "Authorization": f"Bearer {api_key}"
542
+ }
543
+
544
+ # Build system message
545
+ if research_question:
546
+ system_content = (
547
+ f"You are a helpful assistant that extracts categories from text responses. "
548
+ f"The specific task is to identify {specificity} categories of responses to a text prompt. "
549
+ f"The research question is: {research_question}"
550
+ )
551
+ else:
552
+ system_content = "You are a helpful assistant."
553
+
554
+ payload = {
555
+ "model": user_model,
556
+ "messages": [
557
+ {"role": "system", "content": system_content},
558
+ {"role": "user", "content": prompt}
559
+ ],
560
+ }
561
+
562
+ if creativity is not None:
563
+ payload["temperature"] = creativity
564
+
565
+ response = requests.post(endpoint, headers=headers, json=payload, timeout=120)
566
+ response.raise_for_status()
567
+ result = response.json()
568
+
569
+ return result["choices"][0]["message"]["content"]
570
+
571
+ def get_anthropic_top_n(
572
+ prompt,
573
+ user_model,
574
+ model_source,
575
+ specificity,
576
+ api_key,
577
+ research_question,
578
+ creativity
579
+ ):
580
+ """
581
+ Get response from Anthropic API with system prompt.
582
+
583
+ Uses direct HTTP requests instead of Anthropic SDK for lighter dependencies.
584
+ """
585
+ import requests
586
+
587
+ endpoint = "https://api.anthropic.com/v1/messages"
588
+
589
+ headers = {
590
+ "Content-Type": "application/json",
591
+ "x-api-key": api_key,
592
+ "anthropic-version": "2023-06-01"
593
+ }
594
+
595
+ # Build system prompt
596
+ if research_question:
597
+ system_content = (f"You are a helpful assistant that extracts categories from text responses. "
598
+ f"The specific task is to identify {specificity} categories of responses to a text prompt. "
599
+ f"The research question is: {research_question}")
600
+ else:
601
+ system_content = "You are a helpful assistant."
602
+
603
+ payload = {
604
+ "model": user_model,
605
+ "max_tokens": 4096,
606
+ "system": system_content,
607
+ "messages": [{"role": "user", "content": prompt}],
608
+ }
609
+
610
+ if creativity is not None:
611
+ payload["temperature"] = creativity
612
+
613
+ response = requests.post(endpoint, headers=headers, json=payload, timeout=120)
614
+ response.raise_for_status()
615
+ result = response.json()
616
+
617
+ # Parse response - Anthropic returns content as a list
618
+ content = result.get("content", [])
619
+ if content and content[0].get("type") == "text":
620
+ return content[0].get("text", "")
621
+
622
+ return ""