AshwinPathi / claude-api-py

Unofficial Python API for Anthropic's Claude LLM
https://pypi.org/project/claude-api-py/
MIT License
108 stars 11 forks source link

I found that the interface can not get the data, is the format changed? Or something? #14

Closed winie-hy closed 4 months ago

winie-hy commented 11 months ago

{'completion': '', 'stop_reason': 'stop_sequence', 'model': 'claude-2.0', 'stop': '\n\nHuman:', 'log_id': '21dd0513512255a6ee47a1dc3c7945aad0f13208b3d9b74f51d3c282c3068592', 'messageLimit': {'type': 'within_limit'}}

winie-hy commented 11 months ago

https://github.com/Explosion-Scratch/claude-unofficial-api/issues/39This is the reference I found, can the author help me fix it

winie-hy commented 11 months ago

from datetime import datetime

def get_latest_reply(uuid: str) -> str: history = claude_api.chat_conversation_history(uuid) sorted_entries = sorted(history["chat_messages"], key=lambda entry: datetime.strptime(entry["created_at"], "%Y-%m-%dT%H:%M:%S.%f%z")) return sorted_entries[-1]["text"] if sorted_entries[-1]["sender"] == "assistant" else ""

这是我找的参考和临时方案

winie-hy commented 11 months ago

image help~

Hongbin98 commented 11 months ago

@winie-hy I also meet this problem :( Did you solve it finally?

AshwinPathi commented 11 months ago

Yea I'm aware of this issue. Will try to put out a fix soon.

winie-hy commented 11 months ago

`# Send Message to Claude def send_message(self, prompt, conversation_id, attachment=None): url = "https://claude.ai/api/append_message"

Upload attachment if provided

attachments = [] if attachment: attachment_response = self.upload_attachment(attachment) if attachment_response: attachments = [attachment_response] else: return {"Error: Invalid file format. Please try again."}

Ensure attachments is an empty list when no attachment is provided

if not attachment: attachments = []

payload = json.dumps({ "completion": { "prompt": f"{prompt}", "timezone": "Asia/Kolkata", "model": "claude-2" }, "organization_uuid": f"{self.organization_id}", "conversation_uuid": f"{conversation_id}", "text": f"{prompt}", "attachments": attachments })

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', 'Accept': 'text/event-stream, text/event-stream', 'Accept-Language': 'en-US,en;q=0.5', 'Referer': 'https://claude.ai/chats', 'Content-Type': 'application/json', 'Origin': 'https://claude.ai', 'DNT': '1', 'Connection': 'keep-alive', 'Cookie': f'{self.cookie}', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'TE': 'trailers' }

response = requests.post(url, headers=headers, data=payload, stream=True) decoded_data = response.content.decode("utf-8") data_strings = decoded_data.strip().split('\n') data_strings = [item for item in data_strings if item != ''] completions = [] for data_string in data_strings: json_str = data_string[6:].strip() data = json.loads(json_str) if 'completion' in data: completions.append(data['completion'])

answer = ''.join(completions)

Returns answer

return answer`

winie-hy commented 11 months ago

@AshwinPathi Can you update your code with this idea, thank you, I have tested it is feasible

winie-hy commented 11 months ago

I modified this according to your code, which can be successfully sent and received the reply, but there are still problems in deleting the session interface, I hope you can update it together def _send_message1( self, organization_uuid: str, conversation_uuid: str, message: str, attachments: List, timezone: constants.Timezone, model: constants.Model, ) -> str: payload = json.dumps({ "completion": { "prompt": message, "timezone": "Asia/Kolkata", "model": "claude-2" }, "organization_uuid": organization_uuid, "conversation_uuid": conversation_uuid, "text": message, "attachments": attachments })

    headers = {
        'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
        'Accept': 'text/event-stream, text/event-stream',
        'Accept-Language': 'en-US,en;q=0.5',
        'Referer': 'https://claude.ai/chats',
        'Content-Type': 'application/json',
        'Origin': 'https://claude.ai',
        'DNT': '1',
        'Connection': 'keep-alive',
        'Cookie': f"sessionKey={self._session_key}",
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-origin',
        'TE': 'trailers'
    }

    response = requests.post(self._get_api_url(constants.APPEND_MESSAGE_API_ENDPOINT), headers=headers, data=payload, stream=True)
    decoded_data = response.content.decode("utf-8")
    data_strings = decoded_data.strip().split('\n')
    data_strings = [item for item in data_strings if item != '']
    completions = []
    for data_string in data_strings:
        json_str = data_string[6:].strip()
        data = json.loads(json_str)
        if 'completion' in data:
            completions.append(data['completion'])

    answer = ''.join(completions)
    return answer
winie-hy commented 11 months ago

@AshwinPathi

winie-hy commented 11 months ago

I think it is the problem of the request header, if you delete it, maybe you can refer to my above header code

AshwinPathi commented 11 months ago

@winie-hy I attempted to fix it, try downloading from github. The response format and usage should be the exact same thing as before, but now the completion field shouldn't be blank.

winie-hy commented 11 months ago

Thank you for your support, I try to pull your code to compare the effect ~

winie-hy commented 11 months ago

claude_obj.delete_conversation(conversation_uuid) Returned false,and my code is

header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', 'Accept-Language': 'en-US,en;q=0.5', 'Content-Type': 'application/json', 'Content-Length': '38', 'Referer': 'https://claude.ai/chats', 'Origin': 'https://claude.ai', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'Connection': 'keep-alive', 'Cookie': f"sessionKey={self._session_key}", 'TE': 'trailers' }

    payload = json.dumps(f"{conversation_uuid}")

    # response = custom_requests.delete(
    #     self._get_api_url(
    #         constants.DELETE_CONVERSATION_API_ENDPOINT.format(
    #             organization_uuid=organization_uuid,
    #             conversation_uuid=conversation_uuid,
    #         )
    #     ),
    #     headers=header,
    # )
    url = self._get_api_url(
            constants.DELETE_CONVERSATION_API_ENDPOINT.format(
                organization_uuid=organization_uuid,
                conversation_uuid=conversation_uuid,
            )
        )
    response = requests.request("DELETE", url, headers=header, data=payload)
    print(response)
    # Returns True if deleted or False if any error in deleting
    if response.status_code == 204:
        return True
    else:
        return False
winie-hy commented 11 months ago

@AshwinPathi Delete the function of the interface can be repaired, above is my implementation, looks a little rough.

AshwinPathi commented 11 months ago

@winie-hy I can't reproduce this. I ran my code locally and ran some test code with delete_conversation() and it worked. Are you sure you are deleting a valid conversation uuid?

Running the example.py provided in the repo works, which also calls delete_conversation() and asserts for its result to be true, which also works.

winie-hy commented 11 months ago

image

My code looks like this. It returns "false."Only in the way I mentioned above can the deletion be successful and true @AshwinPathi

winie-hy commented 11 months ago

It looks the same as in the example. I don't understand why mine can't work.

AshwinPathi commented 11 months ago

@winie-hy I'm going to add some logging that you can use to debug yourself. In the meantime, I would try and hack at the code to see if your request is formed correctly, you aren't making any silly mistakes, etc. Does running example.py work for you?

winie-hy commented 11 months ago

Unfortunately, I used the sample code and got false

AshwinPathi commented 11 months ago

I added some logging functionality, create the claude client like so:

client = claude_client.ClaudeClient(SESSION_KEY, logging_level=claude_client.LOG_LEVEL_DEBUG)

This will enable verbose debugging information. Paste the results of this information here for a simple script with deleting to see what the result is.

winie-hy commented 11 months ago

thanks for you!

winie-hy commented 11 months ago

Sending DELETE request to: https://claude.ai/api/organizations// with headers: {'content-type': 'application/json', 'authority': 'claude.ai', 'accept': '/', 'accept-language': 'en-US,en;q=0.9', 'dnt': '1', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'same-origin', 'upgrade-insecure-requests': '1', 'connection': 'keep-alive', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', 'cookie': 'sessionKey=sk-****'} [11-Aug-23 15:30:12:root:INFO][claude_client.py:186 - delete_conversation() ] Response json object: Response(ok=False, data=b'', status_code=None, error='HTTP Error 500: Internal Server Error') False image @AshwinPathi Can you see the mistake

winie-hy commented 11 months ago

header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', 'Accept-Language': 'en-US,en;q=0.5', 'Content-Type': 'application/json', 'Content-Length': '38', 'Referer': 'https://claude.ai/chats', 'Origin': 'https://claude.ai', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'Connection': 'keep-alive', 'Cookie': f"sessionKey={self._session_key}", 'TE': 'trailers' }

This is my adjusted head, I get true from this, I suspect it's the head.