
    {Ji9L                         S r SSKrSSKrSSKrSSKJrJrJrJr  SSK	J	r	  \R                  " \5      r " S S5      r " S S5      rg)	u|   
Writeup 智能分类服务

使用 AI 对上传的 Writeup 进行智能分类，匹配已有知识点或建议新标签。
    N)DictListAnyOptional)datetimec                       \ rS rSrSrSrSS jrS rS\S\	\
   4S	 jrS
\	\
   S\4S jrSS\S\S\4S jjrS\S\
4S jr SS\S\S\S\
\\4   4S jjr  SS\	\
   S\S\S\S\	\
   4
S jjrSrg)WriteupClassifier   u\   Writeup 智能分类器

分析 Writeup 内容，匹配已有知识点或建议新标签。
u  你是一位 CTF 知识库管理专家。请分析以下 Writeup 内容，判断它属于哪个知识点分类。

## 当前方向
{category_name} ({category_id})

## 已有知识点列表
{existing_items}

## Writeup 内容
```
{content}
```

## 任务
1. 分析这篇 Writeup 的主要技术内容
2. 判断它是否匹配已有知识点列表中的某个知识点
3. 如果匹配，给出匹配的知识点名称和置信度
4. 如果不匹配任何已有知识点，建议新的标签/分类名称
5. 生成一个简短的摘要（50字以内）

## 输出格式（严格 JSON）
```json
{{
    "matched_items": [
        {{"name": "知识点名称", "confidence": 0.95, "reason": "匹配原因"}}
    ],
    "suggested_tags": ["标签1", "标签2"],
    "suggested_category": "建议的知识分类名称（如果是新类型）",
    "summary": "这是一篇关于...的 Writeup",
    "difficulty": "简单/中等/困难",
    "languages": ["Python", "PHP"],
    "is_new_category": false
}}
```

注意：
- matched_items 按置信度从高到低排序，最多返回 3 个
- 如果没有匹配的知识点，matched_items 为空数组
- suggested_tags 是从内容中提取的关键技术标签
- is_new_category 为 true 表示建议创建新的知识点Nc                     Xl         g)ue   初始化分类器

Args:
    ai_provider: AI 提供商实例，如果为 None 则使用默认配置
Nai_provider)selfr   s     Q   /Users/yu22x/Desktop/ddd_副本6/ctf/app/services/knowledge/writeup_classifier.py__init__WriteupClassifier.__init__A   s
     '    c                 h    U R                   (       a  U R                   $ SSKJn  UR                  5       $ )u   获取 AI 提供商r   )AIProviderFactory)r    app.services.ai_driver.providersr   create_default)r   r   s     r   _get_ai_provider"WriteupClassifier._get_ai_providerI   s,    ### 	G //11r   category_idreturnc                     SSK Jn  UR                  R                  USS9R	                  5       nU Vs/ s H'  nUR
                  UR                  UR                  S.PM)     sn$ s  snf )u   获取已有的知识点列表r   )KnowledgeItemT)r   enabled)idnamedescription)app.models.database.modelsr   query	filter_byallr   r   r    )r   r   r   itemsitems        r   _get_existing_items%WriteupClassifier._get_existing_itemsR   sn    <##--# . 
 #% 	 "#!D ww		$BRBRS!# 	# #s   .A$r%   c                     U(       d  g/ n[        US5       HD  u  p4UR                  S5      (       a  SUS   SS  S3OSnUR                  U S	US
    U 35        MF     SR                  U5      $ )u%   格式化知识点列表用于 Promptu   （暂无已有知识点）   r    z - N2   z... z. r   
)	enumerategetappendjoin)r   r%   linesir&   descs         r   _format_items_for_prompt*WriteupClassifier._format_items_for_prompt^   s|    0 *GA:>((=:Q:QSm,Sb12#6WYDLLA3bftf56 + yyr   content
max_lengthc                 x    [        U5      U::  a  U$ [        US-  5      n[        US-  5      nUSU S-   X* S -   $ )u!   截取内容，保留关键部分gffffff?g      ?Nu   

... [内容已截断] ...

)lenint)r   r7   r8   head_lengthtail_lengths        r   _truncate_content#WriteupClassifier._truncate_contentj   sT    w<:%N *s*+*t+,|$'JJWUaUbMcccr   responsec                 0   [         R                  " SU[         R                  5      nU(       a  UR                  S5      nOUn [        R
                  " U5      nU$ ! [        R                   a&    [        R                  SUSS  35        / / SSSS	.s $ f = f)
u   解析 AI 响应z```json\s*(.*?)\s*```r*   zFailed to parse AI response: N   u   无法解析 AI 响应Tparse_failedmatched_itemssuggested_tagssummaryis_new_categoryerror)	researchDOTALLgroupjsonloadsJSONDecodeErrorloggerwarning)r   r@   
json_matchjson_strresults        r   _parse_ai_response$WriteupClassifier._parse_ai_responseu   s     YY7299M
!''*H  H	ZZ)FM## 		NN:8DS>:JKL!#"$3#'' 		s   A 7BBcategory_namec                     U R                  U5      nU R                  R                  U=(       d    UUU R                  U5      U R	                  U5      S9nU R                  5       nU(       d  / / SSSS.$ UR                  SUS./5      nU R                  U5      n[        R                  " 5       R                  5       US'   U$ ! [         a?  n	[        R                  S	U	 35        / / S
[        U	5       3S[        U	5      S.s Sn	A	$ Sn	A	ff = f)u   对 Writeup 内容进行分类

Args:
    content: Writeup 内容
    category_id: 方向 ID
    category_name: 方向名称（可选）
    
Returns:
    分类结果字典
)rX   r   existing_itemsr7   u   AI 服务不可用Tno_ai_providerrD   user)roler7   classified_atzClassification failed: u   分类失败: N)r'   CLASSIFICATION_PROMPTformatr5   r>   r   chatrV   r   now	isoformat	ExceptionrQ   rI   str)
r   r7   r   rX   rZ   promptproviderr@   rU   es
             r   classifyWriteupClassifier.classify   s    )	!55kBN //66+:{'#<<^L..w7	 7 F ,,.H%'&(3'+-   }}F3& H
 ,,X6F&.lln&>&>&@F?#M 	LL21#67!#"$+CF84#'Q 	s%   A2C 5AC 
D4DDDwriteupsprogress_callbackc                     / n[        U5      n[        U5       H^  u  pxU(       a  U" US-   U5        U R                  UR                  SS5      UUS9n	UR                  S5      U	S'   UR	                  U	5        M`     U$ )u   批量分类 Writeup

Args:
    writeups: Writeup 列表，每个包含 id 和 content
    category_id: 方向 ID
    category_name: 方向名称
    progress_callback: 进度回调函数 (current, total)
    
Returns:
    分类结果列表
r*   r7   r,   r7   r   rX   r   
writeup_id)r:   r.   ri   r/   r0   )
r   rk   r   rX   rl   resultstotalr3   wprU   s
             r   batch_classify WriteupClassifier.batch_classify   s     Hx(EA !!a%/]]y"-'+ # F
 $&66$<F< NN6" ) r   r   N)i  NN)__name__
__module____qualname____firstlineno____doc__r_   r   r   re   r   r   r'   r5   r;   r>   rV   r   ri   callablers   __static_attributes__ r   r   r	   r	      s    '@R'2
#s 
#tDz 
#
 d4j 
 S 
 	d 	d# 	d 	d3 4 2 '+5 5# 5 #5/3CH~5p -159tDz  &)*2>B4j r   r	   c                       \ rS rSrSrS r SS\S\S\S\S	\S
\4S jjr	S\S
\4S jr
  SS\S\\   S\S
\4S jjr    S S\S\S\S\S\\   S\S	\S
\4S jjrS!S\S	\S
\4S jjrS\S
\4S jr  S"S\S\S\S\S
\4
S jjrS\S
\4S jrSrg)#WriteupClassificationService   u_   Writeup 分类管理服务

提供完整的 Writeup 上传、分类、审核、入库流程。
c                 "    [        5       U l        g ru   )r	   
classifier)r   s    r   r   %WriteupClassificationService.__init__   s    +-r   Nr   filenamer7   	file_sizeuser_idr   c           
         SSK Jn  SSKJn  U" UUUU=(       d    [	        UR                  S5      5      UR                  US9nUR                  R                  U5        UR                  R                  5         UR                  5       $ )u   上传 Writeup 到待处理区

Args:
    category_id: 方向 ID
    filename: 文件名
    content: 文件内容
    file_size: 文件大小
    user_id: 上传用户 ID
    
Returns:
    创建的 PendingWriteup 记录
r   PendingWriteupdbzutf-8)r   r   r7   r   statusuploaded_by)r!   r   appr   r:   encodeSTATUS_PENDINGsessionaddcommitto_dict)	r   r   r   r7   r   r   r   r   pendings	            r   upload_writeup+WriteupClassificationService.upload_writeup   sn     	> #?3w~~g'>#?!00
 	

w


  r   ro   c                    SSK JnJn  SSKJn  UR
                  R                  U5      nU(       d  SSS.$ UR
                  R                  UR                  5      nU(       a  UR                  OUR                  nU R                  R                  UR                  UR                  US9nUR                  U5        UR                  Ul        UR                  R!                  5         SUUS	.$ )
uk   对单个 Writeup 进行 AI 分类

Args:
    writeup_id: PendingWriteup ID
    
Returns:
    分类结果
r   r   CategoryConfigr   F   Writeup 不存在successrI   rn   T)r   ro   classification)r!   r   r   r   r   r"   r/   r   r   r   ri   r7   set_ai_classificationSTATUS_CLASSIFIEDr   r   r   )	r   ro   r   r   r   r   categoryrX   rU   s	            r   classify_writeup-WriteupClassificationService.classify_writeup  s     	N &&**:6$/BCC "''++G,?,?@)1w7J7J ))OO++' * 
 	%%f-'99


 $$
 	
r   writeup_idsrl   c                 Z   SSK JnJn  SSKJn  UR
                  R                  US9nU(       a+  UR                  UR                  R                  U5      5      nOUR                  UR                  S9nUR                  5       nU(       d  SSSS.$ UR
                  R                  U5      n	U	(       a  U	R                  OUn
SnSn[        U5       Hn  u  pU(       a  U" US	-   [        U5      5         U R                   R#                  UR$                  UU
S
9nUR'                  U5        UR(                  Ul        US	-  nMp     UR2                  R5                  5         SUU[        U5      S.$ ! [,         a5  n[.        R1                  SUR                   SU 35        US	-  n SnAM  SnAff = f)u   批量分类 Writeup

Args:
    category_id: 方向 ID
    writeup_ids: 要分类的 ID 列表，为空则分类所有待分类的
    progress_callback: 进度回调
    
Returns:
    批量分类结果
r   r   r   r   r   Tu   没有待分类的 Writeup)r   
classifiedmessager*   rn   zFailed to classify writeup : N)r   r   failedrq   )r!   r   r   r   r   r"   r#   filterr   in_r   r$   r/   r   r.   r:   r   ri   r7   r   r   r   rd   rQ   rI   r   r   )r   r   r   rl   r   r   r   r"   pending_listr   rX   r   r   r3   r   rU   rh   s                    r   rs   +WriteupClassificationService.batch_classify2  s    	N $$..;.GLL!2!2!6!6{!CDEOO>+H+HOIEyy{#1A]^^ "''++K8)1{ 
#L1JA !!a%\):;11#OO +"/ 2  --f5!/!A!Aa
 2$ 	

 $&	
 	
  :7::,bLM!s   1AE++
F*5*F%%F*knowledge_item_idnew_item_namenew_item_category_idtagsqualityc                    SSK JnJn	Jn
JnJn  SSKJn  SSKJ	n  UR                  R                  U5      nU(       d  SSS.$  U(       a)  U	R                  R                  U5      nU(       d  SSS.$ GO;U(       Ga.  U(       a  U
R                  R                  U5      nOUR                  5       nUR                  S	S
5      nU
R                  R                  UR                  US9R                  5       nU(       dF  U
" UR                  US9nUR                   R#                  U5        UR                   R%                  5         U	" UR                  UR&                  US9nU(       a  UR)                  U5        UR                   R#                  U5        UR                   R%                  5         OSSS.$ U" UR&                  UR*                  UUR,                  UR.                  S9nUR                   R#                  U5        UR0                  Ul        UR&                  Ul        UR7                  U=(       d    / 5        Xol        Xl        U" 5       Ul        UR                   R?                  5         SUUR&                  UR@                  UR&                  S.$ ! [B         aM  nUR                   RE                  5         [F        RI                  SU SU 35        S[K        U5      S.s SnA$ SnAff = f)ug  审核通过并入库 Writeup

Args:
    writeup_id: PendingWriteup ID
    knowledge_item_id: 归属的知识点 ID（已有知识点）
    new_item_name: 新知识点名称（创建新知识点时）
    new_item_category_id: 新知识点的分类 ID
    tags: 标签列表
    quality: 质量评级
    user_id: 审核人 ID
    
Returns:
    入库结果
r   )r   r   KnowledgeCategoryWriteupFiler   r   get_beijing_nowFr   r   u   知识点不存在suggested_categoryu	   未分类)r   r   )r   knowledge_category_idr   u*   请指定知识点或新建知识点名称)r   r   r   r7   r   T)r   ro   r   knowledge_item_namewriteup_file_idzFailed to approve writeup r   N)&r!   r   r   r   r   r   r   r   app.utils.time_utilsr   r"   r/   get_ai_classificationr#   r   firstr   r   flushr   set_tagsr   r7   r   STATUS_APPROVEDr   final_knowledge_item_idset_final_tagsfinal_qualityapproved_byapproved_atr   r   rd   rollbackrQ   rI   re   )r   ro   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r&   kcai_classsuggested_catwriteup_filerh   s                         r   approve_writeup,WriteupClassificationService.approve_writeupp  s   $	
 	
 	8 &&**:6$/BCCK	7 $**../@A',7KLL  (*00445IJB  '<<>H$,LL1E{$SM*00::$+$7$7* ;  eg 
 .(/(;(;!. 

r*

((* % ' 3 3*,%%&
 MM$'

t$

  "#(3_`` '"&'' ))!++L JJNN<( ,;;GN.2ggG+""4:2.$+!")"1"3GJJ  (%)WW'+yy#/??   	7JJ!LL5j\A3GH$s1v66	7s-   -J 1D<J .C J 
K&AK!K&!K&c                     SSK Jn  SSKJn  SSKJn  UR                  R                  U5      nU(       d  SSS.$ UR                  Ul	        X&l
        U" 5       Ul        UR                  R                  5         SUS	.$ )
uq   拒绝 Writeup

Args:
    writeup_id: PendingWriteup ID
    user_id: 操作人 ID
    
Returns:
    操作结果
r   r   r   r   Fr   r   Tr   ro   )r!   r   r   r   r   r   r"   r/   STATUS_REJECTEDr   r   r   r   r   )r   ro   r   r   r   r   r   s          r   reject_writeup+WriteupClassificationService.reject_writeup  sk     	>8 &&**:6$/BCC'77%-/


z::r   c                     SSK Jn  SSKJn  UR                  R                  U5      nU(       d  SSS.$ UR                  R                  U5        UR                  R                  5         SUS.$ )	uc   删除待处理的 Writeup

Args:
    writeup_id: PendingWriteup ID
    
Returns:
    操作结果
r   r   r   Fr   r   Tr   )	r!   r   r   r   r"   r/   r   deleter   )r   ro   r   r   r   s        r   delete_writeup+WriteupClassificationService.delete_writeup  s\     	> &&**:6$/BCC


'"


z::r   r   pageper_pagec                 p   SSK Jn  UR                  R                  US9nU(       a  UR                  US9nUR	                  UR
                  R                  5       5      nUR                  X4SS9nUR                   Vs/ s H  oR                  5       PM     snUR                  UUUR                  S.$ s  snf )u   获取待处理 Writeup 列表

Args:
    category_id: 方向 ID
    status: 状态筛选
    page: 页码
    per_page: 每页数量
    
Returns:
    分页列表
r   r   r   r   F)r   r   	error_out)r%   rq   r   r   pages)r!   r   r"   r#   order_by
created_atr4   paginater%   r   rq   r   )	r   r   r   r   r   r   r"   
paginationr&   s	            r   get_pending_list-WriteupClassificationService.get_pending_list	  s     	>$$..;.GOO6O2E~88==?@^^E^R
 2<1A1AB1Alln1AB%% %%
 	
Bs   =B3c                 L   SSK Jn  SSKJn  UR                  R                  US9R                  UR                  UR                  UR                  5      5      R                  UR                  5      R                  5       nSSSSSS.nU H  u  pgXuU'   US==   U-  ss'   M     U$ )uZ   获取分类统计信息

Args:
    category_id: 方向 ID
    
Returns:
    统计信息
r   r   )funcr   )r   r   approvedrejectedrq   rq   )r!   r   
sqlalchemyr   r"   r#   with_entitiesr   countr   group_byr$   )r   r   r   r   statsrU   r   r   s           r   get_statistics+WriteupClassificationService.get_statistics)  s     	>#$$..;.GUU!!JJ~(()
 (>((
)##% 	 
 #MF"6N7Ou$O # r   )r   rv   )NNNNBNru   )Nr*      )rw   rx   ry   rz   r{   r   re   r;   r   r   r   r   r|   rs   r   r   r   r   r   r}   r~   r   r   r   r      se   
. >B!# ! !s !"%!7:!FJ!>$
3 $
4 $
L IM59<
# <
DI <
*2<
>B<
| IMOS?B'+h7# h7# h7'*h7ILh7"3ih79<h7 "%h7 15h7T; ;s ;d ;4; ; ;* @D8:
C 
 
"
25
?C
@# $ r   r   )r{   rN   loggingrJ   typingr   r   r   r   r   	getLoggerrw   rQ   r	   r   r~   r   r   <module>r      sG      	 , , 			8	$P Pfb br   