
    P1i                        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 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mZmZmZ ddl m!Z!m"Z" ddl#m$Z$ d dl%m&Z& d dl'Z' G d dejP                        Z) ejT                  e       G d dejV                               Z, ejT                  e       G d dejV                               Z- G d dejP                        Z. ejT                  e       G d dejV                               Z/ ejT                  e       G d dejV                               Z0 G d dejP                        Z1 ejT                  e       G d  d!ejV                               Z2 G d" d#      Z3 G d$ d%e      Z4 G d& d'ejV                        Z5d d(l6m7Z7  G d) d*e7      Z8d d+l9m:Z:  G d, d-      Z;d. Z< e<       e;_=         G d/ d0e5      Z> e>e;ej~                        ej~                  j                  e;<    ejT                  e       G d1 d2ejV                               ZA ejT                  e       G d3 d4ejV                               ZBy)5    )admin)gettext_lazy)format_html)forms)pathreverse)JsonResponse)	mark_safe)
ChangeList)Q)timezone)TemplateResponse   )PromptTemplatePromptPlaceholderAIProviderConfigConversationConfigAdminAIAnalysisConversationMessage)validate_templateget_template_statistics)run_admin_llm_inference)PermissionDeniedNc                   $    e Zd ZdZ G d d      Zy)PromptTemplateAdminFormzV
    Form for the PromptTemplate admin with a custom widget for the content field
    c                   D    e Zd ZeZdZd ej                  ddd      iZy)PromptTemplateAdminForm.Meta__all__content   zfont-family: monospace;)rowsstyle)attrsN)	__name__
__module____qualname__r   modelfieldsr   Textareawidgets     */home/cursorai/projects/iching/ai/admin.pyMetar      s)    ~u~~RB[,\]
r-   r/   N)r%   r&   r'   __doc__r/   r,   r-   r.   r   r      s    
 
r-   r   c                   6    e Zd ZeZdZdZdZdZdgZ	dddif e
d	      d
ddf e
d      dddf e
d      dddffZdZd Z e
d      e_        d Z e
d      e_        d Z e
d      e_         fdZd Z e
d      e_         fdZd Z G d d      Z xZS )PromptTemplateAdmin)namedivination_typelanguagestatuscolored_statusvalidation_status
created_by
updated_at)r4   r5   r6   r9   )r3   descriptionr    )
created_atr:   last_validatedvalidation_warnings_displayvalidate_selected_templatesNr)   )r3   r;   r4   r5   r6   Content)r    )wider)   classes
Validation)r>   r=   collapseHistoryr9   r<   modified_byr:   Tc                 x    dddd}t        d|j                  |j                  d      |j                               S )zReturn colored status indicatororangegreengray)draftactivearchivedz"<span style="color: {};">{}</span>black)r   getr6   get_status_display)selfobjcolorss      r.   r7   z"PromptTemplateAdmin.colored_status8   sD     

 0JJszz7+""$
 	
r-   Statusc                 z    |j                   st        d      S |j                  dk(  rt        d      S t        d      S )z*Return colored validation status indicatoru,   <span style="color: green;">✓ Valid</span>rO   u,   <span style="color: red;">⚠ Invalid</span>u0   <span style="color: orange;">⚠ Warnings</span>)validation_warningsr   r6   rT   rU   s     r.   r8   z%PromptTemplateAdmin.validation_statusF   s;    &&MNNZZ8#MNNQRRr-   c                     |j                   st        d      S |j                   }t        |t              r"t	        ddj                  d |D                    S t        |      S )z.Display validation warnings in a formatted wayzNo validation warningsz<ul style="color: red;">{}</ul> c              3   (   K   | ]
  }d | d  yw)z<li>z</li>Nr,   ).0warnings     r.   	<genexpr>zBPromptTemplateAdmin.validation_warnings_display.<locals>.<genexpr>Y   s     FX'$wiu-Xs   )rY   _
isinstancelistr   joinstr)rT   rU   warningss      r.   r>   z/PromptTemplateAdmin.validation_warnings_displayP   sZ    &&-..**h%1FXFF  8}r-   zValidation Warningsc                     |j                   s|j                  |_        |j                  |_        t        |   ||||       yz5Override save_model to set created_by and modified_byNiduserr9   rI   super
save_modelrT   requestrU   formchange	__class__s        r.   rm   zPromptTemplateAdmin.save_model^   3    vv$\\CN!,,7Cv6r-   c           
          |D ]k  }|j                         \  }}|r!| j                  |d|j                   d       9| j                  |d|j                   ddj                  |       d       m y)z+Admin action to validate selected templatesz
Template "z
" is validz" has warnings: z, r_   )levelN)validatemessage_userr3   rd   )rT   ro   querysettemplateis_validrf   s         r.   r?   z/PromptTemplateAdmin.validate_selected_templatese   sw     H!)!2!2!4Hh!!'Zj+QR!! /?		(@S?TU# "  !r-   zValidate selected templatesc                     t         |          }t        d| j                  j	                  | j
                        d      g}||z   S )Nz<int:template_id>/validate/ai_prompttemplate_validater3   )rl   get_urlsr   
admin_site
admin_viewvalidate_template_viewrT   urlscustom_urlsrr   s      r.   r~   zPromptTemplateAdmin.get_urlss   sJ    w!-**4+F+FG1
 T!!r-   c                 z   	 | j                   j                  j                  |      }|j                         \  }}|j	                         }t        d|||d      S # | j                   j                  $ r t        dt        d      dd      cY S t        $ r#}t        dt        |      dd	      cY d
}~S d
}~ww xY w)z#AJAX view for validating a template)pkT)successrz   rf   
statisticsFzTemplate not foundr   errori  r6   i  N)
r(   objectsrR   rv   get_statisticsr	   DoesNotExistra   	Exceptionre   )rT   ro   template_idry   rz   rf   statses           r.   r   z*PromptTemplateAdmin.validate_template_view~   s    	zz))---=H!)!2!2!4Hh ++-E$$#	!   zz&& 	 /0!    	 Q!  	s$   AA 2B:B:B5/B:5B:c                       e Zd ZddiZdZy)PromptTemplateAdmin.Mediaall)zcss/admin/prompttemplate.css)zjs/admin/prompttemplate.jsN)r%   r&   r'   cssjsr,   r-   r.   Mediar      s    4
 -r-   r   )r%   r&   r'   r   rp   list_displaylist_filtersearch_fieldsreadonly_fieldsactionsra   	fieldsetssave_on_topr7   short_descriptionr8   r>   rm   r?   r~   r   r   __classcell__rr   s   @r.   r2   r2      s    "D HLIK6McO,-G	V
 	 
9" 
 	 
<G$
 	 
9O$
 	I" K
 (){N$S +,L/' 566K4L17 566S4T1	"4- -r-   r2   c                   8    e Zd ZdZdZdZd Z ed      e_        y)PromptPlaceholderAdmin)r3   r4   description_short)r4   )r3   r;   c                 n    t        |j                        dkD  r|j                  dd dz   S |j                  S )zReturn shortened description2   N...)lenr;   rZ   s     r.   r   z(PromptPlaceholderAdmin.description_short   s3    s"$??3B'%//r-   DescriptionN)	r%   r&   r'   r   r   r   r   ra   r   r,   r-   r.   r   r      s&    CL&K+M
 +,M*:'r-   r   c                   6     e Zd ZdZ G d d      Z fdZ xZS )AIProviderConfigAdminFormzW
    Custom form for AIProviderConfig with dynamic model choices based on provider
    c                       e Zd ZeZdZy)AIProviderConfigAdminForm.Metar   N)r%   r&   r'   r   r(   r)   r,   r-   r.   r/   r      s     r-   r/   c                    t        
|   |i | dg}| j                  r| j                  j                  r| j                  j                  rm| j                  j                  }t        j                  | j                  j                        }d }|D ]  \  }}||k(  s|} n |r|n|}	|j                  ||	f       t        j                  |      | j                  d   _        d| j                  d   _        y )Nr\   z	---------choicesr(   T)rl   __init__instancer   r(   r   get_available_modelsproviderappendr   Selectr)   widgetrequiredrT   argskwargsinitial_choicescurrent_modelmodel_choicesfriendly_name
model_code
model_namedisplay_namerr   s             r.   r   z"AIProviderConfigAdminForm.__init__   s    $)&) -- ==T]]--$--2E2E MM//M,AA$--BXBXYM M*7&
J.$.M +8 -:=}L""M<#@A&+ll?&KG#(,G%r-   r%   r&   r'   r0   r/   r   r   r   s   @r.   r   r      s     - -r-   r   c                        e Zd ZeZdZdZdZdZddgZ	dd e
d	      d
f e
d      dddffZd Z e
d      e_         fdZd Z e
d      e_        d Z e
d      e_        d fd	Zd fd	Z G d d      Z xZS )AIProviderConfigAdmin)r4   r   model_display	is_activer:   rI   )r   r   r4   )r4   r(   r<   r:   activate_configsdeactivate_configsN)r4   r   r(   r   zConfigure AI provider and model for each divination type. Separate configurations are available for analysis (BaZi, LiuYao, Number) and conversations (BaZi Conversation, LiuYao Conversation). Only one configuration per divination type can be active.r)   r;   rG   rH   rE   rB   c                     t        j                  |j                        }|D ]-  \  }}||j                  k(  st	        d||j                        c S  |j                  S )z-Display model with friendly name if availablez<span title="{}">{}</span>)r   r   r   r(   r   )rT   rU   r   r   r   s        r.   r   z#AIProviderConfigAdmin.model_display   sQ    (==cllK&3"J
SYY&"#?SYYWW '4 yyr-   Modelc                     |j                   s|j                  |_        |j                  |_        t        |   ||||       yrh   ri   rn   s        r.   rm   z AIProviderConfigAdmin.save_model   rs   r-   c                 R    |j                  d      }| j                  || d       y)z0Admin action to activate selected configurationsTr   z! configuration(s) were activated.Nupdaterw   rT   ro   rx   updateds       r.   r   z&AIProviderConfigAdmin.activate_configs   s*    //D/1'gY.O#PQr-   z Activate selected configurationsc                 R    |j                  d      }| j                  || d       y)z2Admin action to deactivate selected configurationsFr   z# configuration(s) were deactivated.Nr   r   s       r.   r   z(AIProviderConfigAdmin.deactivate_configs   s*    //E/2'gY.Q#RSr-   z"Deactivate selected configurationsc                     |xs i }i }t         j                  D ]  \  }}t        j                  |      ||<    t        j                  |      |d<   t
        |   ||||      S z4Override change_view to add model choices to contextprovider_models_jsonr   PROVIDER_CHOICESr   jsondumpsrl   change_view	rT   ro   	object_idform_urlextra_contextprovider_modelsprovider_codeprovider_namerr   s	           r.   r   z!AIProviderConfigAdmin.change_view   l    %+ ,<,M,M(M=-=-R-RS`-aOM* -N 15

?0K,-w"7IxOOr-   c                     |xs i }i }t         j                  D ]  \  }}t        j                  |      ||<    t        j                  |      |d<   t
        |   |||      S z1Override add_view to add model choices to contextr   r   r   r   r   r   rl   add_viewrT   ro   r   r   r   r   r   rr   s          r.   r   zAIProviderConfigAdmin.add_view  j    %+ ,<,M,M(M=-=-R-RS`-aOM* -N 15

?0K,-w=AAr-   c                       e Zd ZdZy)AIProviderConfigAdmin.Media)zjs/admin/aiproviderconfig.jsNr%   r&   r'   r   r,   r-   r.   r   r     s    .r-   r   r\   N)r%   r&   r'   r   rp   r   r   r   r   r   ra   r   r   r   rm   r   r   r   r   r   r   r   s   @r.   r   r      s    $DmL>K0M2O!#78G	K  Y  Z
 	 
9O$
 		I '(jM#7R *++M)N&T ,--Q+R(
P
B/ /r-   r   c                   n     e Zd ZdZdZdZdZdd ed      df ed	      d
ddffZ fdZ	d fd	Z
 xZS )ConversationConfigAdminz.Admin interface for Conversation Configuration)max_messagesr   r:   rI   r   r   N)r   r   zNConfigure conversation limits. Only one configuration can be active at a time.r   rG   rH   rE   rB   c                     |j                   s|j                  |_        |j                  |_        t        |   ||||       yrh   ri   rn   s        r.   rm   z"ConversationConfigAdmin.save_model'  rs   r-   c                     |r@|j                   r4t        j                  j                  d      j	                         }|dk  ryt
        |   ||      S )z/Prevent deletion if it's the only active configTr   r   F)r   r   r   filtercountrl   has_delete_permission)rT   ro   rU   active_countrr   s       r.   r   z-ConversationConfigAdmin.has_delete_permission.  sK    3==-55<<t<LRRTLq w,Wc::r-   N)r%   r&   r'   r0   r   r   r   ra   r   rm   r   r   r   s   @r.   r   r     s]    8ML K2O	3mn
 	 
9O$
 		I7; ;r-   r   c                   6     e Zd ZdZ G d d      Z fdZ xZS )AdminAIAnalysisAdminFormzV
    Custom form for AdminAIAnalysis with dynamic model choices based on provider
    c                       e Zd ZeZdZy)AdminAIAnalysisAdminForm.Metar   N)r%   r&   r'   r   r(   r)   r,   r-   r.   r/   r   :  s    r-   r/   c                    t        
|   |i | dg}| j                  r| j                  j                  r| j                  j                  rm| j                  j                  }t        j                  | j                  j                        }d }|D ]  \  }}||k(  s|} n |r|n|}	|j                  ||	f       t        j                  |      | j                  d   _        d| j                  d   _        | j                  d   j                  j                  j                  ddi       | j                  d   j                  j                  j                  ddi       y )	Nr   r   r(   Tr   classzprovider-selectzmodel-select)rl   r   r   r   r(   r   r   r   r   r   r   r)   r   r   r$   r   r   s             r.   r   z!AdminAIAnalysisAdminForm.__init__>  s)   $)&) -- ==T]]--$--2E2E MM//M,AA$--BXBXYM M*7&
J.$.M +8 -:=}L""M<#@A&+ll?&KG#(,G% 	J&&,,33W>O4PQG##))00'>1JKr-   r   r   s   @r.   r   r   6  s     L Lr-   r   c                        e Zd ZeZdZdZdZdZdddif e	d      d	d
df e	d      dd
dffZ
d ZddZd ZddZ fdZ fdZd Zd fd	Zd fd	Z G d d      Z xZS )AdminAIAnalysisAdmin)titler   r(   r6   r9   r<   )r  promptresponse)r   r(   r6   r<   )r  r6   r9   r<   r:   Nr)   )r  r  r   r(   Results)r  r6   metarE   rB   rG   )r9   r<   r:   c                 8    |j                   j                  d      S Nzai.can_send_admin_llm_analysisrk   has_permrT   ro   s     r.   has_module_permissionz*AdminAIAnalysisAdmin.has_module_permissionp      ||$$%EFFr-   c                 8    |j                   j                  d      S r
  r  rT   ro   rU   s      r.   has_view_permissionz(AdminAIAnalysisAdmin.has_view_permissions  r  r-   c                 8    |j                   j                  d      S r
  r  r  s     r.   has_add_permissionz'AdminAIAnalysisAdmin.has_add_permissionv  r  r-   c                 8    |j                   j                  d      S r
  r  r  s      r.   has_change_permissionz*AdminAIAnalysisAdmin.has_change_permissiony  r  r-   c                     |j                   s|j                  |_         t        |   ||||       |j                  dk(  rt        |       y y )Npending)r9   rk   rl   rm   r6   r   rn   s        r.   rm   zAdminAIAnalysisAdmin.save_model|  sC    ~~$\\CN7Cv6 ::"#C( #r-   c                     t         |          }t        d| j                  j	                  | j
                        d      g}||z   S )z"Add custom URLs for AJAX endpointszget-models/<str:provider>/ai_adminaianalysis_get_modelsr}   )rl   r~   r   r   r   get_models_viewr   s      r.   r~   zAdminAIAnalysisAdmin.get_urls  sJ    w!,**4+?+?@4
 T!!r-   c           
          	 t        j                  |      }t        d|D cg c]
  \  }}||d c}}d      S c c}}w # t        $ r#}t        dt	        |      dd      cY d}~S d}~ww xY w)	z0AJAX view to get available models for a providerT)rj   r3   )r   modelsFr   i  r   N)r   r   r	   r   re   )rT   ro   r   r   coder3   r   s          r.   r  z$AdminAIAnalysisAdmin.get_models_view  s{    
	,AA(KMHUV*$$5V!  V 	 Q!  	s+    A ;	A A 	A-
A("A-(A-c                     |xs i }i }t         j                  D ]  \  }}t        j                  |      ||<    t        j                  |      |d<   t
        |   ||||      S r   r   r   s	           r.   r   z AdminAIAnalysisAdmin.change_view  r   r-   c                     |xs i }i }t         j                  D ]  \  }}t        j                  |      ||<    t        j                  |      |d<   t
        |   |||      S r   r   r   s          r.   r   zAdminAIAnalysisAdmin.add_view  r   r-   c                       e Zd ZdZy)AdminAIAnalysisAdmin.Media)zjs/admin/adminaianalysis.jsNr   r,   r-   r.   r   r"    s    -r-   r   r   r   )r%   r&   r'   r   rp   r   r   r   r   ra   r   r  r  r  r  rm   r~   r  r   r   r   r   r   s   @r.   r  r  [  s    #DWL3M?KVO	>
 	 
94$
 	 
9@$
 	IGGGG)
"
P
B. .r-   r  c                   ,    e Zd ZdZddZ G d d      Zy)AIReportProxyz:Virtual model to represent reports from all analysis typesc                 @   || _         || _        || _        | d|j                   | _        t	        |dd       xs t	        |dd       | _        t	        |dd       | _        t	        || dd      | _        t	        || dd      | _        t	        || d	d      | _	        t	        || d
d       | _
        t	        || dd      | _        t	        || dd      | _        t	        || dd       | _        t	        || dd       | _        |dk(  r#|j                  | _        |j                   | _        y |dk(  r#|j                  | _        |j                   | _        y |dk(  rC|j"                  d d t%        |j"                        dkD  rdndz   | _        |j&                  | _        y y )Nra   r9   rk   r<   analysis_reportedFreport_categoryr\   report_messagereport_timestampreport_statusreport_admin_notesreport_resolved_byreport_resolved_atbazinumberliuyaor   r   )rU   analysis_typeprefixrj   getattrrk   r<   reportedr'  r(  r)  r*  r+  r,  r-  r3   
birth_datequestionr   qdate)rT   rU   r1  r2  s       r.   r   zAIReportProxy.__init__  s   * #O1SVVH-Ct4RVT8R	!#|T:  x/@%A5I&svho,FK%cfX^+DbI 'x7G-H$ O$SVHM*BBG")#&9K/Lb"Q")#&9K/Ld"S")#&9K/Ld"S F"DI!nnDOh&DI!nnDOh&Sb)c#,,6G"6LURTUDI!iiDO 'r-   c                       e Zd ZdZdZy)AIReportProxy.MetaAI Analysis ReportAI Analysis ReportsN)r%   r&   r'   verbose_nameverbose_name_pluralr,   r-   r.   r/   r9    s    +3r-   r/   N)r\   )r%   r&   r'   r0   r   r/   r,   r-   r.   r$  r$    s    D(@4 4r-   r$  c                       e Zd ZdZd Zy)AIReportsChangeListz Custom ChangeList for AI Reportsc                    ddl m} ddlm} g }|j                  j                  d      j                  dd      }|D ]  }|j                  t        |dd	               |j                  j                  d
      j                  dd      }|D ]  }|j                  t        |dd               |j                  j                  d      j                  dd      }|D ]  }	|j                  t        |	dd               |j                  d d       |j                  j                  d      }
|
r|D cg c]  }|j                  |
k(  s| }}|j                  j                  d      }|r|D cg c]  }|j                  |k(  s| }}|j                  j                  d      }|r|D cg c]  }|j                  |k(  s| }}|| _        t!        |      | _        t!        |      | _        y c c}w c c}w c c}w )Nr   Personr0  Tbazi_analysis_reportedr9   bazi_report_resolved_byr.  bazi_number_analysis_reportednumber_report_resolved_byr/  number_r&  rk   r,  r0  r\   c                     | j                   xs8 t        j                  j                  j	                  t        j
                        S )N)tzinfo)r)  r   datetimeminreplaceutc)xs    r.   <lambda>z1AIReportsChangeList.get_results.<locals>.<lambda>  s3    1#5#5#k9J9J9N9N9V9V^f^j^j9V9k#kr-   )keyr   report_status__exactreport_category__exactanalysis_type__exact)bazi.modelsrB  liuyao.modelsr0  r   r   select_relatedr   r$  sortGETrR   r*  r'  r1  result_listr   result_countfull_result_count)rT   ro   rB  r0  reportsbazi_reportspersonnumber_reportsliuyao_reportsentrystatus_filterrcategory_filteranalysis_type_filters                 r.   get_resultszAIReportsChangeList.get_results  s   &( ~~,,D,IXXYe  hA  B"FNN=AB #  ...M\\]i  lG  H$FNN=9EF %  ...FUUV\^rs#ENN="=> $ 	kuyz  (>?")N'QQ__-Mq'GN!++//*BC")R'QQ->->/-Qq'GR&{{/EF")U'QQ__@T-Tq'GU"L!$W O S Vs$   1G,G,-G1G1)G6>G6N)r%   r&   r'   r0   rk  r,   r-   r.   r?  r?    s
    *(.r-   r?  c                      e Zd ZdZdZg Zg Zg dZd ZddZ	ddZ
d Zd	 Zd
 Zde_        d Zde_        d Zde_        d Zde_        d Zde_        d Zde_        d Zde_        d Zde_        d Zde_        d Zde_        y)AIReportsAdminz7Centralized admin interface for all AI analysis reports)	report_idanalysis_type_displayuser_displayname_displaycategory_displaystatus_displayr)  admin_action_buttons)mark_as_reviewedmark_as_resolvedmark_as_dismissedc                      y)z(Reports are created by users, not adminsFr,   r  s     r.   r  z!AIReportsAdmin.has_add_permission      r-   Nc                      y)z,Reports should not be deleted, only resolvedFr,   r  s      r.   r   z$AIReportsAdmin.has_delete_permission!  ry  r-   c                      y)z"Reports are read-only in this viewFr,   r  s      r.   r  z$AIReportsAdmin.has_change_permission%  ry  r-   c                     t         S )zUse custom ChangeList)r?  )rT   ro   r   s      r.   get_changelistzAIReportsAdmin.get_changelist)  s    ""r-   c                     g S )z8Return empty queryset since we handle this in ChangeListr,   r  s     r.   get_querysetzAIReportsAdmin.get_queryset-  s	     	r-   c                     |j                   S )zDisplay report ID)rj   rZ   s     r.   rn  zAIReportsAdmin.report_id2  s    vvr-   z	Report IDc                     dddd}dddd}t        d|j                  |j                  d	      |j                  |j                  |j                              S )
zDisplay analysis type with iconu   🔮u   🔢u   ☯️)r.  r/  r0  BaZiNumberLiuYaoz{} {}r\   )r   rR   r1  )rT   rU   iconsnamess       r.   ro  z$AIReportsAdmin.analysis_type_display7  sa     
 

 7EIIc.?.?$DeiiPSPaPacfctctFuvvr-   zAnalysis Typec                     |j                   sy|j                   j                   d|j                   j                   j                         }|sd}t	        d||j                   j
                        S )zDisplay user informationzUnknown User zNo Namez=<strong>{}</strong><br><small style="color: #666;">{}</small>)rk   
first_name	last_namestripr   phone)rT   rU   	full_names      r.   rp  zAIReportsAdmin.user_displayF  sa    xx!xx**+1SXX-?-?,@AGGI	!IKHHNN
 	
r-   Userc                     |j                   S )zDisplay name/questionr}   rZ   s     r.   rq  zAIReportsAdmin.name_displayV  s    xxr-   zName/Questionc                     dddddd}dddd	d
d}|j                  |j                  d      }|j                  |j                  |j                        }t        d||      S )z)Display report category with color codingz#dc3545z#fd7e14z#6610f2z#6c757d)inappropriate_contentinaccurate_analysisoffensive_languagetechnical_errorotheru   内容不当u   分析不准确u   语言冒犯u   技术错误u   其他z5<span style="color: {}; font-weight: bold;">{}</span>)rR   r'  r   )rT   rU   category_colorscategory_namescolorr3   s         r.   rr  zAIReportsAdmin.category_display[  s|     &/#,"+(
 &4#4"0-
  ##C$7$7C!!#"5"5s7J7JKRTY[_``r-   Categoryc                     |j                   dk(  rt        d      S |j                   dk(  rt        d      S |j                   dk(  rt        d      S |j                   dk(  rt        d      S t        d	      S )
z'Display report status with color codingr  uD   <span style="color: orange; font-weight: bold;">⏳ 待处理</span>revieweduF   <span style="color: blue; font-weight: bold;">👁️ 已审核</span>resolveduC   <span style="color: green; font-weight: bold;">✅ 已解决</span>	dismisseduB   <span style="color: gray; font-weight: bold;">❌ 已忽略</span>u/   <span style="color: red;">🚩 已举报</span>)r*  r   rZ   s     r.   rs  zAIReportsAdmin.status_displayr  sv    	)eff*,ghh*,dee+-cddPQQr-   rW   c                 |   |j                   dv rt        d      S |j                  dk(  r#t        d|j                  j
                  g      }nf|j                  dk(  r#t        d|j                  j
                  g      }n4|j                  dk(  r#t        d|j                  j
                  g      }nd	}t        d
|      S )z(Display action buttons for quick actions)r  r  u?   <span style="color: #666; font-style: italic;">已处理</span>r.  zadmin:bazi_person_change)r   r/  r0  zadmin:liuyao_liuyao_change#u   <a href="{}" class="button" style="background-color: #007cba; color: white; padding: 4px 8px; text-decoration: none; border-radius: 3px; font-size: 11px; margin-right: 5px;">查看详情</a>)r*  r   r1  r   rU   rj   )rT   rU   
change_urls      r.   rt  z#AIReportsAdmin.admin_action_buttons  s     99`aa & !;377::,OJ(* !;377::,OJ(* !=SWWZZLQJJ M
 	
r-   Actionsc                    d}|D ]  }|j                   dk(  s|j                  dv r[|j                  dk(  r|j                   dnd}t        |j                  | dd       |j                  j	                  | dg	       n=|j                  d
k(  r.d|j                  _         |j                  j	                  dg	       |dz  } | j                  || d       y)z!Mark selected reports as reviewedr   r  r.  r/  r.  ra   rK  r*  r  update_fieldsr0  r   u    个举报已标记为已审核N)r*  r1  setattrrU   saverw   rT   ro   rx   r   reportfield_prefixs         r.   ru  zAIReportsAdmin.mark_as_reviewed  s     F##y0''+==AGAUAUY_A_f&:&:%;1#=enLFJJ<.(F
SJJOOl^=3Q2ROS))X5/9FJJ,JJOO?2COD
  	'eW,K#LMr-   u   标记为已审核c           	         d}|D ]  }|j                   dk(  s|j                  dv r|j                  dk(  r|j                   dnd}t        |j                  | dd       t        |j                  | d	|j                         t        |j                  | d
t        j                                |j                  j                  | d| d	| d
| dg       n||j                  dk(  rmd|j                  _         |j                  |j                  _        t        j                         |j                  _	        |j                  j                  g d       |j                  dv r dnd}t        |j                  |d      st	 ddlm} |j                  ra|j                  j                  rK ||j                  |j                  |j                  d|j                         t        |j                  |d       |dz  } | j!                  || d       y# t        $ r(}| j!                  |dt#        |              Y d}~Jd}~ww xY w)z!Mark selected reports as resolvedr   r  r  r.  ra   rK  r*  r  r,  r-  report_resolution_email_sentr  r0  )r*  r,  r-  r  F)!send_user_resolution_notificationTu&   举报已解决但邮件发送失败: Nr   u    个举报已解决)r*  r1  r  rU   rk   r   nowr  r,  r-  r3  	api.utilsr  emailr+  r   rw   re   )	rT   ro   rx   r   r  r  email_sent_fieldr  r   s	            r.   rv  zAIReportsAdmin.mark_as_resolved  s&   F##y0''+==AGAUAUY_A_f&:&:%;1#=enLFJJ<.(F
SFJJ<.8J(KW\\ZFJJ<.8J(KX\\^\JJOO'.6'.(:;~M_=`'.(DE3O 
 ))X5/9FJJ,4;LLFJJ14<LLNFJJ1JJOO 3O  U[ThThl~T~l^3O#P  Ec vzz+;UCfO!;;6;;+<+<= &VZZ9M9Mz[a[t[t $FJJ0@$G 
G J 	'eW,?#@A % f))'5[\_`a\b[c3deefs   A3H	I	!II	u   标记为已解决c                    d}|D ]U  }|j                   dk(  s|j                  dv r|j                  dk(  r|j                   dnd}t        |j                  | dd       t        |j                  | d	|j                         t        |j                  | d
t        j                                |j                  j                  | d| d	| d
g       n||j                  dk(  rmd|j                  _         |j                  |j                  _        t        j                         |j                  _	        |j                  j                  g d       |dz  }X | j                  || d       y)z"Mark selected reports as dismissedr   r  r  r.  ra   rK  r*  r  r,  r-  r  r0  )r*  r,  r-  r   u    个举报已忽略N)r*  r1  r  rU   rk   r   r  r  r,  r-  rw   r  s         r.   rw  z AIReportsAdmin.mark_as_dismissed  sS   F##y0''+==AGAUAUY_A_f&:&:%;1#=enLFJJ<.(FTFJJ<.8J(KW\\ZFJJ<.8J(KX\\^\JJOO'.6'.(:;~M_=`3O  ))X5/:FJJ,4;LLFJJ14<LLNFJJ1JJOO 3O + 
- 0 	'eW,?#@Ar-   u   忽略举报r   )r%   r&   r'   r0   r   r   r   r   r  r   r  r}  r  rn  r   ro  rp  rq  rr  rs  rt  ru  rv  rw  r,   r-   r.   rm  rm    s    A
 lLKMKG#
 #.Iw />+
 &,L" &5L"a* *4&R (0N$
& .7*N  *>&(BR *>&B8 +9'r-   rm  )	AdminSitec                   $     e Zd ZdZd fd	Z xZS )CustomAdminSitez9Custom admin site with additional features for AI reportsc                     t         |   ||      }ddddddddd	d
ddddddddddddddddgd}|j                  |       |S )z&Add custom AI Reports section to adminr;  
ai_reportszAll BaZi Reports
BaziReport3/admin/bazi/person/?bazi_analysis_reported__exact=1NT)r3   object_name	admin_urladd_url	view_onlyzAll Number ReportsNumberReport5/admin/bazi/person/?number_analysis_reported__exact=1zAll LiuYao ReportsLiuYaoReport0/admin/liuyao/liuyao/?analysis_reported__exact=1zPending Reports (All Types)PendingReport5/admin/bazi/person/?bazi_report_status__exact=pending)r3   	app_labelr  )rl   get_app_listr   )rT   ro   r  app_listai_reports_apprr   s        r.   r  zCustomAdminSite.get_app_list  s    7'; *% /#/!V#!% 1#1!X#!% 1#1!S#!% :#2!X#!%-!
H 	'r-   r   )r%   r&   r'   r0   r  r   r   s   @r.   r  r    s    C+ +r-   r  )appsc                       e Zd ZdZd Zd Zy)AIReportProxyModelzP
    Model-like class for admin registration with complete meta attributes.
    c                      y r   r,   rT   s    r.   r   zAIReportProxyModel.__init__,  s    r-   c                      y)Nr;  r,   r  s    r.   __str__zAIReportProxyModel.__str__/  s    $r-   N)r%   r&   r'   r0   r   r  r,   r-   r.   r  r  (  s    %r-   r  c                      t        j                  d      }  t        ddi dddddd	d
dddd| dddddddd dddddd dd dg dg dg dd i             }|S )Nair/   r,   r<  r:  r=  r;  r  r  r  r   aireportproxymodel
app_configabstractFmanagedproxyswappedauto_createddb_tableai_report_proxy	get_fieldc                      y r   r,   rT   r3   s     r.   rT  zcreate_meta.<locals>.<lambda>C  s    r-   
get_fieldsc                     g S r   r,   r  s    r.   rT  zcreate_meta.<locals>.<lambda>D  s    2r-   concrete_fieldslocal_fieldsmany_to_manyget_field_by_namec                      y)N)NNFFr,   r  s     r.   rT  zcreate_meta.<locals>.<lambda>H  s    0Jr-   )r  get_app_configtype)ai_app_configr  s     r.   create_metar  3  s   ''-M4 ,4 	+ 	T	
 	* 	m 	E 	5 	 	4 	 	% 	, 	o 	2  	!" 	#$ 	J%  	D* Kr-   c                   $    e Zd ZdZg Zg Zg ZddZy)AIReportsAdminFixedz:Fixed version that completely bypasses database operationsNc                 p   ddl m} ddlm} |j                  j                  d      j                         }|j                  j                  d      j                         }|j                  j                  d      j                         }|j                  j                  d	      j                         }|j                  j                  d
      j                         }	|j                  j                  d      j                         }
ddlm} ddd t        dddddddd             ddddd|j                  |      |j                  |j                  |j                   t        dd||z   |z   ||z   |z   d             d||dddd||	dddd ||
d!d"dgd#}|r|j                  |       t        |d$|      S )%zJOverride changelist_view to show reports summary with Django admin stylingr   rA  rC  TrD  rH  rL  r  )bazi_report_status)number_report_status)r*  )siter;  z9Centralized view of all AI analysis reports in the systemr  optsr,   r  r:  r  )r  r   r<  r=  r  FFakeChangeList)r_  r`  zBaZi Reportsr  r  )r3   r   r  view_all_urlpending_urlzNumber Reportsr  z7/admin/bazi/person/?number_report_status__exact=pendingzLiuYao Reportsr  z2/admin/liuyao/liuyao/?report_status__exact=pending)r  subtitler  r  r  r  r  r   is_nav_sidebar_enabledavailable_appssite_header
site_titleindex_titleclreports_summaryzadmin/ai/reports_dashboard.html)rY  rB  rZ  r0  r   r   r   django.contrib.adminr  r  r  r  r  r  r   r   )rT   ro   r   rB  r0  
bazi_countnumber_countliuyao_countpending_bazipending_numberpending_liuyaor  contexts                r.   changelist_viewz#AIReportsAdminFixed.changelist_viewX  s   &( ^^**$*GMMO
~~,,d,KQQS~~,,t,DJJL ~~,,	,JPPR..I.NTTV..Y.GMMO 	. +SD!2 4'<3&   $("'%*%*&*"//8++//++$' *\ 9L H%/,%>%M.   +'+$Y#Z -)-$[#\ -)-$V#W 30
d NN=))JGTTr-   r   )r%   r&   r'   r0   r   r   r   r  r,   r-   r.   r  r  P  s    D LKMGUr-   r  c                       e Zd ZdZdZdZdZdZdddif ed	      d
ddf ed      dddffZ	d Z
 ed      e
_        d Z ed      e_        y)ConversationAdminz&Admin interface for Conversation model)rj   r  rk   rc  message_countr<   r:   r   )r  user__phoneuser__emailperson__name)r<   r:   message_count_displayNr)   )rk   rc  r  
Statistics)r	  rE   rB   
Timestampsc                 "    |j                         S )zDisplay message countget_message_countrZ   s     r.   r  zConversationAdmin.message_count      $$&&r-   Messagesc                 "    |j                         S )z$Display message count in detail viewr  rZ   s     r.   r	  z'ConversationAdmin.message_count_display  r  r-   zTotal Messages)r%   r&   r'   r0   r   r   r   r   ra   r   r  r   r	  r,   r-   r.   r  r    s    0aL.KKMKO	1
 	 
<0$
 	 
<2$
 	I' '(
mM#' /00@.A+r-   r  c                   ~    e Zd ZdZdZdZdZdZdddif ed	      d
ddf ed      dddffZ	d Z
 ed      e
_        y)MessageAdminz!Admin interface for Message model)rj   conversationrolecontent_previewr   r(   r<   )r  r   r<   r  )r    conversation__titleconversation__person__name)r<   Nr)   )r  r  r    zAI Metadata)r   r(   r  rE   rB   r  c                 v    t        |j                        dkD  r|j                  dd dz   }|S |j                  }|S )zDisplay content previewd   Nr   )r   r    )rT   rU   previews      r.   r  zMessageAdmin.content_preview  s>    /23;;/?#/E#++ds#e+ LO;;r-   r@   )r%   r&   r'   r0   r   r   r   r   ra   r   r  r   r,   r-   r.   r  r    sy    +gLDKTM%O	9
 	 
=	3$
 	 
<%$
 	I )*)O%r-   r  )Cdjango.contribr   django.utils.translationr   ra   django.utils.htmlr   djangor   django.urlsr   r   django.httpr	   django.utils.safestringr
   django.contrib.admin.views.mainr   django.db.modelsr   django.utilsr   django.template.responser   r  r   r   r   r   r   r   r   utils.template_validationr   r   utils.admin_llmr   django.core.exceptionsr   r   	ModelFormr   register
ModelAdminr2   r   r   r   r   r   r  r$  r?  rm  r  r  r  django.appsr  r  r  _metar  r  	_registryr  r  r,   r-   r.   <module>r0     sU     6 )  % $ - 6  ! 5 D  D  D Q 4 3 	
eoo 	
 ~-%** ~-  ~-@ !"
;U-- 
; #
;- -B  !G/E,, G/ "G/R "#;e.. ; $;>#Lu #LJ  \.5++ \. !\.@$4 $4N*.* *.Z_9U%% _9F +.i .b % %4 '=  OU. OUd ,??QSXS]S]+^

  ' ( B(( B B> 55## 5 5r-   