
    P1i`                     
   d Z ddl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mZmZmZ ddlmZ  ej4                  e      Z	 d%dedeeeef      dedee   def
dZ	 	 d&dedee   dedee   def
dZ 	 d'dededdfdZ!	 d'dedeeeef      dedee   def
dZ"	 	 	 	 d(dededee   dee   dee   dee   defdZ#	 d%deded ee   defd!Z$	 d%d"ed ee   defd#Z%	 d%d ee   defd$Z&y))z`
Utility functions for handling AI conversations about divination records (BaZi, LiuYao, etc.).
    N)DictAnyOptionalList)timezone)settings)LLMServiceFactory)get_ai_config)prepare_bazi_prompt)prepare_liuyao_prompt)ConversationMessageConversationSubjectConversationConfig)Persondivination_promptconversation_historycurrent_messagecontext_summaryreturnc                    t        | j                  d            }|rt        |j                  d            nd}t        d |D              }t        |j                  d            }t        |      dz  }|rdnd}	||z   |z   |z   |z   |	z   }
|
S )ap  
    Calculate the total context size in characters.
    
    Args:
        divination_prompt: Full divination prompt (BaZi, LiuYao, etc.)
        conversation_history: List of previous messages
        current_message: Current user message
        context_summary: Optional summary of older messages
        
    Returns:
        Total size in characters (bytes)
    utf-8r   c              3   p   K   | ].  }t        |j                  d d      j                  d             0 yw)content r   N)lengetencode.0msgs     7/home/cursorai/projects/iching/ai/utils/conversation.py	<genexpr>z)calculate_context_size.<locals>.<genexpr>+   s3      'C 	CGGIr"))'23's   462   d   )r   r   sum)r   r   r   r   prompt_sizesummary_sizehistory_sizemessage_sizeformatting_overheadsummary_overhead
total_sizes              r"   calculate_context_sizer.      s    & '..w78K <K3--g67PQL  ' L --g67L 23b8 .s1|+l:\IL__brrJ    conversationmessages_to_summarizelanguageexisting_summaryc                    |s|xs dS | j                         }|s)t        j                  d| j                   d       |xs dS | j                  j
                  dk(  rt        ||      }|dk(  rdnd}nb| j                  j
                  d	k(  rt        ||      }|dk(  rd
nd}n2t        j                  d| j                  j
                          |xs dS d}|D ]*  }|j                  dk(  rdnd}	||	 d|j                   dz  }, |dk(  r+|rd| d| d|dd  d| d| d}
n=d| d| d|dd  d| d	}
n*|rd| d| d|dd  d| d | d!}
nd| d| d|dd  d"| d#	}
| j                  j
                   d$}t        |      }|d%   }|d&   }t        j                  |      }|r|j                  |       |j                  |
d'd()      }|r|j                         S |xs dS )*a  
    Generate a summary of conversation messages using AI.
    Uses incremental summarization: combines existing summary with new messages.
    
    Args:
        conversation: Conversation object
        messages_to_summarize: List of Message objects to summarize (new messages since last summarization)
        language: Language for summary ('zh-hans' or 'en')
        existing_summary: Optional existing summary to combine with new summary
        
    Returns:
        Combined summary text
    r   Conversation  has no valid subject objectbazir2   enzBaZi (Four Pillars of Destiny)u   八字（四柱命理）liuyaozLiuYao (Six Lines Divination)u   六爻Unsupported content type: userUser	Assistant: 

z+You are summarizing a conversation about a z	 chart.

z Chart Context:
Ni  z<... (truncated for summary)

Previous Conversation Summary:
z/

New Conversation Messages to Add to Summary:
a  

Please provide a concise summary that:
1. Combines the previous summary with the new messages
2. Preserves key questions asked by the user (from both old and new messages)
3. Preserves important insights and analysis provided (from both old and new messages)
4. Maintains context about specific BaZi elements discussed
5. Is concise but comprehensive (aim for 1000-2000 words total)
6. Integrates the new information naturally with the existing summary

Updated Summary:z@... (truncated for summary)

Conversation History to Summarize:
a   

Please provide a concise summary of this conversation that:
1. Preserves key questions asked by the user
2. Preserves important insights and analysis provided
3. Maintains context about specific BaZi elements discussed
4. Is concise but comprehensive (aim for 1000-2000 words)

Summary:u   你正在总结一段关于u   命盘的对话。

u   命盘上下文：
u6   ...（为摘要而截断）

之前的对话摘要：
u-   

需要添加到摘要的新对话消息：
u  

请提供一段简洁的摘要，要求：
1. 将之前的摘要与新消息结合起来
2. 保留用户提出的关键问题（包括旧消息和新消息中的）
3. 保留提供的重要见解和分析（包括旧消息和新消息中的）
4. 保持讨论的具体八字元素的上下文
5. 简洁但全面（目标1000-2000字）
6. 自然地将新信息与现有摘要整合

更新的摘要：u<   ...（为摘要而截断）

需要总结的对话历史：
u   

请提供这段对话的简洁摘要，要求：
1. 保留用户提出的关键问题
2. 保留提供的重要见解和分析
3. 保持讨论的具体八字元素的上下文
4. 简洁但全面（目标1000-2000字）

摘要：_conversationprovidermodelg333333?i  prompttemperature
max_tokens)get_subject_objectloggererroridsubjectcontent_typer   r   roler   r
   r	   get_servicechange_modelget_completionstrip)r0   r1   r2   r3   subject_objr   divination_type_nameconversation_textr!   
role_labelsummary_promptconversation_config_typeconfigrB   rC   llm_servicesummarys                    r"   generate_conversation_summaryr\   ?   s   & !%2% 113K}\__$55QRS%2%((F2/hOCKtCS?Ys				*	*h	61+QBJdBR>X`1,2F2F2S2S1TUV%2% $"xx61V{

|2ckk]$?? %
 4!LMaLb c  5D        
N* "MMaLb c  5D     	N  !<=Q<R S  5D        
N* "==Q<R S  5D     
N" #/"6"6"C"C!DMR34Fj!H7OE $//9K  ' (( ) G &7==?C,<,BCr/   c           	         t        | j                  j                  d            }t        j                         }t        |      |k  ry| j                  s$t        j                  d| j                   d       y| j                         }|s$t        j                  d| j                   d       y| j                  j                  dk(  rt        ||      }nT| j                  j                  dk(  rt        ||      }n-t        j                  d	| j                  j                          y|| d }|D cg c]  }|j                  |j                  d
 }}|rt!        d |D              t        |      z  nd}	t#        ||dt%        |	      z  | j&                        }
t)        t*        dd      }|
|kD  rg }| j,                  xs d}|D ](  }|j                  |kD  s||vs|j/                  |       * |r	 t1        | ||| j&                        }|| _        t3        j4                         | _        |r|d   j                  nd| _        | j9                  g d       t        j;                  d| j                   dt        |       d       yyyc c}w # t<        $ r8}t        j                  d| j                   dt?        |              Y d}~yd}~ww xY w)z
    Check context size and generate summary if needed.
    Called before sending each new message.
    
    Args:
        conversation: Conversation object
        language: Language for summary generation
    
created_atNr5   z has no subjectr6   r7   r8   r:   r;   rN   r   c              3   F   K   | ]  }t        |j                          y wN)r   r   r   s     r"   r#   z.manage_conversation_context.<locals>.<genexpr>   s     D|3s{{+|s   !r    )r   r   r   r   CONVERSATION_CONTEXT_THRESHOLD順 )r0   r1   r2   r3   )r   context_summary_updated_atlast_summarized_message_idupdate_fieldsz7Generated incremental context summary for conversation z (summarized z new messages)z,Failed to generate summary for conversation r?   ) listmessagesorder_byr   get_max_messagesr   rL   rI   rJ   rK   rH   rM   r   r   rN   r   r&   r.   intr   getattrr   rg   appendr\   r   nowrf   saveinfo	Exceptionstr)r0   r2   all_messagesmax_messagesrS   r   last_messagesr!   recent_historyavg_message_sizecontext_size	thresholdr1   start_idnew_summaryes                   r"   manage_conversation_contextr      s    --66|DEL &668L
<L( }\__$5_EF113K}\__$55QRS((F2/hO				*	*h	61+Q1,2F2F2S2S1TUV !,0M ! C ckk2    ]isD|DDs<GXXno *++c"233$44	L "BFKI i !#::?aCvv S%=%,,S1   !i <!-*?%%1%A%A	 0;,:B,,.7Zo:OPR:S:V:Vuy7!! 1!  UVbVeVeUffstw  yN  uO  tP  P^  _  `3 !  )r  iKLOOK\\^_bcd_e^fghhis   3 J4BJ 	K.KKuser_messagec                    | j                         }|st        d| j                   d      | j                  j                  dk(  r@t        ||      }t        |d      r|j                  nd}|dk(  r
d| d	| d
}nd| d| d}n{| j                  j                  dk(  r@t        ||      }t        |d      r|j                  nd}|dk(  r
d| d| d}n,d| d| d}n"t        d| j                  j                         d}| j                  r&|dk(  rd| j                   d}nd| j                   d}d}	|rC|D ]>  }
|
j                  dd      }|
j                  dd      }|dk(  r
|	d| dz  }	6|	d | dz  }	@ | | d!|	 d| d"}|S )#a  
    Prepare a prompt for conversation with divination context and managed history.
    Supports BaZi, LiuYao, and other divination types via ConversationSubject.
    
    Args:
        conversation: Conversation object (for accessing summary and subject)
        conversation_history: List of recent messages (last N, configurable)
        user_message: The current user message
        language: Language for the response ('zh-hans' or 'en')
        
    Returns:
        Formatted prompt string
    r5   r6   r7   r8   nameUnknownr9   znYou are an expert in BaZi (Four Pillars of Destiny) analysis. You are having a conversation with a user about z-'s BaZi chart.

Full BaZi Chart Information:
z

Please provide helpful, accurate analysis and answer questions about this BaZi chart. Be conversational and engaging while maintaining accuracy. Reference specific pillars and elements when relevant.uQ   你是一位八字（四柱命理）分析专家。你正在与用户讨论关于u*   的八字命盘。

完整八字信息：
u   

请提供有帮助、准确的分析，并回答关于这个八字命盘的问题。保持对话性和吸引力，同时保持准确性。在相关时引用具体的柱和五行。r:   questionzYou are an expert in LiuYao (Six Lines Divination) analysis. You are having a conversation with a user about their LiuYao divination.

Question: z&

Full LiuYao Divination Information:
z

Please provide helpful, accurate analysis and answer questions about this LiuYao divination. Be conversational and engaging while maintaining accuracy. Reference specific hexagrams, lines, and elements when relevant.ub   你是一位六爻分析专家。你正在与用户讨论关于他们的六爻占卜。

问题：u   

完整六爻信息：
u   

请提供有帮助、准确的分析，并回答关于这个六爻占卜的问题。保持对话性和吸引力，同时保持准确性。在相关时引用具体的卦象、爻位和五行。r;   r   z!

Previous Conversation Summary:

u   

之前的对话摘要：
rN   r<   r   zUser: r@   zAssistant: z

Recent Conversation:
z

Assistant:)rH   
ValueErrorrK   rL   rM   r   hasattrr   r   r   r   r   )r0   r   r   r2   rS   r   subject_namesystem_promptcontext_sectionrU   r!   rN   r   full_prompts                 r"   prepare_conversation_promptr   6  sQ   ( 113K=(99UVWW ((F2/hO+2;+G{''Yt !O  P\  O] ]   HKM !rr~q @   uxM 
			*	*h	61+Q/6{J/O{++U^t!.    Y\M!

    ADM 5l6J6J6W6W5XYZZ O##t D\EaEaDbbdeO >|?[?[>\\^_O 'C7766*Dggi,Gv~!vgYd%;;!!{7)4%@@! ( #OO#44NO`Naaghtgu  vD  EKr/   rB   rC   existing_user_messagec           	         d}	 t        | |       |r;|}|j                  |k7  r||_        d|_        d|_        |j	                  g d       n#t
        j                  j                  | d|d      }|r|s6| j                  j                   d}t        |      }|xs |d	   }|xs |d
   }t        j                         }	| j                  j                  |j                        j!                  d      }
t#        |
      |	 d }|D cg c]  }|j$                  |j                  d }}	 t'        | |||      }tE        jF                  |      }|r|jI                  |       t*        jK                  d| j4                          |jM                  |dd      }|st3        d      t
        j                  j                  | d|jO                         ||d|i       }d!|_        |j	                  d"g       tQ        jR                         | _*        | j	                  d#g       t*        jK                  d$| j4                          |S c c}w # t(        $ r&}t*        j-                  dt/        |              | j1                         }|st3        d| j4                   d      | j                  j                  dk(  rt7        ||      }nI| j                  j                  dk(  rt9        ||      }n"t3        d| j                  j                         t;        t<        dd      }g }t?        |      D ]/  }|g|z   }tA        |||      }||k  r|jC                  d|       / n t'        | |||      }Y d}~:d}~ww xY w# t(        $ r{}|rRt/        |      }d%|_        ||_        |j	                  d"d&g       t*        jW                  d'|j4                   d(|        t*        jW                  d)t/        |               d}~ww xY w)*a  
    Send a user message and get AI response in a conversation.
    Includes context management.
    
    Args:
        conversation: Conversation object
        user_message: User message content
        provider: Optional AI provider override
        model: Optional AI model override
        language: Language for the conversation ('zh-hans' or 'en')
        existing_user_message: Optional existing Message object to reuse (for retries)
    
    Returns:
        Assistant Message object
    Nr8   pending)r   statuserror_messagerh   r<   )r0   rN   r   r   rA   rB   rC   )pkr^   r_   )r0   r   r   r2   zHFailed to prepare prompt with summary, falling back to limited history: r5   r6   r7   r:   r;   rc   rd   )r   r   r   r   z.Sending conversation message for conversation gffffff?i   rD   zEmpty response from LLM service	assistantr2   )r0   rN   r   rB   rC   metasentr   
updated_atz8Successfully created assistant message for conversation failedr   zMarked user message z as failed: z$Error sending conversation message: ),r   r   r   r   rr   r   objectscreaterL   rM   r
   r   rm   rk   excluder   rl   rj   rN   r   rt   rI   warningru   rH   r   rK   r   r   ro   r   reversedr.   insertr	   rO   rP   rs   rQ   rR   r   rq   r   rJ   )r0   r   rB   rC   r2   r   user_msgrX   rY   rw   rv   rx   r!   r   rE   r   rS   r   r|   limited_historytest_history	test_sizerZ   ai_responseassistant_msg	error_msgs                             r"   send_conversation_messager     s   . HD#L8D !,H</#/ 'HO%)H"MM(NMO --)$ 	 . H u*6*>*>*K*K)LM'Z$"#;<F56*#5H,VG_E *::<#,,444DMMl[\*L=>: % 
$ XX#++6$ 	  
*	0)%9)!	FX (33H=$$U+ 	D\__DUVW!00 1 
 >??  ..%%%'h' / 
 !XJ/ #+,,.7N|N_`am 
  #	NNefijkflemno&99;K =0AA]!^__##00F:$7h$W!%%22h>$9+PX$Y! #=l>R>R>_>_=`!abb*JFSI !O 45 #u62&7)5$0	
 	)#**1c2 6 1)%4)!	F=#	T  
AI&HO%.H"MM?(CMDLL/}LTU;CF8DE
sW   DM;  I'M; *I 9D	M; M; 
M8DM3-M; 3M88M; ;	O?A6O::O?rM   	object_idtitlec           
      v   t        j                  ||      }|j                         }|s9|dk(  r|rd|j                   }n"|dk(  r|rd|j                  dd  }nd| d| }t
        j                  j                  | ||      }t        j                  d|j                   d	| j                   d
| d|        |S )aQ  
    Create a new conversation thread.
    
    Args:
        user: User object
        content_type: Type of divination ('bazi' or 'liuyao')
        object_id: ID of the divination record (Person ID for BaZi, LiuYao ID for LiuYao)
        title: Optional title for the conversation
        
    Returns:
        Conversation object
    r7   zConversation about r:   Nr$   z #)r<   rL   r   zCreated conversation z
 for user z about )r   get_or_create_subject
get_objectr   r   r   r   r   rI   rs   rK   )r<   rM   r   r   rL   rS   r0   s          r"   create_conversationr   0  s    & "77iPG $$&K6!k)+*:*:);<EX%+)+*>*>s*C)DEE),r)EE''.. / L KK''8
477)7S_R``bclbmnor/   personc                 2    t        | d|j                  |      S )a   
    Create a new BaZi conversation thread (convenience function).
    
    Args:
        user: User object
        person: Person (BaZi chart) object
        title: Optional title for the conversation
        
    Returns:
        Conversation object
    r7   r   rK   )r<   r   r   s      r"   create_bazi_conversationr   Y  s      tVVYY>>r/   c                 2    t        | d|j                  |      S )z
    Create a new LiuYao conversation thread (convenience function).
    
    Args:
        user: User object
        liuyao: LiuYao object
        title: Optional title for the conversation
        
    Returns:
        Conversation object
    r:   r   )r<   r:   r   s      r"   create_liuyao_conversationr   l  s      tXvyy%@@r/   ra   )zh-hansN)r   )NNr   N)'__doc__loggingtypingr   r   r   r   django.utilsr   django.confr   ai.services.factoryr	   ai.utils.configr
   ai.utils.bazir   ai.utils.liuyao_analysisr   	ai.modelsr   r   r   r   bazi.modelsr   	getLogger__name__rI   ru   rn   r.   r\   r   r   r   r   r   r    r/   r"   <module>r      sL    , , !   1 ) - : T T 			8	$ &*	**tCH~.* * c]	*
 	*` &*	LDLD=LD LD sm	LD
 	LDb dididi 
diX (	XXtCH~.X X sm	X
 	X| #'/3\\\ sm\ C=	\
 sm\ $G,\ \F  	&& & C=	&
 &X  ?? C=? 	?,  A C=A 	Ar/   