
    Ti=                       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 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l.m/Z/ ddl0m1Z1 ddl2m3Z3  e3e4          Z5 eddg          Z6d:dZ7e68                    ddd !          d;d3            Z9e68                    d4d5e6          d<d9            Z:dS )=u  QA (智能问答) endpoint — SSE streaming answer with graph + ES retrieval.

智能问答接口模块。
基于知识图谱 + ES 混合检索进行上下文召回，通过 LLM 生成回答，
以 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)	QARequestQASearchDocumentQASearchRequestQASearchResponse)ResearchChunk)EmbeddingService)GraphQueryService)PermissionService)ResearchEngine)EmbeddingClient)ESClient)	LLMClient)MySQLClient)Neo4jClient)RedisClient)build_research_session_store)
get_loggerz/qaqa)prefixtagsgenAsyncIterator[ResearchChunk]returnAsyncIterator[str]c                  K   | 2 3 d{V }t          j        |                    d          d          }d| dW V  ;6 dS )u=   将 ResearchChunk 异步生成器转换为 SSE data 帧流。NT)exclude_noneF)ensure_asciizdata: z

)jsondumps
model_dump)r%   chunkpayloads      'D:\work\zm-rag\backend\app\api\v1\qa.py_sse_streamr2   .   s{        % % % % % % %e*U--4-@@uUUU$w$$$$$$$$ sss   A  u   智能问答 (SSE 流式)z2Server-Sent Events stream of ResearchChunk objects)summaryresponse_descriptionbodyr   user1Annotated[UserContext, Depends(get_current_user)]	es_client+Annotated[ESClient, Depends(get_es_client)]neo4j_client1Annotated[Neo4jClient, Depends(get_neo4j_client)]redis_client1Annotated[RedisClient, Depends(get_redis_client)]mysql_client8Annotated[MySQLClient | None, Depends(get_mysql_client)]embedding_client9Annotated[EmbeddingClient, Depends(get_embedding_client)]
llm_client-Annotated[LLMClient, Depends(get_llm_client)]r   c           	       K   t                               d|j        t          | j                  | j        t          | j        pg                      t          |          }|                    |           d{V }	t          |          }
t          |          }t          ||          }t          ||
|||          }|                    | j        |	| j        | j                  }t          t          |          dd	d
dd          S )uZ   接收用户问题，经 RAG 检索增强后由 LLM 生成回答，以 SSE 流式返回。
qa_request)user_idquestion_len
session_idseed_doc_countr=   Nr=   r?   r9   embedding_servicegraph_servicerC   session_store)rI   seed_doc_idsztext/event-streamzno-cachez
keep-aliveno)zCache-Control
ConnectionzX-Accel-Buffering)
media_typeheaders)loggerinforG   lenquestionrI   rQ   r   resolver   r   r    r   r"   r   r2   )r6   r7   r9   r;   r=   r?   rA   rC   perm_servicepermembedding_svc	graph_svcrP   enginer%   s                  r1   r"   r"   7   sH       KK''?4,233     %,???L%%d++++++++D$%566M!,//I0!!  M '#  F ))?&	   C C&'&!%
 
       z/searchu0   QA 材料检索（仅检索，不生成回答）)r4   response_modelr   r   c                v  K   t                               d|j        t          | j                  t          | j        pg                      t          |          }|                    |           d{V }	t          |          }
t          |          }t          ||          }t          ||
|||          }|                    | j        |	| j                   d{V }d |d	         D             }t          | j        |d
         |d         t          |          ||d         |d         |d                   S )u  仅执行 QA 检索流水线（关键词提取 → 图谱规划 → 多路召回 → 合并），
    返回结构化的文档列表和格式化的参考材料文本，不调用 LLM 生成回答。

    适用于三方系统需要获取检索材料后自行处理的场景。
    qa_search_request)rG   rH   rJ   rK   NrL   rM   )rQ   c                &    g | ]}t          d i |S ) )r   ).0docs     r1   
<listcomp>zqa_search.<locals>.<listcomp>   s'    HHHS!((C((HHHr`   	documentskeywordsintentcontext_textgraph_evidence_textguide_evidence_text)rY   rj   rk   totalri   rl   rm   rn   )rV   rW   rG   rX   rY   rQ   r   rZ   r   r   r    r   	qa_searchr   )r6   r7   r9   r;   r=   r?   rA   rC   r[   r\   r]   r^   rP   r_   resultri   s                   r1   rp   rp   r   s     ( KK''4,233	     %,???L%%d++++++++D$%566M!,//I0!!  M '#  F ##& $        F IHF;4GHHHI
#h)nnN+"#89"#89	 	 	 	r`   )r%   r&   r'   r(   )r6   r   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   r'   r   )r6   r   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   r'   r   );__doc__
__future__r   r,   typingr   r   fastapir   r   fastapi.responsesr   app.api.depsr	   r
   r   r   r   r   r   r   app.api.schemas.qar   r   r   r   app.api.schemas.researchr   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__rV   routerr2   postr"   rp   re   r`   r1   <module>r      s    # " " " " "  + + + + + + + + & & & & & & & & / / / / / /	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ^ ] ] ] ] ] ] ] ] ] ] ] 2 2 2 2 2 2 / / / / / / : : : : : : 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			%tf	-	-	-% % % % 'M   
3 3 3 
3l >#   
8 8 8 
8 8 8r`   