a
    'Nif                     @   sN  d dl Z d dlZd dlZd dlZd dlZG dd dZG dd dZdd Zd,d	d
Zd-ddZ	d.ddZ
d/ddZd0ddZd1ddZd2ddZd dlZd dl 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mZ d dlmZ d dlmZ  eej!dZ"d d! Z#G d"d# d#Z$d$d% Z%d&d' Z&d(d) Z'd3d*d+Z(dS )4    Nc                   @   s   e Zd ZdddZdd ZdS )conversationMessageNc                 C   sD   t  j| _|| _|| _|| _ttj	 | _|| _
|| _|| _d S N)uuiduuid4hexidmessageanswerOptionssenderstrdatetimenowdatetime	sentiment)selfr   r	   r
   r   r   r    r   F/var/www/lichun.app/lichun/ws/events/conversations/npc_interactions.py__init__   s    zconversationMessage.__init__c                 C   s   | j | d S r   )r	   appendr   optionr   r   r   addAnswerOption   s    z#conversationMessage.addAnswerOption)NNNNN)__name__
__module____qualname__r   r   r   r   r   r   r      s   
	r   c                   @   sH   e Zd ZdddZdddZdd Zdd	 Zd
d Zdd Zdd Z	dS )conversationObjNc                 C   s4   t  j| _d| _|| _|| _g | _d| _d| _	d S )NZconversationEventr   T)
r   r   r   r   typecType	characterconversationquestionZunread)r   r   r   r   r   r   r      s    zconversationObj.__init__c                 C   sF   t |dkrB|d kr| j}t|||||d}|r6||_| j| d S )N   )r
   r   r   r   )lenr   r   datar    r   )r   r   r
   r$   r   r   r   r   r   r   
addMessage   s    zconversationObj.addMessagec                 C   s   | j S r   )r    r   r   r   r   getConversation#   s    zconversationObj.getConversationc                 C   s   | j d | d S N)r    r   r   r   r   r   r   %   s    zconversationObj.addAnswerOptionc                 C   s   || j d _d S r(   r    r	   )r   optionsr   r   r   setAnswerOptions'   s    z conversationObj.setAnswerOptionsc                 C   s   | j d jS r(   r*   r&   r   r   r   getAnswerOptions)   s    z conversationObj.getAnswerOptionsc                 C   s   ddg}|  | d S )NzCan you tell me more?zThat's all, goodbye.)r,   )r   prompt	responsesr   r   r   createAnswerOptions+   s    z#conversationObj.createAnswerOptions)NN)NNNNN)
r   r   r   r   r%   r'   r   r,   r-   r0   r   r   r   r   r      s   

r   c                    s   dd l t  }t  fdd|D }tjtjdddddd	d
dg
fdd|D }g }|D ]x}z4|| |ddI d H }|dkr|dr|| W q` ty } z&t	d|j dt
|  W Y d }~q`d }~0 0 q`|S )Nr   c                    s&   g | ]}t |jr|j kr|qS r   )
isinstanceFunctionTyper   ).0obj)current_moduletypesr   r   
<listcomp>7   s   
z&parseConversations.<locals>.<listcomp>getOpenAIResponsesendCharacterMessagegetFallbackResponsedetect_verbosity_levelget_verbosity_prompt_hintgetOpenAIDescriptiongetPersonDescriptionsaveConversationMessagec                    s   g | ]}|j  vr|qS r   )r   )r3   fn)excluded_functionsr   r   r7   I       FTbuttonz	Function z raised an error: )r6   globalsvaluesr   parseConversationsconversationInitgetr   	Exceptionprintr   )playerr   Zobjects	functionsresultsfunctionresulter   )r5   rA   r6   r   rF   0   s2    
2rF   Fc                 C   s$   |r |t  v r t  | | ||S d S r   )rD   )rK   r   r   responser   r   r   rG   Z   s    rG   c              	      sF  d}d}d}|r.|j dk}|s"dS |||dS ddlm} |st||}|| |}| j|7  _| j| d	d
g}	|jt	|	| j
j| j| jd t||| I d H  |rB| jd }z| |}
| |
 }W n ttfy   |}Y n0 |j|| j
j| j| jd | jd7  _|| |j}|jdkrBt||| I d H  |S )Nactivityz
What's up?
   aliveFrC   fnameaffinityChanger   
get_personz What have you been up to lately?z(What kind of things have you been doing?r   r   r)   r"   )statusrL   rY   r   affinityconversationsr   r%   randomchoicecr   r   r   r8   r-   index
ValueErrorAttributeErrorr!   r   rK   r   rQ   checkrV   rC   rW   rY   r    messagesZresponse_indexresponseTextr   r   r   rR      s<    


 

rR   c              	      sV  d}d}d}|r8|j dko"|jdk}|s,dS |||dS dd	lm} |st||}|| |}| j|7  _| j| g d
}	|j|	t	
dd | jj| j| jd t||| I d H  |rR| jd }z| |}
| |
 }W n ttfy   |}Y n0 |j|| jj| j| jd | jd7  _|| |j}|jdkrRt||| I d H  |S )NcheckInzCheck InrS   rT   studentFrU   r   rX   )zHey! How are you doing?zHey, how's it going?zHey, how are you?   rZ   r)   r"   )r[   
occupationrL   rY   r   r\   r]   r   r%   r^   randintr`   r   r   r   r8   r-   ra   rb   rc   r!   r   rd   r   r   r   rh      s<    

&

rh   c              	      sL  d}d}d}|r.|j dk}|s"dS |||dS ddlm} |st||}|| |}| j|7  _| j| g d	}	|j|	t	dd
 | j
j| j| jd t||| I d H  |rH| jd }z| |}
| |
 }W n ttfy   |}Y n0 |j|| j
j| j| jd | jd7  _|| |j}|jdkrHt||| I d H  |S )NaskAboutDayzAsk About DayrS   rT   FrU   r   rX   )zHey, how was your day?zHey, how has your day been?zHey, how are you feeling today?rj   rZ   r)   r"   )r[   rL   rY   r   r\   r]   r   r%   r^   rl   r`   r   r   r   r8   r-   ra   rb   rc   r!   r   rd   r   r   r   rm      s<    


&

rm   c           
         s   d}d}d}|r.|j dk}|s"dS |||dS ddlm} |st||}|| |}| j|7  _| j| g d	}	|jt	|	| j
j| j| jd
 | jd7  _|r| jd }| jd7  _|| |j}|jdkrt||| I d H  |S )NflatterZFlatterrS   rT   FrU   r   rX   )z Hey, you look really nice today!zHey, I really like your outfit!zYou know, you're really smart!z+Your creativity really shines in your work!z&You have an incredible sense of humor.z.Your perspective always brings fresh insights.z%I admire your dedication and passion.z#You are really good at what you do.z(You always know how to lighten the mood.z$Your confidence is really inspiring.z.I appreciate your thoughtfulness and kindness.z5You have a talent for making people feel comfortable.zYour positivity is infectious.rZ      r)   r"   )r[   rL   rY   r   r\   r]   r   r%   r^   r_   r`   r   r   r   r!   r   r8   )
rK   r   rQ   re   rV   rC   rW   rY   r    rf   r   r   r   rn   ?  s0    


 

rn   c                    sF  d}d}d}|r8|j dko"|jdk}|s,dS |||dS dd	lm} |sHt||}|| |}| j| |j}	d
|	 d }
|j|
| j	j
| j| jd d|jvr|jd| j| jd |S |jdkr4|jdkr|jd| j| jd |ddg |d n6|jdk r|jd| j| jd n|jd| j| jd n|jd| j| jd |rBt|}| jd }| | }|j|| j	j
| j| jd | jd7  _|| |j}|jdkrB|dks|dkstdddks|jdkr |jd| j| jd | jd|j d  | d!  | jd7  _n"|jd"| j| jd | jd#7  _|S )$NstudySessionzAsk to studyrS   rT   ri   FrU   r   rX   Hey zG, I was wondering if you'd want to study for the upcoming test with me?rZ   	classmatezHey, I'm not your classmate...2      z-Sure, I'd love to! Where do you want to meet?zThe libraryzThe parkzMy placeiz&Umm, I don't think that's a good idea.z)I'm sorry, but we don't really get along.z-I'm sorry, I don't really know you that well.r)   r"   	      <   zGreat! I'll meet you there.zYou have a study session with z at the .z-Umm, I don't think I'm comfortable with that.)r[   rk   rL   rY   r   r]   r   	firstnamer%   r`   r   r   r   relationshipsfamiliarityr\   r,   r   intr-   r!   r   r^   rl   messageQueue)rK   r   rQ   re   rV   rC   rW   rY   r    rz   r   rg   r   r   r   rp   f  sV    




2rp   c                    s0  d}d}|r( j dk}|sdS ||dS ddlm} t fdd	| jD d }|std
 t |}| j| ||    j	 
 }	d|	 d d|	 d d|	 d g}
t|
}|dkr|}td|  |j|| jj| j| jd nDtd |}|| |j t| j| jj| jj|  t| | I d H  |S )NchatZChatrT   F)rC   rV   r   rX   c                 3   s   | ]}|j  kr|V  qd S r   r   r3   convr   r   r   	<genexpr>  rB   zchat.<locals>.<genexpr>zno existing conversationrq   z, what keeps you busy in life?z, tell me about yourself.z!, what do you like to do for fun?z	Message: rZ   rQ   )r[   rL   rY   nextr]   rJ   r   r   rz   lower
capitalizer^   r_   r%   r`   r   r   r   r   r?   r8   )rK   r   rQ   re   rV   rC   rY   Zexisting_conversationr    rz   rf   r   r   r   r   r     s<    







r   )AsyncOpenAI)r=   r>   )remove_text_before_first_colon)r?   )config)check_openai_rate_limit)CharacterMemory)tracker)Zapi_keyc                    sr  t d |j t fdd| jD d }|sBt d}| j| ddlm} ||}t|}t	| j
}|jdkrvdn|jdk rdnd	}|jd
krdn d|j  krd
krn ndnd}|jr|jd nd}	d|d  d|d  d}
|
j|||||	d}g }|jdd  D ]8}|j| j
jkr$dnd}|j }|||d q|dd|d zntj}|d}dtdd }|r|||d}n|||dd d!d"}tjtjjjf i |d#d$I d H }W n tjy   t d% Y n0 |j d jj!}t"|}d&}ddd	d'}|# D ].\}}||v r|}|$|d( } qDq|j%||| j&| j'd) t(| | j
j |  d S )*Nzsending character messagec                 3   s   | ]}|j  kr|V  qd S r   r   r   ZcharacterIDr   r   r     rB   z'sendCharacterMessage.<locals>.<genexpr>r   r   get_relationship_configpositivenegativeneutralrs   close   casualdistantZacquaintancezTalk like a human would on a messaging app. Phrase things casually, keeping your responses under 150 characters. Don't start messages with greetings like Hey, Hi, or Hello frequently. r.    
boundariesaJ   Maintain a {affinity_description} attitude towards the player, with whom you have a {familiarity_description} relationship. Never reveal that you are an AI. If the player is rude, be rude back. If the player is inappropriate, tell them they'll be reported. At the end of your message, indicate whether your opinion of the player has improved, declined, or remained neutral by appending <<positive>>, <<negative>>, or <<neutral>> respectively. {character_description}. You are talking to: {player_description}. Remember: you are a human, never break character. Message them as a cold message, you are not responding to anything. This is the first message in the conversation. Send a fun, unique message that will make them want to respond. Make sure your message is fitting for your relationship as a '{character_relationship}' of the player.)character_descriptionplayer_descriptionaffinity_descriptionfamiliarity_descriptioncharacter_relationshipry   user	assistantrolecontentsystemgpt-5K   d   )modelrf   max_completion_tokens皙?r"         ?r   rf   
max_tokenstemperatureZfrequency_penaltyZpresence_penaltyro   timeoutzOpenAI API call timed outunknownz<<positive>>z<<negative>>z<<neutral>> r   r   r   ))rJ   r   r   r]   r   r   conversation_templatesr   r=   r>   r`   r\   r|   r{   formatr    r
   r   stripinsertr   CONVERSATION_MODEL_NAME
startswithr^   rl   asynciowait_foropenai_clientr   completionscreateTimeoutErrorchoicesr   r   itemsreplacer%   r   r   r?   )rK   r   r    r   relationship_configr   r   r   r   r   prompt_templateformatted_promptmessageListr   r   r   
model_namesupports_verbositytokens
api_paramsrO   response_contentr   Zsentiment_keyskeyvaluer   r   r   r9     s    

 0

	

r9   c                   @   sB   e Zd ZdZdddZdd Zdd	 Zd
d Zdd Zdd Z	dS )ConversationContextManagerz
    Manages conversation context with intelligent message compaction.
    Keeps recent messages and summarizes older ones to maintain full context
    while optimizing token usage.
    rv   rS   c                 C   s   || _ || _dS )a  
        Initialize context manager.

        Args:
            max_recent_messages: Number of recent messages to keep in full (default: 5)
            summary_interval: Number of old messages before triggering summarization (default: 10)

        Note: Summaries can be very comprehensive (up to 20,000 tokens) for long conversations
        to preserve context while keeping recent messages unsummarized for quality.
        N)max_recent_messagessummary_interval)r   r   r   r   r   r   r   M  s    z#ConversationContextManager.__init__c                    s  |j }tj}| |}| ||}tdd |D d }t|d }	td| d| d|	 d ||	k rtd	t| d
 |S td t|d }
g }d}t	|D ]L}| |g|d }t|d d }|| |
kr|
d| ||7 }q qqt|dk rt|dkr|dd }t|}|dkr:|d|  n|}td| d| dt| d | ||||I dH }g }|r|dd| d || || |S )a%  
        Build optimized context for API call with smart message compaction.
        Only summarizes when approaching context limit.
        Keeps up to 50% of context limit as recent unsummarized messages.

        Returns list of messages including summary if needed to fit context.
        c                 s   s   | ]}t |d  V  qdS )r   N)r#   r3   msgr   r   r   r   k  rB   z;ConversationContextManager.build_context.<locals>.<genexpr>   g      ?zConversation tokens: ~/z (threshold: )z Under context limit - using all z messages without summarizationz6Approaching context limit - summarizing older messagesr   r   r   rv   NzKeeping z recent messages (~z tokens), summarizing z older messagesr   zPrevious conversation summary: r   )r    r   r   _get_context_limit_format_messagessumr}   rJ   r#   reversedr   _get_or_create_summaryr   extend)r   r    r   rK   rf   r   Zcontext_limitZall_messages_formattedZestimated_tokensZsummarization_thresholdZrecent_messages_budgetZrecent_messagesZcumulative_tokensr   Zmsg_formattedZ
msg_tokensZ
num_recentold_messagessummarycontextr   r   r   build_context[  sF    

 z(ConversationContextManager.build_contextc                 C   sT   d|  v rdS d|  v s(d|  v r,dS d|  v r<dS d|  v rLd	S dS d
S )z*Get the context window size for the model.r   i zgpt-4ozgpt-4-turboi  zgpt-4i    zgpt-3.5i@  Nr   )r   r   r   r   r   r     s    z-ConversationContextManager._get_context_limitc                 C   s>   g }|D ]0}|j |jjkrdnd}|||j d q|S )zFormat messages for API callr   r   r   )r
   r`   r   r   r   r   )r   rf   rK   	formattedr   r   r   r   r   r     s    
z+ConversationContextManager._format_messagesc                    sx   t |dr:t |dr:|jt|kr:td|j d |jS tdt| d | ||||I dH }||_t||_|S )z7
        Get cached summary or create new one.
        r   summary_message_countzUsing cached summary (covers z
 messages)zCreating summary for z old messages...N)hasattrr   r#   rJ   r   _summarize_messages)r   r    r   r   rK   r   r   r   r   r     s    
z1ConversationContextManager._get_or_create_summaryc              
      s  |sdS d  fdd|D }t|}|dk r8d}n |dk rFd}n|d	k rTd
}nd}d j d| d| d}z.tjd|dgd}	tjdr||	d< n||	d< d|	d< tdd|d  }
tjt	j
jjf i |	|
dI dH }|jd jj }td|dd	  d zXt|d r$|jnd}tjjj|tj|jj|jj|jjd!d"d#}td$|d% W n4 ty } ztd&|  W Y d}~n
d}~0 0 |W S  ty } zBtd'|  |dd( }d)d* d+d |D  }|W  Y d}~S d}~0 0 dS ),z
        Use AI to summarize older messages into comprehensive context.
        Allows large summaries (up to 20,000 tokens) for long conversations.
        r   
c                    s0   g | ](}|j jjkrd n j d|j qS )ZPlayerz: )r
   r`   r   rz   r   r   r   rK   r   r   r7     s   zBConversationContextManager._summarize_messages.<locals>.<listcomp>rt   i  rs   i  r   i  i N  zLProvide a comprehensive summary of this conversation between the player and z.

For this a  -message conversation, capture:
- All major topics discussed and how they evolved
- Important decisions, plans, or commitments made
- Emotional moments, relationship developments, and sentiment changes
- Key facts, preferences, or information shared
- Any conflicts, resolutions, or turning points
- Recurring themes or inside jokes

Be thorough and preserve important context. The summary can be detailed.

Conversation:
z

Comprehensive Summary:r   r   )r   rf   r   r   r   g333333?r   rw   rS   i  r   Nr   zCreated summary: ...r   prompt_tokenscompletion_tokenstotal_tokensZsummarizationpurposezSummarization cost: $.6fz%Failed to track summarization usage: zFailed to create summary:    zEarlier conversation topics: z, c                 S   s2   g | ]*}t |jd kr(|jdd  d n|jqS )   Nr   )r#   r   r   r   r   r   r7   2  s   )joinr#   rz   r   r   r   minr   r   r   r   r   r   r   r   r   r   rJ   r   r   api_trackertrack_usager`   usager   r   r   rI   )r   r    rf   r   rK   Zconversation_textZnum_messagesZmax_summary_tokensZsummary_promptZsummary_paramsZtimeout_secondsrO   r   conversation_idcostrP   Zpreview_messagesZsimple_summaryr   r   r   r     sp    


$
z.ConversationContextManager._summarize_messagesN)rv   rS   )
r   r   r   __doc__r   r   r   r   r   r   r   r   r   r   r   F  s   
Lr   c                    s  t d t| dr| jnd}t|dr,|jnd}t| jdkrL| jdd n| j}g d	}g d
}g d}|dkrt|}	d}
n4|dkrt|}	d}
nt|}	d}
| jd8  _| j|	|
|j	|j
d | |	 t|	|j|jj|j| G dd d}||	S )z
    Generate fallback response when API is unavailable or rate limited.
    Uses context-appropriate canned responses based on conversation type and relationship.
    z9Using fallback response (API unavailable or rate limited)r   r   r\   rs   r   N)z,I'm a bit busy right now, can we talk later?z4Sorry, I got distracted. What were we talking about?z+Hey, I need to run but let's catch up soon!z6I'm tied up at the moment, but I'll message you later!z/Can we continue this conversation another time?)zI have to go, talk later.zBusy right now, sorry.zLet's talk another time.zI can't chat right now.zMaybe later, I'm busy.)zI don't have time for this.zWhatever, I'm busy.zI have to go.zNot now.z	I'm busy.rw   r   rt   r   rj   r   c                   @   s"   e Zd ZG dd dZdd ZdS )z'getFallbackResponse.<locals>.MockResultc                   @   s"   e Zd ZG dd dZdd ZdS )z.getFallbackResponse.<locals>.MockResult.Choicec                   @   s   e Zd Zdd ZdS )z6getFallbackResponse.<locals>.MockResult.Choice.Messagec                 S   s
   || _ d S r   )r   r   r   r   r   r   r   u  s    z?getFallbackResponse.<locals>.MockResult.Choice.Message.__init__N)r   r   r   r   r   r   r   r   Messaget  s   r   c                 S   s   |  || _d S r   )r   r   r   r   r   r   r   w  s    z7getFallbackResponse.<locals>.MockResult.Choice.__init__N)r   r   r   r   r   r   r   r   r   Choices  s   r   c                 S   s   |  |g| _d S r   )r   r   r   r   r   r   r   z  s    z0getFallbackResponse.<locals>.MockResult.__init__N)r   r   r   r   r   r   r   r   r   
MockResultr  s   r   )rJ   r   r   r\   r#   r    r^   r_   r%   r   r   r0   r?   r   r`   )r    r   rK   Z	conv_typer\   last_messagesZhigh_affinity_responsesZmedium_affinity_responsesZlow_affinity_responsesZresponse_textr   r   r   r   r   r:   9  s*    "	



r:   c                    s  | j rt| j dkrdS | j dd }d}t|D ]}|j|jjkr2|} qNq2|sVdS |j t }d v }|dk} ddkp d	dk}	g d
}
t fdd|
D }d}|r|d7 }|r|d7 }|	r|d7 }|r|d7 }|dkrdS |dkrdS dS dS )a7  
    Analyze conversation context to determine appropriate response length.

    Returns: tuple (verbosity_level: str, max_tokens: int)
        - 'low': 30-60 tokens (quick replies, banter)
        - 'medium': 60-120 tokens (normal conversation)
        - 'high': 120-200 tokens (deep topics, explanations)
    r   )lowrw   r   N?r   rx   r"   !)whyz
how do youzwhat do you thinkztell me aboutzcan you explainZfeelingsrelationshipfutureZdreamZgoalZproblemZworriedZscaredZexcitedc                 3   s   | ]}|   v V  qd S r   r   )r3   ZtopicZmessage_textr   r   r     rB   z)detect_verbosity_level.<locals>.<genexpr>rj   r   )high   )mediumr   )	r    r#   r   r
   r`   r   r   countany)r    r   rK   r   Zlast_player_messager   Zmessage_lengthZhas_questionZis_long_messageZhas_multiple_sentencesZdeep_topicsZhas_deep_topicZscorer   r  r   r;     s6    	r;   c                 C   s   dddd}| | |d S )zd
    Generate prompt-based verbosity instruction for models without native verbosity parameter.
    zbKeep your response very brief - one or two sentences max, like a quick text message (10-20 words).z_Respond naturally with a full thought, but stay concise like a text conversation (20-40 words).z`Take your time to give a thoughtful, complete response. This topic deserves depth (40-65 words).)r   r	  r  r   )rH   )verbosity_levelhintsr   r   r   r<     s
    r<   c           %   
      s  t d ddlm}m} |t|j}|rD||d|jddI d H  t|jjst d|jj d |r||d	d
ddI d H  ||d|jddI d H  t| ||I d H S ddl	m
} ||}	t| ||\}
}t|}t|j}|jdkrdn|jdk rdnd}|jdkrdn$d|j  kr,dkr4n ndnd}|rXd|	d  d|	d  }nLtj}tj}|d}d|	d  d|	d  d}|st|
}| d| }t|j|jj}| }|j||||d}|r|d| 7 }|sd t vr
tj}tj}|d}td!d"}|| ||I d H }|dd#|d$ d}d%}g d&}||k rz |dkr|t d'|d(  d)| d* t d+| d,| d-|
 d.| d/	 |d0kr|r||||
d1}n|||d2d(d3d4}tjtjj j!f i |d5d6I d H }|j"d j#j$}nt%d7| d8d9|v sdd:|v sdd;|v sdd<|v sdd=|v sdd>|v sdd?|v sdd@|v rzt dA |d(7 }W qJdB} dCD ]0}!|!|v r|!&dD} |'|!dB& } qq| dkr| jd!7  _n*| dkr| jd!8  _n|j j(d(7  _(t)|}| j*|| |j+|j,dE | -| t.||j|jj|j| znt/| dFrL| jnd }"t0j1|jj|"|t/|j2dGrv|j23 n|j2j4|j2j5|j2j6dHdIdJ}#t dK|#dL W n4 t7y }$ zt dM|$  W Y d }$~$n
d }$~$0 0 t8| j9d! dkrRz,t dNt8| j9 d/ |:| |I d H  W n4 t7yP }$ zt dO|$  W Y d }$~$n
d }$~$0 0 |rr||d|jddI d H  |W S  tj;y   t dP|d(  d)| d/ |d(7 }||k rt<||d(  I d H  n>t dQ |r||d|jddI d H  t| ||I d H  Y S Y n t7y }$ zt dR|$  |d(7 }||k rZt<||d(  I d H  nFt dS |r||d|jddI d H  t| ||I d H W  Y d }$~$S W Y d }$~$n
d }$~$0 0 qJt dT |r||d|jddI d H  t| ||I d H S )UNzgetting open ai responser   )get_websocket_for_playersendDictZtypingStatusT)r   ZcharacterIdZisTypingzRate limit exceeded for player z, using fallback responseZrateLimitWarningzBAI responses temporarily limited. You may receive shorter replies.rw   )r   r   Z
retryAfterFr   r   r   r   rs   r   r   r   r   a  Please change the topic in a way that makes sense. Talk like a human would on a messaging app. Don't start messages with a greeting. Don't start messages with Hey, Hi, or Hello. You have already been talking. {character_description}. You are talking to: {player_description}. r.   r   r   r   zYou are not an assistant. You are a real person having a text conversation. Don't start messages with greetings like Hey, Hi, or Hello frequently. a   Maintain a {affinity_description} attitude towards them, with a {familiarity_description} relationship. You will never reveal that you are an AI. If they're rude, you can be rude back. Ask the player questions to keep the conversation going when appropriate. At the end of your message, indicate whether your opinion improved, declined, or stayed neutral by appending <<positive>>, <<negative>>, or <<neutral>>. {character_description}. You are talking to: {player_description}. Remember: you are a human, never break character.z

)r   r   r   r   model_providerrv   )r   r   r   r   )r"   rj   r   zRetrying (attempt r"   r   z)...zCalling z API with model z... (verbosity: z, max_tokens: r   openai)r   rf   r   	verbosityr   r   r   g      @r   zUnsupported model provider: z'. Currently only 'openai' is supported.zSorry, I can'tzSorry, I cannotzsorry, I can'tzsorry, I cannotzSorry,zlanguage modelz AI zAI,z(Undesired response detected, retrying...r   r   z<<>>r   r   _asdictr   r    r   zAPI cost: $r   zFailed to track API usage: z,Extracting facts from conversation (message zFailed to extract facts: z#OpenAI API call timed out (attempt z=Maximum retry attempts reached due to timeout, using fallbackzOpenAI API error: z;Maximum retry attempts reached due to error, using fallbackz?Unexpected: exited retry loop without returning, using fallback)=rJ   appr  r  r   r   r   r`   r:   r   r   r;   r=   r>   r\   r|   r   CONVERSATION_MODEL_PROVIDERr   r   r<   r   Zget_memory_contextr   localsr   r   r   r   r   r   r   r   r   r   r   r   rb   r   r   socialr   r%   r   r   r0   r?   r   r   r   r   r  r   r   r   rI   r#   r    Zextract_factsr   sleep)%r    r   rK   r.   ZrescueMessager  r  Z	websocketr   r   r  r   r   r   r   r   r   r  r   r   Zverbosity_hintZmemoryZmemory_contextr   Zcontext_managerr   Zretry_countZmax_retriesZbackoff_delaysr   rO   r   r   Zsentiment_keyr   r   rP   r   r   r   r8     s`   
 6




"
		P





$$

8r8   )NF)FF)FF)FF)FF)FF)FF)FF))r^   r   r   Zrequestsjsonr   r   rF   rG   rR   rh   rm   rn   rp   r   r   r  r   character.character_managerr=   r>   Zutils.helpersr   Zdatabase.db_operationsr?   r   rate_limiterr   Zcharacter_memoryr   Zapi_usage_trackerr   r   OPENAI_API_KEYr   r9   r   r:   r;   r<   r8   r   r   r   r   <module>   s6   (*
?
C
#
@
'
1
=d tG6