
    OaHj3                     :   S r SSKrSSKrSSKrSSKrSSKrSSKrSSKJr  SSKJ	r	J
r
  SSKrSSKJr  SSKJr  \R                   " \R"                  S9  \R$                  " \5      r\R*                  R-                  SS	5      r\R*                  R-                  S
S5      r\R*                  R-                  SS5      r\R*                  R-                  SS5      r\" \R*                  R-                  SS5      5      r\R*                  R-                  SS5      r\R*                  R-                  SS5      r\" SS\\S9r    SQS\ S\
\    S\
\!   S\S\
\"   S\#4S jjr$S S!S"S#S$S%S&S'.0S$/S(.S).S*.S S+S,S#S$S%S-S'.0S$/S(.S).S*.S S.S/S#S0S%S1S'.0/ S(.S).S*.S S2S3S#0 / S(.S).S*.S S4S5S#S6S%S7S'.0S6/S(.S).S*./r%S8\!S\!4S9 jr&SRS8\!S:\S;\S\!4S< jjr'S=\!S\	4S> jr(S?\!S@\#S\!4SA jr)SB\!S\!4SC jr*SB\!S8\!S\ 4SD jr+\RY                  SESF9SSSB\!S8\
\!   S\!4SG jj5       r-\RY                  SHSF9SB\!S\!4SI j5       r.\RY                  SJSF9SB\!S8\!S\!4SK j5       r/\SL:X  aO  SSK0r0\1" \0Rd                  5      SM:  a  \0Rd                  SM   OSNr3\Ri                  SO\3\\5        \Rk                  \3SP9  gg)Tu9   MCP Server for 5号机 Qwen3.6-27B-AWQ with tool calling.    N)datetime)AnyOptional)FastMCP)Image)levelVLLM_BASE_URLzhttp://127.0.0.1:8000/v1VLLM_API_KEYnone
MODEL_NAMEzqwen3.6-27b-awqMCP_HOSTz0.0.0.0MCP_PORT8080RAG_BASE_URLzhttp://192.168.192.223:8765SEAWEED_FILER_URLzhttp://192.168.192.223:8888zqwen-serveru   通过 MCP 调用 5号机上的 Qwen3.6-27B 大模型。支持直接对话（qwen_chat）和带工具自主调用的对话（qwen_agent）。)instructionshostportmessagestoolstool_choice
max_tokenstemperaturereturnc                 $   [         U US.nUb  XS'   Ub  X%S'   Ub  XES'   SS0n[        (       a  [        S:w  a  S[         3US	'   [        R                  " [        R                  S
5       S3UUSS9nUR                  5         UR                  5       $ )uG   通过 requests 调用 vLLM chat completions API，返回原始 dict。)modelr   r   r   r   r   zContent-Typeapplication/jsonr   zBearer Authorization/z/chat/completionsi,  )jsonheaderstimeout)r   r
   requestspostr	   rstripraise_for_statusr    )r   r   r   r   r   payloadr!   resps           mcp_server_qwen.py_call_vllm_chatr*   $   s      G
  !,!,12G|.%,\N#; ==$
%%67	D 	99;    function	rag_queryu   查询223号机器的RAG知识库，返回相关知识片段。当用户问题可能涉及项目知识、文档、既往记录时使用。objectqstringuL   查询问题或关键词，建议带上 project:项目名 以便精确检索)typedescription)r1   
propertiesrequired)namer2   
parameters)r1   r,   rag_chatuB   让223号机器的RAG知识库以客服口吻直接返回答案。u   要问的问题seaweed_listuN   列出223号机器SeaweedFS文件存储中指定路径下的文件和目录。pathu3   要列出的路径，如 / 或 /files，默认为 /current_timeu   获取当前时间。
calculatoru   进行基础数学计算。
expressionu   数学表达式，如 1+2*3	image_urlc                    [        U [        5      (       a  U R                  5       (       d  U $ U R                  S5      (       a  U $ U R                  S5      (       a  U $ [        R
                  R                  U R                  5       5      n[        R
                  R                  U5      (       a  [        R
                  R                  U5      S   R                  5       nSSSSSSS	.R                  US
5      n[        US5       n[        R                  " UR                  5       5      R                  S5      nSSS5        [         R#                  SX5        SU SW 3$ U $ ! , (       d  f       N.= f)u   把图片来源统一转成 base64 data URL。

支持：
  - data:image/*;base64,... 原样返回
  - http(s)://... 原样返回（由 vLLM 自行下载）
  - 本地绝对/相对路径，读取文件后转 base64

data:image)zhttp://zhttps://   z	image/pngz	image/gifz
image/webpz	image/bmpz
image/tiff)z.pngz.gifz.webpz.bmpz.tiffz.tifz
image/jpegrbasciiNzLoaded local image: %s (%s)zdata:z;base64,)
isinstancestrstrip
startswithosr9   
expanduserisfilesplitextlowergetopenbase64	b64encodereaddecodeloggerinfo)r=   r9   extmimefb64s         r)   _resolve_image_urlrX      s1    i%%Y__->->L))34477ioo/0D	ww~~dggt$Q'--/!! 
 #c<
  	 $""1668,33G<C 14>tfHSE**	 s   4E
E-
max_pixelsqualityc           	         [        U [        5      (       a  U R                  S5      (       d  U $  U R                  SS5      u  p4[        R
                  " U5      n[        U5      S-  n[        R                  " [        R                  " U5      5       nUR                  S;   a  UR                  S5      nUR                  u  p[        X5      n
X:  aH  X-  n[        X-  5      [        X-  5      4nUR!                  U[        R"                  R$                  5      n[        R                  " 5       nUR'                  USUSS	9  UR)                  5       n[        U5      S-  n[        R*                  " U5      R-                  S
5      nSSS5        [.        R1                  SUWWW	WR2                  UR4                  5        SW 3$ ! , (       d  f       NB= f! [6         a"  n[.        R9                  SU5        U s SnA$ SnAff = f)u   压缩 base64 图片，减小传输和推理开销。

仅处理 data:image/*;base64,... 格式。HTTP(S) URL 原样返回。
压缩策略：等比缩放最长边到 max_pixels，再用 JPEG quality 编码。
r?   ,r@      )RGBAPRGBJPEGT)formatrZ   optimizerB   Nz5Image compressed: %.1f KB -> %.1f KB (%dx%d -> %dx%d)zdata:image/jpeg;base64,z,Image compression failed: %s, using original)rC   rD   rF   splitrN   	b64decodelenr   rM   ioBytesIOmodeconvertsizemaxintresize
ResamplingLANCZOSsavegetvaluerO   rQ   rR   rS   widthheight	Exceptionwarning)r=   rY   rZ   headerb64_dataraworiginal_kbimgrs   rt   max_siderationew_sizebuffer
compressedcompressed_kbcompressed_b64excs                     r)   _compress_image_data_urlr      s    i%%Y-A-A,-O-O$??32x(#hoZZ

3(Cxx=(kk%(HHME5)H$"-.FN0CDjj5+;+;+C+CDZZ\FHHVFGdHK*J
Od2M#--j9@@IN! )$ 	CvIIszz	

 )(899/ )(0  EsKs7   A"G C2F?;G ?
G	G 
G<G71G<7G<exprc                 t    [         R                  " SSU 5      nU(       d  [        S5      e[        US0 00 5      $ )u=   安全地计算数学表达式，只允许数字和 +-*/()。z[^0-9+\-*/().\s] u   无效的数学表达式__builtins__)resub
ValueErroreval)r   cleaneds     r)   
_safe_evalr      s8    ff("d3G344."-r22r+   r5   	argumentsc           
          U S:X  aM  UR                  SS5      n[        R                  " [         S3SU0SS9nUR	                  5         UR
                  $ U S:X  aM  UR                  SS5      n[        R                  " [         S3SU0S	S9nUR	                  5         UR
                  $ U S
:X  GaX  UR                  SS5      =(       d    SnUR                  S5      (       d  SU-   nSS0n[        R                   " [        R                  S5       U 3USS9nUR	                  5         UR                  5       nUR                  S/ 5      nSUR                  SU5       3S[        U5       3/nU H|  n	U	R                  SS5      n
U	R                  SS5      n[        U	R                  SS5      S-  5      nU	R                  SS5      nUR                  U(       a  SOS SU
 SU SU 35        M~     U(       a  SR                  U5      $ S $ U S!:X  a#  [        R                  " 5       R!                  5       $ U S":X  a"  UR                  S#S5      nU S$[#        U5       3$ S%U  3$ ! [$         a  n	S&U  S'U	 3s S(n	A	$ S(n	A	ff = f))u6   执行模型选择的工具并返回字符串结果。r-   r/   r   z/query   )r    r"   r7   z/chat<   r8   r9   r   Acceptr   )r!   r"   EntrieszPath: Pathz	Entries: FullPathFileSizer   Modei @  Mtimez[DIR] z[FILE] z size=z mtime=
u	   空目录r:   r;   r<   z = u   未知工具: u   工具执行错误 (z): N)rL   r#   r$   r   r&   textrF   r   r%   r    rf   boolappendjoinr   now	isoformatr   ru   )r5   r   r/   r(   r9   r!   dataentrieslinesefullrk   is_dirmtimer   s                  r)   execute_toolr      sk   $3;c2&A==L>!8QxQSTD!!#99Zc2&A==L>!7sAhPRSD!!#99^#==-4D??3''Tz!34G<<#4#;#;C#@"A$ HRYcefD!!#99;Dhhy"-Gdhhvt456)CL>8RSEuuZ,uuZ+aeeFA.89gr*FA4&tfT[\a[bcd  (-499U#=+=^#<<>++--\!==r2DV3z$/011#D6** 3%dV3qc223sD   AI AI (EI I (I 0'I I 
I9'I4.I94I9promptc           	        #    SU S./nSn[        U5       GH!  n[        U[        SSS9nUS   S   S	   nUR                  S
/ 5      =(       d    / nU(       a  [        R                  SUS-   [        U5      5        UR                  SUR                  S5      =(       d    SUS.5        U Hn  nUS   S   n [        R                  " US   S   5      n	[        X5      n
[        R                  SU[        U
5      5        UR                  SUS   U
SS S.5        Mp     GM  UR                  S5      =(       d    Ss  $    g! [        R                   a    0 n	 Nf = f7f)u0   与模型对话并允许其自动调用工具。userrolecontent   auto   )r   r   r   r   choicesr   message
tool_callsz)Round %s: model requested %s tool call(s)r@   	assistantr   r   )r   r   r   r,   r5   r   zTool %s returned %s charstoolidNi@  )r   tool_call_idr   u9   达到最大工具调用轮数，请简化问题重试。)ranger*   TOOLSrL   rR   rS   rf   r   r    loadsJSONDecodeErrorr   )r   r   max_iterationsir   r   r   tcr5   argsresults              r)   chat_with_tool_callingr     s]    F34HN>"	
 y/!$Y/[[r28b
KKCQUCPZO\OO#";;y17R( 
 !*~f-::bn[&ABD &d17s6{K"$&tH%et}!  ! ;;y)/R/= #> G ++ Ds+   B2E5D=A,E=EEEEc                 F    [        U5      n[        U5      nSSU0S.SU S./$ )ue   构造包含图片和文本的 OpenAI 多模态 content 数组，自动加载本地路径并压缩。r=   url)r1   r=   r   )r1   r   )rX   r   )r   r=   resolved_urlcompressed_urls       r)   _build_multimodal_contentr   =  s5    %i0L-l;NE>+BC( r+   u   向 Qwen3.6-27B 大模型提问（简单模式，直接回答）。image_url 支持本地文件路径、base64 数据 URL（data:image/jpeg;base64,...）或普通 HTTP(S) URL。)r2   c                    #     U(       a  [        X5      OU n[        SUS./S9nUS   S   S   R                  SS5      $ ! [         a*  n[        R
                  " S	[        U5      0S
S9s S nA$ S nAff = f7fNr   r   )r   r   r   r   r   r   errorFensure_ascii)r   r*   rL   ru   r    dumpsrD   )r   r=   r   r   r   s        r)   	qwen_chatr   G  sy     ABK+F>QW&W)M(NOIq!),00B?? Azz7CF+%@@As3   A7;A  A7 
A4
A/)A4*A7/A44A7uO   向 Qwen3.6-27B 大模型提问，模型可自主调用RAG、SeaweedFS等工具c                    #     [        U 5      I S h  vN $  N! [         a*  n[        R                  " S[	        U5      0SS9s S nA$ S nAff = f7f)Nr   Fr   )r   ru   r    r   rD   )r   r   s     r)   
qwen_agentr   Q  sG     A+F3333 Azz7CF+%@@As<   A  A 
AAAAAAu   使用 Qwen3.6-27B 大模型识别图片。image_url 支持本地文件路径、base64 数据 URL（data:image/jpeg;base64,...）或普通 HTTP(S) URL。c                    #     [        S[        X5      S./S9nUS   S   S   R                  SS5      $ ! [         a*  n[        R
                  " S	[        U5      0S
S9s S nA$ S nAff = f7fr   )r*   r   rL   ru   r    r   rD   )r   r=   r   r   s       r)   qwen_visionr   Y  st     A%2KF2^_`
 Iq!),00B?? Azz7CF+%@@As0   A,05 A,
A)A$A)A,$A))A,__main__r@   ssez+Starting Qwen MCP Server (%s mode) on %s:%s)	transport)NNr   N)r]   U   )N)6__doc__rN   rg   r    loggingrG   r   r   typingr   r   r#   mcp.server.fastmcpr   PILr   basicConfigINFO	getLogger__name__rR   environrL   r	   r
   r   r   rm   r   r   r   mcplistrD   floatdictr*   r   rX   r   r   r   r   r   r   r   r   r   sysrf   argvr   rS   run r+   r)   <module>r      s   ?  	   	 	     &    ',, '			8	$

0JKzz~~nf5ZZ^^L*;<
::>>*i0rzz~~j&12zz~~n.KLJJNN#68UV  a			 !!%#'D> # 	
 % 
H  h  ('u !E	
$ _  ('8 !E	
$ "k  ('\ 	
$ "2  
  8   ('D# *N	
AQ	h# # B( ( (c ([^ (V3S 3S 3&3s &3t &3 &3R#G #G #GLc c d    J  KAC AHSM AS A KA ghAS AS A iA   r  sAc Ac Ac A sA z"388}q0eI
KK=y(T\]GGiG  r+   