dm-aioaiagent 0.3.2__py3-none-any.whl → 0.3.3__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.
dm_aioaiagent/__init__.py CHANGED
@@ -2,4 +2,5 @@ from dotenv import load_dotenv
2
2
  load_dotenv()
3
3
  from .ai_agent import DMAIAgent
4
4
  from .async_ai_agent import DMAioAIAgent
5
+ from .image_message_content_builder import ImageMessageContentBuilder
5
6
  from .types import Message
dm_aioaiagent/ai_agent.py CHANGED
@@ -16,6 +16,8 @@ __all__ = ["DMAIAgent"]
16
16
  class DMAIAgent:
17
17
  agent_name = "AIAgent"
18
18
  _allowed_roles = ("user", "ai")
19
+ _response_if_request_fail = "I can't provide a response right now. Please try again later."
20
+ _response_if_invalid_image = "The image is unavailable or the link is incorrect."
19
21
  MAX_MEMORY_MESSAGES = 20 # Only INT greater than 0
20
22
 
21
23
  def __init__(
@@ -29,6 +31,8 @@ class DMAIAgent:
29
31
  input_output_logging: bool = True,
30
32
  is_memory_enabled: bool = True,
31
33
  max_memory_messages: int = None,
34
+ response_if_request_fail: str = None,
35
+ response_if_invalid_image: str = None
32
36
  ):
33
37
  if not os.getenv("OPENAI_API_KEY"):
34
38
  raise EnvironmentError("'OPENAI_API_KEY' environment variable is not set!")
@@ -38,6 +42,8 @@ class DMAIAgent:
38
42
  self._input_output_logging = bool(input_output_logging)
39
43
  self._is_memory_enabled = bool(is_memory_enabled)
40
44
  self._max_memory_messages = self._validate_max_memory_messages(max_memory_messages)
45
+ self._response_if_request_fail = str(response_if_request_fail or self._response_if_request_fail)
46
+ self._response_if_invalid_image = str(response_if_invalid_image or self._response_if_invalid_image)
41
47
 
42
48
  prompt = ChatPromptTemplate.from_messages([SystemMessage(content=system_message),
43
49
  MessagesPlaceholder(variable_name="messages")])
@@ -85,7 +91,6 @@ class DMAIAgent:
85
91
  self._memory[self._validate_memory_id(memory_id)] = []
86
92
 
87
93
  def _prepare_messages_node(self, state: State) -> State:
88
- state.memory_id = self._validate_memory_id(state.memory_id)
89
94
  state.input_messages = state.input_messages or [{"role": "user", "content": ""}]
90
95
  for item in state.input_messages:
91
96
  if isinstance(item, dict):
@@ -102,14 +107,23 @@ class DMAIAgent:
102
107
  state.messages.append(item)
103
108
 
104
109
  if self._input_output_logging:
105
- self._logger.debug(f"Query:\n{state.messages[-1].content}", memory_id=state.memory_id)
110
+ log_kwargs = {} if state.memory_id is None else {"memory_id": state.memory_id}
111
+ self._logger.debug(f"Query:\n{state.messages[-1].content}", **log_kwargs)
106
112
  if self._is_memory_enabled:
107
113
  state.messages = self.get_memory_messages(state.memory_id) + state.messages
108
114
  return state
109
115
 
110
- def _invoke_llm_node(self, state: State) -> State:
116
+ def _invoke_llm_node(self, state: State, second_attempt: bool = False) -> State:
111
117
  self._logger.debug("Run node: Invoke LLM")
112
- ai_response = self._agent.invoke({"messages": state.messages})
118
+ try:
119
+ ai_response = self._agent.invoke({"messages": state.messages})
120
+ except Exception as e:
121
+ self._logger.error(e)
122
+ if second_attempt:
123
+ response = self._response_if_invalid_image if "invalid_image_url" in str(e) else self._response_if_request_fail
124
+ state.messages.append(AIMessage(content=response))
125
+ return state
126
+ return self._invoke_llm_node(state, second_attempt=True)
113
127
  state.messages.append(ai_response)
114
128
  return state
115
129
 
@@ -148,12 +162,14 @@ class DMAIAgent:
148
162
  def _exit_node(self, state: State) -> State:
149
163
  answer = state.messages[-1].content
150
164
  if self._input_output_logging:
151
- self._logger.debug(f"Answer:\n{answer}", memory_id=state.memory_id)
165
+ log_kwargs = {} if state.memory_id is None else {"memory_id": state.memory_id}
166
+ self._logger.debug(f"Answer:\n{answer}", **log_kwargs)
152
167
 
153
168
  if self._is_memory_enabled:
169
+ memory_id = self._validate_memory_id(state.memory_id)
154
170
  messages_to_memory = state.messages[-self._max_memory_messages:]
155
171
  # drop ToolsMessages from start of list
156
- self._memory[state.memory_id] = list(dropwhile(lambda x: isinstance(x, ToolMessage), messages_to_memory))
172
+ self._memory[memory_id] = list(dropwhile(lambda x: isinstance(x, ToolMessage), messages_to_memory))
157
173
  state.response = answer
158
174
  else:
159
175
  state.response = state.messages[len(state.input_messages):]
@@ -1,6 +1,6 @@
1
1
  import sys
2
2
  import asyncio
3
- from langchain_core.messages import ToolMessage
3
+ from langchain_core.messages import AIMessage, ToolMessage
4
4
 
5
5
  from .ai_agent import DMAIAgent
6
6
  from .types import *
@@ -18,9 +18,17 @@ class DMAioAIAgent(DMAIAgent):
18
18
  state = await self._graph.ainvoke({"input_messages": input_messages, "memory_id": memory_id})
19
19
  return state["response"]
20
20
 
21
- async def _invoke_llm_node(self, state: State) -> State:
21
+ async def _invoke_llm_node(self, state: State, second_attempt: bool = False) -> State:
22
22
  self._logger.debug("Run node: Invoke LLM")
23
- ai_response = await self._agent.ainvoke({"messages": state.messages})
23
+ try:
24
+ ai_response = await self._agent.ainvoke({"messages": state.messages})
25
+ except Exception as e:
26
+ self._logger.error(e)
27
+ if second_attempt:
28
+ response = self._response_if_invalid_image if "invalid_image_url" in str(e) else self._response_if_request_fail
29
+ state.messages.append(AIMessage(content=response))
30
+ return state
31
+ return await self._invoke_llm_node(state, second_attempt=True)
24
32
  state.messages.append(ai_response)
25
33
  return state
26
34
 
@@ -0,0 +1,15 @@
1
+ class ImageMessageContentBuilder(list):
2
+ def __init__(self, image_url: str, text: str = None):
3
+ content = []
4
+ if isinstance(text, str):
5
+ content.append({
6
+ "type": "text",
7
+ "text": text
8
+ })
9
+ content.append({
10
+ "type": "image_url",
11
+ "image_url": {
12
+ "url": image_url
13
+ }
14
+ })
15
+ super().__init__(content)
dm_aioaiagent/types.py CHANGED
@@ -4,12 +4,33 @@ from pydantic import BaseModel, Field
4
4
  from langchain_core.messages import BaseMessage
5
5
 
6
6
 
7
- class Message(TypedDict):
7
+ class ImageMessageTextMessage(TypedDict):
8
+ type: Literal['text']
9
+ text: str
10
+
11
+
12
+ class ImageMessageImageItem(TypedDict):
13
+ type: Literal['image_url']
14
+ image_url: dict
15
+
16
+
17
+ ImageMessageContent = list[Union[ImageMessageTextMessage, ImageMessageImageItem]]
18
+
19
+
20
+ class ImageMessage(TypedDict):
21
+ role: Literal["user"]
22
+ content: ImageMessageContent
23
+
24
+
25
+ class TextMessage(TypedDict):
8
26
  role: Literal["user", "ai"]
9
27
  content: str
10
28
 
11
29
 
30
+ Message = Union[TextMessage, ImageMessage]
31
+
12
32
  InputMessagesType = list[Union[Message, BaseMessage]]
33
+
13
34
  ResponseType = Union[str, list[BaseMessage]]
14
35
 
15
36
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dm-aioaiagent
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: This is my custom aioaiagent client
5
5
  Home-page: https://pypi.org/project/dm-aioaiagent
6
6
  Author: dimka4621
@@ -18,6 +18,7 @@ Requires-Dist: pydantic<3.0.0,>=2.9.2
18
18
  Requires-Dist: langchain~=0.3.0
19
19
  Requires-Dist: langchain-core~=0.3.5
20
20
  Requires-Dist: langgraph~=0.2.23
21
+ Requires-Dist: grandalf>=0.8
21
22
  Requires-Dist: langchain-community~=0.3.0
22
23
  Requires-Dist: langchain-openai~=0.2.0
23
24
 
@@ -137,6 +138,34 @@ if __name__ == "__main__":
137
138
  asyncio.run(main())
138
139
  ```
139
140
 
141
+ ### Image vision
142
+
143
+ ```python
144
+ from dm_aioaiagent import DMAIAgent, ImageMessageContentBuilder
145
+
146
+ def main():
147
+ # create an agent
148
+ ai_agent = DMAIAgent(agent_name="image_vision", model="gpt-4o")
149
+
150
+ # create an image message content
151
+ # NOTE: text argument is optional
152
+ img_content = ImageMessageContentBuilder(image_url="https://your.domain/image",
153
+ text="Hello, what is shown in the photo?")
154
+
155
+ # define the conversation message
156
+ messages = [
157
+ {"role": "user", "content": "Hello!"},
158
+ {"role": "user", "content": img_content},
159
+ ]
160
+
161
+ # call an agent
162
+ answer = ai_agent.run(messages)
163
+
164
+
165
+ if __name__ == "__main__":
166
+ main()
167
+ ```
168
+
140
169
  ### Set custom logger
141
170
 
142
171
  _If you want set up custom logger_
@@ -0,0 +1,9 @@
1
+ dm_aioaiagent/__init__.py,sha256=pq9gL6E1VN4Tkx9PD83AIW9e_-N5REqJeC0TE8bZua4,215
2
+ dm_aioaiagent/ai_agent.py,sha256=TTMSL2B-fdv_q7ytO38kC5fd8uB1Vk71ev7tS5tJMwE,9284
3
+ dm_aioaiagent/async_ai_agent.py,sha256=qg7LZRxC7MSzjjburEX09T5EF15ZXAWAd_9RB8vA0oE,2599
4
+ dm_aioaiagent/image_message_content_builder.py,sha256=mAJnsWdnpYpaFAdcCsVwgWH480Q4WfVEpM-Y6KdjyEc,435
5
+ dm_aioaiagent/types.py,sha256=H2_iICmWr6u9d1-6BtSxdt6qV6Jm8v7Zh8das5kV6I4,989
6
+ dm_aioaiagent-0.3.3.dist-info/METADATA,sha256=i06u5vC73yDmx73r5lUCr0Okw1vtf1FwKJgjpuZiKY0,5032
7
+ dm_aioaiagent-0.3.3.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
8
+ dm_aioaiagent-0.3.3.dist-info/top_level.txt,sha256=CbasLH0KI7zA77XwT6JDCnmRascxKNGvUVV9MgYjHAU,14
9
+ dm_aioaiagent-0.3.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,8 +0,0 @@
1
- dm_aioaiagent/__init__.py,sha256=8B0XQR-XE2VieU7-LOHCjqDYv0gSYqkgAkj_eq6XAhI,145
2
- dm_aioaiagent/ai_agent.py,sha256=2IcRBAXsp8JJQ8otNnJjeLwzYZK9vlKa6rbUv-F1WjQ,8213
3
- dm_aioaiagent/async_ai_agent.py,sha256=n7OfJUHRwjk92gae9NkpPKQ21Xost2-JsQ0JyzYTXT4,2146
4
- dm_aioaiagent/types.py,sha256=Xvx0x1GxLAvCot_3CZGgD8BFWwnTEc1lg7moLxkkJoc,587
5
- dm_aioaiagent-0.3.2.dist-info/METADATA,sha256=WNAzIo7kKPRsPFxVeSPWSzSgn2VOeLCkEV3HRZulU4w,4299
6
- dm_aioaiagent-0.3.2.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
7
- dm_aioaiagent-0.3.2.dist-info/top_level.txt,sha256=CbasLH0KI7zA77XwT6JDCnmRascxKNGvUVV9MgYjHAU,14
8
- dm_aioaiagent-0.3.2.dist-info/RECORD,,