Skip to content

Commit

Permalink
chore: fixing build issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Will Jutsum committed Nov 8, 2024
1 parent 98533be commit aeeadf7
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 53 deletions.
72 changes: 40 additions & 32 deletions src/claudesync/cli/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ def delete_all_chats(provider, organization_id):
if not chats:
break
uuids_to_delete = [chat["uuid"] for chat in chats[:50]]
deleted, _ = delete_chats(provider, organization_id, uuids_to_delete)
deleted, _ = delete_chats(
provider, organization_id, uuids_to_delete)
total_deleted += deleted
bar.update(len(uuids_to_delete))
click.echo(f"Chat deletion complete. Total chats deleted: {total_deleted}")
Expand Down Expand Up @@ -135,7 +136,8 @@ def confirm_and_delete_chat(provider, organization_id, chat):
):
deleted, _ = delete_chats(provider, organization_id, [chat["uuid"]])
if deleted:
click.echo(f"Successfully deleted chat: {chat.get('name', 'Unnamed')}")
click.echo(
f"Successfully deleted chat: {chat.get('name', 'Unnamed')}")
else:
click.echo(f"Failed to delete chat: {chat.get('name', 'Unnamed')}")

Expand Down Expand Up @@ -191,55 +193,61 @@ def message(config, message, chat, timezone, image):
"""Send a message to a specified chat or create a new chat and send the message."""
provider = validate_and_get_provider(config, require_project=True)
active_organization_id = config.get("active_organization_id")
active_project_id = config.get("active_project_id")
active_project_name = config.get("active_project_name")

message = " ".join(message) # Join all message parts into a single string

try:
chat = create_chat(
config,
active_project_id,
active_project_name,
config.get("active_project_id"),
config.get("active_project_name"),
chat,
active_organization_id,
provider,
)
if chat is None:
return

# Upload images if provided
files = []
for img_path in image:
try:
uploaded_img = provider.upload_image(active_organization_id, img_path)
file_uuid = uploaded_img["file_uuid"]
files.append(file_uuid)
click.echo(f"Uploaded image: {img_path} ({file_uuid})")
except Exception as e:
click.echo(f"Failed to upload image {img_path}: {str(e)}")

# Send message and process the streaming response
for event in provider.send_message(
active_organization_id, chat, message, timezone, files
):
if "completion" in event:
click.echo(event["completion"], nl=False)
elif "content" in event:
click.echo(event["content"], nl=False)
elif "error" in event:
click.echo(f"\nError: {event['error']}")
elif "message_limit" in event:
click.echo(
f"\nRemaining messages: {event['message_limit']['remaining']}"
)

files = upload_images(provider, active_organization_id, image)
process_message_response(
provider.send_message(active_organization_id,
chat, message, timezone, files)
)
click.echo() # Print a newline at the end of the response

except Exception as e:
click.echo(f"Failed to send message: {str(e)}")


def upload_images(provider, organization_id, image_paths):
"""Upload images and return list of file UUIDs."""
files = []
for img_path in image_paths:
try:
uploaded_img = provider.upload_image(organization_id, img_path)
file_uuid = uploaded_img["file_uuid"]
files.append(file_uuid)
click.echo(f"Uploaded image: {img_path} ({file_uuid})")
except Exception as e:
click.echo(f"Failed to upload image {img_path}: {str(e)}")
return files


def process_message_response(response_stream):
"""Process the streaming response from the message API."""
for event in response_stream:
if "completion" in event:
click.echo(event["completion"], nl=False)
elif "content" in event:
click.echo(event["content"], nl=False)
elif "error" in event:
click.echo(f"\nError: {event['error']}")
elif "message_limit" in event:
click.echo(
f"\nRemaining messages: {event['message_limit']['remaining']}"
)


def create_chat(
config,
active_project_id,
Expand Down
20 changes: 13 additions & 7 deletions src/claudesync/providers/base_claude_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,17 @@ def _configure_logging(self):

def login(self):
click.echo(
"A session key is required to call: " + self.config.get("claude_api_url")
"A session key is required to call: " +
self.config.get("claude_api_url")
)
click.echo("To obtain your session key, please follow these steps:")
click.echo("1. Open your web browser and go to https://claude.ai")
click.echo("2. Log in to your Claude account if you haven't already")
click.echo("3. Once logged in, open your browser's developer tools:")
click.echo(" - Chrome/Edge: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)")
click.echo(" - Firefox: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)")
click.echo(
" - Chrome/Edge: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)")
click.echo(
" - Firefox: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)")
click.echo(
" - Safari: Enable developer tools in Preferences > Advanced, then press Cmd+Option+I"
)
Expand Down Expand Up @@ -118,7 +121,8 @@ def get_organizations(self):
{"id": org["uuid"], "name": org["name"]}
for org in response
if (
{"chat", "claude_pro"}.issubset(set(org.get("capabilities", [])))
{"chat", "claude_pro"}.issubset(
set(org.get("capabilities", [])))
or {"chat", "raven"}.issubset(set(org.get("capabilities", [])))
)
]
Expand Down Expand Up @@ -207,7 +211,8 @@ def delete_chat(self, organization_id, conversation_uuids):
return self._make_request("POST", endpoint, data)

def _make_request(self, method, endpoint, data=None):
raise NotImplementedError("This method should be implemented by subclasses")
raise NotImplementedError(
"This method should be implemented by subclasses")

def create_chat(self, organization_id, chat_name="", project_uuid=None):
"""
Expand Down Expand Up @@ -242,8 +247,9 @@ def _generate_uuid(self):
def _make_request_stream(self, method, endpoint, data=None):
# This method should be implemented by subclasses to return a response object
# that can be used with sseclient
raise NotImplementedError("This method should be implemented by subclasses")

raise NotImplementedError(
"This method should be implemented by subclasses")

def send_message(self, organization_id, chat_id, prompt, timezone="UTC", files=None):
endpoint = (
f"/organizations/{organization_id}/chat_conversations/{chat_id}/completion"
Expand Down
7 changes: 0 additions & 7 deletions src/claudesync/providers/claude_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import string
from datetime import datetime, timezone
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from .base_claude_ai import BaseClaudeAIProvider
from ..exceptions import ProviderError

Expand Down Expand Up @@ -153,12 +152,6 @@ def generate_boundary(self):
string.ascii_letters + string.digits, k=16))
return prefix + random_sequence

def generate_boundary(self):
prefix = 'WebKitFormBoundary'
random_sequence = ''.join(random.choices(
string.ascii_letters + string.digits, k=16))
return prefix + random_sequence

def upload_image(self, organization_id, file_path):

self.logger.debug(f"Uploading image: {file_path}")
Expand Down
11 changes: 8 additions & 3 deletions tests/mock_http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def do_GET(self):

def do_POST(self):
content_length = int(self.headers["Content-Length"])
post_data = self.rfile.read(content_length)
parsed_path = urlparse(self.path)

if parsed_path.path.endswith("/chat_conversations"):
Expand All @@ -111,6 +112,7 @@ def do_POST(self):
response = json.dumps({'file_id': 'uploaded_image_1'})
self.wfile.write(response.encode())
elif parsed_path.path.endswith("/completion"):
data = json.loads(post_data.decode("utf-8"))
self.send_response(200)
self.send_header("Content-type", "text/event-stream")
self.end_headers()
Expand All @@ -121,8 +123,10 @@ def do_POST(self):
)
self.wfile.write(b"event: done\n\n")
if 'files' in data and data['files']:
self.wfile.write(b'data: {"completion": "Analyzing image..."}\n\n')
self.wfile.write(b'data: {"completion": "The image shows a cat."}\n\n')
self.wfile.write(
b'data: {"completion": "Analyzing image..."}\n\n')
self.wfile.write(
b'data: {"completion": "The image shows a cat."}\n\n')
else:
# time.sleep(0.01) # Add a small delay to simulate network latency
content_length = int(self.headers["Content-Length"])
Expand All @@ -135,7 +139,8 @@ def do_POST(self):
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
response = json.dumps({"uuid": "new_proj", "name": "New Project"})
response = json.dumps(
{"uuid": "new_proj", "name": "New Project"})
self.wfile.write(response.encode())
elif parsed_path.path.startswith(
"/api/organizations/"
Expand Down
8 changes: 4 additions & 4 deletions tests/test_claude_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ def test_upload_file(self):
with patch.object(
self.provider, "_make_request", return_value={"uuid": "file1"}
):
result = self.provider.upload_file("org1", "proj1", "test.txt", "Hello")
result = self.provider.upload_file(
"org1", "proj1", "test.txt", "Hello")
self.assertEqual(result["uuid"], "file1")

def test_delete_file(self):
Expand Down Expand Up @@ -160,7 +161,6 @@ def test_handle_http_error_403(self):
self.provider.handle_http_error(mock_error)
self.assertIn("403 Forbidden error", str(context.exception))


def test_upload_image(self):
mock_file_content = b'fake image data'
with patch('builtins.open', mock_open(read_data=mock_file_content)):
Expand All @@ -175,8 +175,8 @@ def test_send_message_with_image(self):
b'event: done\n\n'
)
with patch.object(self.provider, '_make_request_stream', return_value=mock_response):
messages = list(self.provider.send_message('org1', 'chat1', 'Describe this image', files=[{'file_id': 'image1'}]))

messages = list(self.provider.send_message(
'org1', 'chat1', 'Describe this image', files=[{'file_id': 'image1'}]))
self.assertEqual(len(messages), 2)
self.assertEqual(messages[0]['completion'], 'Analyzing image...')
self.assertEqual(messages[1]['completion'], 'The image shows a cat.')
Expand Down

0 comments on commit aeeadf7

Please sign in to comment.