lionagi 0.0.312__py3-none-any.whl → 0.2.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (268) hide show
  1. lionagi/__init__.py +61 -3
  2. lionagi/core/__init__.py +0 -14
  3. lionagi/core/_setting/_setting.py +59 -0
  4. lionagi/core/action/__init__.py +14 -0
  5. lionagi/core/action/function_calling.py +136 -0
  6. lionagi/core/action/manual.py +1 -0
  7. lionagi/core/action/node.py +109 -0
  8. lionagi/core/action/tool.py +114 -0
  9. lionagi/core/action/tool_manager.py +356 -0
  10. lionagi/core/agent/__init__.py +0 -3
  11. lionagi/core/agent/base_agent.py +45 -36
  12. lionagi/core/agent/eval/evaluator.py +1 -0
  13. lionagi/core/agent/eval/vote.py +40 -0
  14. lionagi/core/agent/learn/learner.py +59 -0
  15. lionagi/core/agent/plan/unit_template.py +1 -0
  16. lionagi/core/collections/__init__.py +17 -0
  17. lionagi/core/collections/_logger.py +319 -0
  18. lionagi/core/collections/abc/__init__.py +53 -0
  19. lionagi/core/collections/abc/component.py +615 -0
  20. lionagi/core/collections/abc/concepts.py +297 -0
  21. lionagi/core/collections/abc/exceptions.py +150 -0
  22. lionagi/core/collections/abc/util.py +45 -0
  23. lionagi/core/collections/exchange.py +161 -0
  24. lionagi/core/collections/flow.py +426 -0
  25. lionagi/core/collections/model.py +419 -0
  26. lionagi/core/collections/pile.py +913 -0
  27. lionagi/core/collections/progression.py +236 -0
  28. lionagi/core/collections/util.py +64 -0
  29. lionagi/core/director/direct.py +314 -0
  30. lionagi/core/director/director.py +2 -0
  31. lionagi/core/engine/branch_engine.py +333 -0
  32. lionagi/core/engine/instruction_map_engine.py +204 -0
  33. lionagi/core/engine/sandbox_.py +14 -0
  34. lionagi/core/engine/script_engine.py +99 -0
  35. lionagi/core/executor/base_executor.py +90 -0
  36. lionagi/core/executor/graph_executor.py +330 -0
  37. lionagi/core/executor/neo4j_executor.py +384 -0
  38. lionagi/core/generic/__init__.py +7 -0
  39. lionagi/core/generic/edge.py +112 -0
  40. lionagi/core/generic/edge_condition.py +16 -0
  41. lionagi/core/generic/graph.py +236 -0
  42. lionagi/core/generic/hyperedge.py +1 -0
  43. lionagi/core/generic/node.py +220 -0
  44. lionagi/core/generic/tree.py +48 -0
  45. lionagi/core/generic/tree_node.py +79 -0
  46. lionagi/core/mail/__init__.py +7 -3
  47. lionagi/core/mail/mail.py +25 -0
  48. lionagi/core/mail/mail_manager.py +142 -58
  49. lionagi/core/mail/package.py +45 -0
  50. lionagi/core/mail/start_mail.py +36 -0
  51. lionagi/core/message/__init__.py +19 -0
  52. lionagi/core/message/action_request.py +133 -0
  53. lionagi/core/message/action_response.py +135 -0
  54. lionagi/core/message/assistant_response.py +95 -0
  55. lionagi/core/message/instruction.py +234 -0
  56. lionagi/core/message/message.py +101 -0
  57. lionagi/core/message/system.py +86 -0
  58. lionagi/core/message/util.py +283 -0
  59. lionagi/core/report/__init__.py +4 -0
  60. lionagi/core/report/base.py +217 -0
  61. lionagi/core/report/form.py +231 -0
  62. lionagi/core/report/report.py +166 -0
  63. lionagi/core/report/util.py +28 -0
  64. lionagi/core/rule/__init__.py +0 -0
  65. lionagi/core/rule/_default.py +16 -0
  66. lionagi/core/rule/action.py +99 -0
  67. lionagi/core/rule/base.py +238 -0
  68. lionagi/core/rule/boolean.py +56 -0
  69. lionagi/core/rule/choice.py +47 -0
  70. lionagi/core/rule/mapping.py +96 -0
  71. lionagi/core/rule/number.py +71 -0
  72. lionagi/core/rule/rulebook.py +109 -0
  73. lionagi/core/rule/string.py +52 -0
  74. lionagi/core/rule/util.py +35 -0
  75. lionagi/core/session/__init__.py +0 -3
  76. lionagi/core/session/branch.py +431 -0
  77. lionagi/core/session/directive_mixin.py +287 -0
  78. lionagi/core/session/session.py +230 -902
  79. lionagi/core/structure/__init__.py +1 -0
  80. lionagi/core/structure/chain.py +1 -0
  81. lionagi/core/structure/forest.py +1 -0
  82. lionagi/core/structure/graph.py +1 -0
  83. lionagi/core/structure/tree.py +1 -0
  84. lionagi/core/unit/__init__.py +5 -0
  85. lionagi/core/unit/parallel_unit.py +245 -0
  86. lionagi/core/unit/template/__init__.py +0 -0
  87. lionagi/core/unit/template/action.py +81 -0
  88. lionagi/core/unit/template/base.py +51 -0
  89. lionagi/core/unit/template/plan.py +84 -0
  90. lionagi/core/unit/template/predict.py +109 -0
  91. lionagi/core/unit/template/score.py +124 -0
  92. lionagi/core/unit/template/select.py +104 -0
  93. lionagi/core/unit/unit.py +362 -0
  94. lionagi/core/unit/unit_form.py +305 -0
  95. lionagi/core/unit/unit_mixin.py +1168 -0
  96. lionagi/core/unit/util.py +71 -0
  97. lionagi/core/validator/__init__.py +0 -0
  98. lionagi/core/validator/validator.py +364 -0
  99. lionagi/core/work/__init__.py +0 -0
  100. lionagi/core/work/work.py +76 -0
  101. lionagi/core/work/work_function.py +101 -0
  102. lionagi/core/work/work_queue.py +103 -0
  103. lionagi/core/work/worker.py +258 -0
  104. lionagi/core/work/worklog.py +120 -0
  105. lionagi/experimental/__init__.py +0 -0
  106. lionagi/experimental/compressor/__init__.py +0 -0
  107. lionagi/experimental/compressor/base.py +46 -0
  108. lionagi/experimental/compressor/llm_compressor.py +247 -0
  109. lionagi/experimental/compressor/llm_summarizer.py +61 -0
  110. lionagi/experimental/compressor/util.py +70 -0
  111. lionagi/experimental/directive/__init__.py +19 -0
  112. lionagi/experimental/directive/parser/__init__.py +0 -0
  113. lionagi/experimental/directive/parser/base_parser.py +282 -0
  114. lionagi/experimental/directive/template/__init__.py +0 -0
  115. lionagi/experimental/directive/template/base_template.py +79 -0
  116. lionagi/experimental/directive/template/schema.py +36 -0
  117. lionagi/experimental/directive/tokenizer.py +73 -0
  118. lionagi/experimental/evaluator/__init__.py +0 -0
  119. lionagi/experimental/evaluator/ast_evaluator.py +131 -0
  120. lionagi/experimental/evaluator/base_evaluator.py +218 -0
  121. lionagi/experimental/knowledge/__init__.py +0 -0
  122. lionagi/experimental/knowledge/base.py +10 -0
  123. lionagi/experimental/knowledge/graph.py +0 -0
  124. lionagi/experimental/memory/__init__.py +0 -0
  125. lionagi/experimental/strategies/__init__.py +0 -0
  126. lionagi/experimental/strategies/base.py +1 -0
  127. lionagi/integrations/bridge/autogen_/__init__.py +0 -0
  128. lionagi/integrations/bridge/autogen_/autogen_.py +124 -0
  129. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  130. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  131. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  132. lionagi/integrations/bridge/llamaindex_/llama_pack.py +227 -0
  133. lionagi/integrations/bridge/llamaindex_/node_parser.py +6 -9
  134. lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +1 -0
  135. lionagi/integrations/bridge/transformers_/__init__.py +0 -0
  136. lionagi/integrations/bridge/transformers_/install_.py +36 -0
  137. lionagi/integrations/chunker/__init__.py +0 -0
  138. lionagi/integrations/chunker/chunk.py +312 -0
  139. lionagi/integrations/config/oai_configs.py +38 -7
  140. lionagi/integrations/config/ollama_configs.py +1 -1
  141. lionagi/integrations/config/openrouter_configs.py +14 -2
  142. lionagi/integrations/loader/__init__.py +0 -0
  143. lionagi/integrations/loader/load.py +253 -0
  144. lionagi/integrations/loader/load_util.py +195 -0
  145. lionagi/integrations/provider/_mapping.py +46 -0
  146. lionagi/integrations/provider/litellm.py +2 -1
  147. lionagi/integrations/provider/mlx_service.py +16 -9
  148. lionagi/integrations/provider/oai.py +91 -4
  149. lionagi/integrations/provider/ollama.py +7 -6
  150. lionagi/integrations/provider/openrouter.py +115 -8
  151. lionagi/integrations/provider/services.py +2 -2
  152. lionagi/integrations/provider/transformers.py +18 -22
  153. lionagi/integrations/storage/__init__.py +3 -0
  154. lionagi/integrations/storage/neo4j.py +665 -0
  155. lionagi/integrations/storage/storage_util.py +287 -0
  156. lionagi/integrations/storage/structure_excel.py +285 -0
  157. lionagi/integrations/storage/to_csv.py +63 -0
  158. lionagi/integrations/storage/to_excel.py +83 -0
  159. lionagi/libs/__init__.py +26 -1
  160. lionagi/libs/ln_api.py +78 -23
  161. lionagi/libs/ln_context.py +37 -0
  162. lionagi/libs/ln_convert.py +21 -9
  163. lionagi/libs/ln_func_call.py +69 -28
  164. lionagi/libs/ln_image.py +107 -0
  165. lionagi/libs/ln_knowledge_graph.py +405 -0
  166. lionagi/libs/ln_nested.py +26 -11
  167. lionagi/libs/ln_parse.py +110 -14
  168. lionagi/libs/ln_queue.py +117 -0
  169. lionagi/libs/ln_tokenize.py +164 -0
  170. lionagi/{core/prompt/field_validator.py → libs/ln_validate.py} +79 -14
  171. lionagi/libs/special_tokens.py +172 -0
  172. lionagi/libs/sys_util.py +107 -2
  173. lionagi/lions/__init__.py +0 -0
  174. lionagi/lions/coder/__init__.py +0 -0
  175. lionagi/lions/coder/add_feature.py +20 -0
  176. lionagi/lions/coder/base_prompts.py +22 -0
  177. lionagi/lions/coder/code_form.py +13 -0
  178. lionagi/lions/coder/coder.py +168 -0
  179. lionagi/lions/coder/util.py +96 -0
  180. lionagi/lions/researcher/__init__.py +0 -0
  181. lionagi/lions/researcher/data_source/__init__.py +0 -0
  182. lionagi/lions/researcher/data_source/finhub_.py +191 -0
  183. lionagi/lions/researcher/data_source/google_.py +199 -0
  184. lionagi/lions/researcher/data_source/wiki_.py +96 -0
  185. lionagi/lions/researcher/data_source/yfinance_.py +21 -0
  186. lionagi/tests/integrations/__init__.py +0 -0
  187. lionagi/tests/libs/__init__.py +0 -0
  188. lionagi/tests/libs/test_field_validators.py +353 -0
  189. lionagi/tests/{test_libs → libs}/test_func_call.py +23 -21
  190. lionagi/tests/{test_libs → libs}/test_nested.py +36 -21
  191. lionagi/tests/{test_libs → libs}/test_parse.py +1 -1
  192. lionagi/tests/libs/test_queue.py +67 -0
  193. lionagi/tests/test_core/collections/__init__.py +0 -0
  194. lionagi/tests/test_core/collections/test_component.py +206 -0
  195. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  196. lionagi/tests/test_core/collections/test_flow.py +145 -0
  197. lionagi/tests/test_core/collections/test_pile.py +171 -0
  198. lionagi/tests/test_core/collections/test_progression.py +129 -0
  199. lionagi/tests/test_core/generic/__init__.py +0 -0
  200. lionagi/tests/test_core/generic/test_edge.py +67 -0
  201. lionagi/tests/test_core/generic/test_graph.py +96 -0
  202. lionagi/tests/test_core/generic/test_node.py +106 -0
  203. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  204. lionagi/tests/test_core/test_branch.py +115 -292
  205. lionagi/tests/test_core/test_form.py +46 -0
  206. lionagi/tests/test_core/test_report.py +105 -0
  207. lionagi/tests/test_core/test_validator.py +111 -0
  208. lionagi/version.py +1 -1
  209. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/LICENSE +12 -11
  210. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/METADATA +19 -118
  211. lionagi-0.2.1.dist-info/RECORD +240 -0
  212. lionagi/core/branch/__init__.py +0 -4
  213. lionagi/core/branch/base_branch.py +0 -654
  214. lionagi/core/branch/branch.py +0 -471
  215. lionagi/core/branch/branch_flow_mixin.py +0 -96
  216. lionagi/core/branch/executable_branch.py +0 -347
  217. lionagi/core/branch/util.py +0 -323
  218. lionagi/core/direct/__init__.py +0 -6
  219. lionagi/core/direct/predict.py +0 -161
  220. lionagi/core/direct/score.py +0 -278
  221. lionagi/core/direct/select.py +0 -169
  222. lionagi/core/direct/utils.py +0 -87
  223. lionagi/core/direct/vote.py +0 -64
  224. lionagi/core/flow/base/baseflow.py +0 -23
  225. lionagi/core/flow/monoflow/ReAct.py +0 -238
  226. lionagi/core/flow/monoflow/__init__.py +0 -9
  227. lionagi/core/flow/monoflow/chat.py +0 -95
  228. lionagi/core/flow/monoflow/chat_mixin.py +0 -263
  229. lionagi/core/flow/monoflow/followup.py +0 -214
  230. lionagi/core/flow/polyflow/__init__.py +0 -1
  231. lionagi/core/flow/polyflow/chat.py +0 -248
  232. lionagi/core/mail/schema.py +0 -56
  233. lionagi/core/messages/__init__.py +0 -3
  234. lionagi/core/messages/schema.py +0 -533
  235. lionagi/core/prompt/prompt_template.py +0 -316
  236. lionagi/core/schema/__init__.py +0 -22
  237. lionagi/core/schema/action_node.py +0 -29
  238. lionagi/core/schema/base_mixin.py +0 -296
  239. lionagi/core/schema/base_node.py +0 -199
  240. lionagi/core/schema/condition.py +0 -24
  241. lionagi/core/schema/data_logger.py +0 -354
  242. lionagi/core/schema/data_node.py +0 -93
  243. lionagi/core/schema/prompt_template.py +0 -67
  244. lionagi/core/schema/structure.py +0 -910
  245. lionagi/core/tool/__init__.py +0 -3
  246. lionagi/core/tool/tool_manager.py +0 -280
  247. lionagi/integrations/bridge/pydantic_/base_model.py +0 -7
  248. lionagi/tests/test_core/test_base_branch.py +0 -427
  249. lionagi/tests/test_core/test_chat_flow.py +0 -63
  250. lionagi/tests/test_core/test_mail_manager.py +0 -75
  251. lionagi/tests/test_core/test_prompts.py +0 -51
  252. lionagi/tests/test_core/test_session.py +0 -254
  253. lionagi/tests/test_core/test_session_base_util.py +0 -312
  254. lionagi/tests/test_core/test_tool_manager.py +0 -95
  255. lionagi-0.0.312.dist-info/RECORD +0 -111
  256. /lionagi/core/{branch/base → _setting}/__init__.py +0 -0
  257. /lionagi/core/{flow → agent/eval}/__init__.py +0 -0
  258. /lionagi/core/{flow/base → agent/learn}/__init__.py +0 -0
  259. /lionagi/core/{prompt → agent/plan}/__init__.py +0 -0
  260. /lionagi/core/{tool/manual.py → agent/plan/plan.py} +0 -0
  261. /lionagi/{tests/test_integrations → core/director}/__init__.py +0 -0
  262. /lionagi/{tests/test_libs → core/engine}/__init__.py +0 -0
  263. /lionagi/{tests/test_libs/test_async.py → core/executor/__init__.py} +0 -0
  264. /lionagi/tests/{test_libs → libs}/test_api.py +0 -0
  265. /lionagi/tests/{test_libs → libs}/test_convert.py +0 -0
  266. /lionagi/tests/{test_libs → libs}/test_sys_util.py +0 -0
  267. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
  268. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,419 @@
1
+ """
2
+ Copyright 2024 HaiyangLi
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ import os
18
+ import asyncio
19
+ import numpy as np
20
+ from dotenv import load_dotenv
21
+ from lionagi.libs import SysUtil, BaseService, StatusTracker, APIUtil, to_list, ninsert
22
+ from .abc import Component, ModelLimitExceededError
23
+
24
+ load_dotenv()
25
+
26
+
27
+ _oai_price_map = {
28
+ "gpt-4o": (5, 15),
29
+ "gpt-4-turbo": (10, 30),
30
+ "gpt-3.5-turbo": (0.5, 1.5),
31
+ }
32
+
33
+
34
+ class iModel:
35
+ """
36
+ iModel is a class for managing AI model configurations and service
37
+ integrations.
38
+
39
+ Attributes:
40
+ ln_id (str): A unique identifier for the model instance.
41
+ timestamp (str): The timestamp when the model instance is created.
42
+ endpoint (str): The API endpoint for the model service.
43
+ provider_schema (dict): The schema for the service provider.
44
+ provider (BaseService): The service provider instance.
45
+ endpoint_schema (dict): The schema for the endpoint configuration.
46
+ api_key (str): The API key for the service provider.
47
+ status_tracker (StatusTracker): Instance of StatusTracker to track
48
+ service status.
49
+ service (BaseService): Configured service instance.
50
+ config (dict): Configuration dictionary for the model.
51
+ iModel_name (str): Name of the model.
52
+ """
53
+
54
+ default_model = "gpt-4o"
55
+
56
+ def __init__(
57
+ self,
58
+ model: str = None,
59
+ config: dict = None,
60
+ provider: str = None,
61
+ provider_schema: dict = None,
62
+ endpoint: str = "chat/completions",
63
+ token_encoding_name: str = None,
64
+ api_key: str = None,
65
+ api_key_schema: str = None,
66
+ interval_tokens: int = None,
67
+ interval_requests: int = None,
68
+ interval: int = None,
69
+ service: BaseService = None,
70
+ allowed_parameters=[],
71
+ device: str = None,
72
+ costs=None,
73
+ **kwargs, # additional parameters for the model
74
+ ):
75
+ """
76
+ Initializes an instance of the iModel class.
77
+
78
+ Args:
79
+ model (str, optional): Name of the model.
80
+ config (dict, optional): Configuration dictionary.
81
+ provider (str, optional): Name or class of the provider.
82
+ provider_schema (dict, optional): Schema dictionary for the
83
+ provider.
84
+ endpoint (str, optional): Endpoint string, default is
85
+ "chat/completions".
86
+ token_encoding_name (str, optional): Name of the token encoding,
87
+ default is "cl100k_base".
88
+ api_key (str, optional): API key for the provider.
89
+ api_key_schema (str, optional): Schema for the API key.
90
+ interval_tokens (int, optional): Token interval limit, default is
91
+ 100,000.
92
+ interval_requests (int, optional): Request interval limit, default
93
+ is 1,000.
94
+ interval (int, optional): Time interval in seconds, default is 60.
95
+ service (BaseService, optional): An instance of BaseService.
96
+ **kwargs: Additional parameters for the model.
97
+ """
98
+ self.ln_id: str = SysUtil.create_id()
99
+ self.timestamp: str = SysUtil.get_timestamp(sep=None)[:-6]
100
+ self.endpoint = endpoint
101
+ self.allowed_parameters = allowed_parameters
102
+ if isinstance(provider, type):
103
+ provider = provider.__name__.replace("Service", "").lower()
104
+
105
+ else:
106
+ provider = str(provider).lower() if provider else "openai"
107
+
108
+ from lionagi.integrations.provider._mapping import (
109
+ SERVICE_PROVIDERS_MAPPING,
110
+ )
111
+
112
+ self.provider_schema = (
113
+ provider_schema or SERVICE_PROVIDERS_MAPPING[provider]["schema"]
114
+ )
115
+ self.provider = SERVICE_PROVIDERS_MAPPING[provider]["service"]
116
+ self.endpoint_schema = self.provider_schema.get(endpoint, {})
117
+ self.token_limit = self.endpoint_schema.get("token_limit", 100_000)
118
+
119
+ if api_key is not None:
120
+ self.api_key = api_key
121
+
122
+ elif api_key_schema is not None:
123
+ self.api_key = os.getenv(api_key_schema)
124
+ else:
125
+ api_schema = self.provider_schema.get("API_key_schema", None)
126
+ if api_schema:
127
+ self.api_key = os.getenv(
128
+ self.provider_schema["API_key_schema"][0], None
129
+ )
130
+
131
+ self.status_tracker = StatusTracker()
132
+
133
+ set_up_kwargs = {
134
+ "api_key": getattr(self, "api_key", None),
135
+ "schema": self.provider_schema or None,
136
+ "endpoint": self.endpoint,
137
+ "token_limit": self.token_limit,
138
+ "token_encoding_name": token_encoding_name
139
+ or self.endpoint_schema.get("token_encoding_name", None),
140
+ "max_tokens": interval_tokens
141
+ or self.endpoint_schema.get("interval_tokens", None),
142
+ "max_requests": interval_requests
143
+ or self.endpoint_schema.get("interval_requests", None),
144
+ "interval": interval or self.endpoint_schema.get("interval", None),
145
+ }
146
+
147
+ set_up_kwargs = {
148
+ k: v
149
+ for k, v in set_up_kwargs.items()
150
+ if v is not None and k in self.allowed_parameters
151
+ }
152
+
153
+ self.config = self._set_up_params(
154
+ config or self.endpoint_schema.get("config", {}), **kwargs
155
+ )
156
+
157
+ if not model:
158
+ if "model" not in self.config:
159
+ model = SERVICE_PROVIDERS_MAPPING[provider]["default_model"]
160
+
161
+ if self.config.get("model", None) != model and model is not None:
162
+ self.iModel_name = model
163
+ self.config["model"] = model
164
+ ninsert(self.endpoint_schema, ["config", "model"], model)
165
+
166
+ else:
167
+ self.iModel_name = self.config["model"]
168
+
169
+ if device:
170
+ set_up_kwargs["device"] = device
171
+ set_up_kwargs["model"] = self.iModel_name
172
+ self.service: BaseService = self._set_up_service(
173
+ service=service,
174
+ provider=self.provider,
175
+ **set_up_kwargs,
176
+ )
177
+ if self.iModel_name in _oai_price_map:
178
+ self.costs = _oai_price_map[self.iModel_name]
179
+ else:
180
+ self.costs = costs or (0, 0)
181
+
182
+ def update_config(self, **kwargs):
183
+ """
184
+ Updates the configuration with additional parameters.
185
+
186
+ Args:
187
+ **kwargs: Additional parameters to update the configuration.
188
+ """
189
+ self.config = self._set_up_params(self.config, **kwargs)
190
+
191
+ def _set_up_config(self, model_config, **kwargs):
192
+ """
193
+ Sets up the model configuration.
194
+
195
+ Args:
196
+ model_config (dict): The default configuration dictionary.
197
+ **kwargs: Additional parameters to update the configuration.
198
+
199
+ Returns:
200
+ dict: Updated configuration dictionary.
201
+ """
202
+ return {**model_config, **kwargs}
203
+
204
+ def _set_up_service(self, service=None, provider=None, **kwargs):
205
+ """
206
+ Sets up the service for the model.
207
+
208
+ Args:
209
+ service (BaseService, optional): An instance of BaseService.
210
+ provider (str, optional): Provider name or instance.
211
+ **kwargs: Additional parameters for the service.
212
+
213
+ Returns:
214
+ BaseService: Configured service instance.
215
+ """
216
+ if not service:
217
+ provider = provider or self.provider
218
+ a = provider.__name__.replace("Service", "").lower()
219
+ if a in ["openai", "openrouter"]:
220
+ kwargs.pop("model", None)
221
+
222
+ return provider(**kwargs)
223
+ return service
224
+
225
+ def _set_up_params(self, default_config=None, **kwargs):
226
+ """
227
+ Sets up the parameters for the model.
228
+
229
+ Args:
230
+ default_config (dict, optional): The default configuration
231
+ dictionary.
232
+ **kwargs: Additional parameters to update the configuration.
233
+
234
+ Returns:
235
+ dict: Updated parameters dictionary.
236
+
237
+ Raises:
238
+ ValueError: If any parameter is not allowed.
239
+ """
240
+ kwargs = {k: v for k, v in kwargs.items() if v is not None}
241
+ params = {**default_config, **kwargs}
242
+ allowed_params = self.endpoint_schema.get(
243
+ "required", []
244
+ ) + self.endpoint_schema.get("optional", [])
245
+
246
+ if allowed_params != []:
247
+ if (
248
+ len(
249
+ not_allowed := [k for k in params.keys() if k not in allowed_params]
250
+ )
251
+ > 0
252
+ ):
253
+ raise ValueError(f"Not allowed parameters: {not_allowed}")
254
+
255
+ return params
256
+
257
+ async def call_chat_completion(self, messages, **kwargs):
258
+ """
259
+ Asynchronous method to call the chat completion service.
260
+
261
+ Args:
262
+ messages (list): List of messages for the chat completion.
263
+ **kwargs: Additional parameters for the service call.
264
+
265
+ Returns:
266
+ dict: Response from the chat completion service.
267
+ """
268
+
269
+ num_tokens = APIUtil.calculate_num_token(
270
+ {"messages": messages},
271
+ "chat/completions",
272
+ self.endpoint_schema.get("token_encoding_name", None),
273
+ )
274
+
275
+ if num_tokens > self.token_limit:
276
+ raise ModelLimitExceededError(
277
+ f"Number of tokens {num_tokens} exceeds the limit {self.token_limit}"
278
+ )
279
+
280
+ return await self.service.serve_chat(
281
+ messages, required_tokens=num_tokens, **kwargs
282
+ )
283
+
284
+ async def call_embedding(self, embed_str, **kwargs):
285
+ """
286
+ Asynchronous method to call the embedding service.
287
+
288
+ Args:
289
+ input_file (str): Path to the input file.
290
+ **kwargs: Additional parameters for the service call.
291
+
292
+ Returns:
293
+ dict: Response from the embedding service.
294
+ """
295
+ return await self.service.serve_embedding(embed_str, **kwargs)
296
+
297
+ async def embed_node(self, node, field="content", **kwargs) -> bool:
298
+ """
299
+ if not specify field, we embed node.content
300
+ """
301
+ if not isinstance(node, Component):
302
+ raise ValueError("Node must a lionagi item")
303
+ embed_str = getattr(node, field)
304
+
305
+ if isinstance(embed_str, dict) and "images" in embed_str:
306
+ embed_str.pop("images", None)
307
+ embed_str.pop("image_detail", None)
308
+
309
+ num_tokens = APIUtil.calculate_num_token(
310
+ {"input": str(embed_str) if isinstance(embed_str, dict) else embed_str},
311
+ "embeddings",
312
+ self.endpoint_schema["token_encoding_name"],
313
+ )
314
+
315
+ if self.token_limit and num_tokens > self.token_limit:
316
+ raise ModelLimitExceededError(
317
+ f"Number of tokens {num_tokens} exceeds the limit {self.token_limit}"
318
+ )
319
+
320
+ payload, embed = await self.call_embedding(embed_str, **kwargs)
321
+ payload.pop("input")
322
+ node.add_field("embedding", embed["data"][0]["embedding"])
323
+ node._meta_insert("embedding_meta", payload)
324
+
325
+ def to_dict(self):
326
+ """
327
+ Converts the model instance to a dictionary representation.
328
+
329
+ Returns:
330
+ dict: Dictionary representation of the model instance.
331
+ """
332
+ return {
333
+ "ln_id": self.ln_id,
334
+ "timestamp": self.timestamp,
335
+ "provider": self.provider.__name__.replace("Service", ""),
336
+ "api_key": self.api_key[:4]
337
+ + "*" * (len(self.api_key) - 8)
338
+ + self.api_key[-4:],
339
+ "endpoint": self.endpoint,
340
+ "token_encoding_name": self.service.token_encoding_name,
341
+ **{
342
+ k: v
343
+ for k, v in self.config.items()
344
+ if k in getattr(self.service, "allowed_kwargs", []) and v is not None
345
+ },
346
+ "model_costs": None if self.costs == (0, 0) else self.costs,
347
+ }
348
+
349
+ async def compute_perplexity(
350
+ self,
351
+ initial_context: str = None,
352
+ tokens: list[str] = None,
353
+ system_msg: str = None,
354
+ n_samples: int = 1, # number of samples used for the computation
355
+ use_residue: bool = True, # whether to use residue for the last sample
356
+ **kwargs, # additional arguments for the model
357
+ ) -> tuple[list[str], float]:
358
+ tasks = []
359
+ context = initial_context or ""
360
+
361
+ n_samples = n_samples or len(tokens)
362
+ sample_token_len, residue = divmod(len(tokens), n_samples)
363
+ samples = []
364
+
365
+ if n_samples == 1:
366
+ samples = [tokens]
367
+ else:
368
+ samples = [tokens[: (i + 1) * sample_token_len] for i in range(n_samples)]
369
+
370
+ if use_residue and residue != 0:
371
+ samples.append(tokens[-residue:])
372
+
373
+ sampless = [context + " ".join(sample) for sample in samples]
374
+
375
+ for sample in sampless:
376
+ messages = [{"role": "system", "content": system_msg}] if system_msg else []
377
+ messages.append(
378
+ {"role": "user", "content": sample},
379
+ )
380
+
381
+ task = asyncio.create_task(
382
+ self.call_chat_completion(
383
+ messages=messages,
384
+ logprobs=True,
385
+ max_tokens=sample_token_len,
386
+ **kwargs,
387
+ )
388
+ )
389
+ tasks.append(task)
390
+
391
+ results = await asyncio.gather(*tasks) # result is (payload, response)
392
+ results_ = []
393
+ num_prompt_tokens = 0
394
+ num_completion_tokens = 0
395
+
396
+ for idx, result in enumerate(results):
397
+ _dict = {}
398
+ _dict["tokens"] = samples[idx]
399
+
400
+ num_prompt_tokens += result[1]["usage"]["prompt_tokens"]
401
+ num_completion_tokens += result[1]["usage"]["completion_tokens"]
402
+
403
+ logprobs = result[1]["choices"][0]["logprobs"]["content"]
404
+ logprobs = to_list(logprobs, flatten=True, dropna=True)
405
+ _dict["logprobs"] = [(i["token"], i["logprob"]) for i in logprobs]
406
+ results_.append(_dict)
407
+
408
+ logprobs = to_list(
409
+ [[i[1] for i in d["logprobs"]] for d in results_], flatten=True
410
+ )
411
+
412
+ return {
413
+ "tokens": tokens,
414
+ "n_samples": n_samples,
415
+ "num_prompt_tokens": num_prompt_tokens,
416
+ "num_completion_tokens": num_completion_tokens,
417
+ "logprobs": logprobs,
418
+ "perplexity": np.exp(np.mean(logprobs)),
419
+ }