
    EޣjP                       d Z ddlZddlZddlZddlZddlZddlZddlZej	        
                    ej	        
                    ej	                            e                              Zej	                            ed          Zej	                            d          Zej	                            ed          Zej	                            ed          Zej	                            ed          Zej	                            ed          Zd	Zej	                            ed
          Zej	                            ed          ZdZddddZd Zd Zd Zd ZddZd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d  Z)d! Z*d" Z+i Z,d# Z-d$ Z.d% Z/h d&Z0d' Z1d( Z2d)g d*iZ3i d+d+d,gd-g d.d/d/d0gd1d1d2gd3g d4d5d5d6gd7g d8d9g d:d;d<d=gd>g d?d@d@dAgdBdBgdCdCdDgdEdEgdFdFgdGdGgdHdHdIgdJdKgdLgdMZ4g dNZ5g dOdPgdQZ6i Z7ddSZ8ddTZ9dU Z:dVZ;dWZ<ddl=Z=ej	                            edX          Z>ej	                            edY          Z?dZZ@d[ZAd\ZBd]ZCd^ZDddd_ZEh d`ZFda ZGi ZHdb ZIdc ZJh ddZKde ZLdf ZMddgZNi ZOdaPdh ZQdi ZRdj ZSeAeBdfdkZTddmZUdn ZVdaWdo ZXdp ZYdq ZZddrZ[ds Z\dt Z]du Z^ej	                            edv          Z_g dwZ`dx Zady Zbdz Zcd{ Zddd|Zed} Zfd~ ZgddZdddddiZhd Zid ZjddZkddZlddZmi dg ddg ddg ddg ddg ddg ddddgdg ddg ddg ddddgdg ddg ddg ddg ddg ddg dg dg dg ddZnddZoi ddgddgdddgddgdddgdddgddgddgddgddgddgddgddgddgddgddgddgddgiZph dͣZqd΄ Zrdτ ZsdЄ Ztdф Zudd҄ZvddӄZwdԄ ZxdՄ Zydք ZzdZ{dZ|dل Z}dڄ Z~dۄ Zej	                            edܦ          Zd݄ Zdބ Zd߄ Zd ZddZddZddZd	dZd
dZddZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdddddZd Zd Zd Zd Zd  ZdS (  u  
宝锐销售工作台 · AI 智能问答模块

被 销售工作台服务.py 的 /api/chat 端点调用。
职责：
  1. 只答工作问题（system prompt 铁律）
  2. 客户问题权限隔离（按角色过滤可见客户，只注入权限范围内的客户摘要）
  3. 行业/市场/竞品问题自由回答（不注入客户数据）

仅依赖 Python 标准库 + yaml（读取 Hermes config）。
    N   数据u:   ~/Library/Application Support/宝锐工作台/生成文件filesz
index.jsonzchat_history.jsonzai_token_usage.json   zai_deepseek_quota.jsonzuser_permissions.json<   u   诊断原料   生命科学u   诊断原料+生命科学)dalsbothc                  $   	 t           j                            t                    rYt	          t          d          5 } t          j        |           }ddd           n# 1 swxY w Y   t          |t                    r|S n# t          $ r Y nw xY wi S )u.   读取历史文件，返回 {name: [messages]}utf-8encodingN)
ospathexistsHISTORY_FILEopenjsonload
isinstancedict	Exceptionfds     B   /Users/liuxinyuan/Desktop/Hermes输出-工作类/脚本/ai_chat.py_load_historyr   &   s    7>>,'' 	lW555 !IaLL! ! ! ! ! ! ! ! ! ! ! ! ! ! !!T""    I4   :B  AB  A!!B  $A!%B   
BBc                 ,   	 t          j        t          d           t          dz   }t	          |dd          5 }t          j        | |dd	           d
d
d
           n# 1 swxY w Y   t          j        |t                     dS # t          $ r Y dS w xY w)u!   写回历史文件（原子写）Texist_ok.tmpwr   r   F   ensure_asciiindentN)	r   makedirsDATA_DIRr   r   r   dumpreplacer   datatmpr   s      r   _save_historyr/   3   s    
Ht,,,,V##sW--- 	=IdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=

3%%%t   uu4   7B AB A""B %A"&B 
BBc                 F    t                                          | g           S )u0   返回某用户的历史（可能为空列表）)r   getnames    r   _get_historyr5   @   s    ??tR(((    c                     t                      }|r!t          |          t           d         || <   n|                    | d           t	          |           dS )u$   设置某用户的历史（截断）N)r   listMAX_HISTORYpopr/   )r4   messageshs      r   _set_historyr=   E   sW    A x..+/$	dD!r6    c           
      ^   | r|sdS 	 ddl m } i }t          j                            t                    rYt          t          d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                    r|}t          |                                                                          |                                                    d          |pdt          |                    d          pd          t          |                    d	          pd          t          |                    d
          pd          |pddd         d}|                    | g                               |           ||          dd         || <   t          j        t$          d           t          dz   }	t          |	dd          5 }t          j        ||dd           ddd           n# 1 swxY w Y   t          j        |	t                     dS # t*          $ r Y dS w xY w)uR   记录一次 AI 调用的 token 消耗（按 name 分桶，保留最近 500 条）Nr   datetimer   r   %Y-%m-%dr>   prompt_tokenscompletion_tokenstotal_tokensP   )tsdatemodelprompt
completiontotalqiTr    r"   r#   Fr$   r%   )rA   r   r   r   TOKEN_USAGE_FILEr   r   r   r   r   intnow	timestampstrftimer2   
setdefaultappendr(   r)   r*   r+   r   )
r4   usagequestionrI   rA   r-   r   _drecr.   s
             r   _record_token_usagerY   O   s    u %%%%%%7>>*++ 	&999 "QYq\\" " " " " " " " " " " " " " ""d## hllnn..0011LLNN++J77[b%))O449::eii(;<<ABB>227a88.b#2#&
 
 	b!!((---$Z&T

Ht,,,,'#sW--- 	=IdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=

3()))))   s[   AH 
A+H +A//H 2A/3EH G7+H 7G;;H >G;?H 
H,+H,c                  $   	 t           j                            t                    rYt	          t          d          5 } t          j        |           }ddd           n# 1 swxY w Y   t          |t                    r|S n# t          $ r Y nw xY wi S )u8   读取 DeepSeek 每日限流计数 {name: {date: count}}r   r   N)
r   r   r   DEEPSEEK_QUOTA_FILEr   r   r   r   r   r   r   s     r   _load_deepseek_quotar\   o   s    7>>-.. 	)G<<< !IaLL! ! ! ! ! ! ! ! ! ! ! ! ! ! !!T""    Ir   c                 ,   	 t          j        t          d           t          dz   }t	          |dd          5 }t          j        | |dd	           d
d
d
           n# 1 swxY w Y   t          j        |t                     d
S # t          $ r Y d
S w xY w)u"   原子写回 DeepSeek 限流计数Tr    r"   r#   r   r   Fr$   r%   N)	r   r(   r)   r[   r   r   r*   r+   r   r,   s      r   _save_deepseek_quotar^   |   s    
Ht,,,,!F*#sW--- 	=IdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=

3+,,,,,   r0   c                    ddl m } |                                                    d          }t                                          | i           }t          |                    d          |k    r|                    d          pd          S )uF   返回某用户今天已用的 DeepSeek 次数（跨天自动归零）r   r@   rB   rH   count)rA   rP   rR   r\   r2   rO   )r4   rA   todaybuckets       r   _deepseek_used_todayrc      s    !!!!!!LLNN##J//E!##''b11Fvzz&!!U*Bvzz'/B/BGaHHHr6   c                 V    t          |           }|dk     rdS t          |           |k     S )uU   DeepSeek 是否还有今日额度（limit=-1 不限；否则按 per-user limit 计）r   T)_get_ds_limitrc   )r4   limits     r   _deepseek_quota_availablerg      s0    $Eqyyt%%--r6   c                 l   ddl m } |                                                    d          }t                      }|                    | i           }|                    d          |k    r|dd}t          |                    d          pd          dz   |d<   ||| <   t          |           |d         S )uF   消耗一次 DeepSeek 今日额度（返回消耗后的已用次数）r   r@   rB   rH   )rH   r`   r`   r$   )rA   rP   rR   r\   r2   rO   r^   )r4   rA   ra   r-   rb   s        r   _consume_deepseek_quotari      s    !!!!!!LLNN##J//E!!DXXdBFzz&U""!,,&**W--233a7F7ODJ'?r6   c                  $   	 t           j                            t                    rYt	          t          d          5 } t          j        |           }ddd           n# 1 swxY w Y   t          |t                    r|S n# t          $ r Y nw xY wi S )uU   读取按人权限覆盖 {name: {ds_limit, tabs, extra_customers, blocked_customers}}r   r   N)
r   r   r   PERMISSIONS_FILEr   r   r   r   r   r   r   s     r   _load_user_permissionsrl      s    7>>*++ 	&999 !QIaLL! ! ! ! ! ! ! ! ! ! ! ! ! ! !!T""    Ir   c                 ,   	 t          j        t          d           t          dz   }t	          |dd          5 }t          j        | |dd	           d
d
d
           n# 1 swxY w Y   t          j        |t                     dS # t          $ r Y dS w xY w)u   原子写回权限覆盖文件Tr    r"   r#   r   r   Fr$   r%   N)	r   r(   r)   rk   r   r   r*   r+   r   r,   s      r   _save_user_permissionsrn      s    
Ht,,,,'#sW--- 	=IdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=

3()))t   uur0   c                 F    t                                          | i           S )u8   返回某用户的权限覆盖 dict（可能为空 {}）)rl   r2   r3   s    r   _get_user_permrp      s    !##''b111r6   c                     t          |           }|                    d          }|t          S 	 t          |          }n# t          $ r
 t          cY S w xY w|dk     rdS |S )uk   返回某用户 DeepSeek 每日限流次数。-1=不限；<=0 或缺省用全局默认 DEEPSEEK_DAILY_LIMITds_limitNr   )rp   r2   DEEPSEEK_DAILY_LIMITrO   r   )r4   pvs      r   re   re      sw    tA	jAy##$FF $ $ $####$1uurHs   ? AAc                     	 ddl } |                     t          t          j                            d          d                    }|                    di                               di           }|                    dd	          |                    d
          pd                    d          |                    d          pddS # t          $ r}dt          |          icY d}~S d}~ww xY w)u0   从 ~/.hermes/config.yaml 读取 DeepSeek 凭证r   N~/.hermes/config.yamlr   r   	providersdeepseekapi_keyr>   base_urlzhttps://api.deepseek.com/default_modelzdeepseek-v4-pror{   r|   rI   error
yaml	safe_loadr   r   r   
expanduserr2   rstripr   str)r   cfgdses       r   _load_deepseek_cfgr      s    
!nnT"'"4"45L"M"MX_```aaWW["%%))*b99vvi,,
++I/IQQRUVVVVO,,A0A
 
 	

  ! ! !Q       !   CC 
C-C("C-(C-c                     	 ddl } |                     t          t          j                            d          d                    }|                    di                               di           }|                    dd	          |                    d
          pd                    d          |                    d          pddS # t          $ r}dt          |          icY d}~S d}~ww xY w)uF   从 ~/.hermes/config.yaml 读取智谱 GLM 凭证（providers.zhipu）r   Nrx   r   r   ry   zhipur{   r>   r|   z$https://open.bigmodel.cn/api/paas/v4r}   r~   zglm-5.3-flashr   r   r   )r   r   zr   s       r   _load_glm_cfgr      s    
!nnT"'"4"45L"M"MX_```aaGGK$$(("55uuY++z**T.T\\]`aaUU?++>
 
 	

  ! ! !Q       !r   c                     g } 	 t           j                            t          dd          }t           j                            |          r=t          |d          5 }t          j        |          } ddd           n# 1 swxY w Y   n# t          $ r g } Y nw xY wg }	 t           j                            t          d          }t           j                            |          rt          |d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                    r|                    dg           }nt          |t                    r|}n# t          $ r g }Y nw xY w| |fS )uE   加载客户数据：诊断原料重点客户 + 生命科学课题组pricingz_key_customers.jsonr   r   Nzls_groups.jsongroups)r   r   joinr)   r   r   r   r   r   r   r   r2   r8   )custsru   r   r   gs        r   _load_customer_datar      s   EGLL9.CDD7>>! 	%a'*** %a	!% % % % % % % % % % % % % % %   F
GLL#3447>>! 	a'*** !aIaLL! ! ! ! ! ! ! ! ! ! ! ! ! ! !!T"" x,,At$$    &=sn   AB A;/B ;A??B A?B BBAE! 1DE! DE! DAE! !E0/E0c            
         dt           v rt           d         S 	 t          j                            t          d          } t          | d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                    r|
                    dg           n|}g }|D ]}|
                    d          }t          |t                    r|
                    dd	          n|rt          |          nd	}|
                    d
          }t          |t                    r|
                    dd	          n|rt          |          nd	}	|                    |
                    d          pd	|
                    d          pd	||	|
                    d          pd	d           |t           d<   n# t          $ r g t           d<   Y nw xY wt           d         S )uO   加载飞书活动数据（daily_activities_mcp.json），返回规范化列表
activitiesdaily_activities_mcp.jsonr   r   Nitemsfield_5f20fclabelr>   ownername_cnr4   field_b99055
start_time)r4   desccustomerr   rH   )	_BG_CACHEr   r   r   r)   r   r   r   r   r   r2   r   rT   r   )
ru   r   r   r   actsitfccustowr   s
             r   _load_activitiesr     s   y  &&%GLL#>??!g&&& 	!	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	&0D&9&9@gr"""q 	 	B''B*4R*>*>[266'2&&&PREZSWWWXZDB-7D-A-A^BFF9b)))SUH]B[]EKKv,"~..4" |,,2      #'	, % % %"$	,%\""s6   6F; A/#F; /A33F; 6A37EF; ;GGc                     dt           v rt           d         S 	 t          j                            t          dd          } t          | d          5 }t          j        |          }ddd           n# 1 swxY w Y   i }t          |t                    r|ng D ]A}|
                    d          pd}|
                    d	          pd}|r|d
k    r	||vr|||<   B|t           d<   n# t          $ r i t           d<   Y nw xY wt           d         S )uD   加载产品库（_all_products.json），构建 sku→名称 映射productsr   z_all_products.jsonr   r   Nskur>   r4   nan)r   r   r   r   r)   r   r   r   r   r8   r2   r   )ru   r   r   pmapprodr   r4   s          r   _load_productsr   +  s]   Y$$#GLL9.BCC!g&&& 	!	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	$Q--5QQ2 	! 	!D((5//'RC88F##)rD !se||4 S	 $	* # # # "	*#Z  s6   7C# A0$C# 0A44C# 7A48A*C# #C:9C:c                 J    ddl }t           |j        d| pd                    S )u1   提取货号（M2181、M2331、FM2181-4-NA 等）r   Nz/(?:[A-Z]{0,3})M\d{3,4}(?:-\d+)*(?:-[A-Z]{1,3})?r>   )resetfindall)textr   s     r   _extract_skusr   ?  s-    IIIzrzLdjVXYYZZZr6   >-      一样   中心   产业   健康   内部   出来   厂家   反馈   发展   哪里   国际   实业   应该   性能   控股   推动   无法   有限   检验   确认   继续   股份   药业   资源   公司   制药   医学   医疗   医药   实验   客户   工程   怎么   技术   检测   测试   生命   生物   研究   科学   科技   诊断   问题   集团   项目c                     t          t          |           dz
            D ] }| ||dz            }|t          v r||v r dS !dS )uD   a 是否含某个非通用 2 字片段，且该片段出现在 b 中r$      TF)rangelen_COMMON_BIGRAM)abisubs       r   _has_common_bigramr   L  s\    3q66A:  !a%j.  !8844 5r6   c                    | r|sdS t          |           t          |          c}fdt          |dz             D             }d\  }}t          d|dz             D ]r}t          ddz             D ]\}| |dz
           ||dz
           k    rB||dz
           |dz
           dz   ||         |<   ||         |         |k    r||         |         }|}]s| ||z
  |         S )uZ   返回 a 与 b 的最长公共连续子串（动态规划）。用于精确简称匹配。r>   c                 "    g | ]}d gdz   z  S )r   r$    ).0_lbs     r   
<listcomp>z-_longest_common_substring.<locals>.<listcomp>\  s#    	0	0	0Q1#a.	0	0	0r6   r$   )r   r   )r   r   )	r   r   ladpmax_lenend_ar   jr   s	           @r   _longest_common_substringr   W  s    A rVVSVVFB	0	0	0	0%Q--	0	0	0BNGU1b1f  q"q&!! 	 	AQx1QU8##a!e9QU+a/1aa58g%% eAhGE	 UW_U"##r6      动物疫病)   非瘟   非洲猪瘟   猪瘟u	   口蹄疫	   禽流感	   新城疫   蓝耳   圆环u	   伪狂犬u	   猪腹泻   流行性腹泻u   细小u   犬瘟u   猫瘟u	   马立克u	   法氏囊u   鸭瘟u   动保r   u   兽医u   兽用u   兽药u   畜牧u   养殖   水产   宠物	   诺唯赞Vazyme   翌圣)r  u   羿圣Yeasen	   全式金TransGenu   生工SangonTakara)r  u	   宝日医u	   宝生物u   天根TIANGEN   康为世纪)u   康为r  CWBIO   近岸蛋白)u   近岸r  Novoproteinu   义翘神州u   义翘SinoBiological   爱博泰克)r  u   艾博泰克Abclonalu   罗氏Rocheu   菲鹏u	   迈迪安Meridianu   华峰u	   白垩纪u   东盛u	   碧云天Beyotime	   索莱宝Solarbio   中科唐碳)r  r  )   竞品u   竞对u   对手u   品牌u   货号u   友商u   竞争)P526QV110Q811zR333-c1Q711AS131)r  r
  Fc           
           sdS t           fdt          D                       sdS d}t                                          D ]$\  }}t           fd|D                       r|} n%|sdS t          j                            t          d          }	 t          j                            |          }n# t          $ r d}Y nw xY wt                              |          }	|	r!|	                    d          |k    r|	d         S |r6|	r4|	                    d          |k    rt                              d	d           t          |         }i d}
t                      D ]}|d
         pddz   |d         pdz   t          fd|D                       s7|
dz  }
                                t                                           D ]!\  }}t          fd|D                       s"                    |dt%                      t%                      t%                      d          }|dxx         dz  cc<   |d         r:|st'          |d         ||          r!|d                             |d                    |d         r)|d                             |d         dd                    t*                              |g           D ]!}|v r|d                             |           "#sd||
fz  }nd}                                D ]'}|d         rt/          |d                   }||k    r|}(d||
|fz  g}t1          fd          D ]}|         }|d         r(d                    t1          |d                             nd}d                    t1          |d                   dd                   }|                    d||d         ||fz             d                     |          }||d!t          |<   |S )"u   主题竞品扫描：问题命中「业务主题 + 竞品意图」时，全量扫描活动提取竞品品牌+货号（非超管过滤客户名）r>   c              3       K   | ]}|v V  	d S Nr   r   krV   s     r   	<genexpr>z,_search_topic_competitors.<locals>.<genexpr>  s'      99qH}999999r6   Nc              3       K   | ]}|v V  	d S r$  r   r%  s     r   r'  z,_search_topic_competitors.<locals>.<genexpr>  s'      **qH}******r6   r   r   mtimesummaryr   r4    r   c              3       K   | ]}|v V  	d S r$  r   )r   r&  r   s     r   r'  z,_search_topic_competitors.<locals>.<genexpr>  s'      **19******r6   r$   c              3   D   K   | ]}|                                 v V  d S r$  lower)r   altls     r   r'  z,_search_topic_competitors.<locals>.<genexpr>  s0      ::BrxxzzR'::::::r6   )r`   	customersdatesskusr`   r   r2  rH   r3  
   r4  uT   【%s主题竞品扫描】相关活动 %d 条，未发现明确竞品品牌提及。u?   【%s主题竞品扫描（相关活动 %d 条，最新 %s）】c                 "    |          d          S )Nr`   r   )x
brand_stats    r   <lambda>z+_search_topic_competitors.<locals>.<lambda>  s    :a=3I2I r6   key   、u   未记录货号   u0   - %s：提及 %d 次；货号：%s；客户：%s
)r)  r*  )any_COMPETITOR_INTENT_TOPIC_KEYWORDSr   r   r   r   r)   getmtimer   _TOPIC_COMPETITOR_CACHEr2   r   r:   r   r/  _COMPETITOR_BRANDSrS   r   _name_visibleadd_COMPETITOR_SKUSvaluesmaxsortedrT   )rV   vcustvgroupsis_admintopictkwsru   r)  c
topic_actsr   bmainaliasesstr   r*  maxdater   linesr   r4  r   r8  r   r1  s   `                      @@@r   _search_topic_competitorsrX    s    r9999&899999 rE!''))  3****c***** 	EE	  r
X:;;A  ##   ##E**A QUU7^^u$$| * *quuW~~..lD)))
%
 CJJ ( (&	R3&!F)/r:****c***** 	a
ZZ\\06688 	( 	(NE7::::'::::: &&uX[X]X]gjglgl.m.mnnBwKKK1KKK} 3( 3mAjM5RY.Z.Z 3;##AjM222y 07&	#2#///'++E266 ( ($;;vJNN3'''(	(  #hlqs}k~~##%% 	  	 B'{  7$$w;;GRV[]gipUqqr
(I(I(I(IJJJ 	m 	mAAB57ZV5::fRZ00111EVDJJvbo66rr:;;ELLKqRTU\R]_cejNkkllll))E""/4%I%IE"Ns   B5 5CCc                    %  sdS t                     }g }t                      }g }|D ]}|s |d         rt          |d         ||          s$|d         dz   |d         z   dz   |d         z   %d}	|d         rt          |d                    rd}	n@|rt	          %fd|D                       rd	}	n |d         rt          |d                    rd
}	|	r|                    |	|f           |rAt                      }
g }|D ]`\  }	}|d         |d         z   |d         z   |d         dd         z   }||
vr,|
                    |           |                    |	|f           a|                    d d           |                    d d           d |D             dd         }dt          |          z  g}|D ]L}|                    d|d         d|d         d|d         d|d         d|d         dd         
           M|                    d
                    |                     |rt                      }g }|D ]}|                    d          d         }|                                D ]Y\  }}||k    s2|                    |dz             s|r4|                    |dz             r|                    |d|            nZt          t                               |                    dd         }|r+|                    d d
                    |          z              	 g }t$          j        
                    t(          d!          }t$          j                            |          rt-          |d"#          5 }t/          j        |          }ddd           n# 1 swxY w Y   |                    d$g           pg D ]b}|                    d%g           pg }|                    d&d          pddz   |                    d'd          pdz   dz   d
                    |          z   dz   d
                    |                    d(g           pg           z   }t	           fd)|D                       }|st          |           r|                    d*i           pi }|                    d+|                    d&d          d,|                    d-d          d.|                    d/d          d0d1
                    |                    d(g           pg                      dt$          j        
                    t(          d2          }t$          j                            |          rt-          |d"#          5 }t/          j        |          }ddd           n# 1 swxY w Y   |                    d3g           pg D ]}|                    d4d          pd} | rt          |            rqd5 |                    d6g           pg D             }!|!rM|                    d7| d8|                    d9d          d:d;
                    |!dd<                              |r3|                    d=d
                    |dd                   z              n# t4          $ r Y nw xY w	 t7           |||          }"|"r|                    |"           n# t4          $ r Y nw xY w	 t9           g           }#|#r|                    |#           n# t4          $ r Y nw xY w	 t;           g           }$|$r|                    |$           n# t4          $ r Y nw xY w|rd>
                    |          ndS )?uu   按问题检索相关背景（飞书活动 + 产品），返回背景文本。非超管按可见名单过滤活动。r>   r   r+  r4   r   r   r   c              3       K   | ]}|v V  	d S r$  r   )r   shays     r   r'  z%_search_background.<locals>.<genexpr>  s'      11q!s(111111r6   r   r$   rH   N   c                 J    | d         d         pd                     dd          S )Nr$   rH   r>   -)r+   r7  s    r   r9  z$_search_background.<locals>.<lambda>  s#    1f!3 < <S" E E r6   Tr;  reversec                     | d         S Nr   r   r`  s    r   r9  z$_search_background.<locals>.<lambda>  s
    ! r6   c                     g | ]\  }}|S r   r   )r   r   r   s      r   r   z&_search_background.<locals>.<listcomp>  s    ###da###r6      u+   【飞书活动记录（最近 %d 条）】- [] u   ｜客户：u   ｜跟进人：r      ｜   r>  r_     ：r5  u   【相关产品】
zproduct_selling_points.jsonr   r   r   r4  product_linecategorycompetitorsc              3       K   | ]}|v V  	d S r$  r   )r   r[  rV   s     r   r'  z%_search_background.<locals>.<genexpr>  s'      ::qAM::::::r6   fabeu   【产品卖点】u   ｜定位：positionu   ｜优势：	advantageu   ｜竞品：r<  zpcr_lamp_selection.jsonr   projectc                 d    g | ]-}|                     d           |                     d d          .S )r   r>   r2   r   rs     r   r   z&_search_background.<locals>.<listcomp>  s;    hhh[\[`[`af[g[ghAEE%,,hhhr6   recommendedu   【选型推荐】   （methodu   ）→  /    u   【产品卖点/选型】


)r   r   rE  r   r?  rT   r   rF  sortr   r   r   splitr   
startswithr8   r   fromkeysr   r   r)   r   r   r   r   r2   r   rX  _selection_block_ls_catalog_block)&rV   rK  rL  rM  r4  partsr   matchedr   prioseenuniqr;  rW  r   plinesr[  baser&  rv   sp_linessp_file_f_spdru   _skus_hay_hit_fbsel_file_seldr   _proj_rec_tc_sb_lbr\  s&   `                                    @r   _search_backgroundr    sc	    r""DEDG & & 	AjM 	-*uV]2^2^ 	
mc!AfI-3ai?Z= 	/*xHH 	DD 	c1111D11111 	DDvY 	-aiBB 	D 	&NND!9%%% 'uu 	' 	'GD!F)a
m+ai7!F)CRC.HC$T1I&&&		EEt	TTT		nnd	333##d###BQB'>TJK 	S 	SALLL&			1V999a
mmmQwZZZ64C4R S S S STYYu%%&&& E 	 	A773<<?D

  166Q\\!c'226t6TTWZ@X@X6MMqqq!!"4555EdmmF++,,SbS1 	ELL/$))F2C2CCDDD',,x)FGG7>>'"" 
	Qg000 %By}}% % % % % % % % % % % % % % %XXj"--3 Q Qfb))/Rnb117R3>!%%
TVBWBWB][]^addgjgogopugvgvvy||  @C  @H  @H  IJ  IN  IN  O\  ^`  Ia  Ia  Ig  eg  @h  @h  h::::E::::: Q-dH== Q%%++1rCOOOnb1111155R3H3H3H3H#''R]_aJbJbJbJbdidndnopotot  vC  EG  pH  pH  pN  LN  eO  eO  eO%P Q Q Q7<<*CDD7>>(## 	Dh111 &R	"& & & & & & & & & & & & & & &ii,,2 D Dy"--3 D/x@@ DhhrvvmR7P7P7VTVhhhD D PUPUPUWYW]W]^fhjWkWkWkWkmrmwmwx|}~}  yA  nB  nB  nB  )C  D  D  D 	RLL68BQB<9P9PPQQQ   '%(KK 	LL   x,, 	LL   "-- 	LL   !&.6;;uB.s   ,AZ N%Z %N))Z ,N)-GZ V"Z "V&&Z )V&*C.Z 
Z&%Z&*)[ 
[! [!%'\ 
\\'] 
]]c                     	 t           j                            d          pQt          t           j                            d          d                                                                          } t           j                            d          pQt          t           j                            d          d                                                                          }| |fS # t          $ r Y dS w xY w)u*   读取 IMA 凭证（client_id + api_key）IMA_OPENAPI_CLIENTIDz~/.config/ima/client_idr   r   IMA_OPENAPI_APIKEYz~/.config/ima/api_key)r>   r>   )	r   environr2   r   r   r   readstripr   )cidr;  s     r   _load_ima_cfgr  ;  s   jnn344  MRW=O=OPi=j=ju|8}8}8}  9C  9C  9E  9E  9K  9K  9M  9Mjnn122  Id27;M;MNe;f;fqx6y6y6y6~6~  7A  7A  7G  7G  7I  7ICx   vvs   C%C( (
C65C6z,fwEO41E0Ef0CfulmtQHYgYQy_jBsbl6tXE5x6VYLIoA=z,lofJ7cHGhLIvU_ISjQ0tmdYkgzvfjhvZrfVaoo4s7Jc=   知识库-copilotzkb_index.jsonrf  i  r   i(#  T)r)  r-   >'      业务   产品   会议   信息   制度   培训   工作   市场   总结   战略   支持   文档   服务   标准   模板   流程   清单   知识   管理   规范   计划   资料   销售   需求r   r   r   r      报告r      方案r   r   r   r   r   r   r   r   c                     	 t           j                            t                    } n# t          $ r Y dS w xY wt
          d         t
          d         | k    rg	 t          t          d          5 }t          j        |          t
          d<   ddd           n# 1 swxY w Y   | t
          d<   n# t          $ r Y dS w xY wt
          d         S )uE   读 kb_index.json（按 mtime 缓存，改索引不用重启服务）Nr-   r)  r   r   )
r   r   rB  KB_INDEX_FILEOSError_KB_IDXr   r   r   r   )mr   s     r   _load_kb_indexr  [  s   G]++   ttv''"2a"7"7	mg666 /!"&)A,,/ / / / / / / / / / / / / / / GG 	 	 	44	6?sB   $' 
55B, -B
B, BB, BB, ,
B:9B:c                 2   |                      d          pd}|r%t          j                            t          |          n9t          j                            t
          |                      d          pd          }d}	 |                                                    d          r7ddl}d                    d |	                    |          D                       }n>t          |d	d
          5 }|
                                }ddd           n# 1 swxY w Y   n# t          $ r t          j                            t
          |                      d          pd          }|rt          j                            |          r	 |                                                    d          r7ddl}d                    d |	                    |          D                       }n>t          |d	d
          5 }|
                                }ddd           n# 1 swxY w Y   n# t          $ r Y Y dS w xY wY dS Y nw xY w|dS |                    d          rE|                    dd          }d|cxk     rdk     r"n n||dz   d                                         }|S )um   读条目正文：优先 PDF 文本缓存 → 转卡层/普通 md 直读 → pymupdf 兜底；剥掉 YAML 头cacher>   content_pathN.pdfr   r>  c              3   >   K   | ]}|                                 V  d S r$  get_textr   pgs     r   r'  z!_kb_entry_text.<locals>.<genexpr>v  s*      DDbBKKMMDDDDDDr6   r   ignore)r   errorsc              3   >   K   | ]}|                                 V  d S r$  r  r  s     r   r'  z!_kb_entry_text.<locals>.<genexpr>  s*      #N#NbBKKMM#N#N#N#N#N#Nr6   z---z
---r   i  r|  )r2   r   r   r   ROOTKB_DIRr/  endswithpymupdfr   r  r   r   r  findlstrip)entryrelru   txtr  r   altends           r   _kb_entry_textr  n  s   
))G


"C#&aT3BGLL>AZAZA`^`,a,aA
C7799f%% 	NNN))DDGLLOODDDDDCCa'(;;; qffhh                 gll6599^#<#<#BCC 	27>>#&& 	99;;''// '"NNN))#N#NGLL<M<M#N#N#NNNCCcGHEEE 'ffhh' ' ' ' ' ' ' ' ' ' ' ' ' ' '   rrr 22 {r
~~e )hhw""s>>>>T>>>>>cAghh-&&((CJs   <A0D ,DD DD DD A&H6A0H1HHH	HH	HH6
H-(H6,H--H65H6c                    |                      d          p|                      d          }t          j                            t          |                      d          pd          }|                      d          r+t          j                            t
          | d                   n|}	 t          j                            |          t          j                            |          z   }n# t          $ r Y dS w xY wt                               |          }|r|d         |k    r|d         S t          |           }||ft          |<   |S )uL   按 mtime 缓存正文，供正文级全文匹配（修「文件名墙」）idr  r>   r  r   r$   )
r2   r   r   r   r  r  rB  r  _KB_TEXT_CACHEr  )r  r;  srcru   r  rQ  rO  s          r   _kb_bodyr    s   
))D//
6UYY~66C
',,vuyy88>B
?
?C.3ii.@.@IT5>***cAGQ"'"2"23"7"77   rr3A QqTQYYtuAa&N3Hs   (?C( (
C65C6>@      一下   一个   一些   一般   不过   主要   什么   介绍   他们   以及   但是   你们   做什   关系   具体   内容   可以   告诉   哪个   哪些   因为   多少   大概   如何   如果   就是   帮忙   帮我   怎样   情况   我们   或者   所以   整体   是否   没有   知道   能做   请问   谢谢   还有   这个   这些   这种   那个   那些   需要   非常   麻烦	   为什么	   什么样	   好不好	   干什么	   怎么办	   怎么样	   是不是	   是什么	   有哪些	   有没有	   行不行   怎么样做   能做什么r      相关c                   	
 | pd}dD ]}|                     |d          }g t                      c
		
fd}t          j        d| pd          D ]} ||           t          j        d|          D ]}|                                }|st          j        d|          rt          |          dk    r ||           Mt          |          d	k    r ||           l ||d
d                    dD ]H}t          t          |          |z
  dz             D ]#}||||z            }|t          vr ||           $Iˉ
d
d         S )uj   查询词：中文整块 + 2/3 字子词（解「整句拼词拼不中」），英文≥3 字，SKU 单列r>   u   的了和与跟是有在把被让向从对这将那更很都也还再又或并及等而之其吗呢吧啊哦嗯些怎么什啥哪呀哇唉r+  c                     |                                  } t          |           dk     s| v s	| t          v rd S                     |                                |            d S )Nr   )r  r   KB_STOP_WORDSrF  rT   )rO  r  termss    r   rF  z_kb_terms.<locals>.add  sX    GGIIq66A::da=&8&8FQr6   z [A-Z]{1,6}\d{2,6}(?:-[A-Z0-9]+)?z[^0-9A-Za-z\u4e00-\u9fff]+z[0-9A-Za-z]+r   r|  Nr=  )r   r   r$      )
r+   r   r   r   r  r  	fullmatchr   r   r"  )queryrawchrF  r  toknr   r   r  r#  s            @@r   	_kb_termsr+    s   
+2C [ # #kk"c""ceeKE4      Z;U[bII  Ax5s;; ! !iikk 	<-- 	3xx1}}Cs88q==CHHHHCBQBLLL ! !s3xx!|a/00 ! !AaAg,C-//C!!
 ":r6   c                    t          t          |          d          }i }| D ]}|                                }d}|                                D ]}||v r|dz  }|t	          |          z  }|dk    rdn|dk    rdn	|dk    rdnd	}	|	dd
t          dt          t          |          dz
  d                    z  z   z  ||<   |S )uy   正文级 IDF：全库都出现的词（原料/产品）≈0，稀有词（海藻糖/冻干）权重高；长词更具体r$   r   g{Gz?      ?g{Gz?g333333?g      ?333333?g333333?gQ?r      )rI  r   r/  rH  floatmin)
r#  bodiesr*  r#   rO  r1  dfr  ratior  s
             r   _kb_weightsr5    s    CKKA
A 	@ 	@WWYY==?? 	 	CSyyaU1XX}}$##!TMMSSt 	sTC3s1vvz1+=+=$>$>>>?!Hr6   c                    |                      d          pd                                }d                    |                      d          pg                                           }d                    |                      d          pg                                           }|                      d          pd                                }|pd                                }|dz   |z   dz   |z   dz   |z   dz   |z   fd|D             }	|	sdg fS g t          |	t          d	
          D ]2t          fdD                       s                               3dg }}
t          |	t          d	
          D ]}|                     |d          }|v rdnd}d}||v r|
d|z  |z  z  }
d	}||v r|
d|z  |z  z  }
d	}||v r|
d|z  |z  z  }
d	}||v r|
d|z  |z  z  }
d	}|r||v r|
d|z  |z  z  }
d	}|r|                    |           |sdg fS fd|D             }t	          |          }|
d|z  z  }
|dk    r|
dz  }
|                      d          s|
dz  }
|                      d          r|
dz  }
|rV|
t          dt	          |          dz            z  }
t	          |          dk    r |t	          |          dz  z  }|dk     r|
d z  }
|
|fS )!up   字段层级评分（标题>路径>关键词>摘要）+ 正文命中 + 概念级覆盖广度；零命中返回 0titler>   r+  pathskeywordsr*  c                     h | ]?}t          |          d k    |                                v +|                                @S )r   )r   r/  )r   rO  r\  s     r   	<setcomp>z_kb_score.<locals>.<setcomp>  sA    LLLQ3q66Q;;17799;K;Kqwwyy;K;K;Kr6           Tra  c              3       K   | ]}|v V  	d S r$  r   )r   rQ  rO  s     r   r'  z_kb_score.<locals>.<genexpr>  s'      ))a16))))))r6         ?r-  皙?F         r|  r=  c                     g | ]}|v |	S r   r   )r   r<   covers     r   r   z_kb_score.<locals>.<listcomp>  s    ***!qEzzAzzzr6   g      @r$   g?autor   in_text_layerg      @g     L@i N       @g?)r2   r/  r   rJ  r   r?  rT   r1  )r  r#  weightsbodyr7  r8  rP  summblr  scorehitsr1  wtr   gotr  densrD  r\  rO  s                     @@@r   	_kb_scorerQ    sq   YYw%2,,..EHHUYYw''-2..4466E
((599Z((.B
/
/
5
5
7
7CIIi  &B--//D
*"				B
#+

#c
)C
/$
6
<r
ACLLLL%LLLG Bw EGd333  ))))5))))) 	LLOOOr4EW#t444  [[S!! ;;CCC;;R"Wq[ EC;;R"Wq[ EC99QVaZEC::QVaZEC 	"((QVaZEC 	KKOOO Bw****t***Dt99D	S4ZEqyy99V 
yy!! 
	 S#b''G+,,,r77U??3r77W,-Dczz$;r6   c                  D   dt           v rt           d         S i i }} 	 t          t          j                            t
          d          d          5 }t          j        |          }d d d            n# 1 swxY w Y   |                    d          pg D ]4}|                    d          r|| |d         	                                <   5d |                    d          pi 
                                D             }n# t          $ r Y nw xY w| t           d<   |t           d	<   | S )
Nr   zproduct_master.jsonr   r   r4  r   c                 @    i | ]\  }}t          |          d k    ||S )r=  r   r   r&  rv   s      r   
<dictcomp>z(_load_product_master.<locals>.<dictcomp>/  s*    RRRtq!c!ffPQkkakkkr6   
name_indexni)	_PM_CACHEr   r   r   r   r)   r   r   r2   upperr   r   )r   rX  r   r   r   s        r   _load_product_masterr[  %  s[   
i~rA"',,x)>??'RRR 	VW	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	v$" 	( 	(AuuU|| (&'!E(..""#RRl 3 3 9r@@BBRRR   IcNIdOHs6   4C< A1%C< 1A55C< 8A59BC< <
D	D	c                     ddl }t          |                    d          at                              | pd                                          S )uN   提取宝锐货号：E02-15 / AS33-B10T / 2FM091 / BR1D301-01 / FE03 / AS16-25r   NzL\b\d?[A-Z]{1,4}\d{1,5}(?:[A-Z]{1,3}\d{1,5})*(?:[-.][A-Za-z0-9]{1,10}){0,3}\br>   )r   _SKU_TOKEN_REcompiler   rZ  )r   _res     r   _find_sku_tokensr`  7  sJ    $stt  $*"!3!3!5!5666r6   c           	      <   t                      }|sdS g t                      }}t          |           D ]}|                    |          }|r
|d         |v r%|                    |d                    d|d         z  d|d         z  g}|                    d          r|                    d|d         z             |                    d          r|                    d	|d         z             |                    d
          r|                    d|d
         z             |                    d          r|                    d|d         z             |                    d          r|                    d|d         z             |                    d          pg }|rD|                    dt          |          d                    d |D                       fz             |                    d                    |                     t                              d          pi }| pd}	d}
t          |
                                d           D ]\  }}||	v rg }|dd         D ][}|                    |                                          pi }|                    |d|                    d          pdd           \|                    d|dd                    |                     |
d z  }
|
d!k    r nd                    |dd"                   S )#uR   货号/产品名直查产品主数据；命中返回可引用文本块，否则 ''r>   r   u   【产品主数据｜%s】u   - 产品名称：%sr4   specu   - 规格：%scatu   - 销售品类：%slife_monthsu   - 有效期：%s 个月	bom_groupu   - 物料类型：%sproducedu   - 是否已转产：%s
componentsu   - 组分(%d)：%s   ；c              3      K   | ]I}|                     d d          d|                     dd          |                     dd          V  JdS )r4   r>   r+  volunit2Nru  r   r7  s     r   r'  z"_product_lookup.<locals>.<genexpr>X  s       Bd BdZ[QUU62....eR0@0@0@!%%QSBTBTBTUBd Bd Bd Bd Bd Bdr6   r>  rX  r   c                 .    t          | d                    S rd  rT  rO  s    r   r9  z!_product_lookup.<locals>.<lambda>^  s    c!A$iiZ r6   r:  NrA  ry  u   规格未标注   ）u   【产品主数据｜u   】
- 货号规格：r$   r   r|  )r[  r   r`  r2   rF  rT   r   r   rY  rJ  r   rZ  )r&  r   outr  rQ  r   lncpsrX  rM   hit_nmnmr4  infosks                  r   _product_lookuprw  @  sY   A rCEECe$$ " "EE!HH 	AeH$$5*QuX57LqQWy7XY55== 	3IIo&	122255<< 	8II+ah677755 	DII/!M2BBCCC55 	>II+an<===55 	@II.:>???eeL!!'R 	fII)SXXuzz Bd Bd_bBd Bd Bd 8d 8d -e e f f f

499R==!!!!	t			"BAF288::+?+?@@@ 	 	D77D3B3i U UEE"((**%%+BBBf0RAR0R0RSTTTTJJJBBBPUPZPZ[_P`P`P`abbbaKF{{99S!Wr6   c           
        
 g g }}|                                  D ]Z}|                    d          r.|r,|                    d                    |                     |g}E|                    |           [|r(|                    d                    |                     g }|D ]

                                

st          
          k    r|                    
           B|                    
fdt          dt          
                    D                        |sg S fd|                    d           fd|d	|         D             }	|	p|d         gS )
uk   按标题切块 → 按命中密度排序 → 取前 per_file 段（替代旧版「整篇前 1500 字」）#r>  c              3   2   K   | ]}||z            V  d S r$  r   )r   r   r   sizes     r   r'  z_kb_chunks.<locals>.<genexpr>~  s/      GG11QX:GGGGGGr6   r   c                 >   |                                  }d}D ]_}t          |          dk     r|                    |                                           }|r ||r                    |d          ndz  z  }`|t	          t          |           dz  d          z  |fS )Nr<  r   r>  r-  g      y@r?  )r/  r   r`   r2   rI  )rQ  clr*  r#   r&  rH  wordss        r   rP  z_kb_chunks.<locals>.dens  s    WWYY 	C 	CA1vvzz##A CQA'++a---cBBCA,,,a00r6   Tra  c                 >    g | ]} |          d          dk    |S )r$   r   r   )r   rQ  rP  s     r   r   z_kb_chunks.<locals>.<listcomp>  s*    <<<ATT!WWQZ!^^a^^^r6   N)	
splitlinesr  rT   r   r  r   extendr   r~  )r   r~  r{  per_filerH  blockscurrq  unitspickedr   rP  s    `` `     @@r   
_kb_chunksr  k  s   bCFoo  == 	# 	MM$))C..)))$CCJJrNNNN
 &diinn%%%E H HGGII 	q66T>>LLOOOOLLGGGGGaQ0F0FGGGGGGG 		1 	1 	1 	1 	1 	1 
JJ4J&&&<<<<yy)<<<FeAhZr6   r   c                    ddl }ddl}| sdS t          |           }t          |           D ]}||vr|                    |           |sdS g }t                      \  }}|r`|r]dk    rt          nt          }		 t          j	        
                    dt          j        |	|d         dd                              d          ||dd	d
          }
t          j	                            |
d          5 }t          j        |                                                    d                    }ddd           n# 1 swxY w Y   |                    d          pi                     d          pg D ]B}|                    d          pd                                }|r|                    |           Cn# t(          $ r Y nw xY wt*          j                            t0          d          }g }t3                      }|r	 fd|                    d          pg D             }i }|D ]9}t5          |                                          ||                    d          <   :t9          ||          }g }|D ][}t;          ||||                    |                    d                              \  }}|dk    r|                    |||f           \|                    d            t?                      dt?                      df\  }}}}|D ]\  }}}|t@          k    s|tB          k    r ng|                    d          }|r||v r<|r|"                    |           |dz  }t5          |          }|sjtG          ||p||          }tI          |          dk    } tK          |          D ]\  }!}"|"                                }"|"s|"dd         }||v r+|"                    |           | rd|!dz   z  nd}#|d         d         &                    dd          }$|                    d          r|$dz  }$|                    d |$|#d!d"                    |dd#                   pd$d%|"           |tI          |"          z  }|tB          k    r nn# t(          $ r Y nw xY w|sr	 g }%|dd&         D ]o}&|                    t*          j                            |d'd(|&z   d(z             d)*          D ]0}'|'|%vr*|''                    d+          s|%                    |'           1p|%dd&         D ]}'	 |''                    d,          r$tQ          |'d-                                          }nM|''                    d.          r7ddl)}(d/                    d0 |((                    |'          D                       }n|                    d t*          j        *                    |'          d%|dd1                    # t(          $ r Y w xY wn# t(          $ r Y nw xY wg })	 tW          |           }*|*r|)                    d2|*z              n# t(          $ r Y nw xY w|r=|)                    d3d/                    d4 |dd&         D                       z              |r+|)                    d5d6                    |          z              |)rd6                    |)          ndS )7uc   检索 IMA 知识库（索引层标题）+ 本地知识库（kb_index.json 索引 + 卡片切块）r   Nr>   r	   z3https://ima.qq.com/openapi/wiki/v1/search_knowledge)knowledge_base_idr&  cursorr   application/json)zima-openapi-clientidzima-openapi-apikeyContent-TypePOSTr-   headersrz  rf  timeoutr-   	info_listr7  r  c                 V    g | ]%}t           r|                    d           ddfv #|&S )lineu   公用r
   )KB_STRICT_LINEr2   )r   r   r  s     r   r   z*_search_knowledge_base.<locals>.<listcomp>  sK     _ _ _Q-_3455==XtU[D\3\3\ 3\3\3\r6   entriesr  c                     | d          S rd  r   rn  s    r   r9  z(_search_knowledge_base.<locals>.<lambda>  s    qte r6   r:  	dup_groupr$   )rH  x   u	    第%d段r8  u   _文本层/rE  u   （自动转卡）u   【u   ｜命中：r<  r|  u   —u   】
r=  z***T)	recursivez	.DS_Store.mdr   r  r>  c              3   >   K   | ]}|                                 V  d S r$  r  r   ru   s     r   r'  z)_search_knowledge_base.<locals>.<genexpr>  s*      'O'O

'O'O'O'O'O'Or6   i  u1   【产品主数据（权威，优先采信）】
u    【IMA 知识库相关材料】
c              3   0   K   | ]}d |dd         z   V  dS )- NrF   r   r   rO  s     r   r'  z)_search_knowledge_base.<locals>.<genexpr>  s/      DgDgWXTAcrcF]DgDgDgDgDgDgr6   u   【本地知识库内容】
r}  ),r   globr+  r   rT   r  	IMA_KB_LSIMA_KB_DIAGurllibrequestRequestr   dumpsencodeurlopenloadsr  decoder2   r  r   r   r   r   r  r  r  r/  r5  rQ  r~  r   KB_TOP_N	KB_BUDGETrF  r  r   	enumerater+   r  r   r  basenamerw  )+r&  r  r_  _glob
core_wordsrv  titlesr  r;  kbreqrw  r   r   rO  kb_dircontent_partsidxvisibler2  r   rH  scoredr[  rM  usedrL   seen_dupr  dgr  chsmulticir(  segr   r  kwfpr  r  _pms+    `                                         r   _search_knowledge_baser    s4    r5!!JE"" " "Zb!!! rFHC
 s $,,YYK	.((EZb:a=\^ _ _``gghopp14Castt	 )  C
 ''Q'77 91Jqvvxxw77889 9 9 9 9 9 9 9 9 9 9 9 9 9 9uuV}}*//<<B % %VVG__*1133 %MM!$$$%  	 	 	D	 W\\$ 344FM


C
 /.	_ _ _ _3779#5#5#; _ _ _GF : :&.qkk&7&7&9&9quuT{{##!*f55GF 0 0#Az7FJJquuT{{<S<STT4q55MM1dA,///KKOOK,,,,/EE1ceeQ,>)D%6$  
4X%%)););EUU;'' ".. %LL$$$!qkk  d&8j'JJJC1'nn  FBB ! TcT(Cd{{ HHSMMM6;C;"q&11CgJqM11-DDEuuV}} 6!55!(((,1E333

488L8L8UPU8U8UWYWY*[ \ \ \SWW$E	)) * 	 	 	D	 	G !n + +**RW\\&$b3%O%O[_*`` + +B(([1I1I(r***+ bqbk  
{{5)) !"2888==??V,, !&"ii'O'Ogll2>N>N'O'O'OOO !(((27;K;KB;O;O;O;OQTUZVZUZQ[Q[)\]]]]    H  	 	 	D	Ee$$ 	ULLMPSSTTT    i8499DgDg\bcedece\fDgDgDg;g;gghhh S4v{{=7Q7QQRRR!&.6;;uB.s   :A7F2 1:D7+F2 7D;;F2 >D;?A2F2 2
F?>F?;JR 
RR$BX -BW42X 3A W43X 4
X>X  XX 
XX)Y 
YYc                 b   | pd                                 }|sdS d|v rWd|v rS|                    d          }|                    d|          }||k    r|d|         ||dz   d         z   }nnd|v rd|v Sd|v rWd|v rS|                    d          }|                    d|          }||k    r|d|         ||dz   d         z   }nnd|v rd|v SdD ]R}|                    |          r;t          |          t          |          z
  d	k    r|dt          |                    }Sd
}|rd}dD ]~}|                    |          rgt          |          t          |          z
  d	k    rD|dk    r$t          |          t          |          z
  dk     rd|dt          |                    }d
}||S )uY   提取客户核心词：去括号 + 去公司/科技/生物等后缀，保留至少 2 字r>   ry  ro  Nr$   ())u   股份有限公司u   有限责任公司u   有限公司r   r   r   TF)
r   r   r   r   r   r   r   r   r   r   r   r   )r  r  r  r   )r4   r[  r   r   sufchangeds         r   
_cust_corer    s   	A r
1**!FF5MMqvveQ//1q55"1"!a%&&	!AA 1**! ((saxxFF3KKQVVC^^q55"1"!a%&&	!AA ((saxx `  ::c?? 	s1vvC0A55*CHH9*A G
 w 	 	Czz# 3q66CHH#4#9#9(??s1vvC'81'<'<jCyjM   Hr6   c                  ^   t           t           S g } 	 t          t          j                            t
          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                    r|
                    dg           n|}|D ]x}t          |t                    r|
                    d          nt          |          }|r;t          |          }|r*t          |          dk    r|                     ||f           yn# t          $ r Y nw xY w| a | S )uC   加载 mcp_customers.json 客户名 → 核心词映射（缓存）Nmcp_customers.jsonr   r   r2  r4   r   )_MCP_CUST_CORESr   r   r   r   r)   r   r   r   r   r2   r   r  r   rT   r   )coresr   r   r   rQ  r4   cores          r   _load_mcp_customer_coresr  2  so    "E"',,x)=>>QQQ 	UV	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	*4Q*=*=Dk2&&&1 	/ 	/A$.q$$7$7C155===SVVD /!$'' /CIINNLL$...	/    OLs6   4D A'D 'A++D .A+/B+D 
D('D(c                    | sdS t                      }d\  }}|D ]/\  }}|r(|| v r$t          |          |k    r|t          |          }}0|r|S |D ]O\  }}|st          ||           }t          |          dk    r$t          |          |k    r|t          |          }}P|r|S |D ];\  }}|r4t          ||           r$t          |          |k    r|t          |          }}<|S )uc   从问题中识别客户名，返回客户全名或空串（最长核心词优先，支持简称）r>   r>   r   r   )r  r   r   r   )rV   r  bestbest_lenr4   r  lcss          r   _identify_customerr  H  s0    r$&&END( - -
d 	-DH$$TX)=)=!3t99(D  , ,
d 	'h77s88q==SXX00!3s88(D  - -
d 	-&tX66 	-3t99x;O;O!3t99(DKr6   c                    | sdS t          |           }|pg D ]R}t          |t                    r|                    d          pdnt	          |          }|r|| k    s
|r||v s||v r dS S|pg D ]R}t          |t                    r|                    d          pdnt	          |          }|r|| k    s
|r||v s||v r dS SdS )u~   判断客户名是否在可见名单内（vcust: 客户, vgroups: 课题组）。用于非超管背景检索的权限过滤。Fr4   r>   T)r  r   r   r2   r   )r4   rK  rL  r  rQ  cnr   gns           r   rE  rE  d  s     udDkr  &0D&9&9EaeeFmm!rs1vv 	2::$:DBJJ"**44m  &0D&9&9EaeeFmm!rs1vv 	2::$:DBJJ"**445r6   c                     t          |           }|sdS t          |            sdS |st          |||          sdS ddlm} g }	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y    fd|                    d	          pg D             }	|	rt          d
 |	D                       }
 |d |	D                       }dt          |	          |
dz  fz  g}|                    dd                    d |                    d          D                       z              d |	D             }|r|                    dt          |          z             t#          |d d          dd         D ]}|                    d          pi }|                    d|                    dd          d|                    dd          d|                    d          pddd         d |                    d!d          d"|                    d#d          d|                    d$d%                     |                    d&                    |                     n# t$          $ r Y nw xY w	 t          t          j                            t          d'          d          5 }t          j        |          }ddd           n# 1 swxY w Y    fd(|                    d)          pg D             }|rd*t          |          z  g}|dd         D ]}|                    d+|                    d,d          d-|                    d.d          d/|                    d0d          d1|                    d2d          d|                    d3          pddd4         
           |                    d&                    |                     n# t$          $ r Y nw xY w	 t          t          j                            t          d5          d          5 }t          j        |          }ddd           n# 1 swxY w Y    fd6|                    d7          pg D             }|rd8t          |          z  g}|dd         D ]}|                    d9|                    d.d          |                    d3d          |                    d:          pddz  |                    d;          pddz  |                    d<          pddz  |                    d=          pddz  |                    d>          pddz  fz             |                    d&                    |                     n# t$          $ r Y nw xY w fd?t'                      D             }|rt#          |d@ d          }dAt          |          z  g}|dd         D ]e}|                    d+|                    dBd          d-|                    d.d          d|                    dC          pdddD                    f|                    d&                    |                     	 t)          |dE          }|r|                    |           n# t$          $ r Y nw xY w	 t          t          j                            t          dF          d          5 }t          j        |          }ddd           n# 1 swxY w Y    fdG|                                D             }|rdHdIdJdKdL}dMg}|dd         D ]X}|                    d|                    |                    d3          dN          dO|                    d.d                     Y|                    d&                    |                     n# t$          $ r Y nw xY w	 t-          dP          pi }d}|                    dQ          pg D ]R}|                    d.          pd} r7 |v s/|                    dR          sn |                    dR          pdv r|} nS|r9|                    dS          pg }|rdT|                    d	d          z  g}|dd         D ]f}|                    dU|                    dVd          |                    d.          pdddW         |                    dX          pddz  fz             g|                    dY           |                    d&                    |                     |                    dZ          rC|                    d[d&                    d\ |dZ         dd]         D                       z              n# t$          $ r Y nw xY w	 t/          |          }|r|                    |           n# t$          $ r Y nw xY w	 t1          |          }|r|                    |           n|                    d^           n# t$          $ r Y nw xY w|sdS d_|z  d`                    |          z   S )au   识别问题中的客户名，拉取该客户 6 维全景（订单/客诉/商机/活动/知识库/材料）。每维失败降级。非超管按可见名单隔离。r>   r   )Counterzshipment_status.jsonr   r   Nc                 F    g | ]}|                     d           pdv |S r   r>   ru  r   or  s     r   r   z%_load_customer360.<locals>.<listcomp>  s5    ZZZzARARAXVX8Y8Y!8Y8Y8Yr6   ordersc              3   D   K   | ]}|                     d           pdV  dS )taxTotalr   Nru  r   r  s     r   r'  z$_load_customer360.<locals>.<genexpr>  s3      ??1quuZ((-A??????r6   c              3   n   K   | ]0}|                     d           pi                      d          pdV  1dS )shipmentstatusLabel	   无物流Nru  r  s     r   r'  z$_load_customer360.<locals>.<genexpr>  sG      eeYZ!%%
++1r66}EETeeeeeer6   u1   【订单/物流】%d 笔，价税合计 %.1f 万'  u	   状态：r<  c              3   *   K   | ]\  }}d ||fz  V  dS )z%s %dNr   rU  s      r   r'  z$_load_customer360.<locals>.<genexpr>  s/      1a1atq!'QF2B1a1a1a1a1a1ar6   r/  c                     g | ]l}d |                     d          pdv sOd|                     d          pdv s6|                     d          pddk    O|                     d          pddk    j|mS )r   
contractNor>   u   样品amountr   r  ru  r  s     r   r   z%_load_customer360.<locals>.<listcomp>  s     _ _ _aeeL>Q>Q>WUW1X1X\dijinino{i|i|  jC  AC  ]D  ]D uuX3!99quuZ?P?P?UTUZ[>[>[ >[>[>[r6   u"   【测试/样品订单】%d 笔：c                 0    |                      d          pdS )N
createDater>   ru  r`  s    r   r9  z#_load_customer360.<locals>.<lambda>  s    AEE,<O<O<USU r6   Tra  rf  r  r  r  ri  orderIdu
   ｜合同 r  r]  u
   ｜单号 
trackingNou
   ｜收件 	recipientr  r  r>  mcp_complaints.jsonc                 F    g | ]}|                     d           pdv |S r  ru  )r   r   r  s     r   r   z%_load_customer360.<locals>.<listcomp>  s5    XXXqdquuZ?P?P?VTV6W6W6W6W6Wr6   r   u   【客诉】%d 条rg  createdrh  r4   u   ｜紧急度 urgency
   ｜状态 statustype(   zopportunity_sandbox.jsonc                 F    g | ]}|                     d           pdv |S r  ru  r  s     r   r   z%_load_customer360.<locals>.<listcomp>  s5    ___aTaeeJFWFWF][]=^=^=^=^=^r6   opportunitiesu   【商机】%d 个u7   - %s｜%s｜目标 %.1f 万｜Q1-Q4 %.1f/%.1f/%.1f/%.1ftargetq1q2q3q4c                 F    g | ]}|                     d           pdv |S r  ru  )r   r   r  s     r   r   z%_load_customer360.<locals>.<listcomp>  s4    OOO!TaeeJ6G6G6M2-N-NA-N-N-Nr6   c                 0    |                      d          pdS )NrH   r>   ru  )r   s    r   r9  z#_load_customer360.<locals>.<lambda>  s    155==+>B r6   u   【近期活动】%d 条rH   r      r   zfile_manifest.jsonc                 F    g | ]}|                     d           pdv |S r4   r>   ru  )r   rv   r  s     r   r   z%_load_customer360.<locals>.<listcomp>  s2    HHHq$155==3FB*G*G*G*G*Gr6   	   拜访卡   市场调研卡u   来访接待u   调研报告)visitmarketvisitorreportu   【已有材料】u   文件rk  zcustomer_360.jsonr2  shorttop_productsu4   【用过的货号】累计 %s 单（主销结构）u   - %s｜%s｜%.1f 万r   2   amtud   → 判断要点：只买原料还是买体系、有无测试装转量产、品类结构是否单一risksu   【风险标记】
c              3   J   K   | ]}d t          |          dd         z  V  dS )z- %sNr  r   rv  s     r   r'  z$_load_customer360.<locals>.<genexpr>  s9      ?p?pZ[QPTQTPT@U?p?p?p?p?p?pr6   r|  uo   【工商背景】暂未获取（可粘贴天眼查内容到 AI 助手，说"存入客户档案"即可补充）u   【客户 360 全景：%s】

r}  )r  r  rE  collectionsr  r   r   r   r   r)   r   r   r2   sumr   rT   most_commonrJ  r   r   r  rH  _wf_json_todo_block
_tyc_block)!rV   rK  rL  rM  r   r  r  r   r   r  taxrU  rW  test_ordersr  shipr   r   oppsr   r   kb_bgr   labelscdrX   rQ  rt  tpsru   tbtyr  s!                                   @r   _load_customer360r$  t  s   h''D rdD r M$w?? r######E"',,x)?@@7SSS 	WX	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	ZZZZaeeHoo3ZZZ 	+???????Cee^deeeeeBHCPVKKY\_dYdKeefELLuzz1a1ar~~^_O`O`1a1a1a'a'aabbb_ _f _ _ _K WACDTDTTUUU1V1V`deeefhghfhi W WA55,,2DLLLlB////y"1E1E1E1E|,,2CRC888!%%b:Q:Q:Q:Qk2....0T0T0T"V W W W W LL5))***   "',,x)>??'RRR 	VW	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	XXXXQUU7^^1rXXX 	+)CJJ67E2A2Y F FEE)R((((!%%*;*;*;*;QUU9b=Q=Q=Q=QEE(B''''!%%--*=2ss)C)CE F F F F LL5))***   "',,x)CDDwWWW 	[\	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	____AEE/228b___ 	+)CII56E"1"X i iVEE&"%%quuVR'8'8UU8__)U2QUU4[[5EA4NUU4[[%A.t1AU0JQUUSW[[M]\]afLfZh h i i i i LL5))***    POOO'))OOOD 'd ? ?NNN+c$ii78bqb 	q 	qALLLQUU62->->->->fb@Q@Q@Q@QTUTYTYZ`TaTaTgegimjmimSnSnoppppTYYu%%&&&&tT22 	 LL   "',,x)=>>QQQ 	UV	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	HHHHAHHJJHHH 	+*6GTbn|}}F)*E2A2Y e eFJJquuV}}h,O,O,O,OQRQVQVW]_aQbQbQbcddddLL5))***   )**0b&&%%+ 	 	Av$"B g$155QX>>K_]_B`B` 
	r''.))/RC /ORURYRYZbdeRfRffgRaR d dALL!7eR((155==+>B*DquuU||GXWX\aFa;c "c d d d d  D  E  E  ETYYu--...www r3dii?p?p_bcj_klnmnln_o?p?p?p6p6ppqqq    	LL    	LLLLL  K  L  L  L    r-4v{{57I7IIIs%  4J :BJ BJ "B#G0J 
J! J!%4P K:.P :K>>P K>DP 
PP4V# 	Q*V# *Q..V# 1Q.2D0V# #
V0/V0'Z6 6
[[4_ ;\_ \  _ #\ $B:_ 
_,+_,0F9f* *
f76f7;&g" "
g/.g/3<h0 0
h=<h=c                 2    | pd}d|v rdS d|v rdS d|v rdS |S )u   部门归一化r>   u	   大客户u   大客户部u   拓展u   销售拓展部r   u   生命科学销售部r   )deptr   s     r   
_norm_deptr'    s@    
Aa~1}}  &&Hr6   c                    t                      }	 t          j                            t          dd          }t          |d          5 }t          j        |                              dg           }ddd           n# 1 swxY w Y   |D ]^}t          |                    dd                    | k    r5|                    d	d
          dk    r|
                    |d                    _n# t          $ r Y nw xY w|S )u!   返回某部门在职人员名单r   z_personnel.jsonr   r   	personnelNr&  r>   r  u   在职u   离职r4   )r   r   r   r   r)   r   r   r   r2   r'  rF  r   )my_deptnamesru   r   plr7  s         r   _dept_personnelr-    s6   EEEGLL9.?@@!g&&& 	3!1!!+r22B	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	% 	%A!%%++,,77AEE(H<U<UYa<a<a		!F)$$$	%    Ls6   7C) )A<0C) <B  C) B A$C) )
C65C6c                 t  	
 t                      \  }}|                     d          pd                                	|                     d          pd                                }|                     d          pd                                }|dv r||fS g g c|dk    rXd|v sd	|v sd
|v r!d	|v rd	nd
|v rd
nd

r
fd|D             n|nGt          t	          |                    fd|D             n	fd|D             	fd|D             t          	          }t          |                    d          pg           t          |                    d          pg           r$fd|D             z   fd|D             z   rfdD             fdD             fS )ui   按角色过滤可见客户/课题组（支持按人 extra_customers 追加 / blocked_customers 屏蔽）r4   r>   rolesalesr&  admingmmanagerr   u   浙江u   广东c                 F    g | ]}|                     d           pdv |S )regionr>   ru  )r   r   	region_kws     r   r   z%_visible_for_user.<locals>.<listcomp>%  s2    QQQQI!%%//:OR,P,Pq,P,P,Pr6   c                 l    g | ]0}|                     d           p|                     d          v .|1S salespersonr0  ru  )r   rQ  
dept_namess     r   r   z%_visible_for_user.<locals>.<listcomp>)  s?    ```1!%%*>*>*P!%%..U_)_)_Q)_)_)_r6   c                 p    g | ]2}|                     d           p|                     d          k    0|3S r9  ru  )r   rQ  r4   s     r   r   z%_visible_for_user.<locals>.<listcomp>,  s?    VVVqaeeM&:&:&LaeeGnnQU%U%U%U%U%Ur6   c                 J    g | ]}|                     d           pdk    | S )r0  r>   ru  )r   r   r4   s     r   r   z%_visible_for_user.<locals>.<listcomp>-  s2    GGGw)=2$(F(F1(F(F(Fr6   extra_customersblocked_customersc                 N    g | ]!}|                     d           pdv |v|"S r  ru  )r   rQ  extrarK  s     r   r   z%_visible_for_user.<locals>.<listcomp>4  s>    ___qaeeFmm.Are-K-KPQY^P^P^P^P^P^r6   c                 N    g | ]!}|                     d           pdv |v|"S r  ru  )r   r   rA  rL  s     r   r   z%_visible_for_user.<locals>.<listcomp>5  s>    fff1155==3FB52P2PUV^eUeUeQUeUeUer6   c                 F    g | ]}|                     d           pdv|S r  ru  )r   rQ  blockeds     r   r   z%_visible_for_user.<locals>.<listcomp>7  s2    JJJqaeeFmm&9r'%I%I%I%I%Ir6   c                 F    g | ]}|                     d           pdv|S r  ru  )r   r   rD  s     r   r   z%_visible_for_user.<locals>.<listcomp>8  s2    NNN!%%--*=2g)M)M1)M)M)Mr6   )r   r2   r  r-  r'  rp   r   )userr   r   r/  r&  permrD  r;  rA  r4   r7  rK  rL  s         @@@@@@@r   _visible_for_userrH    sX   '))ME6HHV"))++DHHV'..00DHHV"))++Df}NE7yd""D(8(8h$>N>N$,$4$4xSWGWGW88]_IU^jQQQQ&QQQQdjGG )D)9)9::J```````EE WVVVEVVVGGGGfGGG $D*++1r22E$((.//5266G g_____E____fffffffff OJJJJEJJJNNNNgNNN'>r6   z"customer_special_requirements.json)u   搭配规则u   配方/体系u   包装/标签u   交付/物流u   质检/文件u   价格/账期   其他c                     	 t          t          d          5 } t          j        |           }ddd           n# 1 swxY w Y   n'# t          $ r g t          t                    dcY S w xY wt          |t
                    r|t          t                    dS t          |                    d          t
                    sg |d<   |                    d          st          t                    |d<   |S )u3   加载全部特殊要求（不做权限过滤）。r   r   N)r   
categoriesr   rK  )	r   SPECIAL_REQ_FILEr   r   r   r8   SPECIAL_REQ_CATEGORIESr   r2   r   s     r   _load_special_reqsrN  D  s2   I"W555 		!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 I I I40F+G+GHHHHHI!T H$/E*F*FGGGaeeGnnd++ '
55 7566,Hs.   A 9A =A  =A !A)(A)c                 2   ddl m } |                                                    d          | d<   t          dz   }t	          |dd          5 }t          j        | |d	d
           ddd           n# 1 swxY w Y   t          j        |t                     | S )uL   原子写回特殊要求文件（先写 tmp 再 replace，防止写坏）。r   r@   %Y-%m-%dT%H:%M:%S
updated_atr"   r#   r   r   Fr   r%   N)	rA   rP   rR   rL  r   r   r*   r   r+   )r-   rA   r.   r   s       r   _save_special_reqsrR  T  s    !!!!!!!001DEED
V
#C	c3	)	)	) 9Q	$a88889 9 9 9 9 9 9 9 9 9 9 9 9 9 9Js$%%%Ks   A22A69A6c                 X    t          |           \  }}t          d |D                       S )uE   当前用户可见客户名集合（与客户档案同一口径）。c              3   n   K   | ]0}t          |t                    |                    d           pdV  1dS )r4   r>   Nr   r   r2   r   rQ  s     r   r'  z*_visible_customer_names.<locals>.<genexpr>b  s@      KKz!T7J7JKf#KKKKKKr6   )rH  r   )rF  rK  _vgs      r   _visible_customer_namesrX  _  s0    "4((JE3KKeKKKKKKr6   c                    t          | t                    rd | D             S t          | t                    r|                     dd                              dd                              dd                              dd          }g }|                    d          D ]D}|                                D ]-}|                                }|r|                    |           .E|S g S )uL   货号字段归一成 list（兼容字符串逗号/顿号/分号分隔）。c                     g | ]D}t          |                                          #t          |                                          ES r   r   r  rl  s     r   r   z!_fmt_sku_list.<locals>.<listcomp>h  s9    <<<1SVV\\^^<A<<<r6      ，,r<  rh  ;)r   r8   r   r+   r  r  rT   )rv   r[  rp  partr)  s        r   _fmt_sku_listr`  e  s    !T =<<<<<<!S IIeS!!))%55==eSIIQQRUWZ[[GGCLL 	$ 	$Dzz|| $ $iikk $JJsOOO$ 
Ir6   c                    t                      }|                    d          pg }t          |           }|                     d          pd                                }g }|D ]R}t	          |t
                    s|                    d          pd}||vr4|r||k    r=|                    |           Si }	|D ]B}|                    d          pd}|	                    |g                               |           Ci }
|D ]5}|                    d          pd}|
                    |d	          d
z   |
|<   6|t          |          t          |	          t          |	
                                          |
|                    d          pt          t                    t          |          ||dv |                    dd          d
S )uN   返回当前用户可见的特殊要求 + 统计信息（权限过滤后）。r   r/  r0  r   r>   u   未知客户rm  rI  r   r$   rK  )r2  r3  r4  rQ  )
r   rL   customer_countcustomers_with_reqby_categoryrK  visible_customersr/  can_manage_allrQ  )rN  r2   rX  r  r   r   rT   rS   r   rJ  keysr8   rM  )rF  r   r-   r   visr/  rp  r   r  by_cust	cat_countrQ  s               r   special_requirements_forrk  u  s   DHHW#E
!$
'
'CHHV'..00D
C  "d## 	VVJ%2S== 	h

2G . .VVJ1>2r""))"----I / /FF:*( }}Q**Q.	!Sg,,$W\\^^44 hh|,,L5K0L0L#C[["<<hh|R00  r6   c                    ddl m } t          |                    d          t                    r|                    d          n|}t          |t                    sdS |                    d          pd                                }|                    d          pd                                }|                    d          pd                                }|sd	S |sd
S t          |           }||vrdS t                      }|                    d          pg }	|                    d          pt          t                    }
|	                                
                    d          }|                    d          pd                                pd}||
vr|
                    |           |
|d<   |r&d}|	D ]4}t          |t                    r|                    d          |k    r|} n5|sdS |                    d          pd|vrdS |                    |||                    d          pd                                |t          |                    d                    |                    d          pd                                |                    d          p|                    d          pd||                     dd          d	           d}nd|	                                
                    d          t          d |	D                       dz   fz  }||||                    d          pd                                |t          |                    d                    |                    d          pd                                d|                     dd          ||d d!}|	                    |           d"}|	|d<   t          |           d#||fS )$u;   新增/更新一条特殊要求。返回 (ok, msg, item)。r   r@   item)Fu   参数错误Nr   r>   contentr  )Fu   请选择客户N)Fu   请填写特殊要求内容N)Fu3   无权操作：该客户不在你的客户范围内Nr   rK  rP  rm  rI  N)Fu'   记录不存在（可能已被删除）N)Fu   无权修改该记录Nr7  r4  noter  activer4   )	r   rm  r7  rn  r4  ro  r  rQ  
updated_byu	   已更新z
sr_%s_%03dz%Y%m%d%H%M%Sc                 <    g | ]}t          |t                    |S r   )r   r   rl  s     r   r   z,save_special_requirement.<locals>.<listcomp>  s'    $M$M$M1At9L9L$MQ$M$M$Mr6   r$   u   工作台录入)r  r   rm  r7  rn  r4  ro  r  
created_by
created_atrQ  sourceu	   已新增T)rA   r   r2   r   r  rX  rN  r8   rM  rP   rR   rT   updater`  r   rR  )rF  payloadrA   rm  r  rn  ridrh  r-   r   catsrP   rc  r  r   actionnewids                    r   save_special_requirementr|    s   !!!!!!",W[[-@-@$"G"GT7;;vWDdD!! +**
((:


$"	+	+	-	-Bxx	""(b//11G88D>>R
&
&
(
(C .-- :99
!$
'
'C	}}QQDHHW#E88L!!AT*@%A%AD
,,..
!
!"5
6
6C88J+8
2
2
4
4
@C
$C!\
 ( 	 	B"d## t(;(; 	JIIJJz""(b4477hhw''-24466!$((6"2"233XXf%%+2244hhx((LFJJx,@,@LH((62..

 

 
	 
	 
	  7 7 G G #$M$M$M$M$M N NQR R T T hhw''-24466!$((6"2"233XXf%%+2244((62..'
 
 	VDMtr6   c                    t          |           }t                      }|                    d          pg }t          |          D ]{\  }}t	          |t
                    ra|                    d          |k    rH|                    d          pd|vr dS |                    |           ||d<   t          |            dS |dS )u@   删除一条特殊要求（权限校验）。返回 (ok, msg)。r   r  r   r>   )Fu$   无权删除该客户的特殊要求)Tu	   已删除)Fu   记录不存在)rX  rN  r2   r  r   r   r:   rR  )rF  rx  rh  r-   r   r   r   s          r   delete_special_requirementr~    s    
!$
'
'CDHHW#E5!! % %2b$ 	%BFF4LLC$7$7z""(b44DDDIIaLLL!DMt$$$$$$##r6   u	   刘子研i@] ihS i؛r i`S )
join_monthfull_year_targetpre_join_targetpost_join_targetpre_join_actualc                     	 t          t          j                            t          |           d          5 }t          j        |          cddd           S # 1 swxY w Y   dS # t          $ r Y dS w xY w)uA   读工作流数据文件（失败返回 None，绝不抛异常）r   r   Nr   r   r   r   r)   r   r   r   )fnamer   s     r   r  r    s    "',,x//'BBB 	 a9Q<<	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	    tt4   4A$ A
A$ AA$ AA$ $
A21A2c                 v     sg S                       d          d          fd|pi D             }                    d          rdd         rdd         ndz   |fd|pi D             z  }t                      g }}|D ]0}||vr*|                    |           |                    |           1|S )un   货号变种展开：母体 → 同母体全部变种（规格后缀 / 批次后缀 / 冻干↔液体对应）r_  r   c                 P    g | ]"}|k    s|                     d z              |#S r_  r  )r   r&  r  r   s     r   r   z!_sku_variants.<locals>.<listcomp>  s2    
M
M
MSALL4L4L1r6   Fr$   Nc                 P    g | ]"}|k    s|                     d z              |#S r  r  )r   r&  pres     r   r   z!_sku_variants.<locals>.<listcomp>  s2    NNN!!s((all396M6M(A(((r6   )r  r  r   rF  rT   )	r   by_baseby_skurp  r  resr&  r  r  s	   `      @@r   _sku_variantsr    s     	99S>>!D
M
M
M
M
Mv|
M
M
MCs QRR 122hDjNNNN2NNNNCr#D  D==HHQKKKJJqMMMJr6   c                 <   t          d          pi }g }|                    d          pg D ]}| |                    d          p| gvr|                    d|                    dd          d|                    dd          d	|                    d
d          d|                    dd                     |                    d          pg D ]s}|                    d|                    dd          d|                    dd          d|                    dd          d|                    dd                     t|                    d          pg D ]}|                    d|z             |                    d          pg D ]Y}|                    d|                    dd          dd                    |                    d          pg                      Z|                    d          pg D ]}|                    d|z             |S ) uD   【当季促销】渲染为提示词行（含档位/赠品/合规）zpromo_campaigns.jsonprogramsrW  u   ★ r4   r>   ry  startu    至 r  u   ）｜目标：goaltiersz   tieru    → 赠品价值 valueu   ｜主推：mainu   ｜备选：r  boostersu      ▶ 加码机制：%spacksu      ▣ 打包方案·apprk  rh  r   
complianceu      ⚠ 合规：%s)r  r2   rT   r   )r  r   rp  ru   rO  r   pkrQ  s           r   _promo_linesr    se   '((.BA
CeeJ%2 1 1g04&11


EE&"quuWb11111553C3C3C3CQUU6SUEVEVEVX 	Y 	Y 	Y%%..&B 	] 	]AJJJfb!!!!155"#5#5#5#5quuVR7H7H7H7H!%%PUWYJZJZJZ\ ] ] ] ]%%
##)r 	7 	7AJJ1A5666655>>'R 	p 	pBJJJr9J9J9J9JEJJWYW]W]^eWfWfWljlLmLmLmnoooo%%%%+ 	1 	1AJJ+a/0000	1Jr6   c           
      b   t          d          pi }g }|                    d          pg D ]}|                    d          p|                    d          r	|d         gng }d|vr| |vr@|                    d|                    dd          d	|                    d
d                     |S )u6   【商务政策】促销期外的销售费用额度等zsales_policy.jsonpoliciesrW  r  r
   r  r7  r>   rk  rule)r  r2   rT   )r  r   rp  ru   rq  s        r   _policy_linesr  .  s    $%%+A
CeeJ%2 J JUU7^^EquuV}} D6"B


!%%"4"4"4"4aeeFB6G6G6GHIIIIJr6   r|  c                 j   g }| pg d|         D ]}t          |t                    r|                    d          pd}|                    d          pdfd|                    d          pg D             }|}|r#|dd                    |dd	                   z  z  }|                    d
          pdt	          fddD                       r|dz  }|                    |           |                    t          |                     d                    d |D                       S )uF   把 systems/systems_lyo 渲染成 ① MD2104-000812 / ② M2181 形式Npriorityr>   r   c                 $    g | ]}||k    
|S r   r   )r   r7  rv  s     r   r   z#_render_systems.<locals>.<listcomp>B  s#    GGG1GqBwwQwwwr6   r4  u   （搭%s）r}   r   r'  c              3       K   | ]}|v V  	d S r$  r   )r   r&  r'  s     r   r'  z"_render_systems.<locals>.<genexpr>G  s'      ::18::::::r6   )u   冻干u   原位u   ·冻干r{  c              3      K   | ]}||V  	d S r$  r   rl  s     r   r'  z"_render_systems.<locals>.<genexpr>L  s'      **A*a******r6   )r   r   r2   r   r?  rT   r   )	lstrf   rp  r[  ru   rA  r  r'  rv  s	          @@r   _render_systemsr  ;  sS   
CiR%   a 	j!!'RAu#BGGGGv!4"GGGEArr"C ;}sxxbqb	':':::%%,,$"C::::%9::::: "z!JJsOOOOJJs1vv::********r6   r   )r   r   asfasfvr  )r  u   猪繁殖与呼吸综合征prrsprrsvr  )r  pcvpcv2u	   猪圆环r   )r   csfcsfvu   古典猪瘟   腹泻)r  pedpedvr  u	   胃肠炎tgevu   轮状r   )r   aivh5h7h9u   禽流感病毒r   ndv   结核)r  mtbu   结核分枝杆菌r"  HPV)hpvu   人乳头瘤u	   宫颈癌HCV)hcvu   丙肝u   丙型肝炎HIVhivu   艾滋SNP)snpu   基因分型u   突变检测u   位点z	micro RNA)micrornamirnaz	micro rnau   小rna   熔曲)u   熔解曲线r  hrmu   熔解u   肠道-粪便直扩)u   直扩u   粪便直扩u	   免提取u   粗提u   粪便u   单管全预混)u	   全预混u   预混premixu   单管u   LAMP-染料法)lamp	   环介导   恒温扩增u   染料)r  r  r  u   探针)u   公卫u	   呼吸道u   流感rsvu	   腺病毒u   诺如)r   u   猪病u   禽病u   牛羊r  r  )u   LAMP-探针法u'   公卫项目/呼吸道/肠道-病原体r   c                    t          d          }|sdS |                    d          pg }|                    d          pi }|                    d          pi }| pd                                }d |pg D             }g }|D ]}	|	                    d          pd}
|	                    d          pd}|	                    d	          pd}d
\  }}g |	                    d          pg |	                    d          pg z   D ]W}t          |t                    r@|                    d          pdgt          |                    d          pg           z   z  X|r t          fd|D                       rd\  }}|sV||
fD ]Q}|s|                                |v rd\  }} n0t                              |g           D ]}||v r	d|z  d}} n|r nR|s5|
r3|
                                |v r|r|                                |v rd\  }}|sH|rF|                                |v r0|	                    d          pd                                |v rd\  }}|r|                    ||	|f           |sdS |	                    d            dg}|dd         D ]L\  }}	}|                    d|	                    dd          |	                    d          rd|	d         z   ndd|	                    d	d          pdd |	                    dd          pd!d"|d#
           t          |	                    d                    t          |	                    d                    }}|r|                    d$|z             |r|                    d%|z             g }d&D ]G\  }}|	                    |          }|r+t          |          d'vr|                    |d(|           H|r+|                    d)d*                    |          z             |	                    d+          r3|                    d,t          |	d+                   dd-         z             |	                    d.          r3|                    d/t          |	d.                   dd-         z             g }|	                    d          pg |	                    d          pg z   D ]A}t          |t                    r*|                    |                    d          pd           B||z  }g }t                              d0 |D                       D ]u}t          |||          }t          |          d1k    rO|                    d2|                    d!          d3         d4d5                    |dd6                              v|r*|                    d7           |                    |           Nd8                    |          S )9uP   诊断原料·四段式第1-2步：产品推荐清单匹配 + 货号变种展开z product_recommendation_list.jsonr>   r   r  r  c                     g | ]}||S r   r   r   r[  s     r   r   z$_selection_block.<locals>.<listcomp>q      )))!q)A)))r6   rs  r   rz  r  systemssystems_lyor   r4  c              3   X   K   | ]#v pt          fd D                       V  $dS )c              3   $   K   | ]
}||v V  d S r$  r   r   r7  r[  s     r   r'  z-_selection_block.<locals>.<genexpr>.<genexpr>}  s,      )E)EQ1)E!q&)E)E)E)E)E)Er6   N)r?  )r   r[  allsks    @r   r'  z#_selection_block.<locals>.<genexpr>}  sJ      TT!U
Ec)E)E)E)E%)E)E)E&E&ETTTTTTr6   )   货号命中d   )u   病种/项目命中rF   u   病种/项目命中(%s)F   )u   类目+方法学命中r  nucleic)u   方法学+核酸命中r  c                     | d          S rd  r   r`  s    r   r9  z"_selection_block.<locals>.<lambda>      QqTE r6   r:  uf   【第1步·产品推荐清单匹配（源：诊断原料产品推荐清单，按优先级给出）】Nr/     ▸  > u   ｜方法：u	   未标注u   ｜核酸：r_  ry  ro  u&      推荐体系（优先级序）：%su&      冻干体系（优先级序）：%s))sample_typeu   样本类型)
can_premixu   可全预混)fast_programu   快速程序)u   否r_  r}   r>   =z   %sri  featureu      一线反馈：%sr  reagent_featureu      试剂要点：%sc                     g | ]}||S r   r   rl  s     r   r   z$_selection_block.<locals>.<listcomp>  s    888aa8888r6   r$   u      - 母体 r   u    的可下单变种：r<  r=  u      第2步·货号变种：r>  )r  r2   r/  r   r   r8   r?  _SEL_SYNONYMSrT   r~  r  r   r   r  r  r   r  r  ) rV   r4  r  r   r   r  r  qlrM  r   projr   methreasonrL  grpcandr  rW  _scwhyrU  ltmetar&  r   rv   targetsvlinesrO  vsr  s                                   @r   r  r  h  s   344A rEE'NN bEeeI$"GUU8__"F
.b			!	!B))
)))DD !- !-vvi  &BffUmm!rx  &BFF9%%+}0E0E0KL 	N 	NC#t$$ N#''%...B/$swwv7L"2M2MMM 	0CTTTTtTTTTT 	0/MFE 	d   ::<<2%%$=MFEE(,,T266  Cbyy(AD(H" !  E  	9$ 	94::<<2#5#5$#54::<<SUCUCU8MFE 	9$ 	94::<<2#5#5266);L;L;RPR:Y:Y:[:[_a:a:a8MFE 	-KKF+,,, rII//I"""uvERaR "! "!RFF9b!!!"&&--#OEBuI$5$5R#O#OFF8R  /K//	21F1F1M#1M1MsssT 	U 	U 	U !	!2!233_RVVMEZEZ5[5[B 	HLLABFGGG 	HLLABFGGG; 	2 	2HAuq		A 2SVV#888uuuaa0111 	5LL5::d#3#3344466) 	LLL/#bm2D2DTcT2JJKKK66#$$ 	TLL/#b9J6K2L2LTcT2RRSSSFF9%%+}0E0E0KL 	5 	5C#t$$ 5swwu~~3444488788899 	p 	pAq'622B2ww{{!''RU,,WX///[`[e[efhikjkikfl[m[m[mnooo 	!LL6777LL   99Ur6   u	   逆转录u	   反转录qpcru   荧光定量zrt-qpcru	   胶回收u	   dna纯化u   核酸纯化u   纯化u   分子量标准markeru   裂解u   蛋白提取u	   内切酶u	   限制酶u   无缝克隆u   快速克隆u   连接u	   dna连接u	   感受态u   转化zrt-lampr  r  u   建库u   建库相关酶>      酶   提取   试剂dnakitrI  pcrrnataqpurer  c                    ddl }| pd                                } t                      }|                    d|           D ]*}|                    |                    d                     +|                    d|           D ]*}|                    |                    d                     +d| v rd|vr|                    d           t          |          D ]5}t                              |g           D ]}|                    |           6|S )u   从问题里提取有意义的检索词：中文串(≥2字) + 英文词(≥3字符)
    刻意不用 bigram——'cDNA合成' 与 'DNA Polymerase' 的 bigram 会互相误命中。r   Nr>   z[a-z][a-z0-9\-]{2,}z[\u4e00-\u9fff]{2,}r  )	r   r/  r   finditerrF  groupr8   _LS_SYNr2   )rM   r_  toksr  rO  r  s         r   _match_tokensr    s    	
bA55D\\0!44  \\0!44  zze4''$ZZ  ;;q"%% 	 	CHHSMMMM	Kr6   c                 l	   t          d          }|sdS |                    d          pg }t          |           }d |pg D             }g }|D ]ъ                    d          pd                    d          pd                    d          pd}}}                    d          pd                                }	                    d	          pdd
                    d          pd}
d\  }}|r!t	          fd|D                       rd\  }}n|D ]H}t          |          dk    r3||	v r/|t          v rdnt          |          dk    rdnd}||k    r|d|z  }}I|D ]&}t          |          dk    r||v r|dk     rdd|z  }}'|D ]&}t          |          dk    r||v r|dk     rdd|z  }}'|D ]&}t          |          dk    r||v r|dk     rdd|z  }}'|D ]$}t          |          dk    r||
v r|dk     rd\  }}%|r|                    ||f           |sdS |                    d            d g}|d!d"         D ]W\  }}|                    d#                    dd          d$                    dd          d%                    dd          d%                    dd          d&|d'                               d(          r9|                    d)d*	                    d(         d!d+                   z                                 d,          s                    d-          rC|                    d.                    d,d          d/                    d-d                                         d0          r+|                    d1                    d0          z                                 d2          r+|                    d3                    d2          z                                 d4          rC|                    d5                    d4d          d
                    d6d                                         d	          r3|                    d7t          d	                   d!d8         z             Yd9	                    |          S ):uI   生命科学·科研产品匹配（含目录价/促销价/促销政策）zls_product_catalog.jsonr>   r   c                     g | ]}||S r   r   r  s     r   r   z%_ls_catalog_block.<locals>.<listcomp>  r  r6   c1c2c3r4   r  r+  r  )r   r>   c              3      K   | ]M                     d           pg v p/t          fd                     d           pg D                       V  NdS )r4  c              3       K   | ]}|v V  	d S r$  r   r  s     r   r'  z._ls_catalog_block.<locals>.<genexpr>.<genexpr>  s'      :b:ba16:b:b:b:b:b:br6   N)r2   r?  )r   r[  r   s    @r   r'  z$_ls_catalog_block.<locals>.<genexpr>  sl      qqghbffVnn23bs:b:b:b:bBFFSYNNL`^`:b:b:b7b7bqqqqqqr6   )r  r  r   7   r|  \   X   u   产品名命中(%s)r   V   u   三级分类命中(%s)N   u   二级分类命中(%s)r   u   一级分类命中(%s)-   )r  u   产品特点命中c                     | d          S rd  r   r`  s    r   r9  z#_ls_catalog_block.<locals>.<lambda>  r  r6   r:  uU   【科研产品匹配（源：生命科学产品清单，含目录价/促销价）】Nr=  r  u    ｜ r  ry  ro  r4  u      货号：%sr{  r/  rb  concu      规格：u   ｜浓度：
list_priceu      目录价(元)：%spromo_priceu1      促销价(元)：%s  ← 报价优先用此价promo_policyu      促销政策：promo_policy2u      特点：%sr  r>  )r  r2   r  r/  r?  r   _LS_GENERICrT   r~  r   r   )rV   r4  r   r   r  rM  r
  r  r  name_lr   rL  r  rO  scrW  _sr   s                    @r   r  r    sN   *++A rEE'NN bE""D))
)))DD * *VVD\\'R);RVVD\\=ORB&&..&B--//&&++1r11266%==3FB3FG
s 	:Cqqqqlpqqqqq 	:,JE33 C Cq66Q;;1;; K//CFFaKKbbRBEzz%')>)Bs C Cq66Q;;177urzz!#%=%B3E C Cq66Q;;177urzz!#%=%B3E C Cq66Q;;177urzz!#%=%B3E : :q66Q;;199!9JE3 	*KKC())) rII//I"""deEBQBx F FBFF62tR 0 0 0 0"&&r2B2B2B2BBFF4QSDTDTDTDTVYVYVY[ 	\ 	\ 	\66&>> 	HLL)EJJr&z"1"~,F,FFGGG66&>> 	dRVVF^^ 	dLLL266&";M;M;M;MrvvV\^`OaOaOabccc66, 	JLL1BFF<4H4HHIII66-   	fLLLrvvVcOdOddeee66.!! 	pLLLbff^R6P6P6P6PRTRXRXYhjlRmRmRmnooo66) 	FLL)C9,>,>tt,DDEEE99Ur6   c           
         t          d          }|r| sdS t          |           p| }d}|                    d          pi                                 D ]'\  }}|| k    s|dd         |v s|dd         | v r|} n(|sdS dddd	                    |                    d
d          d          }d|d|d|                    dd          dg}|                    d          pi }dD ]P\  }}	|                    |          r6|                    d|	dt          ||                   dd                    Q|                    d          pg dd         D ]/}
|                    dt          |
          dd         z             0|                    d          r3|                    dt          |d                   dd         z             d                    |          S )uO   外部工商背景（天眼查缓存/人工录入），带来源与日期标注ztianyancha_cache.jsonr>   N	companiesrf  u   天眼查APIu	   天眼查u   人工录入)apitycmanualru  u   外部u   【工商背景·ry  r\  rH   u   ）】fields))
regCapitalu   注册资本)estiblishTimeu   成立时间)legalPersonNameu   法人)	regStatusu   经营状态)staffNumRangeu   人员规模)industryu   行业)regLocationu   地址)businessScopeu   经营范围r  rk  r  riskr/  u   - ⚠ 风险：%sr'  u   - 原文摘要：%s  r>  )r  _cust_shortr2   r   rT   r   r   )	cust_namer   r  rX   r&  rv   r  rW  r   r   rw  s              r   r  r    s+   ())A I ry!!.YD
C{##)r0022  1	>>T"1"X]]aey.@.@CE /A  r 
O
O
S
STWT[T[\dfhTiTiks
t
tCC6:ddCCCQSATATATATUVERAS A A5 5588 	ALLLs1Q4yy#?@@@ggfoo#RaR( 9 9(3q66$3$<78888
wwu~~ D*SU__TcT-BBCCC99Ur6   c                    t          d          }|r| sdS t          |t                    r|n+|                    d          p|                    d          pg }t	          |           p| fd|D             }|sdS dt          |          z  g}|dd         D ]}t          |t                    r|                    d	|                    d
          p|                    d          pdd|                    d          p|                    d          pdd|                    d          p|                    d          pdd|                    d          pd           d                    |          S )u*   该客户相关待办（未闭环提醒）z
todos.jsonr>   todosr   c                 h    g | ].}d d         d d         t          j        |d          v ,|/S )Nrf  Fr&   )r   r  )r   rO  r  s     r   r   z_todo_block.<locals>.<listcomp>@  sH    ]]]!RaR]d2A2h$*QUZ:[:[:[.[.[A.[.[.[r6   u   【相关待办】%d 条Nr=  rg  duerH   rh  r7  r   u   ｜负责人 r   assigneer  r  r>  )	r  r   r8   r2   r/  r   r   rT   r   )r0  r   r   rM  rW  rO  r  s         @r   r  r  9  s   A I rAt$$RAA155>>+QQUU7^^+QrEy!!.YD]]]]u]]]D r'#d))34E"1"X S Sa 	SLLLe3f333QUU7^^5ZquuV}}5ZXZ5Z5Zg9!%%
"3"39r99155??;Pb;PR S S S 99Ur6   c                     g d}|S )u9   数据导航（告诉模型去哪个文件取什么数）)ud   产品推荐清单(诊断原料)：数据/product_recommendation_list.json（items/by_sku/by_base）uj   科研产品目录(生命科学)：数据/ls_product_catalog.json（含目录价/促销价/促销政策）ub   当季促销：数据/promo_campaigns.json（programs=档位与赠品；rows=打包方案原表）u'   商务政策：数据/sales_policy.jsonuc   客户360：数据/customer_360.json（top_products=用过的货号；activities/opps/complaints）u[   产品卖点：数据/product_selling_points.json｜选型：数据/pcr_lamp_selection.jsonuR   竞品情报：数据/competitor_intel.json｜订单：数据/shipment_status.jsonu]   课题组(生命科学)：数据/ls_groups.json｜工商缓存：数据/tianyancha_cache.jsonr   )r  navs     r   _wf_data_navr9  L  s    	 	 	C Jr6   c                    g }| dk    r|                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d	           |                     d
           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           nz|                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d           |                     d            |                     d!           |                     d"           |                     d           |                     d#           |                     d$           | dk    r|                     d%           n|                     d&           |                     d'           |                     d(           |                     d)           |                     d*           |                     d+           |                     d,           |                     d           t          |           }|r?|                     d-           |                    |           |                     d           t          |           }|r?|                     d.           |                    |           |                     d           |                     d/           |                     d0           |                     d1           |                     d2           |                     d3           |                     d           |                     d4           |                     d5           |                     d6           |                     d7           |                     d           |                     d8           t	          |           D ]}|                     d9|z              |S ):uE   按业务线输出工作流提示词（诊断原料 / 生命科学）r	   u<   【生命科学 AI 助手工作流 v1.0（必须遵守）】u}   核心心法：**先懂导师，再谈方案。** 科研销售的商机单位是课题组（PI 实验室），不是公司。r>   u+   ■ 第0步·权限闸（永不可跳过）uw   问到的课题组/客户不在可见名单内 → 只回"该客户不在您的权限范围内，无法提供信息。"u   禁止侧漏：不确认"是否存在该课题组"、不透露归属人、不含糊说金额量级、不用同校/同院口径反推、上传文件中出现的名单外课题组同样不引用。u[   ■ 工作流 A·课题组背景调研（问"XX课题组/XX老师怎么样"）→ 七步法u\   第1步 课题组识别：定位数据/ls_groups.json（名称/归属销售/状态/区域）uZ   第2步 导师背景（LS 与 DA 最大的差异，必须做，用公开检索补齐）：u      ① 公职与学术地位：职称（教授/研究员/博导）、职务（院长/系主任/重点实验室主任）、人才头衔（杰青/优青/长江学者/院士）un      ② 研究方向：主攻领域与关键词（用来对齐我方产品线）+ 近 3-5 年代表作与专利u      ③ 项目资源：国家自然科学基金（面上/重点/重大）、国家重点研发计划、省部级、横向课题 → 判断经费体量与可持续性uP      ④ 人脉与协作：合作单位、学会任职、附属医院/转化需求us      ⑤ 团队规模：课题组人数（决定用量）、有无专职技术员（决定谁做实验、跟谁谈）u   第3步 方向匹配：把导师方向映射到我方科研产品线（分子生物学/核酸提取纯化/蛋白研究/测序建库/mRNA-circRNA 等）un   第4步 整体解决方案（不罗列单品！）：主推 + 配套 + 可选升级，逐项给货号与价格u   第5步 竞品处理：已知竞品与货号时，先查经验库；有精准 PK 案例→精准输出；无案例→给差异化建议 + 建议对比实验设计ux   第6步 商务联动：当季促销（数据/promo_campaigns.json）+ 促销期外每人每月 700 元销售费用额度u   第7步 输出固定七段：① 课题组画像 ② 导师背景与学术地位 ③ 研究方向匹配 ④ 整体解决方案(货号+价格) ⑤ 竞品应对 ⑥ 商务与促销 ⑦ 下一步动作(动作+负责人+时间)u<   【诊断原料 AI 助手工作流 v1.0（必须遵守）】u~   核心心法：**问一次就给答案，答案都有出处。** 商机单位是公司/工厂，决策链看采购与研发。u   问题涉及客户时，先判断是否在可见名单内。名单外 → 只回"该客户不在您的权限范围内，无法提供信息。"u   禁止侧漏：不确认"是否存在该客户"、不透露归属人、不含糊说金额量级、不用集团/行业口径反推单体客户、上传文件中出现的名单外客户同样不引用、外部工商数据不构成越权豁免。ug   ■ 工作流 A·客户调研（问"XX客户怎么样/调研一下XX"）→ 七源聚合，一次答全uL   ① 飞书活动：最近跟进、谁去过、聊了什么、承诺了什么uV   ② 订单/物流：三年采购趋势、金额、频次、最近一单与签收状态up   ③ 用过的货号：买过什么品类、只买原料还是买体系、有无测试装转量产、主销结构uS   ④ 客诉：历史质量/交付投诉、是否已闭环（未闭环必须提醒）uM   ⑤ 商机/待办：在手商机阶段与金额、卡在哪、下一步动作uk   ⑥ 工商背景：规模/成立/法人/地址/经营范围/股东/风险（数据/tianyancha_cache.json）uS   ⑦ 官网/公开网络：主营管线、技术平台、融资上市、招聘信号u   输出固定六段：① 客户概览(归属+规模) ② 采购画像 ③ 关系与进度 ④ 产品结构机会 ⑤ 风险与阻力 ⑥ 下一步动作(动作+负责人+时间)u5   缺某源就写"该源暂无数据"，严禁编造。uv   ■ 工作流 B·产品问答四段式匹配（销售问产品/选型/报价时，严格按段推进，不得跳段）u   【第0步·强制结构化提问】若销售描述不足以判断，先给出下面模板让他填（不要猜、不要跳过）：u    「请补充一下，我马上给方案：① 课题组/导师研究方向：____ ② 具体实验场景（如 mRNA 体外转录 / 建库 / qPCR 定量）：____ ③ 样本与规模（样本类型/每月反应数）：____ ④ 现状（新开课题 / 替换现有品牌：___ / 扩项）：____ ⑤ 关键要求（灵敏度/纯度/无 RNase/成本）：____ ⑥ 时间节点与预算：____」u    「请补充一下，我马上给方案：① 检测/应用场景（如 非洲猪瘟现场检测 / 水产病原 / 宠物呼吸道）：____ ② 样本类型（血清/全血/组织/拭子/粪便/水样）：____ ③ 方法学（PCR / 荧光定量 / 恒温扩增 LAMP-RPA / 测序）：____ ④ 客户现状（新项目 / 替换品牌___ / 扩项 / 询价）：____ ⑤ 关键要求（灵敏度/出结果速度/免提取/冻干常温运输/成本目标）：____ ⑥ 数量与节奏（首次测试量/预计月用量/时间节点）：____」uD     拿到答复后，先复述确认关键条件，再进入匹配。u   【第1步·匹配产品推荐清单】按"项目/方向 + 方法学 + 样本类型"命中推荐条目，给优先级顺序及特征、样本类型等关键参数。u,  【第2步·货号变种】命中母体后必须展开变种：① 规格后缀(-01/-02/-03) ② 批次/版本后缀(-000812) ③ 冻干↔液体对应(F 前缀) ④ 套装组合。给出可下单的实际货号并说明差异；后缀含义不确定时明说"需与产品部确认该后缀规格"。u   【第3步·经验库】查我方历史经验（飞书活动实测反馈、客诉记录、竞品情报库）：有精准同类案例→直接引案例（客户类型+场景+结果）；只有同类不同场景→标注"同类可参考"并说明差异点。u   【第4步·兜底】以上全无线索才给建议，且必须明说："以下为我方经验的合理推断，暂无内部数据支撑，建议先做小样测试验证"，并给出验证方式。u   【收尾·商务联动】回答价格/方案时，必须主动检查当季促销与销售费用额度，给出"怎么用促销/额度推动这一单"的具体建议。u>   ■ 当季促销（回答报价/方案时必须主动使用）u   ■ 商务政策u?   ■ 外部数据使用规则（天眼查/官网/公开网络）us   1. 每条外部数据必须标注来源与日期：【天眼查】/【公开网络·未核验】/【人工录入】uW   2. 外部数据不得绕过客户权限：权限外客户一律不返回其工商画像uu   3. 公开网络信息可能过期，涉及注册资本/法人等关键字段时提示"建议核实最新工商信息"ue   4. 无外部数据时明说"外部背景暂未获取，可粘贴天眼查内容补充"，绝不编造u+   ■ 沉淀闭环（让好答案被复用）uf   当一次问答产生了可复用的打法/话术/竞品应对/案例时，主动在结尾加一行：uX   「💡 这条经验值得沉淀吗？回复"沉淀"我就整理成知识卡入库。」uk   用户回复"沉淀"后，输出脱敏经验卡（客户名与内部人名用代称，价格区间化）。u   ■ 数据导航r  )rT   r  r  r  r9  )r  rV   r4  Wr,  polr*  s          r   _workflow_linesr=  [  s   
At||	OPPP	  Q  	R  	R  	R		>???	  K  	L  	L  	L	  W  	X  	X  	X		nooo	oppp	mnnn	  A  	B  	B  	B	  B  	C  	C  	C	  x  	y  	y  	y	cddd	  G  	H  	H  	H	  k  	l  	l  	l	  B  	C  	C  	C	  v  	w  	w  	w	  L  	M  	M  	M	  s  	t  	t  	t		OPPP	  R  	S  	S  	S		>???	  b  	c  	c  	c	  G  	H  	H  	H		z{{{	_```	ijjj	  D  	E  	E  	E	fggg	`aaa	~	fggg	  E  	F  	F  	F	HIII	HH  F  G  G  GHH  T  U  U  Ut||	  _  	`  	`  	`  	`	  r  	s  	s  	sHHSTTTHH  u  v  v  vHH  |  }  }  }HH  P  Q  Q  QHH  U  V  V  VHH  x  y  y  yHHRLLL	d		B	 	QRRR		


C
 	#$$$		HHNOOOHH  C  D  D  DHHfgggHH  E  F  F  FHHtuuuHHRLLLHH:;;;HHuvvvHHghhhHHz{{{HHRLLLHH   $  	Hr6   c                    |                      dd          }|                      dd          }|                      dd          }|                      dd          }t                               ||          }g }|                    d           |                    d	|d
|d|d|d	           |                    d           |                    d           |                    d           |                    d           |                    d           |                    d           |dv r	 t          t	                                }	n# t
          $ r d}	Y nw xY w|                    d|z             |                    dt          |          |	fz             |                    d           n*|                    d           |r|D ]}
|
                     d          p|
                     d          pd}|
                     d          pd}	 t          t          |          dz  d          }n# t
          $ r d}Y nw xY w|                    d|
                     dd          d|d|d           |rw|D ]t}|                    d |                     dd          d|                     dd          d!|                     d"d          d#|                     d$d          d	           u|s|s|                    d%           |                    d&           |                    d'           |                    d(           |                    d)           |                    d*           |                    d+           |                    d,           |                    d-           |                    d.           |                    d/           |                    d           |                    d0           |                    d1           t                               |          }|r|                    d           |                    d2           |                    d3||d4         |d5         dz  fz             |                    d6|d7         dz  |d8         dz  ||d9         dz  fz             |                    d           |                    d:           |                    d;           |                    d<           |                    d=           |                    d>           |                    d?           |                    d@           |                    dA           |                    dB           |                    dC           |                    dD           |                    d           |	                    t          |                     |                    d           |                    dE           |                    dF           |                    dG           |                    dH           |                    dI           |                    d           |                    dJ           |                    dK           |                    dL           |                    dM           |                    d           |                    dN           |                    dO           |                    dP           |                    dQ           |                    dR           |                    dS           |                    dT           |                    dU           |                    dV           dW                    |          S )XuP   构建 system prompt（三条铁律 + 可见客户名单 + 业务线工作流）r4   r>   r/  r0  r&  r  r   uF   你是宝锐生物（BIORI BIOTECH）销售工作台的智能助手。u   当前用户：u   （角色：u   ，部门：u   ，业务线：ro  u$   【铁律一：只答工作问题】u   你只回答销售工作相关问题（客户、订单、KPI业绩、产品、行业动态、市场竞争、竞品分析、销售方法论、工作流程等）。u   严禁回答家庭、个人生活、私人事务、娱乐八卦、政治、宗教信仰等与工作无关的问题。遇到此类问题，统一回复："抱歉，我只能协助销售工作相关的问题～"u*   【铁律二：客户数据权限隔离】r1  r   ue   当前用户是超管（%s），拥有全公司客户数据访问权限，不受客户名单限制。u   可查询对象包括：ERP 重点客户（%d 家）、CRM 客户库（%d 家），以及飞书活动、订单物流、价格档案、客诉、商机、测试反馈等数据源中出现的所有客户。u   对于任何客户，只要系统检索到其真实数据（见下方背景）即可引用并回答；检索不到则明确说明"暂无该客户的相关数据"，严禁编造客户数据。uj   你只能谈论当前用户权限范围内的客户/课题组。以下是该用户可见的客户名单：r:  
sales_2026r  r$   r  u   （归属：u   ，2026销售额：u   万）u   - [课题组] u   ，状态：r  u   ，区域：r6  u   （无可见客户记录）u}   名单之外的客户，一律回复"该客户不在您的权限范围内，无法提供信息"。不得编造客户数据。u   用户上传的文件内容同样受此权限约束：文件中若出现名单之外的客户/人员，不得引用其数据。u_   【越权一律不回复·反推断防线（第 5 条铁律，任何情况下不得突破）】uq   a) 不做存在性确认：不得回复"该客户存在但您无权查看"，统一只说权限外无法提供。uB   b) 不透露归属人：不得说出该客户归属哪位同事。uc   c) 不做量级暗示：不得用"金额不小""重点客户""排名靠前"等模糊表述侧漏。u   d) 不做反推聚合：不得用集团/行业/区域口径汇总后变相暴露单体客户（如"华东区某客户采购 800 万"）。u   e) 不做名单比对：用户问"XX 是不是我的客户/在不在名单里"，同样不回是否，只回权限范围内无法提供。uq   f) 外部数据不豁免：天眼查/官网/公开网络查到的工商画像，权限外客户同样不返回。uo   g) 不带例句演示：不得用真实名单外客户名举例说明（示例一律用"某A公司"占位）。u2   【铁律三：行业/市场/竞品自由回答】u{   行业趋势、市场规模、竞品动态、产品技术等非客户专属问题，可自由回答，不受权限限制。u;   【当前员工的 KPI 口径（入职拆分，重要）】uD   %s 于 2026 年 %d 月入职。全年（1-12月）目标 %.1f 万。r  r  u   其中：入职前（1-7月）目标 %.1f 万，已达成 %.1f 万（这是前任业绩，不计入 %s 本人的达成）；入职后（8-12月）目标 %.1f 万，由本人承担。r  r  r  u3   【场景路由与回答框架（务必遵守）】uB   根据用户问题类型，采用对应数据源和回答框架：u   1. 产品选型/产品咨询（问"XX检测/项目推什么体系/货号/多少钱"）→ 严格走下方【工作流 B·产品问答四段式】。u   2. 产品竞争力（问"XX产品优势/有竞争力吗"）→ 用 FABE 四段式（特征→优势→客户利益→证据）回答，引用 数据/product_selling_points.json 的定量证据；无数据明说"需补测"，严禁编造参数。u   3. 竞品对比（问"和XX比/国产替代"）→ 引用 数据/competitor_intel.json + selling_points 的 competitors/evidence，给出差异化打法和胜率判断。u   4. 客户调研（问"XX客户怎么样/调研一下XX"）→ 走下方【工作流 A】，多源聚合一次答全，不要挤牙膏。uw   5. 市场/行业（问"市场规模/趋势"）→ 引用 selling_points 的 market_intel 字段 + 行业报告数据。u   6. 数据查询（问"订单/回款/KPI"）→ 引用 shipment_status / kpi_progress / kpi_dashboard 的真实数字，注明口径。u~   7. 销售打法（问"怎么谈/话术/异议"）→ 引用话术库 + LTC 方法论，给可落地话术和下一步动作。u   通用思考顺序：①识别场景 → ②提取实体（产品/货号/客户/竞品）→ ③权限过滤 → ④检索对应数据源 → ⑤结构化输出。up   涉及产品/竞品问题时，可用工具读取上述 JSON 文件获取卖点、选型、竞品情报数据。u   【回答要求】u*   1. 用中文，简洁专业，条理清晰u    2. 金额统一用"万元"单位u<   3. 涉及客户数据时，只引用上面名单中的信息u0   4. 不确定的数据明确说明，不要编造u$   【高效原则（务必遵守）】u`   优先基于上面的客户名单和背景数据直接回答，不要反复调用工具检索。ub   数据查不到就明确说"暂无相关数据"，严禁为了凑答案反复尝试多个工具。u9   整个回答尽量在 3 步以内完成，避免拖长。u<   【文件输出规则（用户要下载文件时遵守）】um   当用户明确要求生成文件、文档、HTML页面、报告、知识卡、表格等可下载内容时：u   1. 【重要】不要调用 write_file 等工具把文件写到磁盘，也不要提及任何本地文件路径——系统会自动把你输出的内容保存为文件。uo   2. 把完整文件内容（如完整 HTML 代码，不要省略、不要截断）用以下标记包裹输出：u      <<<FILE:文件名.html>>>u      （完整的文件内容；HTML 用纯文字+样式即可，【不要】内嵌 base64 图片——配图位置用文字占位说明，图片由系统/人工后续补充）z   <<<END_FILE>>>uD   3. 标记之外，用 1-2 句简短文字说明生成结果即可。uN   4. 文件名用有意义的中文名，扩展名用 .html/.md/.txt/.csv 等。r>  )r2   
LINE_LABELrT   r   r  r   roundr0  
JOIN_SPLITr  r=  r   )rF  rK  rL  r4   r/  r&  r  
line_labelLcrm_nrQ  sps26s26wr   _jss                   r   _build_system_promptrJ    s	   88FBD88FG$$D88FBD88FD!!Dd++J
AHHUVVVHHHTXTXTXZ^Z^Z^`d`d`dfpfpfpqrrrHHRLLLHH3444HH  r  s  s  sHH  a  b  b  bHHRLLLHH9:::	02233EE 	 	 	EEE		x{  	A  	A  	A	  _  cf  gl  cm  cm  ot  bu  u  	v  	v  	v	  S  	T  	T  	T  	T	}~~~ 	j j jUU=))AQUU7^^AreeL)).Q se!3Q77DD    DDDAEERXZ\L]L]L]L]_a_a_acgcgcghiiii 	n n n\]\a\abhjl\m\m\m\mopototu|  A  pB  pB  pB  pB  DE  DI  DI  JR  TV  DW  DW  DW  DW  YZ  Y^  Y^  _g  ik  Yl  Yl  Yl  Yl  m  n  n  n  n 	4W 	4HH2333	  Q  	R  	R  	R	  S  	T  	T  	T	rsss	  E  	F  	F  	F	UVVV	vwww	  ^  	_  	_  	_	  ^  	_  	_  	_	  E  	F  	F  	F	  C  	D  	D  	DHHRLLLHHABBBHH  K  L  L  L
..

C
 u		NOOO	W[_adeqartw  yK  uL  OT  uT  [U  U  	V  	V  	V	  J  NQ  Rc  Nd  gl  Nl  nq  rC  nD  GL  nL  NR  TW  Xj  Tk  ns  Ts  Mt  t  	u  	u  	uHHRLLLHHBCCCHHQRRRHH  d  e  e  eHH  E  F  F  FHH  z  {  {  {HH  X  Y  Y  YHH  G  H  H  HHH  V  W  W  WHH  N  O  O  OHH  s  t  t  tHH  A  A  AHHRLLLHH_T""###HHRLLLHH!"""HH9:::HH/000HHKLLLHH?@@@HHRLLLHH3444HHopppHHqrrrHHHIIIHHRLLLHHKLLLHH|}}}HH  {  |  |  |HH~HH+,,,HH  ~      HH !!!HHSTTTHH]^^^99Q<<s$   0E EE H44IIc                  (   	 t           j                            t                    rYt	          t          d          5 } t          j        |           }ddd           n# 1 swxY w Y   t          |t                    r|S n# t          $ r Y nw xY wdg iS )u/   读生成文件索引，返回 {'files': [...]}r   r   Nr   )
r   r   r   
FILE_INDEXr   r   r   r   r   r   r   s     r   _load_file_indexrM    s    7>>*%% 	j7333 !qIaLL! ! ! ! ! ! ! ! ! ! ! ! ! ! !!T""    R=r   c                 ,   	 t          j        t          d           t          dz   }t	          |dd          5 }t          j        | |dd	           d d d            n# 1 swxY w Y   t          j        |t                     d S # t          $ r Y d S w xY w)
NTr    r"   r#   r   r   Fr$   r%   )	r   r(   PRIVATE_BASErL  r   r   r*   r+   r   )r  r.   r   s      r   _save_file_indexrP  "  s    
L400006!#sW--- 	<Ic15;;;;	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	<

3
#####   r0   ).htmlz.htmr  .txtz.csvz.jsonr  )u   拜访u   访前r  u	   准备见u   去见u   要见c                 n      sdS t           fdt          D                       sdS t                     S )u2   检测"拜访"意图，返回客户名或空串。r>   c              3       K   | ]}|v V  	d S r$  r   )r   r#   rV   s     r   r'  z'_detect_visit_intent.<locals>.<genexpr>8  s'      33qH}333333r6   )r?  _VISIT_WORDSr  )rV   s   `r   _detect_visit_intentrV  4  sH     r3333l33333 rh'''r6   c                     | pd}dD ]S}|                     |          r<t          |          t          |          z
  dk    r|t          |          d         } nT|p| S )u[   客户简称：去掉常见地名前缀，保留品牌词（如"上海伯杰"→"伯杰"）r>   )u   上海u   北京u   广州u   深圳u   珠海u   杭州u   苏州u   成都u   武汉u   南京u   天津u   重庆u   长沙u   西安u   郑州u   青岛u   厦门u   宁波u   无锡u   佛山r   N)r  r   )r  r[  prefs      r   r/  r/  =  so    
Au  << 	#a&&3t99"4"9"9#d))**AE9r6   c                 J   ddl }t          j                            t          dd          }t          j                            |          sdS 	 t          |d          5 }|                                }ddd           n# 1 swxY w Y   n# t          $ r Y dS w xY wi }	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   n# t          $ r Y nw xY w|                    | i           pi }i }	 t          t          j                            t          dd	          d          5 }t          j        |          }ddd           n# 1 swxY w Y   n# t          $ r Y nw xY wt          |t                    r|                    | i           ni }	d}
g }t          |	t                    re|	                                D ]P\  }}t          |t                     st#          d
 |D                       }|
|z  }
|                    ||f           Q|                    d            g }t          j                            t          d          t          j                            t          dd          fD ]}	 t          |d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                     r|n)|                    d|                    dg                     }t)          |           }t+          |          }|D ]d}t          |t                    r#t-          |                    dd                    nt-          |          }|r||v r|                    |           e n# t          $ r Y w xY wt-          |                    dd          pd                                          }|                    dd          pd}|                    dd          p|                    dd          }|                    d          }t)          |           }t+          |          p	| dd         }d                    d |dd         D                       pd}i d|d| d |d!|d"|d#dd$dd%|d&d'|pd(z   d)z   d*|                    d+d          d,|                    d-d          d.d/t5          |          z  d0d1d2d3t5          |          z  d4d5d6d3t          |	t                    rt5          |	          ndz  d7d8|
rd9|
d:z  z  ndd;d<d=d>dddddddddd?d@}|}|                                D ]\  }}|                    ||          }g } |rp|                     dAdB|d         d                             dC          d                                         ddD         z   dE|d         dF         d:z  z  dGdGdHdI           |rA|                     dAdJdK                    dL |dd         D                       dGdMdNdI           |                     dOdPddMddQdI           g }!|r|!                    dRdSdTdU           |!                    dVdSdWdU           dXdYdZd[d\|
rd]|
d:z  z  nd^dZd[d_d`dZd[da|rdbndcdZd[g}"g }#	 t          t          j                            t          dd          d          5 }t          j        |          }$ddd           n# 1 swxY w Y   |$                    | g           }%t9          |%ddG                   D ]\  }&}'t          |'t                    s|#                    de|&dFz   z  |'                    ddf          |'                    dgd          |'                    dgdh          didhddjdkdldmdndkdldmgdo           n# t          $ r Y nw xY w|#sd|rb|#                    dXdp|d         d                             dC          d                                         ddD         dqdidqdqdjdrdsdmgdo           dt|#fdu| fdv|!fdw|"ffD ]9\  }(})|                    dx|(z  |(dyt          j        |)dZz          d{dF          }:|S )|u   生成基础版拜访卡 HTML（后端自动收集本地数据：分级/决策链链接/价格档案/客诉）。
    返回 html 字符串，失败返回 None。r   Nu   工具u   拜访卡模板.htmlr   r   decision_chain_links.json_archivezprice_archive.jsonc              3   l   K   | ]/}t          |t                    |                    d d          V  0dS r  r   NrU  rl  s     r   r'  z$_build_visit_card.<locals>.<genexpr>j  s=      HH!Jq$4G4GHaeeE1ooHHHHHHr6   c                     | d          S Nr$   r   r`  s    r   r9  z#_build_visit_card.<locals>.<lambda>m      AaD5 r6   r:  r  _backup_erp_20260821_111646r   r-   r4   r>   level   类   级   重点客户r   rB   r   r<  c                     g | ]=}|d                               d          d                                          dd         >S r   |Nr$  r  r  r  s     r   r   z%_build_visit_card.<locals>.<listcomp>  @    HHH1qtzz#q)//11#2#6HHHr6   r   	   待补充u   {{客户简称}}u   {{客户全称}}u   {{客户级别}}u   {{销售员}}u
   {{日期}}u   {{CRM活动数}}u   {{CRM范围}}u   {{今日拜访人}}z{{storage_key}}bp_r   	_visit_v1u   {{决策链URL}}decision_chain_urlu   {{客户链接}}customer_linku   {{KPI1值}}u   %d条u   {{KPI1说明}}u   历史客诉记录u   {{KPI2值}}u   %d个u   {{KPI2说明}}u   在采/在测产品u   {{KPI3值}}u   {{KPI3说明}}u   价格档案SKUu   %.1f万r  u   累计采购额(档案)u   待补充(研发决策)u   待补充(技术对接)u   待补充(采购)uZ   待补充（建议：确认在测项目进展 + 新项目立项时间点 + 客诉闭环）)u   {{KPI4值}}u   {{KPI4说明}}u   {{KR角色名}}u   {{SR1角色名}}u   {{SR2角色名}}u   {{项目1}}u   {{项目2}}u   {{项目3}}u   {{技术员1}}u   {{线1}}u   {{技术员2}}u   {{线2}}u   {{技术员3}}u   {{线3}}u   {{拜访目标占位}}p0u   主采产品：rh  r$  u@   累计采购 %.1f 万，确认在测/在采状态与后续用量r$   r/  u0   确认当前用量、性能反馈、后续需求)r  rN  contextimpactfeasibilitystrategyu   客诉闭环rh  c                 "    g | ]}|d d         S )iNr   rV  s     r   r   z%_build_visit_card.<locals>.<listcomp>  s     -N-N-N!ag-N-N-Nr6   r|  u'   主动汇报处理方案，重建信任p1u   新项目立项u!   摸清产品管线，提前卡位u   客诉影响信任u   中u   主动闭环历史客诉)r7  probcounteru   测试周期拉长u$   设定里程碑，每周同步进度r
  u   带最新测试/采购数据F)r  r   doner  u    带价格档案(累计 %.1f 万)u   带价格档案r  u   确认决策链人物名单c4u   准备客诉闭环方案u   准备新项目推荐方案opps_by_customer.jsonzc%d   商机r  	   待确认testingu   宝锐r  z50%)r4   pctbaru   竞品(待确认))r  r4   r   phasephaseClsr  r  	suppliersu   主采产品u   在采r  z100%rn  topicsr  
prepChecksz%s: [],z: r4  r]  )timer   r   r   r  r   r   r  r   r)   r   r   r2   r   r   r   r8   r  rT   r~  r  r/  r   r  r+   rR   r   r  r  r  )*r0  rF  r  tpl_pathr   tpldcllinkpaprices	total_amttopr&  rv   r  
complaintscpathcompcitems_core_shortr7  rt  
_raw_levellevel_shortr   ra   r  r  top3phhtmlr  r  r  rn  	_opp_data_olist_i_or4   r-   s*                                             r   _build_visit_cardr  H  s    KKKw||D(,BCCH7>>(## t(W--- 	&&((C	 	 	 	 	 	 	 	 	 	 	 	 	 	 	   tt C"',,x)DEEPWXXX 	\])A,,C	 	 	 	 	 	 	 	 	 	 	 	 	 	 	   779b!!'RD	B"',,x5IJJU\]]] 	ab1B	 	 	 	 	 	 	 	 	 	 	 	 	 	 	   &0T&:&:BRVVIr"""FI
C&$ !LLNN 	! 	!DAqa&& HHqHHHHHCIJJ3x    HHH!!!J',,x)>??',,x)FH]^^`  	eg... $!y||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $'d33`TT'488TZ\^K_K_9`9`Fy))E ''F * */9!T/B/BNSvr**+++A *fll%%b)))E 	 	 	H	 TXXgr**0b117799J$$UE22DnKHHWb!!9TXXfb%9%9EMM*%%Ei  D.2A2E::HHBQBHHHIIX[D
E
I
 	K
 		

 	e
 	K
 	
 	u
 	5EOV4{B
 	DHH%92>>
 	DHH_b99
 	wZ0
 3CDX
 	wS)
 ,<=R
 	wFD1I1I"P#f+++qQ
 Tdev
 =FV	Y%677;  kD45/";{%;%;%;"~/
 
 
B2 D

 " "1||Aq!!F
 w42Cc!fQiooVYFZFZ[\F]FcFcFeFefigifiFj2j"dhklmhnophqtyhy"z!"1Btv v 	w 	w 	w  n4."'**-N-Nz"1"~-N-N-N"O"O!"1Bkm m 	n 	n 	n MMt.?Kq>ac c d d dE l3UOijjkkk	LL/Kqrrsss;UKKYby?9uCTUUhy  DI  	J  	J:EJJ:h77Khrwxx	J K"',,x)@AAGTTT 	%XY	!I	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	%y"--rr
++ 	 	FBb$'' rAv&vx00vvh+++66%%*'/5IITgpr  |A  LB  LB  C	  	  	 	 	 		     3 s1vays7K7KA7N7T7T7V7VWZXZWZ7[9Ya#+CGGH
 
 	 	 	
 &{3h5G'SXIY\hjt[uv k k
d||I,444D_dAeAeAeAeAe.fhijjKs  B A?3B ?BB BB 
BB4D  C4(D  4C88D  ;C8<D   
DD+5F  F5F FF F	F 
FF0N5K"N5"K&	&N5)K&	*C	N55
OO4_% \&_% &\**_% -\*.B6_% %
_21_2competitor_intel.jsonc                     | pd                                 }|sdS t                                          D ]8\  }}|D ]0}|                                |                                v r|c c S 19|S )uJ   竞对品牌归一化：别名 → 标准名。未知品牌原样返回。r>   )r  rD  r   r/  )brandr   r  rT  r   s        r   _normalize_competitor_brandr    s    	"A r+1133  g 	 	AwwyyAGGII%% &	 Hr6   c                      	 t          t          d          5 } t          j        |           }d d d            n# 1 swxY w Y   t	          |t
                    r|S n# t          $ r Y nw xY wdg iS )Nr   r   r  )r   COMPETITOR_INTEL_FILEr   r   r   r   r   r   s     r   _load_competitor_intelr    s    ''::: 	a	!A	 	 	 	 	 	 	 	 	 	 	 	 	 	 	a 	H	   r?s.   A 9A =A  =A 
A)(A)c                 .   ddl }t          |                     d          pd          }|                     d          pd                                }|                     d          pd                                }|                     d          pd                                }|                     d          pd                                }|r|s|s|sd	S t	                      }|                    d
g           }	|||f}
|	D ]G}|                    d          |                    d          |                    d          f|
k    r dS H|	                    ||||||                    dd          |                    d          d           |	|d
<   	 t          t          dd          5 }t          j
        ||dd           ddd           n# 1 swxY w Y   ddt          |	          z  fS # t          $ r}dt          |          fcY d}~S d}~ww xY w)uU   写入一条竞对情报（品牌归一化 + 去重 + 落库）。返回 (ok, msg)。r   Nr  r>   r   performancefeedbackr   )FuG   竞对信息不完整：至少要有品牌 + 货号/性能/评价之一r  )Tu$   已存在相同竞对情报，跳过r4   %Y-%m-%d %H:%M:%S)r  r   r  r  r   r   r  r#   r   r   Fr$   r%   Tu!   竞对情报已沉淀（%d 条）)r  r  r2   r  r  rT   rR   r   r  r   r*   r   r   r   )rw  rF  r  r  r   r  r  r   r  r  dup_keyr   r   s                r   _add_competitor_intelr    s   KKK'G(<(<(BCCE;;u#
*
*
,
,C;;}--3::<<KJ''-24466HJ''-24466H ` `[ ` `__
 
"
"Cggi$$Gc8$G @ @EE'NNAEE%LL!%%
*;*;<GG??? HNNs;Htxx';';T]]SfEgEg     C	N'w??? 	<1Ic15;;;;	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	<83w<<GGG   c!ff}sB   G/ +GG/ GG/ GG/ /
H9H	HHc                    t          |           \  }}|                     d          pddv }|r	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   d |                    d	g           D             }n# t          $ r g }Y nw xY wd
 |D             }d |D             }i }	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   |
                                D ]-\  }	}
|	|v r$t          |
t                    rd |
D             ||	<   .n# t          $ r Y nw xY wi }	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   |                    di           }t          |t                    rD|
                                D ]/\  }	}|	|v r&t          |t                    rd |D             ng ||	<   0n# t          $ r Y nw xY wg }	 t          t          j                            t          d          d          5 }t          j        |          }ddd           n# 1 swxY w Y   n# t          $ r Y nw xY w||||dS )uN   活动录入下拉选项（权限过滤）：客户/商机/联系人/货号。r/  r0  r1  r  r   r   Nc                 d    g | ]-}|                     d           |                     d d          .S r  ru  rV  s     r   r   z%_activity_options.<locals>.<listcomp>	  s;    aaa1STSXSXY_S`S`aQUU62..aaar6   r2  c                 d    g | ]-}|                     d           |                     d d          .S r  ru  rV  s     r   r   z%_activity_options.<locals>.<listcomp>	  s5    KKKqQUU6]]Kvr**KKKr6   c                     g | ]}||S r   r   )r   r*  s     r   r   z%_activity_options.<locals>.<listcomp>	  s    33313Q333r6   r{  c                     g | ]Y}t          |t                    |                    d d          |                    dd          |                    dd          dZS )r4   r>   r  url)r4   r  r  rU  r  s     r   r   z%_activity_options.<locals>.<listcomp>'	  sw     C C C !jD.A.ACQUU62%6%6!%%RTBUBU^_^c^cdikm^n^noo C C Cr6   zcustomer_contacts.jsoncontactsc                     g | ]D}t          |                                          #t          |                                          ES r   r[  r  s     r   r   z%_activity_options.<locals>.<listcomp>4	  s9    #T#T#TqSVV\\^^#TCFFLLNN#T#T#Tr6   zsku_list.json)r2  r  r  r4  )rH  r2   r   r   r   r   r)   r   r   r   r   r   r8   r   )rF  rK  rL  rM  r   mcvisible_namesr  opp_datar  olistr  ccclistplistr4  s                   r   _activity_optionsr  	  s9   &t,,NE7  +G?H L	bgll8-ABBWUUU "YZYq\\" " " " " " " " " " " " " " "aa{B8O8OaaaMM 	 	 	MMM	 LKEKKK33333MD"',,x)@AAGTTT 	$XYy||H	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$!)) 	C 	CIB]""z%'>'>"C C%*C C CR	C     H	"',,x)ABBWUUU 	YZ1B	 	 	 	 	 	 	 	 	 	 	 	 	 	 	z2&&eT"" 	x"[[]] x x	E&&XbchjnXoXo#w#T#TE#T#T#T#TuwHRL    D"',,x99GLLL 	 PQ9Q<<D	  	  	  	  	  	  	  	  	  	  	  	  	  	  	    &(TXYYYs   4B0 #B8B0 BB0 B#B0 0B?>B?4F  D2&F  2D66F  9D6:AF   
FF4I# G(I# (G,,I# /G,0A2I# #
I0/I064K *K?K KK KK 
K$#K$c                     ddl ddlddlg fd} j        d|| j                  } j        dd|                                          }|fS )u   从 answer 里提取 <<<FILE:名>>>...<<<END_FILE>>> 标记，保存到私有目录并写索引。

    返回 (clean_text, files)，files = [{'fid': ..., 'name': ...}]
    r   Nc           
         |                      d          pd                                }|                      d          pd                                }|r|sdS  j        dd|                              d          d d         }|sdS t          j                            |          d                                         }|t          vrd}	 t          j        t          d	
           
                    d          dz                                   j        d d         z   }t          j                            t          ||z             }t          |dd          5 }|                    |           d d d            n# 1 swxY w Y   t          j                            |          }t#                      }|                    dg                               |||pd
                    d          |dd           t)          |           	 ddlm}	  |	||           n# t.          $ r Y nw xY w
                    ||d           n# t.          $ r Y nw xY wdS )Nr$   r>   r   z[\\/:*?"<>|\r\n]+r   z._rF   rQ  Tr    z%Y%m%d-%H%M%Sr_  r=  r#   r   r   r   u   未知r  F)fidr4   extr   r  r{  	is_publicr   )archive_one)r  r4   )r  r  r   r   r   splitextr/  _ALLOWED_EXTr(   FILE_DIRrR   uuid4hexr   r   writegetsizerM  rS   rT   rP     文书归档员r  r   )r  r4   rn  r  r  r  r   r{  r  r  r   r   r   r  uuids             r   _savez_extract_files.<locals>._saveK	  s   

 b''))771::#**,, 	7 	2rv*C66<<TBB3B3G 	2gt$$Q'--//l""C	K40000--00369I"1"9MMChc	22Bb#000 !A   ! ! ! ! ! ! ! ! ! ! ! ! ! ! !7??2&&D"$$CNN7B''..D*(DMMBU4V4V50 0   
 S!!!777777Bt,,,,   LLd334444 	 	 	D	rs\   BI
 E?3I
 ?FI
 FBI
 H!  I
 !
H.+I
 -H..I
 

IIz+<<<FILE:([^>]+)>>>\s*(.*?)\s*<<<END_FILE>>>)flagsz\n{3,}r}  )r   r  r  r   DOTALLr  )answerr   r  cleanr   r   r  r  s    `  @@@@r   _extract_filesr  A	  s    
 IIIKKKKKKE# # # # # # # # #J BFA5&XZXabbbEBF9fe,,2244E%<r6   r0  c                    t                      }|dv }g }|                    dg           D ]}|s|                    d          | k    r|                    |                    d          |                    d          |                    d          |                    d          |                    d          t          |                    d                    d	           |                    d
 d           |S )u9   按权限列出文件：admin/gm 全见，否则仅自己r1  r   r   r  r4   r  r{  r  )r  r4   r   r  r{  r  c                 .    |                      dd          S )Nr  r>   ru  r`  s    r   r9  z_list_files.<locals>.<lambda>	  s    155,, r6   Tra  )rM  r2   rT   boolr~  )viewervroler  rM  rp  r   s         r   _list_filesr  u	  s    


C'H
CWWWb!!   	AEE'NNf44

55<<vwEE&MM155==tAEER]L^L^G_G_
 
 	 	 	 	 HH,,dH;;;Jr6   c           	         t                      }|dv }|                    dg           D ]}|                    d          | k    r|s|                    d          |k    r dS t          j                            t
          | |                    dd          z             }t          j                            |          s dS ||                    d	d
          fc S dS )u5   鉴权取文件：返回 (path, name) 或 (None, err)r1  r   r  r   )Nu   无权访问该文件r  rQ  )Nu   文件不存在r4   file)rM  r2   r   r   r   r  r   )r  r  r  r  rM  r   r  s          r   _get_file_pathr  	  s    


C'HWWWb!! ) )55<<3 	1AEE'NNf44000W\\(C!%%w*?*?$?@@w~~b!! 	+***155((((((""r6   c                     t                      }|                    dg           D ]?}|                    d          | k    r$t          |          |d<   t          |            dS @dS )u4   标记/取消公共资源（权限在上层校验）r   r  r  TF)rM  r2   r  rP  )r  r  r  r   s       r   _mark_publicr  	  so    


CWWWb!!  55<<3!)__AkNS!!!44  5r6      c           	      J   ddl }t                      }|                                 | dz  z
  }g }d}|                    dg           D ]F}	 |                    |                    |                    dd          d                    }n$# t
          $ r |                                 }Y nw xY w|                    d          s||k    r|                    |           	 t          j        	                    t          |                    d	d          |                    d
d          z             }t          j                            |          rt          j        |           |dz  }"# t
          $ r |                    |           Y Dw xY w||d<   t          |           |S )uH   清理超过 days 天、且未标记公共的文件，返回删除数量r   NiQ r   r  r>   r  r  r  r  rQ  r$   )r  rM  r2   mktimestrptimer   rT   r   r   r   r  r   removerP  )	days_tr  cutoffkeepremovedr   rG   r  s	            r   _cleanup_expiredr  	  s   


CWWYY%FDGWWWb!!  	2;;quuVR'8'8:MNNOOBB 	 	 	BBB	55 	fKKNNN	heR(8(8155;P;P(PQQBw~~b!! 	"qLGG 	 	 	KKNNNNN	CLSNs%   =B		B*)B*BE))FF   c                    t          |           }|sdS g }t          |          |k    r|d|          ng }|dd         D ]}t          |t                    s|                    d          dk    rdnd}|                    d          pd                                                    d	d
          }|su|                    |d|dd                    |sdS dd	                    |          z   S )u   读该用户历史对话，返回压缩的『记忆』文本（取超出当前上下文的部分，供跨会话连贯）。

    exclude_recent：排除最近 N 条（这些已在当前 messages 里），注入更早的历史。
    r>   Nr/  rF  u   用户u   助手rn  r>  r+  rk  rj  u   【该用户更早的对话记忆（帮助保持上下文连贯，回答时自然引用关键信息，勿逐字复述历史原文）】
)	r5   r   r   r   r2   r  r+   rT   r   )r4   exclude_recenthistrW  poolr  r/  rn  s           r   _load_memoryr  	  sA   
 D rE%(YY%?%?4 . !!RD#$$Z 8 8!T"" 	55==F22xx55##)r0022::4EE 	$$$67777 r W  Z^  Zc  Zc  di  Zj  Zj  j  jr6   c                 $   t                      }d|v rdd|d         z   fS |                    d          sdS |d         d| dg|z   d	d
did}t          j                            d|d         z  t          j        |                              d          dd|d         z  dd          }t          j                            |d          5 }t          j	        |
                                          }ddd           n# 1 swxY w Y   |                    di g          d                             di           }|                    d          pd                                }|s)|                    d          pd                                }|dfS )uU   调用 DeepSeek API（thinking 必须 disabled，否则答案在 reasoning_content）r   Nu   DeepSeek 凭证读取失败：r{   )Nu   DeepSeek 凭证未配置rI   systemr/  rn  i  r  disabled)rI   r;   
max_tokensthinking%s/chat/completionsr|   r   r  	Bearer %sr  Authorizationr  r  r  r  choicesr   messagern  r>   reasoning_content)r   r2   r  r  r  r   r  r  r  r  r  r  	system_promptr;   r   rI  r  rw  r   msgrn  s	            r   _call_deepseekr  	  s   


C#~~5GDDD779 0//W&=AABXMZ(	 D .
 
 J/Z$$W--!3kTWXaTbFbcc	 !  C 
		S		1	1 !QJqvvxx  ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
%%	B4
 
 
#
'
'	2
6
6Cwwy!!'R..00G ?77.//52<<>>D=s   'C>>DDc                    t           j                            d          pd}dd| dg|z   dd}t          j                            dt          j        |                              d	          d
d|z  dd          }	 t          j        	                    |d          5 }t          j
        |                                          }ddd           n# 1 swxY w Y   |                    d          pi }|                    di g          d                             di           }|                    d          pd                                }	|	s)|                    d          pd                                }	|	sdd|fS |	d|fS # t          $ rS}
t          |
          }d|                                v sd|                                v rY d}
~
dS dd|
z  dfcY d}
~
S d}
~
ww xY w)uL   调用 Hermes API Server（OpenAI 兼容，带持久记忆 + 只读工具）API_SERVER_KEYnas-file-share-token-2026hermes-agentr  r  >  )rI   r;   r  )http://127.0.0.1:8642/v1/chat/completionsr   r  r  r  r  r     r  NrU   r  r   r  rn  r>   r  u   Hermes 返回空回答z	timed outr  )u   （该问题处理超时了。请换成更具体的问题，比如具体客户名、订单编号，或「XX客户最近的订单/回款情况」，我能更快回答。）NNu   Hermes 调用失败：%s)r   r  r2   r  r  r  r   r  r  r  r  r  r  r   r   r/  )r  r;   tokenrI  r  rw  r   rU   r  rn  r   _ms               r   _call_hermesr  	  s^   JNN+,,K0KE&=AABXM D
 .
 
 3Z$$W--!3kTYFYZZ	 !  C:^##C#55 	%
16688$$A	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	%g$"eeIt$$Q'++Ir::779%%+2244 	Cww2339r@@BBG 	91588e## : : :VV"((**$$	RXXZZ(?(? M  M  M  M  M  M/!3T9999999	:sO   >!F 'CF CF CB%F  F 
G";GGG"G"c              #     K   t           j                            d          pd}dd| dg|z   ddd}t          j                            d	t          j        |                              d
          dd|z  dd          }t          j        	                    |d          5 }|D ]7}|
                    d
d                                          }|                    d          sA|dd                                         }	|	dk    r n	 t          j        |	          }
n# t          $ r Y w xY w|
                    d          pg }|r|d                             di           ni }t          |t                     r|                    d          pdnd}|r|V  |
                    d          }|r*t          |t                     r|                    |           9ddd           dS # 1 swxY w Y   dS )ua   流式调用 Hermes API Server（SSE），逐段 yield delta 文本；usage 写入 usage_out dictr   r  r  r  r  r  T)rI   r;   r  streamr  r   r  r  r  r  r  ,  r  r  data:r/  N[DONE]r  r   deltarn  r>   rU   )r   r  r2   r  r  r  r   r  r  r  r  r  r  r  r   r   r   rv  )r  r;   	usage_outr  rI  r  rw  r'  r  r-   r   r  r(  rn  us                  r   _call_hermes_streamr  
  se     JNN+,,K0KE&=AABXM	 D .
 
 3Z$$W--!3kTYFYZZ	 !  C 
		S		1	1 $Q 	$ 	$C::gx006688D??7++ 8>>##DxJt$$   eeI&&,"G07?,,,RB3=b$3G3GOrvvi((.BRG gA $Z	400 $  ###'$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $s8   !A(G*
DG*
D,)G*+D,,B1G**G.1G.c                     t                      }d|v rdd|d         z   fS |                    d          sdS |d         d| dg|z   d	d
d}t          j                            d|d         z  t          j        |                              d          dd|d         z  dd          }t          j                            |d          5 }t          j	        |
                                          }ddd           n# 1 swxY w Y   |                    di g          d                             di           }|                    d          pd                                }|s)|                    d          pd                                }|dfS )u   调用智谱 GLM 5.3 Flash（直连 open.bigmodel.cn）。

    GLM 5.3 Flash 是 thinking 模型：真实答案在 content，思考过程在 reasoning_content。
    只取 content（reasoning 是英文思考痕迹，不进正文）。
    r   N   GLM 凭证读取失败：r{   )N   GLM 凭证未配置rI   r  r  r  r.  )rI   r;   r  temperaturer  r|   r   r  r  r  r  r  r  r  r  r   r  rn  r>   r  )r   r2   r  r  r  r   r  r  r  r  r  r  r  s	            r   	_call_glmr  3
  s    //C#~~03w<???779 +**W&=AABXM	 D .
 
 J/Z$$W--!3kTWXaTbFbcc	 !  C 
		S		1	1 !QJqvvxx  ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
%%	B4
 
 
#
'
'	2
6
6Cwwy!!'R..00G ?77.//52<<>>D=s   	'C<<D D c              #   t  K   t                      }d|v rt          d|d         z             |                    d          st          d          |d         d| dg|z   dd	d
d}t          j                            d|d         z  t          j        |                              d          dd|d         z  dd          }t          j        	                    |d          5 }|D ]7}|
                    dd                                          }|                    d          sA|dd                                         }	|	dk    r n	 t          j        |	          }
n# t          $ r Y w xY w|
                    d          pg }|r|d                             di           ni }t          |t                     r|                    d          pdnd}|r|V  |
                    d           }|r*t          |t                     r|                    |           9ddd           dS # 1 swxY w Y   dS )!u  流式调用智谱 GLM 5.3 Flash（SSE）。

    只 yield delta.content（真实答案），跳过 delta.reasoning_content（思考 token，不进正文、不占前端显示）。
    配置缺失时抛异常，由 handle_stream 捕获转 error 事件。
    r   r  r{   r  rI   r  r  r  r.  T)rI   r;   r  r  r
  r  r|   r   r  r  r  r  r  r  r  r  r  r/  Nr  r  r   r  rn  r>   rU   )r   RuntimeErrorr2   r  r  r  r   r  r  r  r  r  r  r  r   r   r   rv  )r  r;   r  r   rI  r  rw  r'  r  r-   r   r  r(  rn  r  s                  r   _call_glm_streamr  S
  s      //C#~~6WEFFF779 20111W&=AABXM D .
 
 J/Z$$W--!3kTWXaTbFbcc	 !  C 
		S		1	1 $Q 	$ 	$C::gx006688D??7++ 8>>##DxJt$$   eeI&&,"G07?,,,RB3=b$3G3GOrvvi((.BRG gA $Z	400 $  ###'$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $s8   $A(H-E"!H-"
E/,H-.E//B1H--H14H1c                      t           j                            dd                                                                          dvS )uV   模型路由总开关：AI_MODEL_ROUTING=off/0 时退回全 DeepSeek（一键回退）AI_MODEL_ROUTINGon)0offfalseno)r   r  r2   r  r/  r   r6   r   _routing_enabledr!  
  s7    :>>,d3399;;AACCKfffr6   c                     |rdS |rdS | pd                                 sdS d}t          fd|D                       rdS dS )uh   复杂度判断：文件上传 / 四步闭环模式 / 深度分析意图词 → 复杂（走 DeepSeek）Tr>   F)u   分析u   对比r  u   生成u   策略r  u   复盘r  360u   全景u   趋势u   预测u   订单u   回款kpiu   达成u   业绩u   金额u   账期u   应收c              3   D   K   | ]}|                                 v V  d S r$  r.  )r   r#   rM   s     r   r'  z_is_complex.<locals>.<genexpr>
  s/      
.
.a1		>
.
.
.
.
.
.r6   )r  r?  )rV   r   step
deep_wordsrM   s       @r   _is_complexr(  
  sv     t t	R  A u_J

.
.
.
.:
.
.
... t5r6   c                     t                      sdS |pddv }|dk    rdS |dk    r'|st          |          rdS ddt          |          z  fS t          | ||          r|st          |          rdS dS dS )u+  决定本次用哪个模型，返回 (target_model, fallback_notice)。

    target_model ∈ {'glm', 'deepseek'}；fallback_notice 非空表示发生了降级（DeepSeek 额度用尽）。
    规则：
      - pref='glm'       → 直接 GLM（无限流）
      - pref='deepseek'  → DeepSeek（admin/gm 豁免限流；其余每人每天 DEEPSEEK_DAILY_LIMIT 次，超限降 GLM）
      - pref='auto'      → 复杂走 DeepSeek（同额度约束），简单走 GLM
      - 路由开关 off      → 一律 DeepSeek（一键回退，不限额）
    )rz   r>   r0  r1  glm)r*  r>   rz   u]   DeepSeek 今日额度已用完（每人每天 %d 次），已自动改用 GLM 快速模型。)r!  rg   re   r(  )rV   r   r&  
model_prefr4   r/  rM  s          r   _route_modelr,  
  s      ~O3HUyZ 	"066 	"!>u  yF  GK  yL  yL  L  L  	L8UD))  	"066 	"!>y9r6   c           	          ddl }|                    t          j        |           dd          }g }|j        D ]}g }|                    d          D ]Z}d |D             }t          |          r(|                    d                    |                     t          |          dk    r n[|r3|                    d	|j
        d
d                    |                     d                    |          dd         S )u2   xlsx/xlsm → 文本（前 200 行，tab 分隔）r   NT)	read_only	data_only)values_onlyc                 4    g | ]}|dnt          |          S )Nr>   r  rV  s     r   r   z _parse_excel.<locals>.<listcomp>
  s&    >>>Q19RR#a&&>>>r6   	rj  z[Sheet: z]
r>  r}  p  )openpyxlload_workbookioBytesIO
worksheets	iter_rowsr?  rT   r   r   r7  )r'  r4  wbr  wsrowsrowcellss           r   _parse_excelr?  
  s   OOO			
344		P	PBEm 	J 	J<<D<11 	 	C>>#>>>E5zz .DIIe,,---4yyC   	JLLLbhhh		$HIIIKK&&r6   c                 "   ddl }|                    | d          }g }t          |          D ]\  }}|dk    r n|                                pd                                }t          |          dk     rg|dk     ra	 |                    d	
          }t          |                    d          d          pd                                }n# t          $ r d}Y nw xY w|r|
                    |           d                    |          dd         S )uM   PDF → 文本（前 20 页；扫描版无文字层时前 3 页 OCR 回退）r   Npdf)r
  filetyper]  r>   r  r   r  )dpipngr>  r3  )r  r   r  r  r  r   
get_pixmap
_parse_ocrtobytesr   rT   r   )r'  r  docr  r   pager  pixs           r   
_parse_pdfrK  
  s!   NNN
,,cE,
2
2CES>>  477E}}$"++--s88b==QUUoo#o..!#++e"4"4e<<BIIKK    	LL99UETE""s   <AC

CCc                    t           j                            |          d         pd}t          j        |          \  }}	 t          j        |d          5 }|                    |            ddd           n# 1 swxY w Y   t          j        dddd	|gd
d          }|j	        pd
                    dd          dd         	 t          j        |           S # t          $ r Y S w xY w# t          $ r* Y 	 t          j        |           dS # t          $ r Y dS w xY ww xY w# 	 t          j        |           w # t          $ r Y w w xY wxY w)u8   docx/doc/rtf/txt → 文本（textutil，macOS 自带）r$   rR  suffixr:  Ntextutilz-convertr  z-stdoutTr  capture_outputr  r6   r   r  r  r3  r>   )r   r   r  tempfilemkstempfdopenr  
subprocessrunstdoutr  unlinkr   )r'  r4   rN  fdr.   r   rw  s          r   _parse_via_textutilr[  
  s   Wd##A&0&Ff---GBYr4   	AGGCLLL	 	 	 	 	 	 	 	 	 	 	 	 	 	 	NJ
E9cJ*.< < <C'''AA%4%H	IcNNNN 	 	 	D	    	IcNNNNN 	 	 	DD		IcNNNN 	 	 	D	s   C* A8,C* 8A<<C* ?A< AC* C
C'&C'*
D4D! 6D 
DDDD! !E#D87E8
EEEEc                 N   t          j        d|z             \  }}	 t          j        |d          5 }|                    |            ddd           n# 1 swxY w Y   t          j        d|dddgd	d
          }|j        pd                    dd          dd         	 t          j	        |           S # t          $ r Y S w xY w# t          $ r* Y 	 t          j	        |           dS # t          $ r Y dS w xY ww xY w# 	 t          j	        |           w # t          $ r Y w w xY wxY w)u.   图片 → 文本（tesseract，chi_sim+eng）.rM  r:  N	tesseractrX  z-lzchi_sim+engTr   rP  r6   r   r  rR  r3  r>   )rS  rT  r   rU  r  rV  rW  rX  r  rY  r   )r'  r  rZ  r.   r   rw  s         r   rF  rF  
  s   cCi000GBYr4   	AGGCLLL	 	 	 	 	 	 	 	 	 	 	 	 	 	 	NKhmL*.< < <C'''AA%4%H	IcNNNN 	 	 	D	    	IcNNNNN 	 	 	DD		IcNNNN 	 	 	D	s   C AC AC AAC !B66
CC
C:C= C( (
C65C69C::C= =D$?DD$
D!D$ D!!D$c                 r   | pd} d| v r.|                      dd          d                                         nd}d}t          |t                    r0	 t	          j        |          }nE# t          $ r |dd         cY S w xY wt          |t          t          f          rt          |          }|dS 	 |dv rt          |          S |dk    r|
                    d	d
          dd         S |dv rt          ||           S |dk    rt          |          S |dv rt          ||          S n# t          $ r Y dS w xY wdS )uK   按扩展名分派解析上传文件，返回文本（失败返回空串）r>   r]  r$   rs   Nr3  )xlsxxlsmcsvr   r  rR  )docxrH  rtfr  rA  )rD  jpgjpeggifwebpbmp)rsplitr/  r   r   base64	b64decoder   bytes	bytearrayr?  r  r[  rK  rF  )r4   r-   r  r'  s       r   _parse_uploadro  
  s   :2D-0D[[$++c1

b
!
'
'
)
)
)bC
C$ 	"4((CC 	 	 	;		D5),	-	- Dkk
{r"""$$$%<<::gh:77>>///&sD111%<<c??">>>c3''' ?   rr2s<   A& &A=<A=0D& $D& (D& <D& D& &
D43D4u   

【当前步骤：🔍 分析】你现在的任务是帮销售做"访前分析"：主动给出客户画像、痛点、竞品、机会，并列出"该问客户什么"。u   

【当前步骤：📢 传递】你现在的任务是帮销售"说对话"：给出场景话术、价值主张、异议处理、竞品对比数据。u   

【当前步骤：✅ 跟进】你现在的任务是帮销售"推落地"：把结论拆解成行动项（负责人/截止日），给出协同推进建议。u   

【当前步骤：📖 沉淀】你现在的任务是帮销售"沉淀经验"：提炼成败原因、关键动作、可复用打法，引导回写知识库。)analyzedeliverfollowreviewc                    |                      d          pd                                }|                      d          pi }|                      d          pg }|                      d          pg }|s|s	|sdddd	fS |                     d
          sdddd	fS 	 t          |          \  }}t          |||          }|                      d          pd                                }|t          v r|t          |         z  }|}	|	st          |          D ]}
t          |
t                    rm|
                     d          dk    rT|
                     d          pd                                r+|
                     d          pd                                }	 nt          |	          }|rt          ||          }|rddl
}t          t          |                    p	|dd         d|                    d          d}d|d|d}t          ||                     d
d                    \  }}dd||t          |          t          |          g dgdfS t!          |	|||                     d          pddv           }t#          |	|                     dd                     }t%          |          }|r|r|d!z   |z   n|}t'          |	|||                     d          pddv           }|r|r|d!z   |z   n|}|r|d!|z   d"z   z  }t)          |                     d
d                    }|r|d!|z   z  }d}g }t          |t*                    r|ng D ]v}t          |t                    s|                     d
          pd}t-          ||                     d#          pd          }|r |                    |           |d$|d%|z  }wg }|d&d         D ]}
t          |
t                    r|
                     d          nd}t          |
t                    r)|
                     d          pd                                nd}|d'v r|r|                    ||d(           |r?d)|z   }|r|                    d|d!z   |z   d(           n3|                    d|d(           n|r|                    d|d(           |                      d*          pd+                                                                } t3          |	||| |                     d
d          |                     dd                    \  }!}"|!d,k    r8t5          |                     d
d                     t7          ||          \  }#}$}%nt9          ||          \  }#}$d}%|$rd-d|$d	fS t          |#|                     d
d                    \  }&}'t;          |                     d
d          |%||!           g }(|D ]})|(                    d.|)z              |r,|r|(                    d/           |(                    d0           |r|(                    d1           |r%|(                    d2t          |          z             |r%|(                    d3t          |          z             |(s|(                    d4           dd|&|'t          |          t          |          ||(dfS # t<          $ r}*d-dt?          |*          d	fcY d}*~*S d}*~*ww xY w)5u4   处理 /api/chat 请求，返回 (status_code, dict)rV   r>   rF  r;   r   r.  Fquestion required)okr   r4   i     未登录，无法回答r&  r/  rn  r   Nr      _拜访卡_%Y%m%drQ  <<<FILE:>>>
   
<<<END_FILE>>>

✅ 已生成拜访卡（含分级、决策链链接、价格档案、客诉）。决策链人物、竞品份额等深度信息标了「待补充」，可继续问我补充。rj  T   拜访卡自动生成)rv  r  r   re  visible_groupsparsed_filessourcesr0  r1  r  r   r}     

（以上是系统检索到的飞书活动、产品、知识库背景，请结合这些信息回答用户问题，不要回复"无法访问飞书信息"。）r-      

=== 文件： ===
rF  	assistantr  o   我上传了文件，请基于文件内容回答问题（文件中涉及客户数据时遵守权限约束）。rI   rE  rz   i     上传文件：   客户360全景   飞书活动+产品背景   IMA知识库   客户数据（%d 条可见）!   课题组数据（%d 条可见）   AI 通用知识) r2   r  rH  rJ  STEP_PROMPTSreversedr   r   rV  r  r  r/  r  rR   r  r   r  r  r  r$  r  r8   ro  rT   r/  r,  ri   r  r  rY   r   r   )+rw  rV   rF  r;   r   rK  rL  
sys_promptr&  _q_for_searchr  
visit_cust_visit_htmlr  _fname_full_clean_files
backgroundr  kb_hitcust360_mem
upload_ctxupload_namesr   r  parsedhistoryr/  rn  up_mp_tm_fnr  errrU   clean_answer	files_outr  r*  r   s+                                              r   handler  $  sO   J''-24466H;;v$"D{{:&&,"HKK  &BE @H @U @5+>????88F G5+EFFFFc3*400w)$w??
F##)r0022<,t,,J  	h''  a&& 155==F+B+BiHXHXH^\^GeGeGgGg+B%&UU9%5%5%;$B$B$D$DME)-88
 		W+J==K W!!!!3>z*?U?U3V3V3hZdegfgegZh3h3hjljujuv~jjjj  A sy  sy  sy  {F  {F  {F  G!/txx7K7K!L!L46F25e**PST[P\P\-/=T<UW W W W (ugQWHXHXHc\chwGwxx
&}dhhvt6L6LMMe 	P:DO*v-55%J#M5'DHHVDTDTD_X_dsCstt 	T<FS*v-77GJ 	U&:-  1U  U  UJDHHVR0011 	(&4-'J
%eT22:%% 	N 	NAa&& EE&MM'RE"5!%%--*=2>>F N##E***
uuuffMM
#$$ 	C 	CA$.q$$7$7?155===RD:DQ:M:MUquuY''-244666SUG,,,,AABBB 	B C  FP  PB @8f;Lr;QRRSSSS2>>???? 	BNNFx@@AAA{{7##-v4466<<>>udC&RTAUAUW[W_W_`fhjWkWkllS*#DHHVR$8$8999!-j'!B!BFC#J88KFCE 	4us3333"0&"9M9M"N"NiDHHVR00%3GGG 	2 	2ANN,q01111 	8 20111NN6777 	+NN>*** 	JNN;c%jjHIII 	ONN>WMNNN 	.NN,---4<)*-e**G%1gG G G 	G  3 3 353q662222222223s-   F9[ L8[ D;[ 
[0[+%[0+[0c              #   ^  K   |                      d          pd                                }|                      d          pi }|                      d          pg }|                      d          pg }|s|s|s	dddV  d	S |                     d
          s	dddV  d	S dddV  	 t          |          \  }}t          |||          }|                      d          pd                                }|t          v r|t          |         z  }|}	|	st          |          D ]}
t          |
t                    rm|
                     d          dk    rT|
                     d          pd                                r+|
                     d          pd                                }	 nt          |	          }|rt          ||          }|rdd	l
}t          t          |                    p	|d	d         d|                    d          d}d|d|d}t          ||                     d
d                    \  }}ddg|ddt          |          t          |          g dV  d	S t!          |	|||                     d          pddv           }t#          |	|                     dd                     }t%          |          }|r|r|d!z   |z   n|}t'          |	|||                     d          pddv           }|r|r|d!z   |z   n|}|r|d!|z   d"z   z  }t)          |                     d
d                    }|r|d!|z   z  }d}g }t          |t*                    r|ng D ]v}t          |t                    s|                     d
          pd}t-          ||                     d#          pd          }|r |                    |           |d$|d%|z  }wg }|d&d	         D ]}
t          |
t                    r|
                     d          nd}t          |
t                    r)|
                     d          pd                                nd}|d'v r|r|                    ||d(           |r?d)|z   }|r|                    d|d!z   |z   d(           n3|                    d|d(           n|r|                    d|d(           |                      d*          pd+                                                                } t3          |	||| |                     d
d          |                     dd                    \  }!}"|!d,k    r#t5          |                     d
d                     d-d.d/                     |!|!          }#dd0|#z  dV  i }$d}%|!d1k    rt6          nt8          }& |&|||$          D ]}'|'r|%|'z  }%d2|'dV  t          |%|                     d
d                    \  }(})t;          |                     d
d          |$||!           g }*|D ]}+|*                    d3|+z              |r,|r|*                    d4           |*                    d5           |r|*                    d6           |r%|*                    d7t          |          z             |r%|*                    d8t          |          z             |*s|*                    d9           d|*|)|!|"pdt          |          t          |          |dV  d	S # t<          $ r},dt?          |,          dV  Y d	},~,d	S d	},~,ww xY w):u$  流式处理 /api/chat：yield 事件 dict，type ∈ {status, delta, done, error}

    与 handle() 逻辑一致（检索背景 → 调 Hermes），区别是：检索前先发 status、
    LLM 回答改走 SSE 逐段 yield delta，避免前端长时间无响应被 240s 超时切断。
    rV   r>   rF  r;   r   r   ru  )r  r   Nr4   rw  r  u   正在检索业务背景…r&  r/  rn  r   r   rx  ry  rQ  rz  r{  r|  ry  r}  z
visit-card)r  r  r   rI   noticere  r~  r  r0  r1  r  r   r}  r  r-   r  r  r  r  r  r  rI   rE  rz   u
   GLM 快速u   DeepSeek 深度)r*  rz   u1   已检索到背景，正在用 %s 思考回答…r*  r  r  r  r  r  r  r  r  ) r2   r  rH  rJ  r  r  r   r   rV  r  r  r/  r  rR   r  r   r  r  r  r$  r  r8   ro  rT   r/  r,  ri   r  r  rY   r   r   )-rw  rV   rF  r;   r   rK  rL  r  r&  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r/  rn  r  r+  target_modelfallback_notice_model_labelrU   	full_text
_stream_fnchunk
clean_textr  r  r*  r   s-                                                r   handle_streamr    s      J''-24466H;;v$"D{{:&&,"HKK  &BE H U (;<<<<<88F (BCCCCC%B
C
CCCCm0*400w)$w??
F##)r0022<,t,,J  	h''  a&& 155==F+B+BiHXHXH^\^GeGeGgGg+B%&UU9%5%5%;$B$B$D$DME)-88
 	+J==K !!!!3>z*?U?U3V3V3hZdegfgegZh3h3hjljujuv~jjjj  A sy  sy  sy  {F  {F  {F  G!/txx7K7K!L!L%#:"; & ,!#,/JJ),W')+ + + + + 'ugQWHXHXHc\chwGwxx
&}dhhvt6L6LMMe 	P:DO*v-55%J#M5'DHHVDTDTD_X_dsCstt 	T<FS*v-77GJ 	U&:-  1U  U  UJDHHVR0011 	(&4-'J
%eT22:%% 	N 	NAa&& EE&MM'RE"5!%%--*=2>>F N##E***
uuuffMM
#$$ 	C 	CA$.q$$7$7?155===RD:DQ:M:MUquuY''-244666SUG,,,,AABBB 	B C  FP  PB @8f;Lr;QRRSSSS2>>???? 	BNNFx@@AAAkk'**4f;;==CCEE
(45$
DHHVR4H4H$((SY[]J^J^)` )`%o:%%#DHHVR$8$8999+9JKKOOP\^jkk)\_k)klllll	)5)>)>%%DW
Z
GU;; 	7 	7E 7U"	&66666 .y$((62:N:N O O
IDHHVR00%<PPP 	2 	2ANN,q01111 	8 20111NN6777 	+NN>*** 	JNN;c%jjHIII 	ONN>WMNNN 	.NN,---!!$(.B$'JJ!$W+- - 	- 	- 	- 	- 	-  0 0 0A///////////0s    &F;\ #R\ 
\,\''\,c                    ddl m } g }t          | t                    r| ng D ]}t          |t                    r|                    d          nd}t          |t                    r)|                    d          pd                                nd}|dv r|r|                    ||d           |sdS d	                    d
 |dd         D                       }g d}	}|D ]8}|d         dk    r	|d         }	|	|                    |	|d         f           d}	9d                    d t          |d          D                       }
d|z   }d}t          |d|dg          \  }}|rd|fS |sdS |                                
                    d	          }d}g }t          |          D ]q\  }}|                                }|dk    r=|                    d          r(|                    d                                          }\|                    |           r|s*d|                                                    d          z   }d	                    |                                          }|}|
r|d|
z   z  }||fS )u   把一段多轮问答链（含补充追问）提炼成结构化经验条目。

    返回 (title, content) 或 (None, error)。
    content = LLM 提炼的结构化正文 + 附带的原始问答链（可追溯）。
    r   r@   r/  r>   rn  r  r  )Nu   没有可归档的对话内容r>  c              3   H   K   | ]}|d          dk    rdnd|d         z   V  dS )r/  rF  u	   用户：u	   助手：rn  Nr   )r   r  s     r   r'  z%archive_experience.<locals>.<genexpr>'  sQ         &	V++)L     r6   r  NrF  r}  c              3   4   K   | ]\  }\  }}d ||||fz  V  dS )u   **Q%d**：%s

**A%d**：%sNr   )r   r   qqaas       r   r'  z%archive_experience.<locals>.<genexpr>4  sK        AxB 	'!RB7     r6   r$   u  以下是宝锐销售工作台 AI 助手与用户的一段多轮对话（含补充追问）。
请把这段对话提炼成一条可复用的销售经验，用 markdown 输出，格式严格如下：

# <一句话标题，概括这条经验的核心结论>

**问题背景**：<初始问题、客户或场景>

**涉及客户**：<对话中提到的客户名，没有就写"无">

**涉及货号/产品**：<对话中提到的货号或产品，没有就写"无">

**关键结论**：<多轮追问后沉淀的核心结论，分点列出>

**建议动作**：<下一步建议或可复用的打法>

要求：简洁、专业、可复用；不得编造对话中没有的信息；保留具体数字与货号。

对话内容：
uf   你是销售知识管理助手，负责把销售对话提炼成结构化、可复用的经验条目。)Nu$   经验提炼失败，请稍后重试ry  u   销售经验_z
%Y%m%d%H%Mu   

---

## 原始问答链

)rA   r   r8   r   r2   r  rT   r   r  r  r  r  r  rP   rR   )r;   rF  rA   chainr  r/  rn  dialogqarM   	raw_chainextract_promptextract_sys	extractedr  rW  r7  
body_linesr   rq  r[  rI  fulls                          r   archive_experiencer    s    "!!!!!E$Xt44<hh" = = *1d 3 3;quuV}}}6@D6I6IQ155##)r00222r(((W(LL$7;;<<< 655 YY  stt    F B  V9)AA]IIq!I,'(((A  $R++    I		 %		%  {K#K6n2]2]1^__NIs
 Sy <;;OO##D))EEJ5!! " "2HHJJ66all3''6HHSMM''))EEb!!!! H(,,.."9"9,"G"GG99Z  &&((DD @3i??$;r6   c                    ddl }d } |d          pi }|                    | i           pi } |d          pi }t          |t                    r|                    | g           ng } |d          pi }t          |t                    r|n@t          |t                    r*|                    d|                    dg                     ng }	t          |           }
t          |
          p	| dd	         }g }|	pg D ]\}t          |t                    st          |                    d
d                    }|r||v s|
r|
|v r|                    |           ] |d          pi }t          |t                    r|                    | i           ni }d}g }t          |t                    rd|	                                D ]O\  }}t          |t                    r5t          d |D                       }||z  }|                    ||f           P|                    d            d                    d |dd         D                       pd}t          |                    dd          pd                                          }|                    dd          pd}|                    dd          p|                    dd          }|                    d          }d}t!          |pg dd                   D ]T\  }}t          |t                    r:|                    dd          }|                    dd          }|d|d z   ||fz  z  }U|sd!}d} |dd         D ]g}|                    d"|                    d#d                    }!|                    d$d          }"|                    d%d          }#| d&|!d'|"d'|#d(z  } h| sd)} |                    d*d          }$|                    d+d          }%d}&|$r|&d,|$z  z  }&|%r|&d-|%z  z  }&|&sd.}&d/|||||| ||&t#          |pg           |d0z  t#          |          ||| ||d0z  fz  }'|'S )1u   生成基础版市场调研卡 HTML（本地数据：画像/商机/决策链/竞对情报/价格档案）。
    深度竞品格局需 Hermes 主 Agent Web 搜索，此处标"待补充"。返回 html 或 None。r   Nc                     	 t          t          j                            t          |           d          5 }t          j        |          cd d d            S # 1 swxY w Y   d S # t          $ r Y d S w xY w)Nr   r   r  )r   r   s     r   _ljz_build_market_card.<locals>._ljc  s    	bgll8T22WEEE $y||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 	 	 	44	r  rZ  r{  r  r   r-   r   r   r>   z_archive/price_archive.jsonc              3   l   K   | ]/}t          |t                    |                    d d          V  0dS r]  rU  rl  s     r   r'  z%_build_market_card.<locals>.<genexpr>  s=      LLa
1d8K8KL!%%q//LLLLLLr6   c                     | d          S r_  r   r`  s    r   r9  z$_build_market_card.<locals>.<lambda>  r`  r6   r:  r<  c                     g | ]=}|d                               d          d                                          dd         >S rg  ri  r  s     r   r   z&_build_market_card.<locals>.<listcomp>  rj  r6   r   rk  rb  rc  rd  re  r   r4   rB   rf  r|  r  r}  zE<tr><td>%d</td><td>%s</td><td><span class="tag b">%s</span></td></tr>r$   uF   <tr><td colspan="3" style="color:#9aa0a6">暂无商机记录</td></tr>r  
competitorproductro  z<tr><td>z	</td><td>z
</td></tr>uc   <tr><td colspan="3" style="color:#9aa0a6">暂无竞对情报沉淀，需 Web 搜索补充</td></tr>rn  ro  uG   <a class="btn" href="%s" target="_blank">🔗 打开飞书决策链</a>uJ   <a class="btn" href="%s" target="_blank">📋 打开飞书客户档案</a>u>   <span style="color:#9aa0a6">暂无飞书决策链链接</span>u.  <!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>%s · 市场调研卡（基础版）</title>
<style>
:root{--pri:#1a73e8;--pri-d:#0d47a1;--bg:#f5f7fa;--card:#fff;--ink:#202124;--sub:#5f6368;--line:#e8eaed;--ok:#10ac84;--warn:#f2994a;--bad:#eb5757}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;background:var(--bg);color:var(--ink);padding:16px;line-height:1.65}
.wrap{max-width:980px;margin:0 auto}
.banner{background:linear-gradient(135deg,#0d47a1,#1565c0,#1a73e8);border-radius:14px;padding:24px 28px;color:#fff;box-shadow:0 4px 16px rgba(13,71,161,.25)}
.banner h1{font-size:21px}.banner .sub{font-size:13px;opacity:.9;margin-top:4px}
.badge{display:inline-block;background:rgba(255,255,255,.22);border-radius:20px;padding:2px 12px;font-size:12px;margin-left:10px;vertical-align:middle}
section{background:var(--card);border-radius:12px;padding:20px 22px;margin-top:16px;box-shadow:0 1px 3px rgba(0,0,0,.05)}
h2{font-size:16px;color:var(--pri-d);margin-bottom:14px;padding-left:10px;border-left:4px solid var(--pri)}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.kpi{background:var(--bg);border-radius:10px;padding:14px 16px;border:1px solid var(--line)}
.kpi .v{font-size:20px;font-weight:800;color:var(--pri)}.kpi .l{font-size:12px;color:var(--sub);margin-top:2px}
table{width:100%%;border-collapse:collapse;font-size:13px}
th{background:#f1f3f4;color:#5f6368;text-align:left;padding:9px 10px;font-weight:600;border-bottom:2px solid var(--line)}
td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:top}
tr:last-child td{border-bottom:none}
.tag{display:inline-block;font-size:11px;border-radius:4px;padding:1px 7px;background:#e8f0fe;color:var(--pri)}
.btn{display:inline-block;background:var(--pri);color:#fff;text-decoration:none;border-radius:8px;padding:8px 16px;font-size:13px;margin:4px 6px 4px 0}
.note{background:#eef4fd;border:1px solid #c9ddf6;border-radius:10px;padding:14px 16px;font-size:13px;margin-top:12px}
</style></head><body><div class="wrap">
<div class="banner"><h1>%s <span class="badge">市场调研卡 · 基础版</span></h1><div class="sub">级别：%s ｜ 对接销售：%s ｜ 编制：%s</div></div>
<section><h2>一、赛道定位</h2><table>
<tr><th style="width:120px">维度</th><th>结论</th></tr>
<tr><td>客户名称</td><td>%s</td></tr>
<tr><td>客户分级</td><td><span class="tag">%s</span></td></tr>
<tr><td>决策链</td><td>%s</td></tr>
<tr><td>终端赛道</td><td><span style="color:var(--warn)">待确认</span>（需 Web 搜索判断：人用IVD / 宠物诊断 / 科研服务 / 食品安全检测）</td></tr>
</table></section>
<section><h2>二、关键数据</h2><div class="kpis">
<div class="kpi"><div class="v">%d</div><div class="l">在跟商机数</div></div>
<div class="kpi"><div class="v">%.1f 万</div><div class="l">累计采购额</div></div>
<div class="kpi"><div class="v">%d</div><div class="l">竞对情报条数</div></div>
<div class="kpi"><div class="v">%s</div><div class="l">主采产品 TOP</div></div>
</div></section>
<section><h2>三、在跟商机</h2><table><tr><th>#</th><th>商机名称</th><th>状态</th></tr>%s</table></section>
<section><h2>四、竞对情报（本地沉淀）</h2><table><tr><th>竞品品牌</th><th>产品/项目</th><th>备注</th></tr>%s</table>
<div class="note">⚠️ 深度竞品格局（终端赛道竞争格局、市场规模、竞品对比）需 Hermes 主 Agent 执行 Web 搜索补全。本基础版仅含本地沉淀数据。</div>
</section>
<section><h2>五、宝锐协同角色</h2><table>
<tr><th style="width:140px">主采产品</th><td>%s</td></tr>
<tr><th>累计采购额</th><td>%.1f 万</td></tr>
</table></section>
</div></body></html>rG  )r  r2   r   r   r8   r  r/  r   rT   r   r  r~  r   r  r+   rR   r  r   )(r0  rF  r  r  r  r  oppr  r  ci_itemsr  r  comp_matchesr7  cnamer  r  r  r  r&  rv   r  r  r  r  r   ra   opp_rowsr   r  rt  rU  	comp_rowsr  r   ro  durlclink	link_btnsr  s(                                           r   _build_market_cardr  _  s    KKK   #)
*
*
0bC779b!!'RD
#%
&
&
,"C&0d&;&;CCGGIr"""E	$	%	%	+BD))trrWabdfjWkWk0swvr@R@R0S0S0SqsHi  D.2A2ELn" # #!T"" 	AEE*b))** 	#eunn$n45=="""	*	+	+	1rB&0T&:&:BRVVIr"""FI
C&$ %LLNN 	% 	%DAq!T"" %LL1LLLLLS 	

As8$$$HHH!!!::HHBQBHHHIIX[DTXXgr**0b117799J$$UE22DnKHHWb!!9TXXfb%9%9EMM*%%EH5;B+,, r r1a 	rvx((Bx--B_cdghchjlnpbqqqH \[I"1" X Xgquu\;??@@uuY##uuVR  	UUUDDDRVRVRVWW		 zy	88("--DHH_b))EI f^aeee	 jadiii	 UT	.\ !%eU{Ii')3|+<+<diy724]14Dd Kr6   c                    |                      d          pd                                }|sg dfS |                      d          pg }|sdg}t          |          }t          |          p	|dd         }t          j                            t          dd          }t          j                            t          d          }g }g }	d|v r	 t          ||          }
|
rt	          j	        |d	
           t          j                            |d|z            }t          |dd          5 }|                    |
           ddd           n# 1 swxY w Y   |                    dt          j                            |t                    |d           n|	                    d           n/# t          $ r"}|	                    d|z             Y d}~nd}~ww xY wd|v r	 t          ||          }
|
rt	          j	        |d	
           t          j                            |d|z            }t          |dd          5 }|                    |
           ddd           n# 1 swxY w Y   |                    dt          j                            |t                    |d           n|	                    d           n/# t          $ r"}|	                    d|z             Y d}~nd}~ww xY w||	rd                    |	          ndfS )u_   处理一个拜访请求：按 types 生成拜访卡 + 市场调研卡。返回 (files, err)。r   r>   zcustomer requiredtypesr  Nr   u   客户管理Tr    u   %s_拜访卡.htmlr#   r   r   )r  r   r   u   拜访卡生成失败u   拜访卡异常: %sr  u   %s_市场调研卡.htmlu   市场调研卡生成失败u   市场调研卡异常: %sz; )r2   r  r  r/  r   r   r   r  r  r(   r   r  rT   relpathr   r  )r  rF  r   r  r  r  card_dirmkt_dirr   errsr  rp  r   r   s                 r   _process_visit_requestr    s   
##)r0022H '&&&GGG"E hD-"1"Ew||D.+>>Hgll400GEDe	3$Xt44D 5Ht4444gll8-@5-HII#sW555 "GGDMMM" " " " " " " " " " " " " " "k27??3PT;U;Uckllmmmm3444 	3 	3 	3KK-122222222	3E!!	9%h55D ;Gd3333gll7,E,MNN#sW555 "GGDMMM" " " " " " " " " " " " " " "&7QTVZA[A[iqrrssss9::: 	9 	9 	9KK3a788888888	9T1$))D///r11s|   	AF& &E<F& EF& EAF& &
G0GGAJ8 8IJ8 IJ8 !I"AJ8 8
K$KK$)r>   )NNF)NFr$  )r   )r|  )r   r>   N)r>   r0  )T)r  )r  )__doc__rk  r6  r   r   rV  rS  urllib.requestr  r   dirnameabspath__file__r  r   r)   r   rO  r  rL  r   rN   rt   r[   rk   r9   r@  r   r/   r5   r=   rY   r\   r^   rc   rg   ri   rl   rn   rp   re   r   r   r   r   r   r   r   r   r   r   rA  rD  r@  rG  rC  rX  r  r  r  r  r   r  r  r  KB_CHUNKKB_CHUNKS_PER_FILEr  r  r  
KB_GENERICr  r  r  r  r"  r+  r5  rQ  rY  r]  r[  r`  rw  r  r  r  r  r  r  rE  r$  r'  r-  rH  rL  rM  rN  rR  rX  r`  rk  r|  r~  rB  r  r  r  r  r  r  r  r  r  r  r  r  r  r9  r=  rJ  rM  rP  r  rU  rV  r/  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r(  r,  r?  rK  r[  rF  ro  r  r  r  r  r  r  r   r6   r   <module>r     sb  
 
  				  				         	wrwrwx'@'@AABB7<<h''w!!"^__7<<g..W\\,55
w||H&9::7<<*?@@  gll8-EFF 7<<*ABB ".B]^^

 
 

 
 
) ) )
     @
 
 
	 	 	I I I. . .  
 
 

 
 
2 2 2
  ! ! !! ! !  4 	# # #8! ! !([ [ [l l l  $ $ $&  z z z+x(,,, +z* x"	
 222 x# 777 === X/0 @@@ x! xj +z* xj +  xj!" +z*#$ z*#$'   , \[[  >==  
  ? ? ? ?De/ e/ e/ e/P   =:	 
				d/	0	0X77 	t
$
$h h h
         F  $r r r! ! !H  "< < < <@ 	  $7 7 7( ( (V "*4FPT $  $  $  $ Nu/ u/ u/ u/v  D   ,  8   EJ EJ EJ EJN	 	 	  # # #T 7<<*NOO  I  I  I      L L L   # # # #LC  C  C L$ $ $$ xT[qx  NU  V  V
    &   *
 
 
 
+ + + +*777HHH 444 777	
 YYY JJJ +u% ;;; 
/// 
,,, 
E8 
<<< === 999 VVV  BBB!" EEE#$ FEE/n/n/nVVV)  0T T T Tp+ +k]
^Y')7& +~. 19;:W z	 $,.?-@	
 ~
 !/
 + !,k] ^$ '/ (  "(.)9  !  fee  $7 7 7t  :  &   T T T Tn` ` `F
 
 
   I R( ( (  O O Of X/FGG 	 	 	    :,Z ,Z ,Z^1 1 1 1h    # # # #       6j j j j.  8: : :@"$ "$ "$J  @+$ +$ +$\g g g
     6' ' '$# # #*  &  $  > ~ j r r	 m3 m3 m3`0 0 0DF F FRy y yx(2 (2 (2 (2 (2r6   