
    Uik0                        d dl Z d dlZd dlZd dlmZ d dlmZmZm	Z	  ej
        e          ZdZ e edd                    ZdZ ee          ez  Zded	efd
Zd	efdZdeded	efdZded	edz  fdZdededed	efdZded	efdZdS )    N)types)get_vertex_clientA_DB_CONFIGC_DB_CONFIGzgemini-3-pro-preview         
session_idreturnc                 l   t          j        j        di t          }|                    d          }	 |                    d| f           |                                pi 	 |                                 |                                 S # |                                 |                                 w xY w)u7   A_DB.user_profile_summary에서 유저 프로필 조회T
dictionarya  
            SELECT session_id, username, final_goal, mbti,
                   spi_language, spi_nonverbal, spi_personality,
                   studyplan_duration, studyplan_status,
                   studyplan_weekday_hours, studyplan_weekend_hours,
                   studyplan_time_slot, it_level, ai_analysis
            FROM user_profile_summary
            WHERE session_id = %s
        N )mysql	connectorconnectr   cursorexecutefetchoneclose)r
   connr   s      '/app/app/models/ai_curriculum_module.py_fetch_user_profiler      s    ?"11[11D[[D[))F  ]	 	 	   &B&

 	

s   ,B	 	*B3c                  b   t          j        j        di t          } |                     d          }	 |                    d           |                                |                                 |                                  S # |                                 |                                  w xY w)u.   C_DB.master_items 전체 조회 (AI 참고용)Tr   z
            SELECT item_id, block_id, name, category, item_type, sort_order
            FROM master_items
            ORDER BY block_id, sort_order, item_id
        Nr   )r   r   r   r   r   r   fetchallr   )r   r   s     r   _fetch_master_itemsr   .   s    ?"11[11D[[D[))F	  	 	 	
   

 	

s   (B *B.profilemaster_itemsc                    g }|                      d          r|                    d| d                     |                      d          r|                    d| d                     |                      d          r|                    d| d                     |                      d          r|                    d| d          d	           |                      d
          r&|                    d| d
         dd                     |rd                    |          nd}d |D             }d| dt          |           dd                    |           dt          |           dt          |           d}|S )uJ   AI에게 PJT 아이템의 우선순위만 결정하게 하는 프롬프트
final_goalu   目標:mbtizMBTI:it_levelzIT:studyplan_weekday_hoursu   平日:hai_analysisu   分析:NP   /u   情報なしc                 P    g | ]#}|d          dk    t          |d                   $S categoryPJTitem_id)str.0ms     r   
<listcomp>z!_build_prompt.<locals>.<listcomp>T   s2    QQQQ!J-5:P:Ps1Y<  :P:P:P    u   IT教育カリキュラムPJT教材の学習順序を最適化してください。
CERT（資格）教材は固定のため、PJTのみ並び替えます。

【ユーザー】u   
【PJT ID(u   個)】,u   

ルール:
- 全uL  個のIDを必ず含めること。省略禁止
- 初心者=基礎→応用,中級者=基礎スキップし応用から
- MBTIに基づき学習スタイルを最適化（例:ENTJ=効率重視で実践から）
- ユーザーの目標に最も関連性の高い分野を前半に配置
出力:1行JSON。改行禁止。{{
"pjt":[全u   個のid]
}})getappendjoinlen)r   r   parts	user_linepjt_idsprompts         r   _build_promptr<   B   s    E{{<   86w|466777{{6 0.WV_..///{{: 207:.00111{{,-- FDw'@ADDDEEE{{=!! ><w}5crc:<<===#(<nI RQ,QQQG   w<<	  !$ 1 1	  
'll  w<<  F Mr2   textc                    	 t          j        |           }t          |t                    r|S n# t           j        $ r Y nw xY wdD ]H}	 t          j        | |z             }t          |t                    r|c S 4# t           j        $ r Y Ew xY wddl}|                    d|           }|rbd |                    d                              d          D             }|r.t          
                    dt          |                      d	|iS dS )
u,   잘린 JSON도 최대한 복구하여 파싱)z]}z]}}z]}}}z]}}}}r   Nz"pjt"\s*:\s*\[([0-9,\s]+)c                     g | ]I}|                                                                 (t          |                                           JS r   )stripisdigitint)r/   xs     r   r1   z#_try_parse_json.<locals>.<listcomp>   s?    ```aAGGIIL]L]L_L_`3qwwyy>>```r2      r3   z#[AI Curriculum] JSON repaired: pjt=pjt)jsonloads
isinstancedictJSONDecodeErrorresearchgroupsplitloggerinfor7   )r=   resultsuffixrK   	pjt_matchr:   s         r   _try_parse_jsonrT   l   sN   D!!fd## 	M	    1  	Zv..F&$'' # 	 	 	H	 III		6==I $``9??1+=+=+C+CC+H+H``` 	$KKLc'llLLMMM7##4s    *. A A -A99B
B	pjt_orderall_pjt_idscert_items_by_dayc                    t                      g }| D ]4}||v r.|vr*|                    |                               |           5fdt          |          D             }|                    |           t
                              dt          |           dt          |           ddt          |           dz              g }d}t          D ]}t          dt          dz             D ]g}	|t          |          k     r|                    ||         |	f           |                    ||	f          }
|
r|                    |
|	f           |dz  }h|S )	uI  
    AI가 정해준 PJT 우선순위 + CERT 고정 순서를 120일에 배치.

    Args:
        pjt_order: AI가 정한 PJT ID 우선순위 리스트
        all_pjt_ids: 유효한 PJT ID 집합
        cert_items_by_day: {(block_id, sort_order): item_id} — CERT 고정 배치

    Returns: [(item_id, sort_order), ...]
    c                     g | ]}|v|	S r   r   )r/   iseens     r   r1   z(_place_items_to_days.<locals>.<listcomp>   s    CCCQd]]1]]]r2   z[AI Curriculum] Placement: PJT=z(+z fallback), zCERT=z items (fixed)r   rD   )setr5   addsortedextendrO   rP   r7   BLOCKSrangeDAYS_PER_BLOCKr4   )rU   rV   rW   	pjt_cleanrZ   missing_pjtrQ   	day_indexblock_id
sort_ordercert_idr[   s              @r   _place_items_to_daysri      s    55DI  QHHQKKK DCCCf[11CCCK[!!!
KKb#i..bbCDTDTbbb>-..>>>? @ @ @ FI 	 	>A#566 	 	J3y>>))y3Z@AAA'++Xz,BCCG 5w
3444NII	 Mr2   c           	          K   	 t                               d             t                     }|sddddS t                      }d |D             }d |D             }i }|D ]'}|d         d	v r|d
         |d         f}|d         ||<   (t	          ||          }t                               dt
           d           t                               dt          |           d           t                               dt          |           dt          |           d           t                      }	|	j        	                    t
          t          j        dt          j        |          g          gt          j        dd                    }
|
j                                        }t                               dt          |           d           t                               d|dd                     |                    d          r6|                    d           }d! |D             }d                     |          }|                    d d"                              d#d"                                          }t)          |          }|d$|vrdd%ddS |d$         }t                               d&t          |           d'           t+          |||          }t          |          d(k     rdd)t          |           d*ddS t                               d+t          |           d,           t-          j        j        d>i t2          }|                                }	 |                    d- f           |j        }t                               d.| d/           d0} fd1|D             }|                    ||           |                                 |j        }t                               d2| d3             d4d5| d6|d|                                 |                                 S # t@          $ ry}|!                                 t           "                    d7|            dd8tG          |           ddcY d}~|                                 |                                 S d}~ww xY w# |                                 |                                 w xY w# tH          j%        $ rR}t           "                    d9|            t           "                    d|dd:                     dd;ddcY d}~S d}~wt@          $ r=}t           "                    d<|            dd=tG          |           ddcY d}~S d}~ww xY w)?u   
    Vertex AI로 우선순위만 결정 → Python이 배치 → user_curriculum에 저장

    Returns:
        {"success": bool, "message": str, "item_count": int}
    z"[AI Curriculum] Fetching data for Fu6   ユーザープロフィールが見つかりませんr   )successmessage
item_countc                     h | ]
}|d          S )r,   r   r.   s     r   	<setcomp>z)generate_ai_curriculum.<locals>.<setcomp>   s    888aQy\888r2   c                 6    h | ]}|d          dk    |d         S r)   r   r.   s     r   ro   z)generate_ai_curriculum.<locals>.<setcomp>   s*    PPPA:%9O9O1Y<9O9O9Or2   r*   )CERTREVIEWrf   rg   r,   z#[AI Curriculum] Calling Vertex AI (z) - PJT only modez[AI Curriculum] Prompt length: z charsz[AI Curriculum] Items: PJT=z, CERT=z (fixed)user)r=   )roler8   g333333?i   )temperaturemax_output_tokens)modelcontentsconfigz%[AI Curriculum] Raw response length: z[AI Curriculum] Raw text: Ni,  ```
c                 `    g | ]+}|                                                     d           )|,S )rz   )r@   
startswith)r/   ls     r   r1   z*generate_ai_curriculum.<locals>.<listcomp>   s3    III1QWWYY-A-A%-H-HIQIIIr2    rE   u8   AI応答の形式が不正です（pjtキーが必要）z [AI Curriculum] AI returned PJT:z items
   u&   有効な項目が少なすぎます (u   件)z[AI Curriculum] Placed z items into schedulez1DELETE FROM user_curriculum WHERE session_id = %sz[AI Curriculum] Deleted z
 old itemsz
                INSERT INTO user_curriculum (session_id, item_id, sort_order, status)
                VALUES (%s, %s, %s, 'NOT_STARTED')
            c                      g | ]
\  }}||fS r   r   )r/   r,   rg   r
   s      r   r1   z*generate_ai_curriculum.<locals>.<listcomp>  s4     ; ; ;+  *5 ; ; ;r2   z[AI Curriculum] Inserted z new items for Tu-   カリキュラムが作成されました（u	   項目）z[AI Curriculum] DB Error: u   DB保存エラー: z"[AI Curriculum] JSON Parse Error: i  u*   AI応答のJSON解析に失敗しましたz[AI Curriculum] Error: u#   カリキュラム生成エラー: r   )&rO   rP   r   r   r<   VERTEX_MODELr7   r   modelsgenerate_contentr   ContentPartGenerateContentConfigr=   r@   r}   rN   r6   replacerT   ri   r   r   r   r   r   r   rowcountexecutemanycommitr   	Exceptionrollbackerrorr-   rF   rJ   )r
   r   r   	valid_idsr:   rW   r0   keyr;   clientresponseraw_textlines	ai_resultrU   
placementsr   r   deleted
insert_sqlrowsinserteddb_errjees   `                        r   generate_ai_curriculumr      sC     nnEEEFFF%j11 	|$1iyz{{{*,, 98<888	PPPPP 	6 	6A} 222}ao6)*9!#& w55Y,YYYZZZIc&kkIIIJJJg#g,,ggsK\G]G]ggghhh"$$=11m
8O8O8O7PQQQR."&   2 
 
 =&&((QCMMQQQRRRA$3$AABBB u%% 	(NN4((EIIIIIEyy''H ##D"--55dB??EEGG $H--	Y 6 6$1k{|}}}e$	Ms9~~MMMNNN *)W>OPP
z??R$1oZ]^hZiZi1o1o1o  @A  B  B  BSc*ooSSSTTT &5555 	NNC   oGKKF7FFFGGGJ; ; ; ;/9; ; ;Dz4000KKMMMHKKYHYYZYYZZZ  ^8^^^&  LLNNNJJLLLL  	g 	g 	gMMOOOLL>f>>???$1Ts6{{1T1TdefffffffLLNNNJJLLLL	g
 LLNNNJJLLLL l l l>">>???B(4C4.BBCCC -Yijkkkkkkkk n n n2q22333 -[SVWXSYSY-[-[klmmmmmmmmns   3S' I"S' A-S' 
AS' %B&P4 (S' 4
R7>AR2R7R: 	(S' 2R77R: :*S$$S' 'V6AU=VV2VVV)rF   loggingmysql.connectorr   google.genair   app.core.configr   r   r   	getLogger__name__rO   r   listra   r`   rb   r7   
TOTAL_DAYSr-   rI   r   r   r<   rT   r\   ri   r   r   r2   r   <module>r      s               G G G G G G G G G G		8	$	$% 
eeArll		S[[>)
C D    (T    (#4 #t # # # # #T# $+    H)D )s ),0)59) ) ) )`unS unT un un un un un unr2   