o
    2i                     @   s  d dl mZ e  d dlZd dlZd dlZd dlmZmZmZm	Z	 d dl
mZmZmZmZ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 d d	lmZ d d	lmZ d dlZd dl Z e!d
Z"e!ddZ#e!dZ$e!ddZ%e!ddZ&d dl'm(Z( e(e$e&dZ'e!ddZ)ej*ej+dd e,e-Z.eddddZ/e/j0edgddgdgd e/1e e/1e e Z2edfde3fd d!Z4G d"d# d#eZ5G d$d% d%eZ6G d&d' d'eZ7G d(d) d)eZ8G d*d+ d+eZ9G d,d- d-eZ:G d.d/ d/eZ;G d0d1 d1eZ<G d2d3 d3eZ=G d4d5 d5eZ>G d6d7 d7eZ?G d8d9 d9eZ@G d:d; d;eZAG d<d= d=eZBG d>d? d?eZCe/Dd@dAdB ZEe/DdCdDdE ZFe/GdFee4fdGe5dHedIe3fdJdKZHe/GdLee4fdGe6dHedIe3fdMdNZIe/GdOee4fdGe7dHedIe3fdPdQZJe/GdRee4fdGe8dHedIe3fdSdTZKe/GdUee4fdGe9dIe3fdVdWZLe/GdXee4fdGe:dHedIe3fdYdZZMe/Gd[ee4fdGe;dIe3fd\d]ZNe/Gd^ee4fdGe<dHedIe3fd_d`ZOe/Ddaee4fdbe3dce3dIe3fdddeZPe/Gdfee4fdGe=dIe3fdgdhZQe/Gdiee4fdGe>dIe3fdjdkZRe/Gdlee4fdGe?dIe3fdmdnZSe/Gdoee4fdGe@dHedIe3fdpdqZTe/Gdree4fdGeAdIe3fdsdtZUe/Gduee4fdGeBdHedIe3fdvdwZVe/Gdxee4fdGeCdHedIe3fdydzZWe/Gd{ee4fdGe@dIe3fd|d}ZXe/Gd~ee4fdGeBdIe3fddZYe/Gdee4fdGeCdIe3fddZZe/Ddee4fde3dce3dIe3fddZ[e/Ddee4fde3dce3dIe3fddZ\e/Ddee4fde3dce3dIe3fddZ]e-dkr	d dl^Z^e^j_e/ddd dS dS )    )load_dotenvN)DictListOptionalAny)FastAPIHTTPExceptionDependsHeaderRequestBackgroundTasks)CORSMiddleware)StreamingResponse)	BaseModelField)MinaionsRFPService)routerANTHROPIC_API_KEYANTHROPIC_MODELzclaude-3-5-haiku-latestOPENAI_API_KEYOPENAI_MODELz Qwen/Qwen3-Next-80B-A3B-Instruct
OPENAI_URLz#https://api.deepinfra.com/v1/openai)OpenAI)api_keybase_urlGENAI_ENGINEclaudez4%(asctime)s - %(name)s - %(levelname)s - %(message)s)levelformatzTender Automation AI Enginez[AI Engine for Getting RFP Documents, RFP Analysis, and Bid Document Generation using Claude2.0.0)titledescriptionversion*T)allow_originsallow_credentialsallow_methodsallow_headers	x_api_keyc                    s&   | r| t jdkrtddd| S )NAI_SERVICE_API_KEYi  zInvalid API keystatus_codedetail)osenvirongetr   )r(    r0   ./var/www/html/minaions-tender/ai-engine/app.pyverify_api_key@   s   r2   c                   @   6   e Zd ZU edddZeed< edddZeed< dS )GetRfpDocumentsRequest.z)Tender ID to get additional documents forr!   	tender_id	Tenant ID	tenant_idN)__name__
__module____qualname__r   r6   str__annotations__r8   r0   r0   r0   r1   r4   J      
 r4   c                   @   J   e Zd ZU edddZeed< edddZeed< edddZeed< d	S )
EstimateAnalysisCostRequest.	Tender IDr5   r6   r7   r8   
Company ID
company_idN)	r9   r:   r;   r   r6   r<   r=   r8   rC   r0   r0   r0   r1   r@   O      
 r@   c                   @   r?   )
AnalyzeRfpRequest.Analysis record IDr5   analysis_idr7   r8   rB   rC   N)	r9   r:   r;   r   rG   r<   r=   r8   rC   r0   r0   r0   r1   rE   U   rD   rE   c                   @   V   e Zd ZU edddZeed< edddZeed< edddZe	e
eef  ed< d	S )
AnalyzeCompanyDocsRequest.r7   r5   r8   rB   rC   z.List of companies documents with their detailsfolder_listN)r9   r:   r;   r   r8   r<   r=   rC   rJ   r   r   r   r0   r0   r0   r1   rI   [      
 $rI   c                   @   rH   )
 EstimateBidGenerationCostRequest.rF   r5   rG   r7   r8   -List of required documents with their detailsrequired_docsN)r9   r:   r;   r   rG   r<   r=   r8   rN   r   r   r   r0   r0   r0   r1   rL   a   rK   rL   c                   @   sj   e Zd ZU edddZeed< edddZeed< edddZe	e
eef  ed< edd	dZeed
< dS )GenerateBidDocumentsRequest.Bid generation record IDr5   bid_generation_idr7   r8   rM   rN   rB   rC   N)r9   r:   r;   r   rQ   r<   r=   r8   rN   r   r   r   rC   r0   r0   r0   r1   rO   g   s
   
  rO   c                   @   sr   e Zd ZU edddZeed< edddZeed< edddZeed< edd	dZ	eed
< edddZ
eed< dS )RegenerateBidDocumentRequest.rP   r5   rQ   r7   r8   z2Document ID of the original document to regeneratedocument_idz$User's instructions for regenerationuser_promptrB   rC   N)r9   r:   r;   r   rQ   r<   r=   r8   rS   rT   rC   r0   r0   r0   r1   rR   n      
 rR   c                   @   r3   )SetupRfpChatRequest.rF   r5   rG   r7   r8   N)r9   r:   r;   r   rG   r<   r=   r8   r0   r0   r0   r1   rV   v   r>   rV   c                   @   sv   e Zd ZU edddZeed< edddZeed< edddZeed< edd	dZ	eed
< edddZ
ee ed< dS )ChatWithRfpRequest.rF   r5   rG   r7   r8   rA   r6   zUser's questionqueryNzClient session ID	client_id)r9   r:   r;   r   rG   r<   r=   r8   r6   rX   rY   r   r0   r0   r0   r1   rW   z   s   
 rW   c                   @   sF   e Zd ZU eed< eZee ed< dZee	 ed< dZ
ee ed< dS )ChatCompletionRequestpromptmodel  
max_tokensgffffff?temperatureN)r9   r:   r;   r<   r=   r   r\   r   r^   intr_   floatr0   r0   r0   r1   rZ      s
   
 rZ   c                   @   s&   e Zd ZU eed< dZee ed< dS )AnalyzeDocumentRequestfile_urltenderdocument_typeN)r9   r:   r;   r<   r=   re   r   r0   r0   r0   r1   rb      s   
 rb   c                   @   sr   e Zd ZU edddZeed< edddZeed< ee ed< edd	dZ	e
ee  ed
< edddZeed< dS )MergeBidDocumentsRequest.rP   r5   rQ   r7   r8   generated_document_idsNz&List of document categories to includedocument_categoriesT)Whether to add page numbers to merged PDFadd_page_numbers)r9   r:   r;   r   rQ   r<   r=   r8   r   rh   r   rj   boolr0   r0   r0   r1   rf      s   
 rf   c                   @   sr   e Zd ZU edddZeed< edddZeed< edddZeed< ed	d
dZ	e
ed< edddZeed< dS )CompressDocumentRequest.rP   r5   rQ   zDocument ID to compressrS   r7   r8   2   5Target size as percentage of original (25, 50, or 75)target_size_percentT4Whether to prioritize quality over exact size targetpreserve_qualityN)r9   r:   r;   r   rQ   r<   r=   rS   r8   ro   r`   rq   rk   r0   r0   r0   r1   rl      rU   rl   c                   @   sz   e Zd ZU edddZeed< edddZeed< edddZe	ed	< ed
ddZ
eed< edddZeee  ed< dS )BatchCompressDocumentsRequest.rP   r5   rQ   r7   r8   rm   rn   ro   Trp   rq   Nz'List of document categories to compressrh   )r9   r:   r;   r   rQ   r<   r=   r8   ro   r`   rq   rk   rh   r   r   r0   r0   r0   r1   rr      s   
  rr   c                   @   s^   e Zd ZU edddZeed< edddZeed< edddZe	ed	< edd
dZ
e	ed< dS )MergeTenderDocumentsRequest.rA   r5   r6   r7   r8   Tri   rj   z#Whether to include linked documentsinclude_linked_docsN)r9   r:   r;   r   r6   r<   r=   r8   rj   rk   rt   r0   r0   r0   r1   rs      s
   
 rs   /c                      s
   ddiS )Nmessagez+Tender Automation AI Engine v2.0 is runningr0   r0   r0   r0   r1   root   s   rw   z/healthc                      s   dddS )Nhealthyr   )statusr"   r0   r0   r0   r0   r1   health_check   s   
rz   z/get_rfp_documentsrequestbackground_tasksr   c              
      sl   z| tj| j| j dd| j | j| jdW S  ty5 } ztd|  tdt	|dd}~ww )zKExtract links from existing RFP documents and download additional documents
processingz-Getting additional RFP documents for tender: )ry   rv   r6   r8   zError getting RFP documents:   r*   N)
add_taskserviceget_rfp_documentsr6   r8   	Exceptionloggererrorr   r<   r{   r|   r   er0   r0   r1   r      s"   
r   z/estimate_analysis_costc              
      sx   zt | j| j| j}|t j| j| j| j| dd|dW S  ty; } zt	d|  t
dt|dd}~ww )z?Estimate the cost for RFP analysis based on document complexityr}   z Analysis cost estimation startedry   rv   rG   z Error estimating analysis cost: r~   r*   N)r   create_analysis_placeholderr6   r8   rC   r   +process_analysis_cost_estimation_backgroundr   r   r   r   r<   )r{   r|   r   rG   r   r0   r0   r1   estimate_analysis_cost   s&   
r   z/analyze_rfpc              
      sd   z| tj| j| j| j dd| jdW S  ty1 } ztd|  t	dt
|dd}~ww )zFAnalyze RFP documents to extract key information and check eligibilityr}   zRFP analysis startedr   zError starting RFP analysis: r~   r*   N)r   r   analyze_rfprG   r8   rC   r   r   r   r   r<   r   r0   r0   r1   r      s"   r   z/analyze_company_docsc              
      s   z*| tj| j| j| j tj| j| jddidt ddid dd| jdW S  t	yK } zt
d	|  t| td
t|dd}~ww )z4Analyze Company documents to extract key informationry   doc_analysis_in_progresslogs)	timestampactionz$set$pushr}   z!Company document analysis started)ry   rv   rC   z*Error starting Company document analysis: r~   r*   N)r   r   analyze_company_docsr8   rJ   rC   
api_clientupdate_company_infotimer   r   r   printr   r<   r   r0   r0   r1   r     s4   r   z/estimate_bid_generation_costc              
      sV   zt | j| j| j}|W S  ty* } ztd|  tdt	|dd}~ww )z-Estimate the cost for bid document generationz&Error estimating bid generation cost: r~   r*   N)
r   estimate_bid_generation_costrG   r8   rN   r   r   r   r   r<   r{   r   resultr   r0   r0   r1   r   A  s   r   z/generate_bid_documentsc              
      sh   z| tj| j| j| j| j dd| jdW S  ty3 } zt	d|  t
dt|dd}~ww )z9Generate complete bid documents using enhanced automationr}   zBid document generation started)ry   rv   rQ   z(Error starting bid document generation: r~   r*   N)r   r   generate_bid_documentsrQ   r8   rN   rC   r   r   r   r   r<   r   r0   r0   r1   r   R  s$   	r   z/regenerate_bid_documentc              
      ^   zt | j| j| j| j| j}|W S  ty. } zt	d|  t
dt|dd}~ww )z9Regenerate a specific bid document based on user feedbackz!Error regenerating bid document: r~   r*   N)r   regenerate_bid_documentrQ   r8   rS   rT   rC   r   r   r   r   r<   r   r0   r0   r1   r   p     r   z/setup_rfp_chatc           
   
      s  z| j }| j}tj|}|stdd| dt|d |kr*tdd| dt|d }tj||}|sBtd|d  |	di }|	drXd	|	d
d|dW S tj
|dd| ddt didt dd|idid tj|ddt dd|idii |tj|| dd|d| ddW S  ty     ty }	 ztd|	  tdt|	dd}	~	ww )z(Setup chat functionality for RFP queries  Analysis record not found: r*   tenantrd   Tender not found: 	chatSetupsetupCompletedalready_completedbidIdz Chat functionality already setup)ry   bid_idrv   rG   	analysis_FT)r   r   setupInProgresssetupStartedr   chat_setup_started
started_by)r   r   detailsr   r   r}   z Chat setup started in background2-5 minutes)ry   rv   rG   r   estimated_timezError starting chat setup: r~   N)rG   r8   r   r   get_analysisr   r<   
get_tender
ValueErrorr/   update_tenderr   update_analysisr   setup_rfp_chat_backgroundr   r   r   )
r{   r|   r   rG   r8   analysisr6   rd   
chat_setupr   r0   r0   r1   setup_rfp_chat  s|   
	r   z /chat_setup_status/{analysis_id}rG   r8   c              
      s^  zt j| }|stdd|  dt|d |kr$tdd|  dt|d }t j||}|s<td|d  |di }|sKdd	| d
W S |dr_dd| |d|ddW S |drsdd| |d|ddW S |drdd| |dddW S dd| |dW S  ty     ty } zt	
d |  td!t|dd"}~ww )#z$Get the status of chat setup processr   r   r*   r   rd   r   r   not_startedz!Chat setup has not been initiatedr   r   	completedz!Chat setup completed successfullyr   setupCompletedAt)ry   rv   rG   r   completed_atsetupFailedfailedzChat setup failederrorMessagefailedAt)ry   rv   rG   r   	failed_atr   r}   zChat setup is in progressr   z1-3 minutes)ry   rv   rG   
started_atestimated_remainingunknownzChat setup status is unclear)ry   rv   rG   r   z!Error getting chat setup status: r~   N)r   r   r   r   r<   r   r   r/   r   r   r   )rG   r8   r   r   r6   rd   r   r   r0   r0   r1   get_chat_setup_status  sd   


	r   z/chat_with_rfpc              
      sj   zt | j| j| j| j| j}|| j| jdW S  ty4 } zt	d|  t
dt|dd}~ww )z8Chat with RFP documents using enhanced search and Claude)responserG   rX   zError processing chat query: r~   r*   N)r   chat_with_rfprG   r8   r6   rX   rY   r   r   r   r   r<   )r{   r   r   r   r0   r0   r1   r   (  s$   	r   z/chat_completionc              
      s   z/ddl }|jtd}|jj| j| j| jd| jdgd}|j	d j
|j|jj|jjddW S  tyL } ztd	|  td
t|dd}~ww )z4Direct Claude API chat completion (utility endpoint)r   Nr   userrolecontentr\   r^   r_   messages)input_tokensoutput_tokens)
completionr\   usagezError in chat completion: r~   r*   )	anthropicClientr   r   creater\   r^   r_   r[   r   textr   r   r   r   r   r   r   r<   )r{   r   r   clientr   r   r0   r0   r1   chat_completionD  s,   


r   z/analyze_documentc              
      s  z&ddl }ddl}ddlm} ddl}|| j}|jdkr&tddd|dd	d
}|	|j
 |j}W d   n1 s@w   Y  zd}	z3t|d$}
||
}tt|jD ]}|j| }|	| d 7 }	q[W d   n1 suw   Y  W n! ty } ztd|  d| j d}	W Y d}~nd}~ww |jtd}d|	dd  d}tdkr|jjtddd|dgd}|j
d j}ntdkrtjjjtd|dgd}|j d j!j
}ddl"}|#d||j$}|rt%&|'d}nzt%&|}W n   d|i}Y | j(|d W t)j*+|rt),| W S W S t)j*+|r(t),| w w  tyE } ztd!|  td"t-|dd}~ww )#z.Analyze a document from URL (utility endpoint)r   N)NamedTemporaryFile     zFailed to download documentr*   Fz.pdf)deletesuffix rbz

z Error extracting text from PDF: z"[Failed to extract text from PDF: ]r   a  
            Please analyze this tender document and extract key information such as:
            
            1. Tender title and ID
            2. Issuing organization
            3. Submission deadline
            4. Eligibility criteria
            5. Scope of work
            6. Required documents
            7. Evaluation criteria
            8. Estimated value (if available)
            
            Document content:
            iP  zv  # Truncate if too long
            
            Provide your analysis in JSON format with these fields.
            r   r]   g?r   r   r   open_llm)r\   r   z```json\n(.*?)\n```   r   )re   r   zError analyzing document: r~   ).r   requeststempfiler   PyPDF2r/   rc   r+   r   writer   nameopen	PdfReaderrangelenpagesextract_textr   r   r   r   r   	llm_modelr   r   r   r   openaichatcompletionsr   choicesrv   researchDOTALLjsonloadsgroupre   r-   pathexistsunlinkr<   )r{   r   r   r   r   r   r   	temp_filetemp_file_pathtext_contentf
pdf_readerpage_numpage	pdf_errorr   r[   response_textr   
json_matchanalysis_jsonr   r0   r0   r1   analyze_documentd  s   




r  z/merge_bid_documentsc              
      s   z&| j stddd|tj| j| j| j | j| j dd| jt	| j ddW S  ty/     t
yJ } ztd|  td	t|dd
}~ww )z0Merge bid documents into a single PDF with indexr   z6generated_document_ids is required and cannot be emptyr*   r}   z(Bid document merge started in backgroundr   )ry   rv   rQ   document_countr   z#Error starting bid document merge: r~   N)rg   r   r   r   merge_bid_documentsrQ   r8   rh   rj   r   r   r   r   r<   r   r0   r0   r1   r    s8   
r  z/compress_documentc              
      r   )zCompress a PDF documentzError compressing document: r~   r*   N)r   compress_documentrQ   rS   r8   ro   rq   r   r   r   r   r<   r   r0   r0   r1   r	    r   r	  z/batch_compress_documentsc              
      sr   z| tj| j| j| j| j| j dd| j| jddW S  ty8 } zt	
d|  tdt|dd}~ww )	z4Batch compress all PDF documents in a bid generationr}   z0Batch document compression started in background5-10 minutes)ry   rv   rQ   ro   r   z+Error starting batch document compression: r~   r*   N)r   r   batch_compress_bid_documentsrQ   r8   ro   rq   rh   r   r   r   r   r<   r   r0   r0   r1   batch_compress_documents	  s*   
r  z/merge_tender_documentsc              
      sj   z| tj| j| j| j| j dd| jddW S  ty4 } zt	d|  t
dt|dd}~ww )	z;Merge all tender/RFP documents into a single PDF with indexr}   z+Tender document merge started in backgroundz3-7 minutes)ry   rv   r6   r   z&Error starting tender document merge: r~   r*   N)r   r   merge_tender_documentsr6   r8   rj   rt   r   r   r   r   r<   r   r0   r0   r1   r  &  s&   	r  z/merge_bid_documents_syncc              
      Z   zt | j| j| j| j}|W S  ty, } ztd|  t	dt
|dd}~ww )z>Merge bid documents into a single PDF with index (synchronous)zError merging bid documents: r~   r*   N)r   r  rQ   r8   rh   rj   r   r   r   r   r<   r   r0   r0   r1   merge_bid_documents_syncB     r  z/batch_compress_documents_syncc              
      r   )zBBatch compress all PDF documents in a bid generation (synchronous)z#Error batch compressing documents: r~   r*   N)r   r  rQ   r8   ro   rq   rh   r   r   r   r   r<   r   r0   r0   r1   batch_compress_documents_syncT  r   r  z/merge_tender_documents_syncc              
      r  )zIMerge all tender/RFP documents into a single PDF with index (synchronous)z Error merging tender documents: r~   r*   N)r   r  r6   r8   rj   rt   r   r   r   r   r<   r   r0   r0   r1   merge_tender_documents_syncg  r  r  z!/merge_status/{bid_generation_id}rQ   c              
      sT  zt j| |}|stddd|dg }|dg }dd |D }|rK|r0t|dd	 d
nd}d||r;|dnd|rF|ddW S ddW S dd |D }|rmt|dd	 d
}	d|	d|	di ddW S dd |D }
|
rt|
dd	 d
}d|dddW S dddW S  ty } ztd|  tdt	|dd}~ww )z*Get the status of document merge operationr   Bid generation not foundr*   mergedDocumentsr   c                 S      g | ]}| d dv r|qS )r   )documents_mergedmerge_startedmerge_failedr/   .0logr0   r0   r1   
<listcomp>  
    z$get_merge_status.<locals>.<listcomp>c                 S      |  ddS Nr   r   r  xr0   r0   r1   <lambda>      z"get_merge_status.<locals>.<lambda>keyNr   r   r   )ry   merged_document_idsr   r   c                 S      g | ]}| d dkr|qS )r   r  r  r  r0   r0   r1   r        c                 S   r  r   r  r!  r0   r0   r1   r#    r$  r   r   ry   r   r   c                 S   r(  )r   r  r  r  r0   r0   r1   r    r)  c                 S   r  r   r  r!  r0   r0   r1   r#    r$  r}   r   ry   r   r   r   z0No merge operation found for this bid generationry   rv   zError getting merge status: r~   
r   r   get_bid_generationr   r/   maxr   r   r   r<   )rQ   r8   r   bid_genmerged_docsr   
merge_logslatest_mergefailed_logslatest_failurestarted_logslatest_startr   r0   r0   r1   get_merge_statusy  sR   r8  z*/batch_compress_status/{bid_generation_id}c              
      s\  zt j| |}|stddd|dg }dd |D }dd |D }|rOt|dd	 d
}d|d|di |di dd|di dddW S dd |D }|rqt|dd	 d
}	d|	d|	di ddW S dd |D }
|
rt|
dd	 d
}d|dddW S dddW S  ty } ztd|  td t	|dd!}~ww )"z-Get the status of batch compression operationr   r  r*   r   c                 S   r  )r   )batch_documents_compressedbatch_compression_startedbatch_compression_failedr  r  r0   r0   r1   r    r  z-get_batch_compress_status.<locals>.<listcomp>c                 S   r(  )r   r9  r  r  r0   r0   r1   r    r)  c                 S   r  r   r  r!  r0   r0   r1   r#    r$  z+get_batch_compress_status.<locals>.<lambda>r%  r   r   r   compressed_countr   overall_compression_ratio)ry   r   r   r<  r=  c                 S   r(  )r   r;  r  r  r0   r0   r1   r    r)  c                 S   r  r   r  r!  r0   r0   r1   r#    r$  r   r   r*  c                 S   r(  )r   r:  r  r  r0   r0   r1   r    r)  c                 S   r  r   r  r!  r0   r0   r1   r#    r$  r}   r
  r+  r   z$No batch compression operation foundr,  z(Error getting batch compression status: r~   Nr-  )rQ   r8   r   r0  r   compress_logscompleted_logslatestr4  r5  r6  r7  r   r0   r0   r1   get_batch_compress_status  sP   

	rA  z/get_rfp_status/{tender_id}r6   c           
         s>  zt j| |}|stddd|dg }td|  dd |D }td|  t|D ]J}|d	}|d
i }|dkrhd|d|dd|ddd|dd d|dd dd  W S |dkr|d|d|ddd  W S q2dddW S  ty }	 zt	d|	  tdt
|	dd}	~	ww ) z-Get the status of get_rfp_documents operationr   zTender not foundr*   r   zLogs found: c                 S   r  )r   )linked_documents_addedget_rfp_documents_failedget_rfp_documents_completedr  r  r0   r0   r1   r  	  r  z,get_rfp_documents_status.<locals>.<listcomp>zFiltered RFP Logs: r   r   rD  r   r   links_foundr   documents_downloadedzProcess completed. Found z links, downloaded z additional documents)ry   r   rE  rF  rv   rC  r   r   zRFP documents extraction failed)ry   r   r   rv   r}   z0Still processing... Check again in a few minutesr,  z$Error getting RFP documents status: r~   N)r   r   r   r   r/   r   inforeversedr   r   r<   )
r6   r8   r   rd   r   rfp_logsr  r   r   r   r0   r0   r1   get_rfp_documents_status  sH   	


 
rJ  __main__z0.0.0.0i@  )hostport)`dotenvr   r-   r   loggingtypingr   r   r   r   fastapir   r   r	   r
   r   r   fastapi.middleware.corsr   fastapi.responsesr   pydanticr   r   minaions_rfp_servicer   bid_processing_apisr   bid_processing_routerlocation_finder_apilocation_finder_routerasyncior   getenvr   r   r   r   r   r   r   r   basicConfigINFO	getLoggerr9   r   appadd_middlewareinclude_routerr   r<   r2   r4   r@   rE   rI   rL   rO   rR   rV   rW   rZ   rb   rf   rl   rr   rs   r/   rw   rz   postr   r   r   r   r   r   r   r   r   r   r   r  r  r	  r  r  r  r  r  r8  rA  rJ  uvicornrunr0   r0   r0   r1   <module>   s    



	




!!'XGk%<@
: