From f6475c547d177b52c25a91131a4c83c171aa46ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EB=AF=BC?= <95125109+javor10@users.noreply.github.com> Date: Tue, 20 May 2025 10:05:58 +0900 Subject: [PATCH] =?UTF-8?q?Refactor:=20=EC=BD=94=EB=93=9C=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert_result/09c953a0.pdf | Bin 0 -> 31628 bytes convert_result/09c953a0.xml | 714 ++++++++++++++++ .../35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.pdf | Bin 0 -> 33536 bytes .../35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.xml | 783 ++++++++++++++++++ .../98f55ceb-b3a2-4b39-bbba-1768dcee6396.txt | 0 .../afbe7119-2470-42f5-a7cb-c5a0a144ac51.pdf | Bin 0 -> 32413 bytes .../afbe7119-2470-42f5-a7cb-c5a0a144ac51.xml | 761 +++++++++++++++++ src/models/__init__.py | 7 +- src/routes/auth.py | 98 ++- src/routes/mypage_result_score.py | 215 ++--- src/routes/mypage_upload_score.py | 198 +++-- src/routes/transform.py | 41 +- src/routes/user.py | 104 +-- src/services/result_service.py | 16 +- src/services/transform_service.py | 25 +- src/services/user_service.py | 0 16 files changed, 2588 insertions(+), 374 deletions(-) create mode 100644 convert_result/09c953a0.pdf create mode 100644 convert_result/09c953a0.xml create mode 100644 convert_result/35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.pdf create mode 100644 convert_result/35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.xml rename src/services/mypage_service.py => convert_result/98f55ceb-b3a2-4b39-bbba-1768dcee6396.txt (100%) create mode 100644 convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.pdf create mode 100644 convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.xml delete mode 100644 src/services/user_service.py diff --git a/convert_result/09c953a0.pdf b/convert_result/09c953a0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0a0982c3abb5f5d9434f65eee137a1dab208f0f9 GIT binary patch literal 31628 zcmeFYWn7ir*62;B2uLF!xd17VX3?F}-6gT;?hffjy1P>vq@+tqx}`g$VG(D6-uu4y zyZ3p{`EtI!OBS=|9AnHm{W1R6xX5IML}(ajnGwi3vpaJT7y$GDD?L*LE-nN*MH72- z5PRxkUmyWwvZeElDCJ{ z8bFyqY5-8mkUCpPpU09V6bGb+8HyG%8!Z$gWG-1-D+338(C^9QAOitVERRi)F9Q_A zUyGSoSqkaeL*xYCd<_0hF61JFrZS%UtS2l!`t4aoBL_8?nJ0G$xX(L^64FDjt* zm(VQ#A;Y7rj}qI0Ebae@Oebh%X%8vd0T>>)N*;ku9%N_bV5<*Nis83bbo`cJ##Q`zXR3Q=2Km&YmT{$<6d;i3wy+l|6 ztiP8KVFR%J$*}|2|Ku3x0g#_R+efD=qh|`ze;Npx1oHFe1UxDKsD%dLUj}}%*k77S zf-H^fjR6dgM+Ksdh>1C5UjTF>=8!EH0_j^BfF5VFvxl5>3k2uX11*h;`35x4%Zkxc z7+p4OWU)-jFJexJXIXqvP#&shS$!m0@1uo%J!aaLv+y<0PH-NcP5+T z*0gWQT5k8|y^tR6J)Ey^4!i;`bv#==n@*AM5_ko#!K*dIhWJZfa~^~|M@#!l+YcLC zTZ_=od)nIC9xN_xBipETZfZ#BHadIn;0EM*REP#1+V*+eFQ1>K)7`B#t<*2xQ+qmt zZ;m)|?s2TIQtrVHS34P=IG%*UewDDVUTzCWhw1)|LLpKrQ1cV(_NZ6yRylH{^9mC@ z?rcKoyl1An;9c^VBWC)VNY;G<9_h@86}>t=KAa{{p<$~-m84;=14z+u)p<+O=q|$* zV9nO&7Li5J@HSI_*EWQ%)`@!V9m?z-IV*P|51%43mMhPZQM<3S&NaOSu8vnRqNx~B z|DmJ@C7jxYdA-w>>qB>Pk{$gL7rls{R$<~7MHjMVlj1nP<9mD|`}O-QDTme!HH#ueI>YWB_2Y-X!gx5E&7>Kwy-{IlI`P6QJh=rjBcxE->60H-7&1buOBSZD5Pvc%A(uaKO&xlV?qw)B%L$`t2 z+;rgK()Wm``VE;W8`9da+;T6kUHZ$GNqf_oX7)9h#^s=pw``B>j)mk1ERc%~KDy0D z)%tr^rxI4oT@tW!j``6UaUH1E9&w6njFjx;+Rs&*E<1gnHStvbQ9T}^1WqH40Zxe$ z=d@^V$u2y=eN=X{-Sdjb|g@y=qXiESW&^Tyb*o%h_Y#U6L;zlhLi;rb8V}~ z>+89%Q$NA(ZVxVr?bPL8Ky_?a(NnsS6D4u|@Z}9G)vig5aZ#y1PUNC8$Xiy_n_SL?6q?y-5`%vDEvgIwv|T64 z7eyj8Rvb?T(+e`nH?H!$TX!|PPQhex?4t0y{yy<}o}26NW6yKHYnW8tX{Jo*OQa?B7IR$>C#TPq8%PkAlM1_Ip@pS&IkH#Tr!( ze8r=fx75|$ghw`BZ7F9=tmVbtiOiKWBac$dykG5p79qgb=JTs)!!4mdA=Zra;Jk*o zvUq`Y?Q=0MJCLv9%z6UQh6c;8V5zuF+EU*3c8E%XxiQnDkK-cvOUitj7+cL$U-|o} zO)2T}M$ey7Hn4MpJb>3F`*-SI-_1Zp(I)8$b?+F-vI$>BbI2c&^1sBc*%$w0%Ux3?t85w)t*)On81{B7cI@d`EbW7yYs+)V5|~@C z`ILC!mpC=KC=7+93x<7_hN^QzU>bx$KnRjr4*}mEN@JC7Lbl=3yd)*GuvGCUbEd4q zEeCCkW||Q3j}C0f20yXv*b6r|nagr4DKf^nyq%UP=rlIY#@{6)RnT@|KBEaZ z(OuNr*Sxb7Z25}9lhEL7LVA0p??}|FHG;r~<1HN`|n`zHQ zR~{sm0%@$Js!qq=Y>hV<@SBT+Y$bd4p?5 z=`>Jl7=t7^E9=GxnzoxWktN>|D)HOQ_3nNY&0?T*i+~gTJw%`;M$pu0!~urPAlDJ! zL4T~)2xpzTsySqp$^7rGOO-U8dJ5zdcZ8@9KZep}bcoXK?#_ar9_qEbvj)7Q(%^)Z@45ALr@BWqVJtyaUU1rXD1 z6?}IkL@Ph4uBHbG91O%lCL+Jz^*GOe4TosD{2Hz#ef(Wb&$GA_t_Ie=@yR}x16mOxe+ytB#90Ylw@yFdWiIk1s;f+4%; zBJ!p>SRXtqkncY5X^u4mvU3n+JTRk7bUr<=J!*YclHSWjY7m~N&P&U2V_v9r3OVk* ziG2Ogl_LkD!RmUDt6{bexf32`X@34HZ5(qI?zCF z%=rAwTlJnoOSVf`mlO(d@D~Hs=Art5ZmlIlX!QI>ZJX}`gRXdZy9&)x!s=`1zm~)D zD>L%Pi=*HAf1nH%hP8e zC-`0c;co3N`;Zyp*TP*IaOw+;rwc-8#Q!aH@VloR@1J8pD)4h(^j~Z}y?QRWP8mYFuqj){ z0o^+6G^}D1Gb;y$Gq@@?6)2L_$;7D~g}GK=tW~JJdZv?&TWYkoHGK@efbq=79Pp(h z>eeY@rY+Rkn7sOmTA~AF8IyGheG%Vf++=qB75Eu?%w}TdjI9#)*+d~*08Ism>4@Z= z75a3pvq$UwkFNpAg;fUO{PWjfBK4|Dgjl;=B)e@Q4V2WucHy$1wHwb@?j;}TA|w&Z zj@cNC!V{{P`%I^gT_b$)+ieU9+)E+_jjsZt5zsL@ur4N|;Ae9}$4*Uw`v)$5@mxjk z*RLntcVZC*svVUyDBw+6G>^mRjF(>I1J%4g;H?+YfCpmJGDlp1V2()c(c+SrDSn~C zN~5OaHeI8&5^!_ud<7x-(K~i#QwB`sK~jUS0pT~elpv{npqqARfq1^M$54{y0H#XJ zPC)9L=;>sgskNPjsVuqE96AYaKqNEKOSN3CKJ%69vKe%E+T6TwdqO32q)?Le?8R;QT8v?}j{9S|$d@2j-T7LkU z7#aVogMvNCLKy&j9Qi07#KQwI0vH~>>__iaOh^G_4`BH1RsO?o{HGWG+ec)8IEf4_ zk0Sr^85w`OpZ`anv0L5ETw~gWcPpBtn>yN6qJ~CdBBrX0Rrp8M+j&>ncyqB>;r^G zR_OJ7_aLRHFXVv03}$yZ&{axrV+xCktb#wSY(={KtzHZr@12b70~xV}3>uS1#62w) ziO}^YTLM?jmA11NJEY4bJ%dtx!u4v3n^T|UY(Ga`x|JT?Q;h0+OyAHlGcCO=%YE>^ zqw({+S_yo}-d9ft@Cdjo0hf5ZGJ8kLz1^SP%+JknS)`MfecA8M*qDUC|C;ay9N6{ow+EudL z1^Lb$)Gk#u?$JO@@QsHBxSU)9SR2dCllbABa{(zX)^$GAB)D7C!fL0iUgIW!W2e!d z{U`||FQj&+l+85NZShO#V%x3i43HUvz3qJ5Aa77F8;G6mej=Sw{r2Qwo*zV>mW&kX zpsGosrCcisVm`bJJi&K}LJ%mX;lulYvEEDdMRl9u;T$n*izqF>W}~CSiVHkDTAM${ z*V(we_^~&SaGGzQwovW+%G zjRWR>-X!;Xli4?`85k7sQPk^70wKjXuW+;o^N|LqPR~i5VN%O?-{lwZc=3Mw&|J(+ z+&qKI;8Q`v_a>+IB?rphp03BUo7-p)6fnh46*Goxv?&I++0t59_+PrEzSrd?Ry{gP zKYlX8F@-L=Jve&;&V4Irk$VnbfSaThwFUx4ob#tf=1U?~Ug?;#vCcc3I)oY>pHS5v zswR1vbQW+Fnpvf%d;XO8RiJRtYN;-#F7L82hIc>9C&@r>VWHN(TWQ=F?PP1mJH|E#^&Nk;pj6LsWP8prFn=D z={SG1NJ(g{8XiVf12WjLlUWpV3$%+LaD#2`2wk#mc6l(IT1Gh9kugUWAKVXNtXlnqXsN|Mw+xm>`5t!})0xbMN^ z4fs*sf(ck?y4)(8Xt`tsiTe*V>zC&Yw@jOmcOasm_+p{+a z(4#=@n*r*J6WgX}s2k&=yCK$YItP5}DvnYw)10=%>jepvIjK!rjo|C9H&&TMsgW`2 zspSLX({m&uPm-kz5aMo?&<2ktL+nF|`Bh{sMgz_e{RJG*@=xBHzh7W$k2&a9V z&12bZN+-PkUJo-Nr*0D#pIOm%*}9rThl-;34JLQ6&XgRQytA3Iy3rf*rw};Ku)1+h zkH^z6v#7XtvQ$>3seb8zDBGjJYu*G1Q*Jz2pCSM>sb=^@8MdYD!T} zN)om<4xqYoHnUOo3z6>7>=f)XGp9~(cZPP>OFr*rcp51=QFZAm=JGn|zzl1U({OM^ zLPI8%cUf}s22sCdLbqO#svFpwR8LL7r8T>qSgkaN$+D}|EuAtH*KI$luBlu7gO@rB zG=pkGy#DSgkb(F{9Qc@*XVQZGQX>7p2GPukh@2|=LH3usi|gd~4xjyS;`+mP zJC+@`?Ls64Jz`3u-UdgzP*w<9Da&*=GdLT1r(-rdz!GSoMvQ#INGCOW`|=JBDF^O( zS&MA4H>;5t@5C85aOGic6AVXaUV#n$8sJupWYv`MO{rE*7{EVgaFl8<}6r`3Kvo(W<# z@#TDV0ADGNBW|O)5+l$dN_09V>Mq~x;JveidE!7i%v9J;;FAMC0h42h#T@$$c>ZDk z)30|8%}72U%DixX#rw~yJS%JNCBGHPOz(=D!JTJ|=|U0J#u1ogz70Ti6YKmw9`Gj7 z;N+kHdwW-Sj(H$#Pu!G*^0Fb*;5EAh^bi4uyM)HP-!f*rhT{eepK2na zN>qnGu}p9c(M!>DTk&hWDE$6YGg(<+n@sU`?^ftuG3|Ei8{&5o8R9D~zH1q1Z8bBT zbU3kPq*MCa8yoXiZ{uD_Nl+U#96}Ra_S+P~7@hJxyquY&JjTQ{)}7OYlWu6un~rVZ z!jJrp-uOa>7>4blIwqh@JcSd^!ks zTqzE4MjC^1wf^Z~g;8AoREO=tnSgo?HkOh#DLg#>;_K#8DgQa#R+%-;=;+tmR5`C= zd<>aVwrAD8har}eemZ$}k|E@_GRALZmMS0(j);P*F9POL#qX7bG{j;aH8`#QaDR*4 zZ<&23I?71q73PWc+R4A0DcJm_lrWNGMxPuy28~#5L~nWSx4Rc}RZEekXbd^0QTV(V z#wyf>{F^3>97y|@;jYPz=4{>b*`k4blPs}ojaXQmY92IOv$@~dA~h+#!?Yzn#d`&6L)gxlP0ORJPS|h2tC|%C65}GiUq{@YkUxxw3#A)i|6B+iqfcu zZnRoS9HFfu_;rGrhzRW(K4G{xh$@9Wm|k4D5^Jb-Q3qF3Z?PdHowKE2>kM=u%t7jz zBY;ayNx}Xu4ckn~cnfD3GwRS08LdP#I+)yqG~jI=V))2MmM=bq>-Q98F=e@a5^Uk> z;l%GQL~Z(W7?>7>-Qrq1gB-XSXBIL@8xB#E!f84K&z#0-1KV)KG*aRya($(&hM{IQ9{#??-&mMawG^^Ht{S#TY zR7q^y88qplFQT>yL=jlTJeM4C zJPoGWPvMjHY?v46_O=+j5Z$`$Jt=)%q;;3waPAkLA5&bX&SHZjdbaLzqy*O4qw8LW zy-n^eKn2O^imCm|hpmpS8Qm)G^Q-DB!k-UzsbZ*(x)&JKmDkH?cQd~ghl}nyeC8#$Jy7eqez94E7K=G}bk+ExzB|_06wOj%H2Q~0 zxEYxm)SAd1hpM!eUIqHIBPQ5NK$u%K>S6!fD2J*G7oGffVjB1wIt!zoJBk8Ua^_wa z8HBGKK|JH}V5D?{ikL)8Y+^Etb&luNhQe<*Rb?665(ue@s^Lz{%4*W)w+1DhRMyGd zrPF`)*khW`rZeCz35Rk~?u{P_I!}ESLmtj^X`X*j=9HUhbBkRle%`pjBXBr#f>uR- zYlXlhYYD>FkgH4(*A3$ibl&L>;tHJ&;DO^@cozdRD?)^U%|e8|_iMpX<0?uZy+BaN z*a!RxE1iiw_c?aW&TTbeP8E8zV;Huj&nvj~^UsQG(rK$xO z4!v^S9w#)F7^7Q`c!|}OXlW$Wk-O5HEJC4S7?MlqNy)G3{DkVGoLpF9P@~rwaz^*z z!!DX>sE4UmgL)~;$!n>mWALrtDL?1APDn}WlejnZpYWaQ7 zt+(BR$5rWR%+22*tR~8PH}W#tv-X9qZ56(DqoX<8B3+8_a8*LI1^50k@w6$6CUES|T zj;MSf49t;;_~EwVOP0nWgmE|9sXLW}RYMqomjTUsIkJ3VB$`?*kQBr9oXZ`%i-h{2 zI8S#qlXCEYn0A=Wv42dO>MSXM=trxb#gB@M% z&&Fw8w$>At@)DfKEYeqR?r_;_7l>6? zfE0Qu74(&Cp;t||El z!|st|F{wv3w^LDLBQnEgz9U}w+n|wgN0x;ibHd$SVfUh~Cn<1-a!G!38kRjECBaoQImT(^1zF~EHGdW|b-&!(N>RG>%Dv&aY>66aaa7}B@ zk7s6@*6fi%TdKom4GtXXuQ~7sO_=>u=jh_dY8n6+xcnY|{+NnF@*h5^s1xf5s^4Vu z=~9X&$+iAaH)zXoe#w)dsR1;$#&46CK}6_eH^Jwzn(n>Hfb+Yh6B5F$`cG!|gohr( z448pze>1bkkcQu}2mfSdkeCt&J^SAgDq=#9nCg+IF(S|j=-PpvA|fEr={GrhBvvkV z5T+$&X=nurlmI{?Ka5NuxXuMY$q$Ko0Z{?yWNZyUwkDQF07@|f2r4tNcY#zYI9OYo zgDf7=89e|(x}Ip*->?qA@K->Gn2@5CsF;wHE+nwyuki?UDvxm^8bEq_0MjF&V`B#} zF#?~yEX?!(MrLLJGmsVV#O;`X5N!8vu_TY-8-Hp2hn_JrvOY@jhciBcI5A5Td%$B9 zkp3f*Gc>U@u>BL$0?>n~Xo&#fdj=+uAdlarr{DS(y4Jrb-v7N#lmr$2(;NT;kRfCu zh|<4#<&!CC{!*U?GUo3dPplIn3uFYtZ($zeMC=~JV{COTA+b7KkAXEj04@>8=P4BB z|I^O+dz7BxzjyyL>M41eg8?!Jq{Pkx(BKkgWPU6{lE;~a>G_#|CrnQX@TroKh4HDx z_SD8K%<@=b76$VC4u1J-JqXl&vfID3)pxLcj4gUH?vo83bu+O9{mcH=R@RRP{OS9j zC;btg{BmY)nACqBW?@T+WgZXezYZGBhrf`nfi48rLT-W`K!f2a5D0>T z6|IykO&*O2V0elM`UkN6TZq2_?LR_y9=`pj+>C!mx&8Ap{(UEY-;qB6TlooKi#nK_ zSU~Fk3%{lZ&@ce$X_?sRSs*uq0kUxbHWnsYMm7dWnA-mUve|%akU?zBOsxOJ*$m7K zv@G-tK$b_y{WsM9x6Z%OHVcrJnUS4^jTQKBh@0_GNYfw04H4;2u+$%>|J43_+y1f` z1AvVY$np=u{fCnOpQ55#R1uvOl+t;(me%vngrhenMF*sQytTmn!90|c_k0j976$e? zl^(H049gFeMdm!ryj9uPYQ4|#g+vu!ypD2cN8xvZsBx6ua=lFF2s=^ zJ)7lUPVZQy`N4R8HKNG^?ExZ_cP%e>9NQDy;9tn^HeP0WA>X)2(fq3I{mcS?1HWBi z8ZiY|kdblg=66P&d1L}#ZXt*jReCDThQe%sitR6}i; z5TYO*_vdjxZNzNJ{e6+I-QXDDNOicTP?#;9M^karMdMx~kq-^8q>Kw zGb#)j>hRQOsas!lF$Kl*pj1qnXa=izD5t7?4_J(#3f_f7NQ($2z7RzWS+GP2{JLg! z6zbsAd(lF0WLaEx=%UwOtR#`XT~tm$34%O1XEqV+J;+X+7V%zfHZF&6D8mgx0(m>pre*>1czWz9isnMJdofZ`DVFRr?OA zs6Pski{okUOMPQ)NHtzb6*_oA@`i)MS)9Q)hM4r70Mn?v9-?6x`NtnVJhiye?K@c; zC{bQS#+W62%yO~QBnY31Zh~l@1>L|19bw&-slPy7r?^=@1%vXSRjm~5QbjhDU&HJ= z+jjGHf2#{YkY*1q`fy9y*T!*e2%0f!@!Sk7&M4v`+jr;r1 zZ0V61nt@+0`@ck(j(&>%{F+(y`O88!Tj%Pb0vMZMu1#X_1R599D3ciY zi1Af9>W_(OpO}!!`PXY!1Uua67fGt!^j@dSZ=C)>UV5*|bb^y&YxC83V50e#!<8hn z0(Z3;T=2Ot~~Cv5j(-wsZnJ zPk8_EPSb!%W?agwlTs>l8POYeA5#yQlPtCDDF??}6RX-l+Q-IO0!`F{aw#Rh#Fzu{t_gn6UHP@B>AEZwW5nbwl$$kxdwBoAyF zTpX#%?_W4?RKHk=8TjQrojACAp2|L+s|ccK#c;ehTv`mpv(`G=!)d!OKSoHux{bl% zy>33HUP;h!bFHf~svId%o*Pb56n9Y9rKNqJ?BUW{VthPJHsck+!N6j|_^r8IMTL8o zsp6}v_DDXs1h4sUZiBXMxwd)gz`wy!n5TFrB5d&%}pjq)wi^0-okFs{)EGRucFTryeq&#QJEgQ6U^w8Z0s)3uW$*%U+@X?qOP$u zzWTT(-q)qN*Y>r2B!!xs71`PSJu*E7Ob>pw(v?X%S*GrLS6@Tdtdb_TUJYpWtp}m2 zqT>kbLd*o#){7karkERO2l&nXfl0HeL+uwlNF;k_&*{pKRO?S$F5;&K-U}MC_|`7( zEi~N0vXDvfmK$f2NR-*QeMyZ&`A%eZ6U1Lo)NB|VjxV$fhhKmpmvH4dM^#aIr#}(0V+mDmVl)_^YF8efWb=y*AO8idh^X6hnlLDd{!F zU1x%s^r81minOW$x4pw+=bs#A+>9w{#-Nj)ha!xIRAP&~gxa6%u>V zM2G5KINo3Uk`Ch}dN@$Qn=YNbnp}z-j4xYg@=`+T0hU};QwMnLG*7#=J|HomW7EVB z9lL_*;$}BKtxJ0}%=jvq_|IOspLf*$a*;?F4z18qCAj#Ct@Ii#B)j-Inf9BQt;S!{v)10L2TAS<(MSP0aJm~MUDWFN-W)}wN z(JS4n3NA2P>%B9~r&rtP!8fPI!kWZvvXQgdUZ%S>v8q&FTXftU^eUpqnRr9y{Lm>( zTM_AE7we!6eLa!vuKUoXxqtp1{UpIn;~Oh#+6gSUOa62I_~XzUF-anTJ2*M>O|rxA#0hM zj7^(Qp~x;Ht5DtROZDmqj#2?eL*CC_>AC|@ulYk%zK~-n=8Z(1z!J0shA4eMOunD` zAwMgf<|Bod!7kR2I+&k__lhM+O?ERsHm+d(IdA7Q|tK7QHQ|aqyY;OjZG-4Z{zn2I4aUF3($l^3Ms_Ud!RF*dN?^qRj=8FkpZV^ZOw=10PA-7;z@F+&2mt z{h<1IBV{i0l}w8_=*XVVKfeWDxjEmD`Qi|9y~FPaNYh|g`l`@CqPf%v8kA1$CO_Bm zHPw;|0bUPD$)w&J+$qSEJ*=N$q$FGG-|g`t2XvM=wrMX1S$R5@)DmQ|hQIA6H3}&p z6>EQoQ5K#WF_WM~uAZVK>6e=L;;t^so{x0Xn!{V6?cz{7?6Nh~_iE+xa^FSAnP9%& zYN=W4O8%-~E2I4?Y0HL~9hgf;&Xh9vdc1o`rkkUwuU2*niRvd`Qkq1uhjniRSuQ}M zO25~)R+p=>8RRgl7`9?KCeQPRqMT|xtBZUx!Md|lZfgUcb+ak(6L+7p&r+jxG!Pb$PM?_YmTs?7*wq3i3@kM_i!Kgucs0Tp4sl-xOkFHz>P{JE45g=X zj`0^rJ`Wy3u0EQ>rq}dU++GD>1Np z0y6C)xnGDRr_eA<)^g%cfsbkD?rxCGXq6-D_sN|$5q;rIE-0TxhAszuzCQ#k${U1& zU@&(>R;a04oZbb5zWB(u>+mJkdxUyJ(R9DF!QmFcT0*RapdrRAz`N-ver`opfc1^a zmn{UQiLbBB^i-s>IzRIYvINh(*8F%=v6)0~r9VAv!vSy$mLC}^K6=j@2p`{((||`?+Ao`eS6!Kmg{h-}EiN%~il-oNqr0+j?4kUPPmHvg z*eRlW^^0^GZxevX_5_V8dPo!nHs5n>tz8vBM*Z?rt^u}a?E79@^ak|NXD+|Wc}=4( zC~x)66?$@Q5hUpfXG~KqQP|94V%SUtUZ-pADu#<&eb8aFE1y!)Hk4G#2fh7_=M|t` zQJl;z#qDxZ^FB$$f_}ZPbR3(0O{6sX&i;H5Pi34$d|S-j(e|$A=gRg41!=Z$Wyd$N z6|)>W%@ED<FE*Jo(;1_Rjnfo~4Uz8P9uhWz%;Q)rMZyw}V|j zEhZ5WSv|+@!}@$X)>|vktQ^;uMMCLa%P>gq9+J9sk9Xo8eu+IWu^06hJ)cdfNV~Bv zW=P=3S^#6?%rFpp2tV(lR1)E@BJa$SsoR-oWY4>LA%)d((biRL?3t_jx$vNE`qo*a z-6^58L07W&atmYSn}Sp6wZRW78!Xo;M&_+0&+w)KBAa{g@_O ztU&Nc#%|&Pb+5`T#dYOPT^qMAo%hsxzFwrrcHCd}9|d@~!!6j!MrN zoo>H;$z}9&7H-67m5l?@u3tW5^ze#_nZuDY2Vro5lX*b?fp7a~m}1)AbAg<>j1pgT(f~wF znLhYP%BKjMQ0kZtij4Kiy*m-Ju$*XskrGkJbHwHG`RW53AMUG7#Uy2_AN##DX6}`^ zk!vnXXjP(xyar2%NW`n}^YSTpz;eF5L=1V(@Wn3aEQ|BPmWeM3VVqR8q8IX=8l4{R zYe6~2B9Oc`=^6s&7Hw;{+rlBEr}URv@|n55ky@#(0#Pk#Pwn$p)B6#d9|p5!^+oOI zMdq6))Nn&;MYGGAAy2bHFg`o-^z{maf4*?0#4`Q4R{2q|kPJs-NVLNYYF-+8dD8_ZrqW1$OLORhZ==Bu1T5Iq47&#SSrul+(P%3 zD8iMj1OYTC5ua`0peDAN80IF(e{QYv12?pp0c@3fq6)h(fET8zOOWQ-tm-pIiy+53 z7ExcM`fO~>EQIbLHn|yuC4ygd5p2t-Bzow{`LcHNWkFxBipsRm+2vl+KXXqeaX@3M zMr?ULHU;~-1y7F_MUFK{T@J~ERltk3Dr@IBEh4+mKXo)Yuz00zN1(dBAVuz3ZKg2g zvzlCNp-Q>6+r*^2(a9>b(@+WLE zx1f_Kzn|J)(q1`2d3>1D;sT=r--LEFrKfX$$OBvfWxuk7h+z{DtHyZDc{7rfl_fOz z<$6Y)Smu1Ffl^8x{;cG1hA;SoRUx>qILj`WdX7rEa$cmPlacKRzMo~z${Tn->LlO% zvJLp7b$G?2M;tYa<0zMHvJ*U<=pY`AzUvy5@4NeTC1NH9I8+mda`ya~Oj(ZAoT}aq zd*ryS+tJSrc4LB4&4jad;H9uoO(~}seGT|v>m3mYRtQ}#o^8>p&k){AZt4ZjPHwbl z5yisL#ix2zrJ!B1cP+w2U5;>PbK5Be1q44fQHca*Utu~`%VlR3jqc)hdh`jBpbvC; z_POj){!py%T(tKeX=u88d$(h`+-~{~I$GQu&Pm|HhPzf4^Z0_$!VS2tjlIKMDUgaQ?p`;S8*g zBwP?E_{g^ffh>>En_p1mF%b~te@d8yAheuI2*~=_gAMe6{!1h0v;Qx}fKV3HYe`D=WhgSX{hxqTn@4v_~fcc-S z{ow)Xzg+GA{^;v}L)!%e9>c|j4V+9YY2>XebS?iobEjcsV*$`GK?21Y7$A=XAir4t z2hz^^?}(j|h3Vhe`tRmHP@Uo5VfvpJkpIARrr$4J|HCAIKjHezB#?M<7WSu*^gmC$ znEo%{G457Je2f?837i;Ii8ttvH=uCzAXBSIbZsLUjFff%P(vwCP9wwUoFH zau(|skI83<-qfnu@viNktEE-1nGL~G`(bFpz--opxjmOf@WLGDMU63>d8fDKa~69u zy(8WS_JqsmY;#t({w({W#;w~eaNC0mtso_FZiIW{3_N^5pvZaSktei>w)e8Aq5Dxo+m6*`ycT<#8&$ME2z8g+)b076*yjJ{d)Z93nQk`T6yTFPb>qj*V=yU7C&1 zz4Cj=ISPj!mgw9Puyc#mIV}j9n5|ND8kpwQz~-0Vik4W4=A?^S z)J^xefunaz;dmp;Z5Xu&7Nzs^JTs?^0mB|8Oz0v51T`+?H2*Q z=VvD%b%o`LQJxvAhtPDNi-3IYT1SmD)@7Kh^{b%_ zTS+D4pCx5Nx+h`CbxTOW1YuM)^Xn~?75rSPIv;Wx!)n@ z%;lIwWr9|Cc*(h_VUM}jQk`ju*+I$;C3s0vvcrAe!59%WBQd-VIeBIU6}V zBB`ZyY*4q&&3`UwDv?!p-0_Q|Z3-hf!)rgz|6mf$^`7r?bf0ha>UibOttmndbbjV* zrw_Mzz{}$%L)2n)nsmKgl-?2;k($Q7XZo-}%}N;hcKerg`{kMYczb;OP2JZUj-v7% zA@_C>um?(nuiaj(fUhvdwgvR`9Ie5N1u>Z6~Z&(sA$RQyUd<$6oY_awHdTYZa8=@Z4q} z^nJfGy7#<2&eT_|YZF)&k4R&a7p1_G$#4a%r?PFkTIz1(1xm|v#JI0$mhvr*a~mb+ z<_81}j~n$C9;{90*9O*WJur?lupe;o3^kty`ptMD;hvLpzQV?>Rrd41POc5uYwsY$ ztn^qthE>V<)#~Yfdx#sdLf|>zd8^y|y+%<1c124|#X~E7m-B;4k-c&A!y?faRLglp zH1mYy61+LMn**PFyU4Egrs3sVwMn#@JE%8X;CXeF8gDdWRP}sw^AYvWNza^c-sALh zr`o2l-t{Q(jMP>XqqN+2apg@%yx@r@Xqstyu$G`HvoN;UUrJ1Ba4x;;YsFPxoS9pw zmGek5Tx$GPkpbQh_j=G4_eeQxly30?Hsfe#4J&XDqO_%c*Id?)x!X!BXrkr1?+Khr z_n@5E&@rt1^33??MGc0*@JB>wDJW`;g=3r<{RLujNh?a%{FXvQjb8gNBOj!|7px1X zJL^|Po#zuk8+-d?`Nq=n+|BiL ztDGs+fIco=kf(*TeR0>>^%;jS?jj0C%VS?SK%laZ{Pli?*!0r~k8QYR&x`kY)sfA~`)n?Ai#q4Z z9)bi7a|63tTB3W&^SdSO2e>GN4UTImUO(8~j~H%@FB#^Yv=LjZH`aX)eFP6IoMgDz zjB=btu0IhG?C$24_b!jdRCtaGo24Kh!XC7v92|YR;2&-6vfd6=SmQ!F1@xH0s5RHV zU}QOwHPDs+^6g-#>e?Xkz-@$A*ocu%=j#LLj`=(-*?umvWwL^jz1fD#`=D}&c_(qwRQ=-Cs z`P`^rBTLXNdBcrkj?!auu2=ih$J`hU)EJhVBpGe5+FGma(WT9MlYCd^buW8|E1?^O zHg{Mq7bGs1*QP(-puY%Da@A6H;MXv`l`|ZeQeN3U;L58FX6%NC=}p`PlK6n&&u~9{ z%h+i$T5Bqy(@M%R$`_Fy%W(rJU8PYc9P+puQ{i0@g8MLHJ#Vf9TUShVE*yrX`(qC) z%(z^?ER6{-=U;GxFD`g@FUmgkFCJVDYjK%?yL@L4Q4fA;Cv&VM6CM)GDCjsTT5>Ho zZl}5x6&>(tbZ+-%&-R+I;aHE~5%kW_TTCp;O6+*F?+F$}I@P8gkH%dyC2-{4$!>pJ zMZanyx*^(*E1bQXP>p%zcaF)m>Ov651$D~jhC{`|H}i0-ds)@iS{zc#0(3Kt8B|}ax+7A+|M|X`?^o4naE-5>bf>$bZ=i=k7o#!&cNUHII?y41mulEcUzKZ#JJz7 zi>u9Av(PU?0-I>P&Lb|c>lbO#y3}!VG!8E>O}!mHnrrR*no-9+diy0l!b_lnfcxU( zc)u5Ey!7a8w$ryZ*%Y=t#dKG(%th3uKye%a_< z{raNkK~9s^UfZ;hsvNKX%8$4p=>rCllgaEs>etWT2X*2_14Ts%PW1RyIv8jQ`l`2# z(rk4YGe**JaOdXca3woQ)3|XbZ1Du|(y!u^;i>Ta6`7s1`*(`tKL^55^cc-Re|(XF z>{nyY%*4dO#mK&PE)$NtRv4BuMHb&rp53bYU=`j^Y*BQbi!X0aR$tTws)+9&gl3!T zOKT9_%6uyvT|7+WS1aU6ji9Fs$m@v>LzX~DYKV?G6%$4V-`dib7+e|fX8epo`bp|b z>Z_TkI@r}!Q;Hxk6&G8#5tWm~h8LD^FBM@aGO1|Ko!9r0;hkIB*1GY%-`kooeRg2V zG@Jv_|Le0BPcdBQ2VV3Jos(w%gR zY5ci{yVcs@ROQx@kS5}5|5tlo85CExt{n)F;1*nhyLTgvC%7jBcXtUA++7+E9!PL^ zcXtc!kl^kPfv=O9IWx)3x%bppb^hI5wQJRWd&%Cb*ZQ*_d12)1d`0U}&vxVSuAOD3 zPR;NaXiyhS>Ym}!6^q*#Vu}xDW2wN%>!~5kjN6Vj*5~!YQ_&@l6U*y4FM5+9%ofHC ztXf?GWapKh1oEg0Dh&(-=W z_(OW>YYBZd3fnKTk4{67QX69x^d%PL;>SlVOB)KQU*vIdx+lSV6C@;tZJgkJ;m4*9A?A$ zk81trSI=SH(6w36;<%;86sdK@y$)G`(%@npKZ=QGd)gDx1S(7$Z%m2zKCRuH-Am5k zd9$h{K5mf^vr|sEwtt$h5G`vqI7} z=}Co}=!@rLlm(Y@r_?yt`mRj)qsqD?<)sor!@6VXHc0u68(ulIl&G92!ChjyMA5IB zTjAEcp~zKPT3V4ZUi5kCo=y9`%6*y?A-?{MYbKz~09euH=kt)Au`sTakR{RaSgKEF zCJS6nNuMago@0pHBduyo`fm*s)E~HXFr!x}<2u8XZ-~gw|XyV>$s7;n7czgP2z`plg z1UScqvY1xXLv1?=+2DTanwoPV_Q6$&OfNLRNo1TQz`;`KGnR0i_Xdz2)6t-fr;2yX zheuEJm_N;&QjmxXsHI=h`}j${CU(%Wja)?+@KnO2kc}kGB$Y37YDQKG)<*7;C7O3>oLLO;tSUQy?T(7)5JWIdHLy@u)#YCjh z`|#y#Ev|lq01W@VRwOc39BBQMet5?AY_jA!=rL9UF0FCKYZN=)Og^mva3^*=>_>*% zHQgb>X9zT%{o$AqGv-d%m}=os!B5K{0h8aTa>l?#qTy|vRYnIE z@SZ)(j}F<*rBd(Vc!a*&N^P&l8x#NDT1FYno__x_PMK8II=??Iv8YwuPA7%+EwW|c zYlj+mh7M{pX6L1;eE#3_TFN>KR;16>Hh z;G^Bpi4VGrhzhdUIPIt2-9U_Xv1+MG zC8`^7ous>KBt9aSUYbv>5y$ZnZ74CPZCeQtE4eE1ov{YCsug5;q?_>Hl;aMM&cuSN zVVhghp2i8^_&QUC6WN!EE%-|bZaO6#9i%PrMw=3UG4io{6So|){Zu%yukUpp42Xiu zj1+S!5|&3W1}0#BR{n@0D3r^eaSiK3-PEa4b^D6W5K95ot!p`<`i#ixJ6?A?UY^+ck#&Nh#X%>+a4;gg5a%Lbr z6IJ>^8nK5sAeHvT`Q!X*98ZdF?V)`yeRHqdTM$_XI1+%S>igJd52>&ZvDs^$)LH3k zCKk#-TjZX)#>p+ORp1_C?cIQtwvKG7|2uCIo@2%vG7=z0XV%O2Bae3*F?4K(I*RP3 zHZMh{2+OB&;8_y2(01O(e@F`&soHZ4Sj$@fERTi~KI}!%3Fii7{nX)@!37!}{#Bii zlsW10f?Fq4C>hIEBspo$e8m)m$j{Yn`z(8J`#t=+pC zLZU3lNpmRX_xX(<-)5ZdqYVi?#L~9LCpC`-Wv@oMG=xOM9)BW@!GsSW6QQARF6|-Z z5o%@;jBHFJX*Hzs!y4Qg5G1Wo7W`spq^r+E1Z`9{iJ|;?-{$6pPD0xZtK$(iGip$% z358U(M0l=&FNH*E@7ll-9%TpQMyb`JfKA8r_me;}+WaC(Rk6nF_TlYhV8IE=It-qV zr}~w3WM&s#Q>_`=gH`JXj}=mzgsf;J__i42gk-YUPAX+a`sN$#T;KV(&dUetf__!SVL4&)(EvW+lb{8EfW|Msw!BrA4?J$COW{U z2eN8Cx!1mzz`lrYor9X7dFn~t+l=ZK7Z&jK(rRIVB=Gu>qFB)@hj1p*xxM;mS2rl_ zK>(TZGXu<33Yv1orx>v-go<@IllCIU4Af*TXIE>3sNVhQh>OkCk76yOUrR#J6JL&e z@#rW_#X#>$7i?cnZpW;^edk6U?(b|Nc}1*FAd;6%!}wY_)}I>R`KhS>mLUpa2sH1| z%3Pxer=2CzYr8rNX`cod{*g3>#}dzsMA0qrK`i7{{1JwA4dS8u$Qd7IR+6~~a;#pk<;k!oxo3hQ7bN^dlbET(}5AZ#x{ zcw2-mHpUXONFCxl^aZ@zYuV2BnY(Zh=W+!pCo(a&HxYksw02XxhA}neg{9#jm^MnN zCKNCp1n@^K|9c!98TH<@wX3)<;uY8$Rw?<|9CWzAIv|QfsI-vFN@q*C z_a5y_?!McDi{6UmeOO~yz!&H009EGuXq8n25O62iwBpWmJF(k}<&~)O`Sy9>0>n`E zjSO1+O1p*=zMQ6$@eecv_fHC-(1WG}j9w3h4Bk?bPM--PPhm5t3?iADl;C`;=KXl$ zW_rOvr=?u|Xaw6TS5zyv9O_E=3udPp{fn9^SI0?OC-I<0{kQs`bk&mCDZGiEOnc@q z7NIjJZ^==zF|T;SkovsfrB&Y+r zHwgX$8JUQTJeSNzs)5;D`n}q0q2~f!isQudL!&1h@rAF8^@Th8*{T%n96ky%1HOr2 z@R@H1zrYC^3i|56TKc5R0t-D;+C{KYdMHI&C}Ic3{<*DMCxJ=~iyB(@XmgxtiyL`KV;%2g`W2k%-ODoYcQgm3<& zRE}w%0qmxG!IH#fcre9sWm4`pIDl>^ztC(SegMP23y5Hv7COeDR@B$wBuQ z?FWm!D(n0W4NDuc{wuW0TlO^~+U<{^7aQl~C8 zr+L@>x|`dhpOx}+8As5&gNqh~FvuRvR)!!1f|`{ThAiDMKJR-rA1sj9VnEfC26qJ` zKjZifT*b~tx{K8&%NJ{rl8HT}bd?&Un@2=e@pt1*$&Hmx$# z_B7qVViPg`;hGaNll!GkGh$gYqx33a*35R7jke|)D{n(*mwFiQTu-ktgTT`8JW>0m zO7?(SK41V<8ErYP_m+T?xVhqX^@Q%&#`Ta*NwwnWKzdU$KlpsHV?SLiAD3^zno9C+ zW9r-d@Ig>U{saim8p_%eK`%Dev%v7C(@HU}$Cqx&#v+EtRZ4dsW+DtuNC#$iB?XdBgayMq==Q1JLgh=*?4^D6;u`K5r7eQ$N3I>@Xmt)Y<*2` z0K4ITgr`oudMWdwm!99PWs{06)wE;9nc8I$A$4^_cZsckh3(~0a-SCY9RUp9;p`%G z`BrzrQKaH=iV|)X+*dWxOsT7slqZ{gwLYe0V0_qKLfvKZ({IqF{a4}E=w)v+(Q!E) z8AaARh(K%-M=Q`oS8u3$FVc7emc6CRb_LOMlu6!^iAmeSwCHMxW(#rEBYDQ_5I=N} z26Nk0LQS+Gj?^&`3%5GN!6-A`VcQ`a4?-0`O;>rjyb2)7B^~bx+np^&1&?vRM^nfIHsZ??ZF5Xzc}E@Rw}`J0g=D*P;BKN&#5+%J!Z+nd?KOm*j(C7q1wrv`LU~W^0=k+Agm>i4z{I z5lA0kjn0jK=m3AV*7|`8eg||pSpmR*F&_R@GyPSW^cP9hzhgZ7gqZ&Kcn`ljGeZXW zC*H%KT0sy*7svrITn0j*Rscj{2!uSdLnKE3)BUq{5b)h)>kq*D5A7iP|1l>1L+zmO zcg6$@3lLI53QmX=@O$xHG|0lj@trCGDSmqbeAf=LumFA&9sXcUK%Rc90{E>R;P-aF zRRO;EFLNFKnK1B|P4G9W!%wUKKP5c;@P7M=@bF{J{e|%G1MdHA4gP`dld%1j@NoBc zx&z>!NlX8R?jZgby2EdNcmIa(0AS&S@EzDd5HmW6zL1p#^gk&J|Nr?8fZt8y|KL0P zw%`BcJN)?l=NWF$*y@)DXjQm5ncVe>=%726_w{CVfWo1Ecm=4DSlMRZuw&dpBd zpm;x%>XHLt?fYHrHYE3tD54ej&%X`Cdm^qLuHM!NtzXoSHfUp}9~sv+^L2LmFKaw7 z6+a+PTO;=zpN@#EXp&AXQRHWQ+6{pc)stD-T$yp_N5|=8DlYk=c5|S@ce{}x(0b0_ zE7Nr|cZltQML#v|;k@4@*UWq{u6>+&Bz$M_RWa(e(7hI}Y=3j>J|n=3>Z4ovMbq=U zz^jWJtF#M+pydo#{}$C-6dT_F^OZ%p=9>GncCnTED~yAM?#Pt(IvU?>6YO=C$iv zlx7Zu*DpP8JFX-wH;3Anzlog1w>YTKEL>fed^_%0b{=DXRxAJ(AlAOE+cfvAy=}I& z{$`$bG%j#VUSet4?6GR~wXKODqTd<|p(fSs8>h!Z^7G02<0t-sEvNgr$DwjoSgFmg zuWn8cdY&sFJoh*{%TP^J9ACbCSX=eH>5phWJtXrLzhTA4>FhEQ#oQi@mn&VFIHlwcs4enD6WS}nGdce~pLVaLujO3M6ypmAm&Q371 z&Yd@&cIQ?6;MHk~7FLT@w>Fx<{f@TxOWkjV8hoDTheNd_AEd;L8mYAE&aeO;5|vDR zfYo=$8(9LJtBAOs(_m)3yAh+i>o95ohc<8viPh3hoNph)8C-{ohtz?_{48z1uW9Do zB8h_S5rS0{59MahnR z#)l_EjP92Q!&SRAhX<2~dm5{zb+xn&ys_Joj;C*=6zyf3oM_bPF5zdN6l zFe_zH-`4p!N}nA;HgxRV6}TOqE?7@p%xN1TCRrX-yg<(vX?0hvUm0AV#u=Qk-%C)& zG}KhTYT9n|T?bxiv%{um=Vy?GqSTXy zbGlcrZP5fR@y_u2VR6^7wrXhM@3EF)7^y0#!w}6hdVu5yf zvDLj49PLiV4)0r%Z$*fe*lEuO-=0u+yl9nM%5g+AdAJG}y5g{yitnn)G1z|+_Yi0n$y%a;pjBv7{Xx@iX~zhAXbu@Ns@`Z$`M~J1O4GIh=qYx zgEcQPt56g_)1b$nQQ2%#>ZT#T^mA|#pyTfN^6Vb7yiynjI?yb00oWc)J}=l^5lnW- zl55WL^89`R5v$?(9d#AVhQ`czcChr-CA7HA;6k4P(5^HN3aS20b~}p19(g;5tN|+5 zypygHRINx>y|VcPca>4bzQx+uB%Hxkhod+?876IbWHTr9gRqpPPU6}d$JBReu2b-l&!058X&^u^W<^zSr((N!p4;^9YN?d zSHa`7Oc`Psg=wxTBc?@KQtfmBqQj(SRuR5*C?T~x@~liDC|x~gxDqs}V}1*B z<$XSPJ^*R2Xm8Vt>E_oo=xQTer)bZDbse{E9+M$F5H-w=v&fi^x#&P_>KBhE^Azrb zap3rMrTgQuk6E7LD1sZk~|wpUE$kMTN5aeP?c ztqX^~O*crQj|`9cYA-Xg#xr~@?phx=+c^~jC)dx9$Vfy z!WG2LD=!U0>fMJSO|nICmYa+xBrYsk?^dV>);oKa3Lyk3#ay62j^u(%-RiWb8i_q5 zk#~s5Yw0~9jy@00ksY^ywMN!WA$S|6(?(NZ>0{|e9iKzgKVGjP_(42>6Z6w%S9Ci_ zlp5Fv`ze^09^S=v;uIdlkZ!>rnw0K?RoW~u#9zgb`{5Z*_bJqB0u*U*p75*a)K?$B z7-PWE%3z&tP&vXhqtBZ(P-h{ePO(QrXK8X#+vj!&JEER$*vOwg zN>;~DuDgrNB#)Ggd1IprPshz=#)>f;=}+{TqU~)cqra?Aql8dGLGdY{3J24A{?Y)* z`jArjOiOmobx1i8MKMt{SW@c#m1AKfYw*>xVL`eS7-H@lk7|!ONf-W~BmlUV$e z9xjqz`PH&UZF7YX*>k=Rm2;M}7JYMVx=l(&&kT!R7e7}t3v;!_xy6^^J|>#rCYdum zQ4-2m>T2eDQvUwZMs==e(mbU{q)vGk7_>ng6t||EH<=e3v6B_Y%WFo&Ve^)OosMKa zm;FNRi#%U02RBM49VhDZ8nep_9ubQjopKtUBKa(rS7wXM(S91Z;`n4_Bv zEq7O8oHlv1WmaTX*P#MsMWbyDKl-M!05zP&`(3y$6v3WyBCG+^*A}+A0D~}s&yid9 zNky_`{TXTvYVWg@ijdJiG$~=OM8lW)f<0iK_GuxLGbj3QU=u+XnABuo6)H%*L$ip% zMKrI`J~|S7FG514NA>b+us3dqiuf_3n`0-to1-xL>SI={s8{KX^(sVq6kWwmLDujY z^o{gzu{B+acRcH!^LiEzB7Mb{_dKmhGOw}t3Qzo)&1QB((7QE1E2yCB5`GEyLz-WS ztED{%A-B=y#Xts+rKs06IjU~#u5gIDrZXKJo##&$a22VwAmz{}EZ=#y=FTlFVjT$_jAiUevX$fqaC9(wH;HK#1#3_}0R--QrL5ipC z=G&lG#pr4<7gP(O0?LE+CF@c%1ZM{IJ&0^Ijc4WiPTY!snxe~qXu{RQr+^&kNyEB5 z$#P{sS0H!WbVpSv5qWl8`c`=%<*`=}>)zMF*#L_dQ>i*kKJU@TCHKb+n8`J2JZK(1 zAl(F(I{31ityl++mb4k0R);Ms&PaVGeP|kT#d?dNYkcCDc)V*Kl<_<@00n6N;vQqg z42N4WtR#~0$!B48^>Wl4E$3=Zc?z>z%kpnkn>~A+==Uy!QREj$`nQNc7J(1D(E zU}{;e9UwI$qVrzw74iPN#2xrIyVUYBZ>iC=yDZ|H3KOFALK-la2#oEeE*(_OWa2jn zHO{X+dMgVln3U=n_7hme$&ET^bsx#5j@Fw~Jg>Ot7YpsVrXny^d&zhk+$JQZ@X=7d zPc5))w0aAG;1?r$iq}&(vW1d($&&HBPoVoIG1&2?feFLpfXFwlDB(oBk6CtjPnNH~ zMUsP(#UA^b_Kxlw@JhJ`3{!HC2;(6#7 z>rf`Us|&i3mQaR^u(R6Po*HxUj8|5-50??aqYR3q=y98r+Ry?Ai0;wZ^_j&FovJmP zqz$ist1ys^k zDfs3Ei36%pjmxa|Z%~m+9h0Icha#13X^!Ww-SSTj=jNSwwXC3080m6FU31Hk-FU7z z>ZZ82s+Am-3E%>o`*^Sk=#foRrXu+r3Dq7%)Q!khn6~AJ%B)wsoiy8;hwN6Z_)5*4 z0;rb3&UXyK&AkeA{fkpPjnW4WwjiNIt`9z<)1R!_8Ir(X5}yt`YR@M0s)LF==jaGF zcOsN$+iv7J`pLtC4m7fd&19$DFUlu83CAloB`xm0l{$8;=Eu-W!INMlpqH z=aW4{K1_+Sx;JY~l)wvKj+9q}Npnr=3)GuDh{?=j#8fOfNKM>BCEq}ZjASXAs~@&u zyM#NKlo^%_i72ie2WvAyG9}fEYi=lRQN}6@L~)l2;&C^Ar{w$P9u|!1dJ6%A+q_C( zl{W%;`gEhBly>#H~xjbrUmc3~U8elt)2Uavf8jw+xjPpRg! z-a2q1QP_B<8#QcBjIgE#JC7WVH|)X7ZV`i4x6lgZb%lM;DZuw4)TAo~CemOTW?!jx+;mO3UYg~1e1~CS?_MLfzICRE{Z3rd_bwAwqG`msZR}Ft z(xZPFJ)*R@>(b=o+NF%lS}eZ6a>3I+U>LSX@P&TbGKqL| zcEK%J&tE^CZV7N$IVW8eTxKAFdYz&fJ1w#FLXEIY6xl}Zv#Y^SiMQqj(K6IPI_16& z|9VnmY;b~!9p=qJ? z>ihocHu(Wkn}@VCF@C|D>1)l1rCo+7q4KQV!KyB$T>L$$jT8fHqA>RzPYP}SW$ieX z!wY$5#;QW(4_W*=pap%#e6UzbUFG$)P$KOl=JWIv#?(WDJ4x4?YBxS#-C5q`+>j?< z)YwzstXwWQGujhI-sNHAZ$@7;QmYCXSuC({Fi>M#mNPS^p9GN?_ZLW7L{z_M)0H#B zx3_#|M$9o50mk9L>^r%dGb!60jv)my4$SwdmbP2x?TWTL_;kuMf`1v#9YKg3}iT>mEm{m<+We+MWyemE=sw{(_&tjV8q+x+j?!yoJJKLj6sEc2h$mVh6o zdw)4<{}TrJ7x=*X7x3X9j1B*U9w3&9KU_tBq`O66mNGT4BSBC{_|4Z3f_Vs8zk~RJ zvO==3{%*SoNlhy(3c(x=ogiME5|)t6voC)yh5qX3>0}Erzl2zUf)Kt-b$`1^IM~@C z-(y7buh@4>(eD?D)xTnF-}B1;6a%nua6llKpJI^AKM>!;Ut<7>!RX&&AP7?NQ(HD5 z8$@;aa}2-&fPWho$jSzp!=Ku+u&_g5nO|d^ z5S!CqVnEh^=nug0w|WpC$zSJ+1@zr~^_TuYpzl_*->*OC8N>qobq-iSAkJT7tSoGQ z`wobQCCjgKz{<`B!JU2{gOwfhJ&V#$;BpX))aH-CLU00b5NdyM0|>FBR* zzo(A+BW7=_3&}2J`y*@i8&elU$o_!9VLyy|e-jKd%UfGR5>x%*#A#=*Yis{wD?wmA O$O1s1q!f`8MfiWW)+sRn literal 0 HcmV?d00001 diff --git a/convert_result/09c953a0.xml b/convert_result/09c953a0.xml new file mode 100644 index 0000000..0e76b55 --- /dev/null +++ b/convert_result/09c953a0.xml @@ -0,0 +1,714 @@ + + + + + 09c953a0 + + 09c953a0 + + Music21 + + 2025-05-19 + music21 v.9.5.0 + + + + + 7 + 40 + + + + + + + + + + + + + 10080 + + 4 + + + + G + 2 + + + + + E + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 5040 + eighth + up + begin + + + + + + + E + 4 + + 5040 + eighth + up + end + + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 5040 + eighth + + single + + + + + + B + 4 + + 5040 + eighth + + single + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + + + + + + B + 4 + + 5040 + eighth + + single + + + + + + B + 4 + + 5040 + eighth + + + + + + + G + 1 + 4 + + 5040 + eighth + + single + + + + + + 5040 + eighth + + + + B + 4 + + 5040 + eighth + + single + + + + + + B + 4 + + 5040 + eighth + + + + + + + G + 1 + 4 + + 5040 + eighth + + single + + + + + + 5040 + eighth + + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + single + J + + + + + E + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 20160 + half + + single + + + + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + single + + + + + + + + + B + 4 + + 5040 + eighth + down + begin + + + + + + + B + 4 + + 5040 + eighth + down + end + + single + + + + + + B + 4 + + 5040 + eighth + down + begin + + single + + + + + + C + 1 + 5 + + 5040 + eighth + down + end + + single + + + + + + B + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + E + 5 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + + + + + + F + 1 + 5 + + 10080 + quarter + + single + + + + + + B + 4 + + 10080 + quarter + + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + E + 4 + + 10080 + quarter + + + + + + + 10080 + quarter + + + light-light + + + + + + + 40320 + + + + \ No newline at end of file diff --git a/convert_result/35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.pdf b/convert_result/35f4eef0-ce39-41fb-9a14-a4fb6c85ad29.pdf new file mode 100644 index 0000000000000000000000000000000000000000..67252ecde9caa0c2227ef9a6ec8f66d75d57be41 GIT binary patch literal 33536 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 + + + + 35f4eef0-ce39-41fb-9a14-a4fb6c85ad29 + + 35f4eef0-ce39-41fb-9a14-a4fb6c85ad29 + + Music21 + + 2025-05-19 + music21 v.9.5.0 + + + + + 7 + 40 + + + + + + + + + + + + + 10080 + + 9 + + + + G + 2 + + + + + E + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + E + -1 + 4 + + 5040 + eighth + up + begin + + + + + + + E + -1 + 4 + + 5040 + eighth + up + end + + + + + + + E + -1 + 4 + + 10080 + quarter + + single + + + + + + E + -1 + 4 + + 10080 + quarter + + single + + + + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + B + -1 + 4 + + 5040 + eighth + flat + + single + + + + + + B + -1 + 4 + + 5040 + eighth + + single + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + + + + + + B + -1 + 4 + + 5040 + eighth + flat + + single + + + + + + B + -1 + 4 + + 5040 + eighth + + + + + + + G + 0 + 4 + + 5040 + eighth + natural + + single + + + + + + 5040 + eighth + + + + B + -1 + 4 + + 5040 + eighth + flat + + single + + + + + + B + -1 + 4 + + 5040 + eighth + + + + + + + G + 0 + 4 + + 5040 + eighth + natural + + single + + + + + + 5040 + eighth + + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + E + -1 + 4 + + 10080 + quarter + + single + J + + + + + E + -1 + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + single + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + single + + + + + + B + -1 + 4 + + 20160 + half + + single + + + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + + single + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + + + + B + -1 + 4 + + 5040 + eighth + flat + down + begin + + + + + + + B + -1 + 4 + + 5040 + eighth + down + end + + single + + + + + + B + -1 + 4 + + 5040 + eighth + down + begin + + single + + + + + + C + 0 + 5 + + 5040 + eighth + natural + down + end + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + 10080 + quarter + + + + + + + E + -1 + 5 + + 10080 + quarter + flat + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + + + + + + F + 0 + 5 + + 10080 + quarter + natural + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + + + + + + G + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + F + 0 + 4 + + 10080 + quarter + natural + + single + + + + + + E + -1 + 4 + + 10080 + quarter + flat + + + + + + + 10080 + quarter + + + light-light + + + + + + + 40320 + + + + \ No newline at end of file diff --git a/src/services/mypage_service.py b/convert_result/98f55ceb-b3a2-4b39-bbba-1768dcee6396.txt similarity index 100% rename from src/services/mypage_service.py rename to convert_result/98f55ceb-b3a2-4b39-bbba-1768dcee6396.txt diff --git a/convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.pdf b/convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.pdf new file mode 100644 index 0000000000000000000000000000000000000000..389ed868c9e4bae47657db646e16204a5afab0b7 GIT binary patch literal 32413 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 KkqOI+!2TC%XHZB0 literal 0 HcmV?d00001 diff --git a/convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.xml b/convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.xml new file mode 100644 index 0000000..5b583ce --- /dev/null +++ b/convert_result/afbe7119-2470-42f5-a7cb-c5a0a144ac51.xml @@ -0,0 +1,761 @@ + + + + + afbe7119-2470-42f5-a7cb-c5a0a144ac51 + + afbe7119-2470-42f5-a7cb-c5a0a144ac51 + + Music21 + + 2025-05-19 + music21 v.9.5.0 + + + + + 7 + 40 + + + + + + + + + + + + + 10080 + + 6 + + + + G + 2 + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + F + 1 + 4 + + 5040 + eighth + up + begin + + + + + + + F + 1 + 4 + + 5040 + eighth + up + end + + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + C + 1 + 5 + + 5040 + eighth + + single + + + + + + C + 1 + 5 + + 5040 + eighth + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + + + + + + C + 1 + 5 + + 5040 + eighth + + single + + + + + + C + 1 + 5 + + 5040 + eighth + + + + + + + B + -1 + 4 + + 5040 + eighth + flat + + single + + + + + + 5040 + eighth + + + + C + 1 + 5 + + 5040 + eighth + + single + + + + + + C + 1 + 5 + + 5040 + eighth + + + + + + + B + -1 + 4 + + 5040 + eighth + flat + + single + + + + + + 5040 + eighth + + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + J + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 20160 + half + + single + + + + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + single + + + + + + + + + C + 1 + 5 + + 5040 + eighth + down + begin + + + + + + + C + 1 + 5 + + 5040 + eighth + down + end + + single + + + + + + C + 1 + 5 + + 5040 + eighth + down + begin + + single + + + + + + E + -1 + 5 + + 5040 + eighth + flat + down + end + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + single + + + + + + 10080 + quarter + + + + + + + F + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + + + + + + G + 1 + 5 + + 10080 + quarter + + single + + + + + + C + 1 + 5 + + 10080 + quarter + + + + + + + B + -1 + 4 + + 10080 + quarter + flat + + single + + + + + + G + 1 + 4 + + 10080 + quarter + + single + + + + + + F + 1 + 4 + + 10080 + quarter + + + + + + + 10080 + quarter + + + light-light + + + + + + + 40320 + + + + \ No newline at end of file diff --git a/src/models/__init__.py b/src/models/__init__.py index a135cf6..d92c010 100644 --- a/src/models/__init__.py +++ b/src/models/__init__.py @@ -1,4 +1,9 @@ from .db import db from .user import User from .score import Score -from .result import Result \ No newline at end of file +from .result import Result +from .resultScore_save import ResultScoreSave +from .uploadScore_save import UploadScoreSave +from .transform import TransformTranspose +from .transform import TransformLyrics +from .transform import TransformMelody \ No newline at end of file diff --git a/src/routes/auth.py b/src/routes/auth.py index fc8bf88..9edcfcf 100644 --- a/src/routes/auth.py +++ b/src/routes/auth.py @@ -1,9 +1,9 @@ import os import requests from flask import Blueprint, redirect, request, jsonify -from src.config import Config -from src.services.auth_service import handle_kakao_login, refresh_access_token from flasgger import swag_from +from src.config import Config +from src.services.auth_service import handle_kakao_login, refresh_access_token auth_bp = Blueprint('auth', __name__, url_prefix='/auth') @@ -79,7 +79,9 @@ def kakao_callback(): 'type': 'object', 'properties': { 'access_token': {'type': 'string'}, - 'refresh_token': {'type': 'string'} + 'refresh_token': {'type': 'string'}, + 'user_id': {'type': 'integer'}, + 'nickname': {'type': 'string'} } } }, @@ -88,23 +90,14 @@ def kakao_callback(): } } }) - def kakao_token(): try: - # 요청 내용 디버깅 로그 - print("🔥 /auth/kakao/token 요청 도착") - print("🔥 REQUEST HEADERS:", dict(request.headers)) - print("🔥 RAW BODY:", request.get_data(as_text=True)) - - # JSON이든 form이든 유연하게 처리 data = request.get_json(silent=True) or request.form or request.values code = data.get('code') if data else None if not code: - print("❌ No code provided") return jsonify({'error': 'No code provided'}), 400 - # 카카오 토큰 요청 token_url = "https://kauth.kakao.com/oauth/token" token_data = { 'grant_type': 'authorization_code', @@ -113,15 +106,11 @@ def kakao_token(): 'code': code, } token_response = requests.post(token_url, data=token_data) - print("🔐 Kakao token response:", token_response.status_code, token_response.text) - token_json = token_response.json() access_token = token_json.get('access_token') if not access_token: - print("❌ Failed to get access token") return jsonify({'error': 'Failed to get Kakao access token'}), 400 - # 유저 정보 요청 user_info_url = "https://kapi.kakao.com/v2/user/me" headers = {"Authorization": f"Bearer {access_token}"} user_info_response = requests.get(user_info_url, headers=headers) @@ -135,15 +124,11 @@ def kakao_token(): return jsonify(result), 200 except Exception as e: - print("❌ Unexpected error in kakao_token:", str(e)) return jsonify({'error': 'Internal server error', 'message': str(e)}), 500 - - @auth_bp.route('/refresh', methods=['POST']) def refresh(): - """ JWT 리프레시 토큰을 이용해 액세스 토큰 재발급 --- @@ -155,6 +140,8 @@ def refresh(): application/json: schema: type: object + required: + - refresh_token properties: refresh_token: type: string @@ -162,15 +149,22 @@ def refresh(): responses: 200: description: 액세스 토큰 재발급 성공 - schema: - type: object - properties: - access_token: - type: string + content: + application/json: + schema: + type: object + properties: + access_token: + type: string + example: "new.access.token" + refresh_token: + type: string + example: "original.refresh.token" + 400: + description: 리프레시 토큰 누락 401: description: 토큰 만료 또는 유효하지 않음 """ - data = request.get_json() refresh_token = data.get('refresh_token') @@ -181,7 +175,11 @@ def refresh(): if error: return jsonify({"error": error}), 401 - return jsonify({"access_token": new_access_token}), 200 + return jsonify({ + "access_token": new_access_token, + "refresh_token": refresh_token + }), 200 + @auth_bp.route("/test-token", methods=["POST"]) def issue_test_token(): @@ -191,28 +189,36 @@ def issue_test_token(): tags: - auth summary: 테스트용 JWT 토큰 발급 - description: 테스트용 유저 정보를 기반으로 accessToken, refreshToken을 발급합니다. + description: 테스트용 유저 정보를 기반으로 access_token, refresh_token을 자동 발급합니다. responses: 200: description: 토큰 발급 성공 - schema: - type: object - properties: - access_token: - type: string - description: "Access Token" - refresh_token: - type: string - description: "Refresh Token" + content: + application/json: + schema: + type: object + properties: + access_token: + type: string + description: "Access Token" + refresh_token: + type: string + description: "Refresh Token" + user_id: + type: integer + example: 1 + nickname: + type: string + example: "테스트유저" """ - # 테스트용 고정 유저 정보 kakao_id = "test_kakao_12345" nickname = "테스트유저" profile_image = "" result = handle_kakao_login(kakao_id, nickname, profile_image) return jsonify(result), 200 - + + @auth_bp.route("/logout", methods=["POST"]) def logout(): """ @@ -225,11 +231,13 @@ def logout(): responses: 200: description: 로그아웃 성공 - schema: - type: object - properties: - message: - type: string - example: "로그아웃 완료" + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: "로그아웃 완료" """ return jsonify({"message": "로그아웃 완료"}), 200 diff --git a/src/routes/mypage_result_score.py b/src/routes/mypage_result_score.py index 0bb015d..1c147ff 100644 --- a/src/routes/mypage_result_score.py +++ b/src/routes/mypage_result_score.py @@ -5,95 +5,107 @@ delete_result_score ) from src.utils.jwt_util import decode_token +from flasgger import swag_from result_score_bp = Blueprint("result_score_bp", __name__, url_prefix="/mypage/result") -@result_score_bp.route("//save", methods=["POST"]) -def save_result(result_id): - """ - 변환 결과 저장 (키 변경, 가사, 멜로디) - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - - in: path - name: result_id - required: true - description: 저장할 결과 ID - schema: - type: integer - responses: - 201: - description: 변환 결과가 저장되었습니다 - 400: - description: 이미 저장된 결과입니다 - 401: - description: 인증 실패 - """ +# ✅ 공통 JWT 인증 함수 +def get_user_id_from_token(): auth_header = request.headers.get("Authorization", None) if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 + return None, jsonify({"message": "토큰이 필요합니다"}), 401 token = auth_header.split(" ")[1] payload, error = decode_token(token) if error: - return jsonify({"message": error}), 401 + return None, jsonify({"message": error}), 401 + + return payload["user_id"], None, None + + +@result_score_bp.route("//save", methods=["POST"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '변환 결과 저장 (키 변경, 가사, 멜로디)', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + }, + { + 'name': 'result_id', + 'in': 'path', + 'required': True, + 'description': '저장할 결과 ID', + 'schema': {'type': 'integer'} + } + ], + 'responses': { + 201: {'description': '변환 결과가 저장되었습니다'}, + 400: {'description': '이미 저장된 결과입니다'}, + 401: {'description': '인증 실패'} + } +}) +def save_result(result_id): + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code - user_id = payload["user_id"] if save_result_score(user_id, result_id): return jsonify({"message": "변환 결과가 저장되었습니다"}), 201 return jsonify({"message": "이미 저장된 결과입니다"}), 400 @result_score_bp.route("", methods=["GET"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '저장한 변환 결과 목록 조회', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + }, + { + 'name': 'type', + 'in': 'query', + 'required': False, + 'description': '결과 타입 필터 (transpose, lyrics, melody)', + 'schema': { + 'type': 'string', + 'enum': ['transpose', 'lyrics', 'melody'] + } + } + ], + 'responses': { + 200: { + 'description': '저장된 변환 결과 목록 반환', + 'content': { + 'application/json': { + 'example': [ + { + 'result_id': 1, + 'result_type': 'transpose', + 'saved_at': '2025-05-18T12:34:56' + } + ] + } + } + }, + 401: {'description': '인증 실패'} + } +}) def get_saved_results(): - """ - 저장한 변환 결과 목록 조회 - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - - in: query - name: type - required: false - description: 결과 타입 필터 (transpose, lyrics, melody) - schema: - type: string - responses: - 200: - description: 저장된 변환 결과 목록 반환 - content: - application/json: - example: - - result_id: 1 - result_type: "transpose" - saved_at: "2025-05-18T12:34:56" - 401: - description: 인증 실패 - """ - auth_header = request.headers.get("Authorization", None) - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"message": error}), 401 - - user_id = payload["user_id"] result_type = request.args.get("type") saved = get_saved_result_scores(user_id, result_type) result = [ @@ -108,43 +120,36 @@ def get_saved_results(): @result_score_bp.route("/", methods=["DELETE"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '저장한 변환 결과 삭제', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + }, + { + 'name': 'result_id', + 'in': 'path', + 'required': True, + 'description': '삭제할 변환 결과 ID', + 'schema': {'type': 'integer'} + } + ], + 'responses': { + 200: {'description': '저장이 해제되었습니다'}, + 404: {'description': '저장 내역이 없습니다'}, + 401: {'description': '인증 실패'} + } +}) def delete_result(result_id): - """ - 저장한 변환 결과 삭제 - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - - in: path - name: result_id - required: true - description: 삭제할 변환 결과 ID - schema: - type: integer - responses: - 200: - description: 저장이 해제되었습니다 - 404: - description: 저장 내역이 없습니다 - 401: - description: 인증 실패 - """ - auth_header = request.headers.get("Authorization", None) - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"message": error}), 401 + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code - user_id = payload["user_id"] if delete_result_score(user_id, result_id): return jsonify({"message": "저장이 해제되었습니다"}), 200 return jsonify({"message": "저장 내역이 없습니다"}), 404 diff --git a/src/routes/mypage_upload_score.py b/src/routes/mypage_upload_score.py index 546edd6..a69475b 100644 --- a/src/routes/mypage_upload_score.py +++ b/src/routes/mypage_upload_score.py @@ -5,88 +5,90 @@ delete_upload_score ) from src.utils.jwt_util import decode_token +from flasgger import swag_from upload_score_bp = Blueprint("upload_score_bp", __name__, url_prefix="/mypage/score") - -@upload_score_bp.route("//save", methods=["POST"]) -def save_score(score_id): - """ - 업로드한 악보 저장 - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - - in: path - name: score_id - required: true - description: 저장할 악보 ID - schema: - type: string - responses: - 201: - description: 업로드한 악보가 저장되었습니다 - 400: - description: 이미 저장된 악보입니다 - 401: - description: 인증 실패 - """ +# ✅ JWT 인증 공통 함수 +def get_user_id_from_token(): auth_header = request.headers.get("Authorization", None) if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 - + return None, jsonify({"message": "토큰이 필요합니다"}), 401 token = auth_header.split(" ")[1] payload, error = decode_token(token) if error: - return jsonify({"message": error}), 401 + return None, jsonify({"message": error}), 401 + return payload["user_id"], None, None - user_id = payload["user_id"] +@upload_score_bp.route("//save", methods=["POST"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '업로드한 악보 저장', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + }, + { + 'name': 'score_id', + 'in': 'path', + 'required': True, + 'description': '저장할 악보 ID', + 'schema': {'type': 'string'} + } + ], + 'responses': { + 201: {'description': '업로드한 악보가 저장되었습니다'}, + 400: {'description': '이미 저장된 악보입니다'}, + 401: {'description': '인증 실패'} + } +}) +def save_score(score_id): + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code if save_upload_score(user_id, score_id): return jsonify({"message": "업로드한 악보가 저장되었습니다"}), 201 return jsonify({"message": "이미 저장된 악보입니다"}), 400 - @upload_score_bp.route("", methods=["GET"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '저장한 업로드 악보 목록 조회', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + } + ], + 'responses': { + 200: { + 'description': '저장된 악보 목록 반환', + 'content': { + 'application/json': { + 'example': [ + { + 'score_id': "abc123", + 'saved_at': "2025-05-18T12:34:56" + } + ] + } + } + }, + 401: {'description': '인증 실패'} + } +}) def get_saved_scores(): - """ - 저장한 업로드 악보 목록 조회 - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - responses: - 200: - description: 저장된 악보 목록 반환 - content: - application/json: - example: - - score_id: "abc123" - saved_at: "2025-05-18T12:34:56" - 401: - description: 인증 실패 - """ - auth_header = request.headers.get("Authorization", None) - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"message": error}), 401 - - user_id = payload["user_id"] saved = get_saved_upload_scores(user_id) result = [ { @@ -97,45 +99,37 @@ def get_saved_scores(): ] return jsonify(result), 200 - @upload_score_bp.route("/", methods=["DELETE"]) +@swag_from({ + 'tags': ['Mypage'], + 'summary': '저장한 업로드 악보 삭제', + 'parameters': [ + { + 'name': 'Authorization', + 'in': 'header', + 'required': True, + 'description': 'Bearer 액세스 토큰', + 'schema': {'type': 'string'} + }, + { + 'name': 'score_id', + 'in': 'path', + 'required': True, + 'description': '삭제할 악보 ID', + 'schema': {'type': 'string'} + } + ], + 'responses': { + 200: {'description': '저장이 해제되었습니다'}, + 404: {'description': '저장 내역이 없습니다'}, + 401: {'description': '인증 실패'} + } +}) def delete_score(score_id): - """ - 저장한 업로드 악보 삭제 - --- - tags: - - Mypage - parameters: - - in: header - name: Authorization - required: true - description: Bearer 액세스 토큰 - schema: - type: string - - in: path - name: score_id - required: true - description: 삭제할 악보 ID - schema: - type: string - responses: - 200: - description: 저장이 해제되었습니다 - 404: - description: 저장 내역이 없습니다 - 401: - description: 인증 실패 - """ - auth_header = request.headers.get("Authorization", None) - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"message": "토큰이 필요합니다"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"message": error}), 401 + user_id, error_response, status_code = get_user_id_from_token() + if error_response: + return error_response, status_code - user_id = payload["user_id"] if delete_upload_score(user_id, score_id): return jsonify({"message": "저장이 해제되었습니다"}), 200 return jsonify({"message": "저장 내역이 없습니다"}), 404 diff --git a/src/routes/transform.py b/src/routes/transform.py index de4bba2..1f17de6 100644 --- a/src/routes/transform.py +++ b/src/routes/transform.py @@ -2,7 +2,7 @@ from src.utils.transpose_helper import transpose_key from src.models.score import Score from src.models.result import Result -from src.services.transform_service import perform_transpose, extract_melody +from src.services.transform_service import perform_transpose, extract_melody, extract_lyrics transform_bp = Blueprint('transform', __name__) @@ -48,12 +48,6 @@ def transpose_preview_route(): example: "F → E (shift -1)" 400: description: 잘못된 요청 - schema: - type: object - properties: - error: - type: string - example: "Invalid key: Z" """ data = request.get_json() current_key = data.get('current_key') @@ -116,12 +110,6 @@ def transform_transpose_route(score_id): example: "Transpose completed successfully" 404: description: 악보 ID를 찾을 수 없음 - schema: - type: object - properties: - error: - type: string - example: "Score not found" """ score = Score.query.get(score_id) if not score: @@ -140,6 +128,7 @@ def transform_transpose_route(score_id): 'message': 'Transpose completed successfully' }), 201 + @transform_bp.route('/score//lyrics', methods=['POST']) def lyrics_extract_route(score_id): """ @@ -172,31 +161,23 @@ def lyrics_extract_route(score_id): example: "Lyrics extracted successfully" 404: description: 악보 ID를 찾을 수 없음 - schema: - type: object - properties: - error: - type: string - example: "Score not found" """ score = Score.query.get(score_id) if not score: return jsonify({'error': 'Score not found'}), 404 - from src.services.transform_service import extract_lyrics result_id = extract_lyrics(score) - result = Result.query.get(result_id) - text_path = result.text_path if result else f"convert_result/{result_id}.txt" + if not result: + return jsonify({"error": "Result not found"}), 500 return jsonify({ 'result_id': result_id, - 'text_path': text_path, + 'text_path': result.download_path, 'message': 'Lyrics extracted successfully' }), 200 - @transform_bp.route('/score//melody', methods=['POST']) def melody_extract_route(score_id): """ @@ -246,12 +227,6 @@ def melody_extract_route(score_id): example: "Melody extracted from measure 1 to 8" 404: description: 악보 ID를 찾을 수 없음 - schema: - type: object - properties: - error: - type: string - example: "Score not found" """ data = request.get_json() start = data.get('start_measure') @@ -262,12 +237,12 @@ def melody_extract_route(score_id): return jsonify({'error': 'Score not found'}), 404 result_id = extract_melody(score, start, end) - result = Result.query.get(result_id) - mp3_path = result.audio_path if result else f"convert_result/{result_id}.mp3" + if not result: + return jsonify({"error": "Result not found"}), 500 return jsonify({ 'result_id': result_id, - 'mp3_path': mp3_path, + 'mp3_path': result.audio_path, 'message': f'Melody extracted from measure {start} to {end}' }), 200 diff --git a/src/routes/user.py b/src/routes/user.py index 4170575..09f442c 100644 --- a/src/routes/user.py +++ b/src/routes/user.py @@ -4,9 +4,30 @@ from src.utils.jwt_util import decode_token from flasgger import swag_from import os +import uuid user_bp = Blueprint('user', __name__, url_prefix='/user') +UPLOAD_FOLDER = 'static/profile_images' +os.makedirs(UPLOAD_FOLDER, exist_ok=True) + +# ✅ 공통 인증 함수 +def get_current_user(): + auth_header = request.headers.get("Authorization") + if not auth_header or not auth_header.startswith("Bearer "): + return None, jsonify({"error": "Missing or invalid Authorization header"}), 401 + + token = auth_header.split(" ")[1] + payload, error = decode_token(token) + if error: + return None, jsonify({"error": error}), 401 + + user = User.query.get(payload["user_id"]) + if not user: + return None, jsonify({"error": "User not found"}), 404 + + return user, None, None + @user_bp.route('/me', methods=['GET']) @swag_from({ @@ -34,18 +55,9 @@ } }) def get_my_info(): - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"error": "Missing or invalid Authorization header"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"error": error}), 401 - - user = User.query.get(payload["user_id"]) - if not user: - return jsonify({"error": "User not found"}), 404 + user, error_resp, status = get_current_user() + if error_resp: + return error_resp, status return jsonify({ "user_id": user.id, @@ -91,21 +103,10 @@ def get_my_info(): 404: {'description': 'User not found'} } }) - - def update_my_info(): - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"error": "Missing or invalid Authorization header"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"error": error}), 401 - - user = User.query.get(payload["user_id"]) - if not user: - return jsonify({"error": "User not found"}), 404 + user, error_resp, status = get_current_user() + if error_resp: + return error_resp, status data = request.get_json() new_nickname = data.get("nickname") @@ -121,10 +122,6 @@ def update_my_info(): }), 200 - -UPLOAD_FOLDER = 'static/profile_images' -os.makedirs(UPLOAD_FOLDER, exist_ok=True) - @user_bp.route("/me/profile-image", methods=["PATCH"]) @swag_from({ 'summary' : '프로필 이미지 업로드/변경', @@ -156,20 +153,10 @@ def update_my_info(): 401: {'description': '유효하지 않은 토큰'} } }) - def update_profile_image(): - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"error": "Missing or invalid Authorization header"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"error": error}), 401 - - user = User.query.get(payload["user_id"]) - if not user: - return jsonify({"error": "User not found"}), 404 + user, error_resp, status = get_current_user() + if error_resp: + return error_resp, status if 'profile_image' not in request.files: return jsonify({"error": "No file part"}), 400 @@ -178,8 +165,8 @@ def update_profile_image(): if file.filename == '': return jsonify({"error": "No selected file"}), 400 - filename = secure_filename(file.filename) - file_path = os.path.join(UPLOAD_FOLDER, filename) + unique_filename = f"{uuid.uuid4().hex}_{secure_filename(file.filename)}" + file_path = os.path.join(UPLOAD_FOLDER, unique_filename) file.save(file_path) user.profile_image = file_path @@ -190,10 +177,11 @@ def update_profile_image(): "nickname": user.nickname, "profile_image": user.profile_image }), 200 - + + @user_bp.route("/me", methods=["DELETE"]) @swag_from({ - 'summary': '회원 탈회', + 'summary': '회원 탈퇴', 'tags': ['user'], 'security': [{'Bearer': []}], 'responses': { @@ -211,27 +199,15 @@ def update_profile_image(): 404: {'description': '사용자 없음'} } }) - - - def delete_my_account(): - auth_header = request.headers.get("Authorization") - if not auth_header or not auth_header.startswith("Bearer "): - return jsonify({"error": "Missing or invalid Authorization header"}), 401 - - token = auth_header.split(" ")[1] - payload, error = decode_token(token) - if error: - return jsonify({"error": error}), 401 - - user = User.query.get(payload["user_id"]) - if not user: - return jsonify({"error": "User not found"}), 404 + user, error_resp, status = get_current_user() + if error_resp: + return error_resp, status db.session.delete(user) db.session.commit() return jsonify({ - "user_id": payload["user_id"], + "user_id": user.id, "message": "User successfully deleted" - }), 200 \ No newline at end of file + }), 200 diff --git a/src/services/result_service.py b/src/services/result_service.py index b342cdb..4b731dd 100644 --- a/src/services/result_service.py +++ b/src/services/result_service.py @@ -9,16 +9,20 @@ def normalize_path(path): # 5-1: 키 변경된 악보 결과 이미지 def get_transpose_image(result_id): result = Result.query.get(result_id) + if not result or result.type != 'transpose': + raise FileNotFoundError("키 변경 악보 이미지 결과를 찾을 수 없습니다") image_path = normalize_path(result.image_path) - if not result or result.type != 'transpose' or not image_path or not os.path.exists(image_path): + if not image_path or not os.path.exists(image_path): raise FileNotFoundError("키 변경 악보 이미지 결과를 찾을 수 없습니다") return send_file(image_path, mimetype='image/png') # 키 변경된 PDF 파일 다운로드 def download_transpose_file(result_id): result = Result.query.get(result_id) + if not result or result.type != 'transpose': + raise FileNotFoundError("키 변경 악보 다운로드 파일을 찾을 수 없습니다") download_path = normalize_path(result.download_path) - if not result or result.type != 'transpose' or not download_path or not os.path.exists(download_path): + if not download_path or not os.path.exists(download_path): raise FileNotFoundError("키 변경 악보 다운로드 파일을 찾을 수 없습니다") return send_file(download_path, as_attachment=True) @@ -32,8 +36,10 @@ def get_lyrics_text(result_id): # 가사 다운로드 파일 def download_lyrics_file(result_id): result = Result.query.get(result_id) + if not result or result.type != 'lyrics': + raise FileNotFoundError("가사 다운로드 파일을 찾을 수 없습니다") download_path = normalize_path(result.download_path) - if not result or result.type != 'lyrics' or not download_path or not os.path.exists(download_path): + if not download_path or not os.path.exists(download_path): raise FileNotFoundError("가사 다운로드 파일을 찾을 수 없습니다") return send_file(download_path, as_attachment=True) @@ -47,7 +53,9 @@ def get_melody_meta_info(result_id): # 멜로디 오디오 MP3 def get_melody_audio(result_id): result = Result.query.get(result_id) + if not result or result.type != 'melody': + raise FileNotFoundError("멜로디 오디오 파일을 찾을 수 없습니다") audio_path = normalize_path(result.audio_path) - if not result or result.type != 'melody' or not audio_path or not os.path.exists(audio_path): + if not audio_path or not os.path.exists(audio_path): raise FileNotFoundError("멜로디 오디오 파일을 찾을 수 없습니다") return send_file(audio_path, mimetype='audio/mpeg', as_attachment=True) diff --git a/src/services/transform_service.py b/src/services/transform_service.py index d201d7f..acbd62f 100644 --- a/src/services/transform_service.py +++ b/src/services/transform_service.py @@ -7,10 +7,9 @@ from music21 import midi, stream, note from src.models.db import db from src.models.score import Score -from src.models.result import Result # ✅ 통합된 Result 모델 +from src.models.result import Result from ML.src.makexml.MakeScore import MakeScore -# ✅ OS별 실행 경로 설정 if platform.system() == "Windows": FFMPEG_CMD = r"C:\ProgramData\chocolatey\lib\ffmpeg\tools\ffmpeg\bin\ffmpeg.exe" TIMIDITY_CMD = "timidity" @@ -20,11 +19,7 @@ TIMIDITY_CMD = "timidity" MSCORE_CMD = os.path.join("squashfs-root", "mscore4portable") - def perform_transpose(score: Score, shift: int) -> int: - """ - 키 변경을 수행하고 결과 PDF를 생성해 Result 테이블에 저장 - """ image_path = os.path.join('uploaded_scores', score.original_filename) img = cv2.imread(image_path, cv2.IMREAD_COLOR) img_list = [img] @@ -41,7 +36,6 @@ def perform_transpose(score: Score, shift: int) -> int: MakeScore.score_to_xml(transposed_score, result_id) - print("[Transpose] 실행 명령어:", [MSCORE_CMD, xml_path, "-o", pdf_path]) subprocess.run([MSCORE_CMD, xml_path, "-o", pdf_path], check=True) result = Result( @@ -54,11 +48,7 @@ def perform_transpose(score: Score, shift: int) -> int: return result.id - def extract_melody(score: Score, start_measure: int, end_measure: int) -> int: - """ - 악보에서 특정 마디 범위의 멜로디를 추출하여 MP3 파일로 저장 후 Result 테이블에 저장 - """ image_path = os.path.join('uploaded_scores', score.original_filename) img = cv2.imread(image_path, cv2.IMREAD_COLOR) img_list = [img] @@ -98,11 +88,7 @@ def extract_melody(score: Score, start_measure: int, end_measure: int) -> int: return result.id - def extract_lyrics(score: Score) -> int: - """ - 악보에서 가사를 추출하여 텍스트로 저장하고 Result 테이블에 저장 - """ image_path = os.path.join('uploaded_scores', score.original_filename) img = cv2.imread(image_path, cv2.IMREAD_COLOR) if img is None: @@ -111,15 +97,14 @@ def extract_lyrics(score: Score) -> int: img_list = [img] score_obj = MakeScore.make_score(img_list) - # 가사 추출 lyrics = [] for el in score_obj.recurse(): if isinstance(el, note.Note) and el.lyric: lyrics.append(el.lyric.strip()) lyrics_text = "\n".join(filter(None, lyrics)).strip() - if not lyrics_text: - raise ValueError("추출된 가사가 없습니다") + # if not lyrics_text: + # raise ValueError("추출된 가사가 없습니다") # 예외 제거 result_id = str(uuid.uuid4()) convert_dir = 'convert_result' @@ -132,8 +117,8 @@ def extract_lyrics(score: Score) -> int: result = Result( score_id=score.id, type='lyrics', - text_path=text_path, # 다운로드용 - text_content=lyrics_text # ✅ API 조회용 + download_path=text_path, + text_content=lyrics_text ) db.session.add(result) db.session.commit() diff --git a/src/services/user_service.py b/src/services/user_service.py deleted file mode 100644 index e69de29..0000000