o
    ưi[9                     @   s   d Z ddlZddlmZmZmZmZmZ ddlZddl	m
Z
 ddlZddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZmZmZm Z m!Z! ddl"m#Z# dZ$G dd deZ%dS )a_  
Manus Files API implementation.

Manus has an OpenAI-compatible Files API with some differences:
- Uses API_KEY header instead of Authorization: Bearer
- File upload is a two-step process:
  1. Create file record to get upload URL
  2. Upload file content to the upload URL

Reference: https://open.manus.im/docs/openai-compatibility#file-management
    N)AnyDictListOptionalUnion)FileDeleted)verbose_logger)extract_file_data)BaseLLMException)BaseFilesConfigLiteLLMLoggingObjOpenAIError)get_secret_str)TwoStepFileUploadConfigTwoStepFileUploadRequest)CreateFileRequestFileContentRequestHttpxBinaryResponseContent%OpenAICreateFileRequestOptionalParamsOpenAIFileObject)LlmProviderszhttps://api.manus.imc                   @   sL  e Zd ZdZdd ZedefddZ		d;ded	e	d
e
dededee	 dee	 defddZd	e	dee fddZdeded	e	dedef
ddZ	d<dee	 dee	 d	e	dededee de	fddZde	dedeeejf defddZd	e	dedededef
dd Zd	ee	 d!ejd"ededef
d#d$Zd%e	dedede e	ef fd&d'Z!d!ejd"ededefd(d)Z"d%e	dedede e	ef fd*d+Z#d!ejd"edede$fd,d-Z%d.ee	 dedede e	ef fd/d0Z&d!ejd"ededee fd1d2Z'd3e(e	e)f defd4d5Z*d6e+dedede e	ef fd7d8Z,d!ejd"edede-fd9d:Z.dS )=ManusFilesConfiga*  
    Configuration for Manus Files API.

    Manus uses:
    - API_KEY header for authentication (not Authorization: Bearer)
    - Two-step file upload process
    - Content-Type: application/json for all requests

    Reference: https://open.manus.im/docs/openai-compatibility#file-management
    c                 C   s   d S N selfr   r   ^/home/app/Keep/.python/lib/python3.10/site-packages/litellm/llms/manus/files/transformation.py__init__6   s   zManusFilesConfig.__init__returnc                 C   s   t jS r   )r   ZMANUSr   r   r   r   custom_llm_provider9   s   z$ManusFilesConfig.custom_llm_providerNheadersmodelmessagesoptional_paramslitellm_paramsapi_keyapi_basec                 C   s2   |pt jptd}|std||dd |S )z
        Validate environment and set up headers for Manus API.

        Manus uses API_KEY header instead of Authorization: Bearer.
        For file uploads, don't set Content-Type - httpx will set it for multipart.
        MANUS_API_KEY\Manus API key is required. Set MANUS_API_KEY environment variable or pass api_key parameter.application/jsonZAPI_KEYzContent-Type)litellmr&   r   
ValueErrorupdate)r   r!   r"   r#   r$   r%   r&   r'   r   r   r   validate_environment=   s   z%ManusFilesConfig.validate_environmentc                 C   s   dgS )z
        Return supported OpenAI file creation parameters for Manus.
        Manus supports the standard 'purpose' parameter.
        purposer   )r   r"   r   r   r   get_supported_openai_paramsb   s   z,ManusFilesConfig.get_supported_openai_paramsnon_default_paramsdrop_paramsc                 C   s   |S )z
        Map OpenAI parameters to Manus-specific parameters.
        Manus is OpenAI-compatible, so no special mapping needed.
        r   )r   r2   r$   r"   r3   r   r   r   map_openai_paramsk   s   z"ManusFilesConfig.map_openai_paramsstreamc                 C   s>   |p
t jp
tdp
t}|d}|dr| dS | dS )z
        Get the complete URL for Manus Files API endpoint.

        Returns:
            str: The full URL for the Manus /v1/files endpoint
        MANUS_API_BASE/z/v1z/filesz	/v1/files)r,   r'   r   r6   rstripendswith)r   r'   r&   r"   r$   r%   r5   r   r   r   get_complete_urlx   s   



z!ManusFilesConfig.get_complete_urlerror_messagestatus_codec                 C   s   t |||dS )z
        Return the appropriate error class for Manus API errors.
        Uses OpenAIError since Manus is OpenAI-compatible.
        )r<   messager!   r   )r   r;   r<   r!   r   r   r   get_error_class   s
   
z ManusFilesConfig.get_error_classcreate_file_datac                 C   s   | d}|du rtdt|}|d pdtt  }|d }| j| d| d|||d	}	| dp=tjp=td
}
|
sDtdt	t
d|	|
ddd|idt
ddi |ddddS )uQ  
        Transform OpenAI-style file creation request into Manus's two-step format.

        Manus API spec (https://open.manus.im/docs/openai-compatibility#file-management):
        1. POST /v1/files with JSON {"filename": "..."} → returns {"id": "...", "upload_url": "..."}
        2. PUT to upload_url with raw file content
        fileNzFile data is requiredfilenamefile_contentr'   r&   r'   r&   r"   r$   r%   r(   r)   POSTr*   r+   )methodurlr!   dataPUT bodyZ
upload_url)Zinitial_requestZupload_requestZupload_url_locationZupload_url_key)getr-   r	   inttimer:   r,   r&   r   r   r   )r   r"   r?   r$   r%   Z	file_dataZextracted_datarA   rC   r'   r&   r   r   r   transform_create_file_request   sP   


	z.ManusFilesConfig.transform_create_file_requestraw_responselogging_objc           
      C   s(  zt| d}|r|}ntd|j  | }td|  | dd}|rOzttt|	dddd	 d
}W n t
tfyN   tt }Y nw tt }t| dd| dd|| ddd| ddd| ddW S  ty }	 ztdt|	  t
dt|	 d}	~	ww )a<  
        Transform Manus's file upload response into OpenAI-style FileObject.

        For two-step uploads, the handler stores the initial response in litellm_params.
        We need to return the file object from the initial POST, not the final PUT.

        Manus initial response format:
        {
            "id": "file-abc123xyz",
            "object": "file",
            "filename": "document.pdf",
            "status": "pending",
            "upload_url": "https://...",
            "upload_expires_at": "...",
            "created_at": "..."
        }
        Zinitial_file_responsezManus raw response text: zManus file response: 
created_atrJ   Z+00:00N   %Y-%m-%dT%H:%M:%Sidbytesr   rA   r@   r0   
assistantsuploadedstatus_detailsrW   rX   rR   rA   objectr0   statusr[   z#Error parsing Manus file response: )rL   r   debugtextjsonrM   rN   mktimestrptimereplacer-   	TypeErrorr   	Exception	exceptionstr)
r   r"   rP   rQ   r%   Zinitial_response_dataresponse_jsoncreated_at_strrR   er   r   r   transform_create_file_response   sJ   





z/ManusFilesConfig.transform_create_file_responsefile_idc                 C   2   | j |d|dd||d}| d| i fS )z)Get URL and params for retrieving a file.r'   r&   rJ   rD   r7   r:   rL   r   rm   r$   r%   r'   r   r   r   transform_retrieve_file_request+     z0ManusFilesConfig.transform_retrieve_file_requestc                 C   s   | j d|||dS )z!Transform retrieve file response.N)r"   rP   rQ   r%   )rl   r   rP   rQ   r%   r   r   r    transform_retrieve_file_response;  s   z1ManusFilesConfig.transform_retrieve_file_responsec                 C   rn   )z'Get URL and params for deleting a file.r'   r&   rJ   rD   r7   ro   rp   r   r   r   transform_delete_file_requestI  rr   z.ManusFilesConfig.transform_delete_file_requestc                 C   s   |  }tdi |S )zTransform delete file response.Nr   )ra   r   )r   rP   rQ   r%   ri   r   r   r   transform_delete_file_responseY  s   z/ManusFilesConfig.transform_delete_file_responser0   c                 C   s8   | j |d|dd||d}i }|r||d< ||fS )z%Get URL and params for listing files.r'   r&   rJ   rD   r0   ro   )r   r0   r$   r%   r'   paramsr   r   r   transform_list_files_requestc  s   z-ManusFilesConfig.transform_list_files_requestc                    s&   |  }|dg } fdd|D S )zTransform list files response.rH   c                    s   g | ]}  |qS r   )_parse_file_dict).0fr   r   r   
<listcomp>  s    zBManusFilesConfig.transform_list_files_response.<locals>.<listcomp>)ra   rL   )r   rP   rQ   r%   ri   Z
files_datar   r   r   transform_list_files_responsev  s   z.ManusFilesConfig.transform_list_files_response	file_dictc                 C   s   | dd}|r/zttt|dddd d}W n ttfy.   tt }Y nw tt }t| dd| d	d
|| ddd| dd| dd| ddS )z(Parse a file dict into OpenAIFileObject.rR   rJ   rS   rT   NrU   rV   rW   rX   r   rA   r@   r0   rY   r^   rZ   r[   r\   )	rL   rM   rN   rb   rc   rd   r-   re   r   )r   r~   rj   rR   r   r   r   ry     s2   




z!ManusFilesConfig._parse_file_dictfile_content_requestc                 C   s>   | d}| j| d| dd||d}| d| di fS )z/Get URL and params for retrieving file content.rm   r'   r&   rJ   rD   r7   z/content)rL   r:   )r   r   r$   r%   rm   r'   r   r   r   transform_file_content_request  s   
z/ManusFilesConfig.transform_file_content_requestc                 C   s
   t |dS )z Transform file content response.)response)r   rs   r   r   r   transform_file_content_response  s   
z0ManusFilesConfig.transform_file_content_response)NNr   )/__name__
__module____qualname____doc__r   propertyr   r    dictrh   listr   r/   r   r   r1   boolr4   r:   rM   r   httpxZHeadersr
   r>   r   r   rO   Responser   r   rl   tuplerq   rt   ru   r   rv   rx   r}   r   r   ry   r   r   r   r   r   r   r   r   r   *   s@   
	
%
	



A
D











r   )&r   rN   typingr   r   r   r   r   r   Zopenai.types.file_deletedr   r,   Zlitellm._loggingr   Z8litellm.litellm_core_utils.prompt_templates.common_utilsr	   Z)litellm.llms.base_llm.chat.transformationr
   Z*litellm.llms.base_llm.files.transformationr   r   Z litellm.llms.openai.common_utilsr   Zlitellm.secret_managers.mainr   Zlitellm.types.filesr   r   Zlitellm.types.llms.openair   r   r   r   r   Zlitellm.types.utilsr   r6   r   r   r   r   r   <module>   s"    