symbolicai 1.5.0__py3-none-any.whl → 1.6.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.
- symai/__init__.py +21 -71
- symai/backend/base.py +0 -26
- symai/backend/engines/drawing/engine_gemini_image.py +101 -0
- symai/backend/engines/embedding/engine_openai.py +11 -8
- symai/backend/engines/neurosymbolic/__init__.py +8 -0
- symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +14 -1
- symai/backend/engines/neurosymbolic/engine_openrouter.py +294 -0
- symai/backend/mixin/__init__.py +4 -0
- symai/backend/mixin/openrouter.py +2 -0
- symai/components.py +203 -13
- symai/extended/interfaces/nanobanana.py +23 -0
- symai/interfaces.py +2 -0
- symai/ops/primitives.py +0 -18
- symai/shellsv.py +2 -7
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/METADATA +2 -9
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/RECORD +20 -43
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/WHEEL +1 -1
- symai/backend/driver/webclient.py +0 -217
- symai/backend/engines/crawler/engine_selenium.py +0 -94
- symai/backend/engines/drawing/engine_dall_e.py +0 -131
- symai/backend/engines/embedding/engine_plugin_embeddings.py +0 -12
- symai/backend/engines/experiments/engine_bard_wrapper.py +0 -131
- symai/backend/engines/experiments/engine_gptfinetuner.py +0 -32
- symai/backend/engines/experiments/engine_llamacpp_completion.py +0 -142
- symai/backend/engines/neurosymbolic/engine_openai_gptX_completion.py +0 -277
- symai/collect/__init__.py +0 -8
- symai/collect/dynamic.py +0 -117
- symai/collect/pipeline.py +0 -156
- symai/collect/stats.py +0 -434
- symai/extended/crawler.py +0 -21
- symai/extended/interfaces/selenium.py +0 -18
- symai/extended/interfaces/vectordb.py +0 -21
- symai/extended/personas/__init__.py +0 -3
- symai/extended/personas/builder.py +0 -105
- symai/extended/personas/dialogue.py +0 -126
- symai/extended/personas/persona.py +0 -154
- symai/extended/personas/research/__init__.py +0 -1
- symai/extended/personas/research/yann_lecun.py +0 -62
- symai/extended/personas/sales/__init__.py +0 -1
- symai/extended/personas/sales/erik_james.py +0 -62
- symai/extended/personas/student/__init__.py +0 -1
- symai/extended/personas/student/max_tenner.py +0 -51
- symai/extended/strategies/__init__.py +0 -1
- symai/extended/strategies/cot.py +0 -40
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/entry_points.txt +0 -0
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {symbolicai-1.5.0.dist-info → symbolicai-1.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
import requests
|
|
5
|
-
import tiktoken
|
|
6
|
-
from bardapi import Bard
|
|
7
|
-
|
|
8
|
-
from ...base import Engine
|
|
9
|
-
from ...mixin.openai import OpenAIMixin
|
|
10
|
-
from ...settings import SYMAI_CONFIG
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class BardEngine(Engine, OpenAIMixin):
|
|
14
|
-
def __init__(self, timeout: int = 30):
|
|
15
|
-
super().__init__()
|
|
16
|
-
self.timeout = timeout
|
|
17
|
-
config = SYMAI_CONFIG
|
|
18
|
-
self.api_key = config['NEUROSYMBOLIC_ENGINE_API_KEY']
|
|
19
|
-
self.model = config['NEUROSYMBOLIC_ENGINE_MODEL']
|
|
20
|
-
logger = logging.getLogger('openai')
|
|
21
|
-
self.tokenizer = tiktoken.encoding_for_model(self.model)
|
|
22
|
-
self.max_tokens = self.api_max_tokens()
|
|
23
|
-
self.bard = None
|
|
24
|
-
logger.setLevel(logging.WARNING)
|
|
25
|
-
|
|
26
|
-
def init_session(self):
|
|
27
|
-
self.session = requests.Session()
|
|
28
|
-
self.session.headers = {
|
|
29
|
-
"Host": "bard.google.com",
|
|
30
|
-
"X-Same-Domain": "1",
|
|
31
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
|
|
32
|
-
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
33
|
-
"Origin": "https://bard.google.com",
|
|
34
|
-
"Referer": "https://bard.google.com/",
|
|
35
|
-
}
|
|
36
|
-
self.session.cookies.set("__Secure-1PSID", self.api_key)
|
|
37
|
-
self.bard = Bard(token=self.api_key,
|
|
38
|
-
session=self.session,
|
|
39
|
-
timeout=self.timeout)
|
|
40
|
-
|
|
41
|
-
def id(self) -> str:
|
|
42
|
-
if self.config['NEUROSYMBOLIC_ENGINE_MODEL'] and \
|
|
43
|
-
(self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('bard')):
|
|
44
|
-
return 'neurosymbolic'
|
|
45
|
-
return super().id() # default to unregistered
|
|
46
|
-
|
|
47
|
-
def command(self, *args, **kwargs):
|
|
48
|
-
super().command(*args, **kwargs)
|
|
49
|
-
if 'NEUROSYMBOLIC_ENGINE_API_KEY' in kwargs:
|
|
50
|
-
self.api_key = kwargs['NEUROSYMBOLIC_ENGINE_API_KEY']
|
|
51
|
-
if 'NEUROSYMBOLIC_ENGINE_MODEL' in kwargs:
|
|
52
|
-
self.model = kwargs['NEUROSYMBOLIC_ENGINE_MODEL']
|
|
53
|
-
|
|
54
|
-
def compute_remaining_tokens(self, prompts: list) -> int:
|
|
55
|
-
# iterate over prompts and compute number of tokens
|
|
56
|
-
prompt = prompts[0]
|
|
57
|
-
val = len(self.tokenizer.encode(prompt))
|
|
58
|
-
return int((self.max_tokens - val) * 0.98)
|
|
59
|
-
|
|
60
|
-
def forward(self, argument):
|
|
61
|
-
if self.bard is None:
|
|
62
|
-
self.init_session()
|
|
63
|
-
|
|
64
|
-
kwargs = argument.kwargs
|
|
65
|
-
prompts_ = argument.prop.prepared_input
|
|
66
|
-
prompts_ = prompts_ if isinstance(prompts_, list) else [prompts_]
|
|
67
|
-
except_remedy = kwargs['except_remedy'] if 'except_remedy' in kwargs else None
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
res = self.bard.get_answer(prompts_[0])
|
|
71
|
-
except Exception as e:
|
|
72
|
-
if except_remedy is None:
|
|
73
|
-
raise e
|
|
74
|
-
callback = self.connection.root.predict
|
|
75
|
-
res = except_remedy(self, e, callback, argument)
|
|
76
|
-
|
|
77
|
-
metadata = {}
|
|
78
|
-
|
|
79
|
-
rsp = [res['content']]
|
|
80
|
-
output = rsp if isinstance(prompts_, list) else rsp[0]
|
|
81
|
-
return output, metadata
|
|
82
|
-
|
|
83
|
-
def prepare(self, argument):
|
|
84
|
-
if argument.prop.raw_input:
|
|
85
|
-
if not argument.prop.processed_input:
|
|
86
|
-
raise ValueError('Need to provide a prompt instruction to the engine if raw_input is enabled.')
|
|
87
|
-
argument.prop.prepared_input = argument.prop.processed_input
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
user: str = ""
|
|
91
|
-
system: str = ""
|
|
92
|
-
system = f'{system}\n' if system and len(system) > 0 else ''
|
|
93
|
-
|
|
94
|
-
ref = argument.prop.instance
|
|
95
|
-
static_ctxt, dyn_ctxt = ref.global_context
|
|
96
|
-
if len(static_ctxt) > 0:
|
|
97
|
-
system += f"[STATIC CONTEXT]\n{static_ctxt}\n\n"
|
|
98
|
-
|
|
99
|
-
if len(dyn_ctxt) > 0:
|
|
100
|
-
system += f"[DYNAMIC CONTEXT]\n{dyn_ctxt}\n\n"
|
|
101
|
-
|
|
102
|
-
payload = argument.prop.payload
|
|
103
|
-
if payload is not None:
|
|
104
|
-
system += f"[ADDITIONAL CONTEXT]\n{payload}\n\n"
|
|
105
|
-
|
|
106
|
-
examples: List[str] = argument.prop.examples
|
|
107
|
-
if examples and len(examples) > 0:
|
|
108
|
-
system += f"[EXAMPLES]\n{str(examples)}\n\n"
|
|
109
|
-
|
|
110
|
-
if argument.prop.prompt is not None and len(argument.prop.prompt) > 0:
|
|
111
|
-
val = str(argument.prop.prompt)
|
|
112
|
-
system += f"[INSTRUCTION]\n{val}"
|
|
113
|
-
|
|
114
|
-
suffix: str = str(argument.prop.processed_input)
|
|
115
|
-
if '=>' in suffix:
|
|
116
|
-
user += f"[LAST TASK]\n"
|
|
117
|
-
|
|
118
|
-
if '[SYSTEM_INSTRUCTION::]: <<<' in suffix and argument.prop.parse_system_instructions:
|
|
119
|
-
parts = suffix.split('\n>>>\n')
|
|
120
|
-
# first parts are the system instructions
|
|
121
|
-
for p in parts[:-1]:
|
|
122
|
-
system += f"{p}\n"
|
|
123
|
-
# last part is the user input
|
|
124
|
-
suffix = parts[-1]
|
|
125
|
-
user += f"{suffix}"
|
|
126
|
-
|
|
127
|
-
if argument.prop.template_suffix is not None:
|
|
128
|
-
user += f"\n[[PLACEHOLDER]]\n{argument.prop.template_suffix}\n\n"
|
|
129
|
-
user += f"Only generate content for the placeholder `[[PLACEHOLDER]]` following the instructions and context information. Do NOT write `[[PLACEHOLDER]]` or anything else in your output.\n\n"
|
|
130
|
-
|
|
131
|
-
argument.prop.prepared_input = [f'---------SYSTEM BEHAVIOR--------\n{system}\n\n---------USER REQUEST--------\n{user}']
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
import openai
|
|
5
|
-
|
|
6
|
-
from ....utils import Args
|
|
7
|
-
from ...base import Engine
|
|
8
|
-
from ...settings import SYMAI_CONFIG
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class GPTFineTuner(Engine):
|
|
12
|
-
def __init__(self):
|
|
13
|
-
super().__init__()
|
|
14
|
-
config = SYMAI_CONFIG
|
|
15
|
-
openai.api_key = config['NEUROSYMBOLIC_ENGINE_API_KEY']
|
|
16
|
-
self.base_model = "babbage"
|
|
17
|
-
|
|
18
|
-
def forward(self, argument):
|
|
19
|
-
kwargs = argument.kwargs
|
|
20
|
-
assert '__cmd__' in kwargs, "Missing __cmd__ argument"
|
|
21
|
-
rsp = None
|
|
22
|
-
|
|
23
|
-
raise NotImplementedError("GPTFineTuner is not implemented yet")
|
|
24
|
-
|
|
25
|
-
del kwargs['__cmd__']
|
|
26
|
-
|
|
27
|
-
metadata = {}
|
|
28
|
-
|
|
29
|
-
return [rsp], metadata
|
|
30
|
-
|
|
31
|
-
def prepare(self, argument):
|
|
32
|
-
assert not argument.prop.processed_input, "GPTFineTuner does not support processed_input."
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from ...base import Engine
|
|
5
|
-
from ...settings import SYMAI_CONFIG
|
|
6
|
-
|
|
7
|
-
import requests
|
|
8
|
-
import json
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class LLaMACppCompletionClient():
|
|
12
|
-
def __init__(self, base_url="http://localhost:8000"):
|
|
13
|
-
self.base_url = base_url
|
|
14
|
-
|
|
15
|
-
def create_completion(self, completion_request):
|
|
16
|
-
# Preparing header information
|
|
17
|
-
headers = {
|
|
18
|
-
'Content-Type': 'application/json',
|
|
19
|
-
'Accept': 'application/json'
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
# Performing POST request
|
|
23
|
-
response = requests.post(f"{self.base_url}/v1/engines/copilot-codex/completions",
|
|
24
|
-
data=json.dumps(completion_request),
|
|
25
|
-
headers=headers)
|
|
26
|
-
|
|
27
|
-
print(response)
|
|
28
|
-
|
|
29
|
-
# Parsing response
|
|
30
|
-
if response.status_code == 200:
|
|
31
|
-
return json.loads(response.text)
|
|
32
|
-
else:
|
|
33
|
-
raise Exception(f"Request failed with status code {response.status_code}")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class LLaMACppCompletionEngine(Engine):
|
|
37
|
-
def __init__(self):
|
|
38
|
-
super().__init__()
|
|
39
|
-
config = SYMAI_CONFIG
|
|
40
|
-
self.model = config['NEUROSYMBOLIC_ENGINE_MODEL']
|
|
41
|
-
logger = logging.getLogger('LLaMA')
|
|
42
|
-
logger.setLevel(logging.WARNING)
|
|
43
|
-
|
|
44
|
-
self.client = LLaMACppCompletionClient() # Initialize LLaMACpp client here
|
|
45
|
-
|
|
46
|
-
def command(self, *args, **kwargs):
|
|
47
|
-
super().command(*args, **kwargs)
|
|
48
|
-
if 'NEUROSYMBOLIC_ENGINE_MODEL' in kwargs:
|
|
49
|
-
self.model = kwargs['NEUROSYMBOLIC_ENGINE_MODEL']
|
|
50
|
-
|
|
51
|
-
def forward(self, argument):
|
|
52
|
-
prompts_ = argument.prop.prepared_input
|
|
53
|
-
prompts_ = prompts_ if isinstance(prompts_, list) else [prompts_]
|
|
54
|
-
kwargs = argument.kwargs
|
|
55
|
-
max_tokens = kwargs['max_tokens'] if 'max_tokens' in kwargs else 4096
|
|
56
|
-
temperature = kwargs['temperature'] if 'temperature' in kwargs else 0.7
|
|
57
|
-
top_p = kwargs['top_p'] if 'top_p' in kwargs else 1
|
|
58
|
-
except_remedy = kwargs['except_remedy'] if 'except_remedy' in kwargs else None
|
|
59
|
-
|
|
60
|
-
completion_request = {
|
|
61
|
-
"prompt": prompts_,
|
|
62
|
-
"stop": ["\n\n", "-------"]
|
|
63
|
-
#"max_tokens": max_tokens,
|
|
64
|
-
#"temperature": temperature,
|
|
65
|
-
#"top_p": top_p,
|
|
66
|
-
#"mirostat_mode": 0,
|
|
67
|
-
#"mirostat_tau": 0.2,
|
|
68
|
-
#"mirostat_eta": 0.5,
|
|
69
|
-
#"echo": False
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
print(completion_request)
|
|
74
|
-
res = self.client.create_completion(completion_request)
|
|
75
|
-
except Exception as e:
|
|
76
|
-
if except_remedy is None:
|
|
77
|
-
raise e
|
|
78
|
-
callback = self.connection.root.predict
|
|
79
|
-
res = except_remedy(self, e, callback, argument)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
metadata = {}
|
|
83
|
-
|
|
84
|
-
rsp = [r['text'] for r in res['choices']]
|
|
85
|
-
output = rsp if isinstance(prompts_, list) else rsp[0]
|
|
86
|
-
return output, metadata
|
|
87
|
-
|
|
88
|
-
def prepare(self, argument):
|
|
89
|
-
if argument.prop.raw_input:
|
|
90
|
-
if not argument.prop.processed_input:
|
|
91
|
-
raise ValueError('Need to provide a prompt instruction to the engine if raw_input is enabled.')
|
|
92
|
-
argument.prop.prepared_input = argument.prop.processed_input
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
user: str = ""
|
|
96
|
-
system: str = ""
|
|
97
|
-
system = f'{system}\n' if system and len(system) > 0 else ''
|
|
98
|
-
|
|
99
|
-
ref = argument.prop.instance
|
|
100
|
-
static_ctxt, dyn_ctxt = ref.global_context
|
|
101
|
-
if len(static_ctxt) > 0:
|
|
102
|
-
system += f"[STATIC CONTEXT]\n{static_ctxt}\n\n"
|
|
103
|
-
|
|
104
|
-
if len(dyn_ctxt) > 0:
|
|
105
|
-
system += f"[DYNAMIC CONTEXT]\n{dyn_ctxt}\n\n"
|
|
106
|
-
|
|
107
|
-
payload = argument.prop.payload
|
|
108
|
-
if payload is not None:
|
|
109
|
-
system += f"[ADDITIONAL CONTEXT]\n{str(payload)}\n\n"
|
|
110
|
-
|
|
111
|
-
examples: List[str] = argument.prop.examples
|
|
112
|
-
if examples and len(examples) > 0:
|
|
113
|
-
system += f"[EXAMPLES]\n{str(examples)}\n\n"
|
|
114
|
-
|
|
115
|
-
if argument.prop.prompt is not None and len(argument.prop.prompt) > 0:
|
|
116
|
-
val = str(argument.prop.prompt)
|
|
117
|
-
system += f"[INSTRUCTION]\n{val}"
|
|
118
|
-
|
|
119
|
-
suffix: str = str(argument.prop.processed_input)
|
|
120
|
-
if '=>' in suffix:
|
|
121
|
-
user += f"[LAST TASK]\n"
|
|
122
|
-
|
|
123
|
-
if '[SYSTEM_INSTRUCTION::]: <<<' in suffix and argument.prop.parse_system_instructions:
|
|
124
|
-
parts = suffix.split('\n>>>\n')
|
|
125
|
-
# first parts are the system instructions
|
|
126
|
-
for p in parts[:-1]:
|
|
127
|
-
system += f"{p}\n"
|
|
128
|
-
# last part is the user input
|
|
129
|
-
suffix = parts[-1]
|
|
130
|
-
user += f"{suffix}"
|
|
131
|
-
|
|
132
|
-
if argument.prop.template_suffix is not None:
|
|
133
|
-
user += f"\n[[PLACEHOLDER]]\n{str(argument.prop.template_suffix)}\n\n"
|
|
134
|
-
user += f"Only generate content for the placeholder `[[PLACEHOLDER]]` following the instructions and context information. Do NOT write `[[PLACEHOLDER]]` or anything else in your output.\n\n"
|
|
135
|
-
|
|
136
|
-
argument.prop.prepared_input = [f'---------SYSTEM BEHAVIOR--------\n{system}\n\n---------USER REQUEST--------\n{user}']
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if __name__ == '__main__':
|
|
140
|
-
engine = LLaMACppCompletionEngine()
|
|
141
|
-
res = engine.forward(["\n\n### Instructions:\nWhat is the capital of Romania?\n\n### Response:\n"])
|
|
142
|
-
print(res)
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from copy import deepcopy
|
|
3
|
-
from typing import List, Optional
|
|
4
|
-
|
|
5
|
-
import openai
|
|
6
|
-
import tiktoken
|
|
7
|
-
|
|
8
|
-
from ....misc.console import ConsoleStyle
|
|
9
|
-
from ....utils import CustomUserWarning
|
|
10
|
-
from ...base import Engine
|
|
11
|
-
from ...mixin.openai import OpenAIMixin
|
|
12
|
-
from ...settings import SYMAI_CONFIG
|
|
13
|
-
|
|
14
|
-
logging.getLogger("openai").setLevel(logging.ERROR)
|
|
15
|
-
logging.getLogger("requests").setLevel(logging.ERROR)
|
|
16
|
-
logging.getLogger("urllib").setLevel(logging.ERROR)
|
|
17
|
-
logging.getLogger("httpx").setLevel(logging.ERROR)
|
|
18
|
-
logging.getLogger("httpcore").setLevel(logging.ERROR)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class InvalidRequestErrorRemedyCompletionStrategy:
|
|
22
|
-
def __init__(self, *args, **kwargs):
|
|
23
|
-
super().__init__(*args, **kwargs)
|
|
24
|
-
|
|
25
|
-
def __call__(self, engine, error, callback, argument):
|
|
26
|
-
openai_kwargs = {}
|
|
27
|
-
kwargs = argument.kwargs
|
|
28
|
-
prompts_ = argument.prop.prepared_input
|
|
29
|
-
# send prompt to GPT-X Completion-based
|
|
30
|
-
stop = kwargs['stop'] if 'stop' in kwargs else None
|
|
31
|
-
model = kwargs['model'] if 'model' in kwargs else None
|
|
32
|
-
|
|
33
|
-
msg = str(error)
|
|
34
|
-
handle = None
|
|
35
|
-
try:
|
|
36
|
-
if "This model's maximum context length is" in msg:
|
|
37
|
-
handle = 'type1'
|
|
38
|
-
max_ = engine.max_context_tokens
|
|
39
|
-
usr = msg.split('tokens. ')[1].split(' ')[-1]
|
|
40
|
-
overflow_tokens = int(usr) - int(max_)
|
|
41
|
-
elif "is less than the minimum" in msg:
|
|
42
|
-
handle = 'type2'
|
|
43
|
-
overflow_tokens = engine.max_response_tokens
|
|
44
|
-
else:
|
|
45
|
-
raise Exception(msg) from error
|
|
46
|
-
except Exception as e:
|
|
47
|
-
raise e from error
|
|
48
|
-
|
|
49
|
-
# unify the format to use same remedy strategy for both chat and completion
|
|
50
|
-
values = prompts_[0].replace('---------SYSTEM BEHAVIOR--------\n', '').split('\n\n---------USER REQUEST--------\n')
|
|
51
|
-
prompts_ = [{'role': 'system', 'content': values[0]}, {'role': 'user', 'content': values[1]}]
|
|
52
|
-
|
|
53
|
-
prompts = [p for p in prompts_ if p['role'] == 'user']
|
|
54
|
-
system_prompt = [p for p in prompts_ if p['role'] == 'system']
|
|
55
|
-
|
|
56
|
-
def compute_required_tokens(prompts: dict) -> int:
|
|
57
|
-
# iterate over prompts and compute number of tokens
|
|
58
|
-
prompts_ = [role['content'] for role in prompts]
|
|
59
|
-
prompt = ''.join(prompts_)
|
|
60
|
-
val = len(engine.tokenizer.encode(prompt, disallowed_special=()))
|
|
61
|
-
return val
|
|
62
|
-
|
|
63
|
-
def compute_remaining_tokens(prompts: list) -> int:
|
|
64
|
-
val = compute_required_tokens(prompts)
|
|
65
|
-
return int((engine.max_context_tokens - val) * 0.99)
|
|
66
|
-
|
|
67
|
-
if handle == 'type1':
|
|
68
|
-
truncated_content_ = [p['content'][overflow_tokens:] for p in prompts]
|
|
69
|
-
truncated_prompts_ = [{'role': p['role'], 'content': c} for p, c in zip(prompts, truncated_content_)]
|
|
70
|
-
CustomUserWarning(f"WARNING: Overflow tokens detected. Reducing prompt size by {overflow_tokens} characters.")
|
|
71
|
-
elif handle == 'type2':
|
|
72
|
-
user_prompts = [p['content'] for p in prompts]
|
|
73
|
-
new_prompt = [*system_prompt]
|
|
74
|
-
new_prompt.extend([{'role': p['role'], 'content': c} for p, c in zip(prompts, user_prompts)])
|
|
75
|
-
overflow_tokens = compute_required_tokens(new_prompt) - int(engine.max_context_tokens * 0.70)
|
|
76
|
-
if overflow_tokens > 0:
|
|
77
|
-
CustomUserWarning(f'WARNING: Overflow tokens detected. Reducing prompt size to 70% of model context size ({engine.max_context_tokens}).')
|
|
78
|
-
for i, content in enumerate(user_prompts):
|
|
79
|
-
token_ids = engine.tokenizer.encode(content)
|
|
80
|
-
if overflow_tokens >= len(token_ids):
|
|
81
|
-
overflow_tokens -= len(token_ids)
|
|
82
|
-
user_prompts[i] = ''
|
|
83
|
-
else:
|
|
84
|
-
new_content = engine.tokenizer.decode(token_ids[:-overflow_tokens])
|
|
85
|
-
user_prompts[i] = new_content
|
|
86
|
-
overflow_tokens = 0
|
|
87
|
-
break
|
|
88
|
-
|
|
89
|
-
new_prompt = [*system_prompt]
|
|
90
|
-
new_prompt.extend([{'role': p['role'], 'content': c} for p, c in zip(prompts, user_prompts)])
|
|
91
|
-
assert compute_required_tokens(new_prompt) <= engine.max_context_tokens, \
|
|
92
|
-
f"Token overflow: prompts exceed {engine.max_context_tokens} tokens after truncation"
|
|
93
|
-
|
|
94
|
-
truncated_prompts_ = [{'role': p['role'], 'content': c.strip()} for p, c in zip(prompts, user_prompts) if c.strip()]
|
|
95
|
-
else:
|
|
96
|
-
raise Exception('Invalid handle case for remedy strategy.') from error
|
|
97
|
-
|
|
98
|
-
truncated_prompts_ = [*system_prompt, *truncated_prompts_]
|
|
99
|
-
|
|
100
|
-
# convert map to list of strings
|
|
101
|
-
max_tokens = kwargs['max_tokens'] if 'max_tokens' in kwargs else compute_remaining_tokens(truncated_prompts_)
|
|
102
|
-
temperature = kwargs['temperature'] if 'temperature' in kwargs else 1
|
|
103
|
-
frequency_penalty = kwargs['frequency_penalty'] if 'frequency_penalty' in kwargs else 0
|
|
104
|
-
presence_penalty = kwargs['presence_penalty'] if 'presence_penalty' in kwargs else 0
|
|
105
|
-
top_p = kwargs['top_p'] if 'top_p' in kwargs else 1
|
|
106
|
-
suffix = kwargs['template_suffix'] if 'template_suffix' in kwargs else None
|
|
107
|
-
|
|
108
|
-
system = truncated_prompts_[0]['content']
|
|
109
|
-
user = truncated_prompts_[1]['content']
|
|
110
|
-
truncated_prompts_ = [f'---------SYSTEM BEHAVIOR--------\n{system}\n\n---------USER REQUEST--------\n{user}']
|
|
111
|
-
|
|
112
|
-
if stop is not None:
|
|
113
|
-
openai_kwargs['stop'] = stop
|
|
114
|
-
|
|
115
|
-
return callback(model=model,
|
|
116
|
-
prompt=truncated_prompts_,
|
|
117
|
-
suffix=suffix,
|
|
118
|
-
max_tokens=max_tokens,
|
|
119
|
-
temperature=temperature,
|
|
120
|
-
frequency_penalty=frequency_penalty,
|
|
121
|
-
presence_penalty=presence_penalty,
|
|
122
|
-
top_p=top_p,
|
|
123
|
-
n=1,
|
|
124
|
-
**openai_kwargs)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
class GPTXCompletionEngine(Engine, OpenAIMixin):
|
|
129
|
-
def __init__(self, api_key: Optional[str] = None, model: Optional[str] = None):
|
|
130
|
-
super().__init__()
|
|
131
|
-
logger = logging.getLogger('openai')
|
|
132
|
-
logger.setLevel(logging.WARNING)
|
|
133
|
-
self.config = deepcopy(SYMAI_CONFIG)
|
|
134
|
-
if self.id() != 'neurosymbolic':
|
|
135
|
-
return # do not initialize if not neurosymbolic; avoids conflict with llama.cpp check in EngineRepository.register_from_package
|
|
136
|
-
openai.api_key = self.config['NEUROSYMBOLIC_ENGINE_API_KEY'] if api_key is None else api_key
|
|
137
|
-
self.model = self.config['NEUROSYMBOLIC_ENGINE_MODEL'] if model is None else model
|
|
138
|
-
self.tokenizer = tiktoken.encoding_for_model(self.model)
|
|
139
|
-
self.max_context_tokens = self.api_max_context_tokens()
|
|
140
|
-
self.max_response_tokens = self.api_max_response_tokens()
|
|
141
|
-
self.except_remedy = None
|
|
142
|
-
|
|
143
|
-
def id(self) -> str:
|
|
144
|
-
if self.config['NEUROSYMBOLIC_ENGINE_MODEL'] and \
|
|
145
|
-
(self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('text-') or \
|
|
146
|
-
self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('davinci') or \
|
|
147
|
-
self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('curie') or \
|
|
148
|
-
self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('babbage') or \
|
|
149
|
-
self.config['NEUROSYMBOLIC_ENGINE_MODEL'].startswith('ada')):
|
|
150
|
-
return 'neurosymbolic'
|
|
151
|
-
return super().id() # default to unregistered
|
|
152
|
-
|
|
153
|
-
def command(self, *args, **kwargs):
|
|
154
|
-
super().command(*args, **kwargs)
|
|
155
|
-
if 'NEUROSYMBOLIC_ENGINE_API_KEY' in kwargs:
|
|
156
|
-
openai.api_key = kwargs['NEUROSYMBOLIC_ENGINE_API_KEY']
|
|
157
|
-
if 'NEUROSYMBOLIC_ENGINE_MODEL' in kwargs:
|
|
158
|
-
self.model = kwargs['NEUROSYMBOLIC_ENGINE_MODEL']
|
|
159
|
-
if 'except_remedy' in kwargs:
|
|
160
|
-
self.except_remedy = kwargs['except_remedy']
|
|
161
|
-
|
|
162
|
-
def compute_required_tokens(self, prompts: list) -> int:
|
|
163
|
-
# iterate over prompts and compute number of tokens
|
|
164
|
-
prompt = prompts[0] # index 0 is correct since we only have one prompt in legacy mode
|
|
165
|
-
val = len(self.tokenizer.encode(prompt, disallowed_special=()))
|
|
166
|
-
return val
|
|
167
|
-
|
|
168
|
-
def compute_remaining_tokens(self, prompts: list) -> int:
|
|
169
|
-
val = self.compute_required_tokens(prompts)
|
|
170
|
-
return min(self.max_context_tokens - val, self.max_response_tokens)
|
|
171
|
-
|
|
172
|
-
def forward(self, argument):
|
|
173
|
-
kwargs = argument.kwargs
|
|
174
|
-
prompts_ = argument.prop.prepared_input
|
|
175
|
-
|
|
176
|
-
# send prompt to GPT-3
|
|
177
|
-
max_tokens = kwargs['max_tokens'] if 'max_tokens' in kwargs else self.compute_remaining_tokens(prompts_)
|
|
178
|
-
stop = kwargs['stop'] if 'stop' in kwargs else None
|
|
179
|
-
model = kwargs['model'] if 'model' in kwargs else self.model
|
|
180
|
-
temperature = kwargs['temperature'] if 'temperature' in kwargs else 0.7
|
|
181
|
-
frequency_penalty = kwargs['frequency_penalty'] if 'frequency_penalty' in kwargs else 0
|
|
182
|
-
presence_penalty = kwargs['presence_penalty'] if 'presence_penalty' in kwargs else 0
|
|
183
|
-
top_p = kwargs['top_p'] if 'top_p' in kwargs else 1
|
|
184
|
-
except_remedy = kwargs['except_remedy'] if 'except_remedy' in kwargs else self.except_remedy
|
|
185
|
-
|
|
186
|
-
try:
|
|
187
|
-
res = openai.completions.create(model=model,
|
|
188
|
-
prompt=prompts_,
|
|
189
|
-
max_tokens=max_tokens,
|
|
190
|
-
temperature=temperature,
|
|
191
|
-
frequency_penalty=frequency_penalty,
|
|
192
|
-
presence_penalty=presence_penalty,
|
|
193
|
-
top_p=top_p,
|
|
194
|
-
stop=stop,
|
|
195
|
-
n=1)
|
|
196
|
-
except Exception as e:
|
|
197
|
-
callback = openai.completions.create
|
|
198
|
-
kwargs['model'] = kwargs['model'] if 'model' in kwargs else self.model
|
|
199
|
-
if except_remedy is not None:
|
|
200
|
-
res = except_remedy(self, e, callback, argument)
|
|
201
|
-
else:
|
|
202
|
-
try:
|
|
203
|
-
# implicit remedy strategy
|
|
204
|
-
except_remedy = InvalidRequestErrorRemedyCompletionStrategy()
|
|
205
|
-
res = except_remedy(self, e, callback, argument)
|
|
206
|
-
except Exception as e2:
|
|
207
|
-
ex = Exception(f'Failed to handle exception: {e}. Also failed implicit remedy strategy after retry: {e2}')
|
|
208
|
-
raise ex from e
|
|
209
|
-
|
|
210
|
-
metadata = {}
|
|
211
|
-
# TODO: remove system behavior and user request from output. consider post-processing
|
|
212
|
-
def replace_verbose(rsp):
|
|
213
|
-
rsp = rsp.replace('---------SYSTEM BEHAVIOR--------\n', '')
|
|
214
|
-
rsp = rsp.replace('\n\n---------USER REQUEST--------\n', '')
|
|
215
|
-
return rsp
|
|
216
|
-
|
|
217
|
-
rsp = [replace_verbose(r.text) for r in res.choices]
|
|
218
|
-
output = rsp if isinstance(prompts_, list) else rsp[0]
|
|
219
|
-
return output, metadata
|
|
220
|
-
|
|
221
|
-
def prepare(self, argument):
|
|
222
|
-
if argument.prop.raw_input:
|
|
223
|
-
if not argument.prop.processed_input:
|
|
224
|
-
raise ValueError('Need to provide a prompt instruction to the engine if raw_input is enabled.')
|
|
225
|
-
value = argument.prop.processed_input
|
|
226
|
-
if type(value) is not list:
|
|
227
|
-
value = [str(value)]
|
|
228
|
-
argument.prop.prepared_input = value
|
|
229
|
-
return
|
|
230
|
-
|
|
231
|
-
_non_verbose_output = """[META INSTRUCTIONS START]\nYou do not output anything else, like verbose preambles or post explanation, such as "Sure, let me...", "Hope that was helpful...", "Yes, I can help you with that...", etc. Consider well formatted output, e.g. for sentences use punctuation, spaces etc. or for code use indentation, etc. Never add meta instructions information to your output!\n"""
|
|
232
|
-
|
|
233
|
-
user: str = ""
|
|
234
|
-
system: str = ""
|
|
235
|
-
|
|
236
|
-
if argument.prop.suppress_verbose_output:
|
|
237
|
-
system += _non_verbose_output
|
|
238
|
-
system = f'{system}\n' if system and len(system) > 0 else ''
|
|
239
|
-
|
|
240
|
-
ref = argument.prop.instance
|
|
241
|
-
static_ctxt, dyn_ctxt = ref.global_context
|
|
242
|
-
if len(static_ctxt) > 0:
|
|
243
|
-
system += f"[STATIC CONTEXT]\n{static_ctxt}\n\n"
|
|
244
|
-
|
|
245
|
-
if len(dyn_ctxt) > 0:
|
|
246
|
-
system += f"[DYNAMIC CONTEXT]\n{dyn_ctxt}\n\n"
|
|
247
|
-
|
|
248
|
-
payload = argument.prop.payload
|
|
249
|
-
if payload is not None:
|
|
250
|
-
system += f"[ADDITIONAL CONTEXT]\n{payload}\n\n"
|
|
251
|
-
|
|
252
|
-
examples: List[str] = argument.prop.examples
|
|
253
|
-
if examples and len(examples) > 0:
|
|
254
|
-
system += f"[EXAMPLES]\n{str(examples)}\n\n"
|
|
255
|
-
|
|
256
|
-
if argument.prop.prompt is not None and len(argument.prop.prompt) > 0:
|
|
257
|
-
val = str(argument.prop.prompt)
|
|
258
|
-
system += f"[INSTRUCTION]\n{val}"
|
|
259
|
-
|
|
260
|
-
suffix: str = str(argument.prop.processed_input)
|
|
261
|
-
if '=>' in suffix:
|
|
262
|
-
user += f"[LAST TASK]\n"
|
|
263
|
-
|
|
264
|
-
if '[SYSTEM_INSTRUCTION::]: <<<' in suffix and argument.prop.parse_system_instructions:
|
|
265
|
-
parts = suffix.split('\n>>>\n')
|
|
266
|
-
# first parts are the system instructions
|
|
267
|
-
for p in parts[:-1]:
|
|
268
|
-
system += f"{p}\n"
|
|
269
|
-
# last part is the user input
|
|
270
|
-
suffix = parts[-1]
|
|
271
|
-
user += f"{suffix}"
|
|
272
|
-
|
|
273
|
-
if argument.prop.template_suffix is not None:
|
|
274
|
-
user += f"\n[[PLACEHOLDER]]\n{argument.prop.template_suffix}\n\n"
|
|
275
|
-
user += f"Only generate content for the placeholder `[[PLACEHOLDER]]` following the instructions and context information. Do NOT write `[[PLACEHOLDER]]` or anything else in your output.\n\n"
|
|
276
|
-
|
|
277
|
-
argument.prop.prepared_input = [f'---------SYSTEM BEHAVIOR--------\n{system}\n\n---------USER REQUEST--------\n{user}']
|