llm-dialog-manager 0.4.4__py3-none-any.whl → 0.4.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  from .chat_history import ChatHistory
2
2
  from .agent import Agent
3
3
 
4
- __version__ = "0.4.4"
4
+ __version__ = "0.4.5"
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  import os
4
4
  import uuid
5
- from typing import List, Dict, Optional, Union
5
+ from typing import List, Dict, Union, Optional, Any
6
6
  import logging
7
7
  from pathlib import Path
8
8
  import random
@@ -97,13 +97,30 @@ def completion(model: str, messages: List[Dict[str, Union[str, List[Union[str, I
97
97
  api_key = os.getenv(f"{service.upper()}_API_KEY")
98
98
  base_url = os.getenv(f"{service.upper()}_BASE_URL")
99
99
 
100
- def format_messages_for_api(model, messages):
101
- """Convert ChatHistory messages to the format required by the specific API."""
100
+ def format_messages_for_api(
101
+ model: str,
102
+ messages: List[Dict[str, Union[str, List[Union[str, Image.Image, Dict]]]]]
103
+ ) -> tuple[Optional[str], List[Dict[str, Any]]]:
104
+ """
105
+ Convert ChatHistory messages to the format required by the specific API.
106
+
107
+ Args:
108
+ model: The model name (e.g., "claude", "gemini", "gpt")
109
+ messages: List of message dictionaries with role and content
110
+
111
+ Returns:
112
+ tuple: (system_message, formatted_messages)
113
+ - system_message is extracted system message for Claude, None for others
114
+ - formatted_messages is the list of formatted message dictionaries
115
+ """
102
116
  if "claude" in model and "openai" not in model:
103
117
  formatted = []
104
118
  system_msg = ""
119
+
120
+ # Extract system message if present
105
121
  if messages and messages[0]["role"] == "system":
106
122
  system_msg = messages.pop(0)["content"]
123
+
107
124
  for msg in messages:
108
125
  content = msg["content"]
109
126
  if isinstance(content, str):
@@ -113,9 +130,12 @@ def completion(model: str, messages: List[Dict[str, Union[str, List[Union[str, I
113
130
  combined_content = []
114
131
  for block in content:
115
132
  if isinstance(block, str):
116
- combined_content.append({"type": "text", "text": block})
133
+ combined_content.append({
134
+ "type": "text",
135
+ "text": block
136
+ })
117
137
  elif isinstance(block, Image.Image):
118
- # For Claude, convert PIL.Image to base64
138
+ # Convert PIL.Image to base64
119
139
  buffered = io.BytesIO()
120
140
  block.save(buffered, format="PNG")
121
141
  image_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
@@ -145,9 +165,12 @@ def completion(model: str, messages: List[Dict[str, Union[str, List[Union[str, I
145
165
  "data": block["image_base64"]["data"]
146
166
  }
147
167
  })
148
- formatted.append({"role": msg["role"], "content": combined_content})
168
+ formatted.append({
169
+ "role": msg["role"],
170
+ "content": combined_content
171
+ })
149
172
  return system_msg, formatted
150
-
173
+
151
174
  elif ("gemini" in model or "gpt" in model or "grok" in model) and "openai" not in model:
152
175
  formatted = []
153
176
  for msg in messages:
@@ -160,40 +183,75 @@ def completion(model: str, messages: List[Dict[str, Union[str, List[Union[str, I
160
183
  if isinstance(block, str):
161
184
  parts.append(block)
162
185
  elif isinstance(block, Image.Image):
186
+ # Keep PIL.Image objects as is for Gemini
163
187
  parts.append(block)
164
188
  elif isinstance(block, dict):
165
189
  if block.get("type") == "image_url":
166
- parts.append({"type": "image_url", "image_url": {"url": block["image_url"]["url"]}})
190
+ parts.append({
191
+ "type": "image_url",
192
+ "image_url": {
193
+ "url": block["image_url"]["url"]
194
+ }
195
+ })
167
196
  elif block.get("type") == "image_base64":
168
- parts.append({"type": "image_base64", "image_base64": {"data": block["image_base64"]["data"], "media_type": block["image_base64"]["media_type"]}})
169
- formatted.append({"role": msg["role"], "parts": parts})
197
+ parts.append({
198
+ "type": "image_base64",
199
+ "image_base64": {
200
+ "data": block["image_base64"]["data"],
201
+ "media_type": block["image_base64"]["media_type"]
202
+ }
203
+ })
204
+ formatted.append({
205
+ "role": msg["role"],
206
+ "parts": parts
207
+ })
170
208
  return None, formatted
171
-
209
+
172
210
  else: # OpenAI models
173
211
  formatted = []
174
212
  for msg in messages:
175
213
  content = msg["content"]
176
214
  if isinstance(content, str):
177
- formatted.append({"role": msg["role"], "content": content})
215
+ formatted.append({
216
+ "role": msg["role"],
217
+ "content": content
218
+ })
178
219
  elif isinstance(content, list):
179
- # OpenAI expects 'content' as string; images are not directly supported
180
- # You can convert images to URLs or descriptions if needed
181
- combined_content = ""
220
+ formatted_content = []
182
221
  for block in content:
183
222
  if isinstance(block, str):
184
- combined_content += block + "\n"
223
+ formatted_content.append({
224
+ "type": "text",
225
+ "text": block
226
+ })
185
227
  elif isinstance(block, Image.Image):
186
- # Convert PIL.Image to base64 or upload and use URL
228
+ # Convert PIL.Image to base64
187
229
  buffered = io.BytesIO()
188
230
  block.save(buffered, format="PNG")
189
231
  image_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
190
- combined_content += f"[Image Base64: {image_base64[:30]}...]\n"
232
+ formatted_content.append({
233
+ "type": "image_url",
234
+ "image_url": {
235
+ "url": f"data:image/jpeg;base64,{image_base64}"
236
+ }
237
+ })
191
238
  elif isinstance(block, dict):
192
239
  if block.get("type") == "image_url":
193
- combined_content += f"[Image: {block['image_url']['url']}]\n"
240
+ formatted_content.append({
241
+ "type": "image_url",
242
+ "image_url": block["image_url"]
243
+ })
194
244
  elif block.get("type") == "image_base64":
195
- combined_content += f"[Image Base64: {block['image_base64']['data'][:30]}...]\n"
196
- formatted.append({"role": msg["role"], "content": combined_content.strip()})
245
+ formatted_content.append({
246
+ "type": "image_url",
247
+ "image_url": {
248
+ "url": f"data:image/jpeg;base64,{block['image_base64']['data']}"
249
+ }
250
+ })
251
+ formatted.append({
252
+ "role": msg["role"],
253
+ "content": formatted_content
254
+ })
197
255
  return None, formatted
198
256
 
199
257
  system_msg, formatted_messages = format_messages_for_api(model, messages.copy())
@@ -546,7 +604,7 @@ class Agent:
546
604
  if __name__ == "__main__":
547
605
  # Example Usage
548
606
  # Create an Agent instance (Gemini model)
549
- agent = Agent("gemini-1.5-flash", "you are Jack101", memory_enabled=True)
607
+ agent = Agent("gemini-1.5-flash-openai", "you are Jack101", memory_enabled=True)
550
608
 
551
609
  # Add an image
552
610
  agent.add_image(image_path="example.png")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: llm_dialog_manager
3
- Version: 0.4.4
3
+ Version: 0.4.5
4
4
  Summary: A Python package for managing LLM chat conversation history
5
5
  Author-email: xihajun <work@2333.fun>
6
6
  License: MIT
@@ -0,0 +1,9 @@
1
+ llm_dialog_manager/__init__.py,sha256=Vai6V5cLO8X7dkHgnALzKyhtDYdPhkd9oD0HPjzdqZ8,86
2
+ llm_dialog_manager/agent.py,sha256=cYK3SMa1zPeSP4QoSxfceQ3YLQYqBTNwDE_ZJdBi7pM,27595
3
+ llm_dialog_manager/chat_history.py,sha256=DKKRnj_M6h-4JncnH6KekMTghX7vMgdN3J9uOwXKzMU,10347
4
+ llm_dialog_manager/key_manager.py,sha256=shvxmn4zUtQx_p-x1EFyOmnk-WlhigbpKtxTKve-zXk,4421
5
+ llm_dialog_manager-0.4.5.dist-info/LICENSE,sha256=vWGbYgGuWpWrXL8-xi6pNcX5UzD6pWoIAZmcetyfbus,1064
6
+ llm_dialog_manager-0.4.5.dist-info/METADATA,sha256=TbPdPjwrncfdYIJjFTzOoaWp5p90zYzpzsazVSK3F_8,4194
7
+ llm_dialog_manager-0.4.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
+ llm_dialog_manager-0.4.5.dist-info/top_level.txt,sha256=u2EQEXW0NGAt0AAHT7jx1odXZ4rZfjcgbmJhvKFuMkI,19
9
+ llm_dialog_manager-0.4.5.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- llm_dialog_manager/__init__.py,sha256=J7qsuEH4NWFkTQVvCqHgxX1jOYnY79s9BMi02KTo3-A,86
2
- llm_dialog_manager/agent.py,sha256=ou9D8NtRt6fDXgrneXP5jZRil7XyKpCTUHCADPJmeeA,25332
3
- llm_dialog_manager/chat_history.py,sha256=DKKRnj_M6h-4JncnH6KekMTghX7vMgdN3J9uOwXKzMU,10347
4
- llm_dialog_manager/key_manager.py,sha256=shvxmn4zUtQx_p-x1EFyOmnk-WlhigbpKtxTKve-zXk,4421
5
- llm_dialog_manager-0.4.4.dist-info/LICENSE,sha256=vWGbYgGuWpWrXL8-xi6pNcX5UzD6pWoIAZmcetyfbus,1064
6
- llm_dialog_manager-0.4.4.dist-info/METADATA,sha256=Rjjs7I8JwbQ21QyMxTDrDrwzmAqMcdY30srUOJxYzWs,4194
7
- llm_dialog_manager-0.4.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
- llm_dialog_manager-0.4.4.dist-info/top_level.txt,sha256=u2EQEXW0NGAt0AAHT7jx1odXZ4rZfjcgbmJhvKFuMkI,19
9
- llm_dialog_manager-0.4.4.dist-info/RECORD,,