
    .mi,                    t   d Z ddlmZ ddlZddlmZmZ ddlmZm	Z	 ddl
mZ ddlmZmZmZmZ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! ddl"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3  e3e4          Z5 eddg          Z6dId&Z7dJd*Z8e69                    d+d,d-.          dKd:            Z:e69                    d;d<e=          dLd@            Z;e69                    dAdBd-.          dMdD            Z<e69                    dEdFd-.          dNdH            Z=dS )Ou7  Research endpoints — legacy SSE plus plan/run Deep Research workflow.

深度研究接口模块。
提供三阶段研究流程：生成研究计划 (plan) -> 执行研究 (run) -> 单章节重跑 (rerun)，
以及兼容旧版的一键流式研究接口。所有生成结果通过 SSE 实时推送到前端。
    )annotationsN)	AnnotatedAsyncIterator)	APIRouterDepends)StreamingResponse)UserContextget_current_userget_embedding_clientget_es_clientget_llm_clientget_mysql_clientget_neo4j_clientget_redis_client)ResearchChunkResearchPlanRequestResearchPlanResponseResearchRequestResearchRunRequestResearchSectionRerunRequest)EmbeddingService)GraphQueryService)PermissionService)ResearchEngine)EmbeddingClient)ESClient)	LLMClient)MySQLClient)Neo4jClient)RedisClient)build_research_session_store)
get_loggerz	/researchresearch)prefixtags	es_clientr   neo4j_clientr   redis_clientr    mysql_clientMySQLClient | Noneembedding_clientr   
llm_clientr   returnr   c                    t          |          }t          |          }t          ||          }t          | ||||          S )u   构建 ResearchEngine 及其依赖服务，各端点共用此辅助函数以减少重复代码。

    Build a ResearchEngine with all required services wired up.
    )r(   r)   )r&   embedding_servicegraph_servicer,   session_store)r   r   r!   r   )	r&   r'   r(   r)   r+   r,   embedding_svc	graph_svcr1   s	            -D:\work\zm-rag\backend\app\api\v1\research.py_build_research_enginer5   9   sa     %%566M!,//I0!!  M '#       genAsyncIterator[ResearchChunk]AsyncIterator[str]c                 K   	 | 2 3 d{V }t          j        |                    d          d          }d| dW V  ;6 dS # t          $ r}t                              dt          |          |	           t          d
t          |                    }t          j        |                    d          d          }d| dW V  Y d}~dS d}~ww xY w)u  Wrap an async generator of ResearchChunks into SSE-format strings.

    将 ResearchChunk 序列化为 SSE data 帧格式，供 StreamingResponse 使用。
    当生成器抛出异常时，向客户端发送 SSE error 事件，避免流被静默截断。
    NT)exclude_noneF)ensure_asciizdata: z

sse_stream_error)errorexc_infor>   )typecontent)jsondumps
model_dump	Exceptionloggerr>   strr   )r7   chunkpayloadexcerror_chunkerror_payloads         r4   _sse_streamrM   Y   s)     	+ 	) 	) 	) 	) 	) 	) 	)%j!1!1t!1!D!DSXYYYG(7(((((((( 33  + + +'s3xx#FFF##c((CCC
;#9#9t#9#L#L[`aaa*}*************+s"   A A6A 
CA;CC u   研究分析 (SSE 流式)z2Server-Sent Events stream of ResearchChunk objects)summaryresponse_descriptionbodyr   user1Annotated[UserContext, Depends(get_current_user)]+Annotated[ESClient, Depends(get_es_client)]1Annotated[Neo4jClient, Depends(get_neo4j_client)]1Annotated[RedisClient, Depends(get_redis_client)]8Annotated[MySQLClient | None, Depends(get_mysql_client)]9Annotated[EmbeddingClient, Depends(get_embedding_client)]-Annotated[LLMClient, Depends(get_llm_client)]r   c           	       K   t                               d|j        t          | j                  | j        t          | j        pg                      t          |          }|                    |           d{V }	t          ||||||          }
|

                    | j        |	| j        | j                  }t          t          |          dddd	d
          S )u  Stream a deep-research answer via Server-Sent Events.

    The response is ``text/event-stream`` emitting JSON-encoded
    :class:`~app.api.schemas.research.ResearchChunk` objects.

    Chunk types
    -----------
    - ``thinking`` — intermediate status update (not part of final answer)
    - ``reference`` — a document that was retrieved and used as context
    - ``text``      — LLM-generated answer token(s)
    - ``done``      — end-of-stream sentinel
    - ``error``     — fatal error during processing
    research_request)user_idquestion_len
session_idseed_doc_countr(   N)r^   seed_doc_idstext/event-streamno-cache
keep-alivenozCache-Control
ConnectionzX-Accel-Buffering
media_typeheaders)rF   infor\   lenquestionr^   ra   r   resolver5   r#   r   rM   rQ   rR   r&   r'   r(   r)   r+   r,   perm_servicepermenginer7   s               r4   r#   r#   r   s     8 KK''?4,233     %,???L%%d++++++++D $<|* F
 //?&	   C C&'&!%
 
   r6   z/planu   生成研究计划)rO   response_modelr   r   c           	     B  K   t                               d|j        | j        j        | j        t          | j        pg                      t          ||||||          }|	                    | j        | j                   d{V }	t          | j        | j        |	          S )u`   根据研究任务定义生成研究计划，包含目标拆解、子问题、章节大纲等。research_plan_request)r\   topicr^   r_   )ra   N)r^   taskplan)rF   rk   r\   rw   rv   r^   rl   ra   r5   
build_planr   )
rQ   rR   r&   r'   r(   r)   r+   r,   rr   rx   s
             r4   research_planrz      s        KKio?4,233     $<|* F
 ""494;L"MMMMMMMMD4?QUVVVVr6   z/runu   执行深度研究 (SSE 流式)r   c           	       K   t                               d|j        | j        j        | j        t          | j        j        p| j	        pg                      t          |          }|                    |           d{V }	t          ||||||          }
|
                    | j        | j        |	| j                  }t          t          |          dddd	d
          S )uV   基于已确认的研究计划执行深度研究，以 SSE 流式返回研究报告。research_run_request)r\   rv   r^   explicit_doc_countr`   N)r^   rb   rc   rd   re   rf   rh   )rF   rk   r\   rw   rv   r^   rl   rx   included_doc_idsra   r   rn   r5   run_deep_researchr   rM   ro   s               r4   research_runr      s       KKio?ty9TT=NTRTUU     %,???L%%d++++++++D $<|* F
 
"
"		?	 #  C C&'&!%
 
   r6   z/sections/rerunu   重跑研究章节 (SSE 流式)r   c                  K   t                               d|j        | j        j        | j        | j        t          | j        pg           t          | j	        j
        p| j        pg                      t          |          }|                    |           d{V }	t          ||||||          }
|
                    | j        | j	        | j        |	| j        | j        | j                  }t#          t%          |          dddd	d
          S )uQ   对研究报告中的单个章节进行重新生成，支持指定来源文档。research_section_rerun_request)r\   rv   section_titler^   source_doc_countr}   r`   N)section_summarysource_doc_idsr^   rb   rc   rd   re   rf   rh   )rF   rk   r\   rw   rv   r   r^   rl   r   rx   r~   ra   r   rn   r5   rerun_sectionr   r   rM   ro   s               r4   research_rerun_sectionr     s>       KK(io(?T06B77ty9TT=NTRTUU     %,???L%%d++++++++D $<|* F
 

		,*?   C C&'&!%
 
   r6   )r&   r   r'   r   r(   r    r)   r*   r+   r   r,   r   r-   r   )r7   r8   r-   r9   )rQ   r   rR   rS   r&   rT   r'   rU   r(   rV   r)   rW   r+   rX   r,   rY   r-   r   )rQ   r   rR   rS   r&   rT   r'   rU   r(   rV   r)   rW   r+   rX   r,   rY   r-   r   )rQ   r   rR   rS   r&   rT   r'   rU   r(   rV   r)   rW   r+   rX   r,   rY   r-   r   )rQ   r   rR   rS   r&   rT   r'   rU   r(   rV   r)   rW   r+   rX   r,   rY   r-   r   )>__doc__
__future__r   rB   typingr   r   fastapir   r   fastapi.responsesr   app.api.depsr	   r
   r   r   r   r   r   r   app.api.schemas.researchr   r   r   r   r   r   app.core.embeddingr   app.core.graph_query_servicer   app.core.permissionr   app.core.research_enginer   #app.infrastructure.embedding_clientr   app.infrastructure.es_clientr   app.infrastructure.llm_clientr   app.infrastructure.mysql_clientr   app.infrastructure.neo4j_clientr   app.infrastructure.redis_clientr     app.infrastructure.session_storer!   app.utils.loggerr"   __name__rF   routerr5   rM   postr#   rz   r   r    r6   r4   <module>r      sV    # " " " " "  + + + + + + + + & & & & & & & & / / / / / /	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	                0 / / / / / : : : : : : 1 1 1 1 1 1 3 3 3 3 3 3 ? ? ? ? ? ? 1 1 1 1 1 1 3 3 3 3 3 3 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 I I I I I I ' ' ' ' ' '	H			+ZL	9	9	9   @+ + + +2 'M   
8 8 8 
8v  '   
W W W 
W: 
-M   
+ + + 
+\ -M   
0 0 0 
0 0 0r6   