Files
tts_trans/app/__pycache__/main.cpython-312.pyc

174 lines
27 KiB
Plaintext
Raw Normal View History

<EFBFBD>
<00><17>i<EFBFBD>=<00><00>P<00>dZddlZddlZddlZddlZddlZddlZddlmZddl m
Z
ddl Z ddl m Z mZmZmZddlmZmZmZddlmZddlmZmZmZmZmZmZmZmZdd l m!Z!m"Z"m#Z#dd
l$m%Z%ddl&Z&e!e&jNd <0B> <0C>Z(e#e(e"d <0B> <0A>Z)Gd<0E>de%<25>Z*Gd<10>de*<2A>Z+Gd<12>de*<2A>Z,dFde-de-de.fd<17>Z/de-de-fd<1A>Z0de-fd<1C>Z1ede fd<1E><04>Z2e de2<65> <20>Z3e3jid!<21>d"e-fd#<23><04>Z5e3jid$<24>d"e-d%e-fd&<26><04>Z6e3jid'<27>d(<28><00>Z7e3jqd'<27>d)efd*<2A><04>Z9e3j?d+<2B>d"e-fd,<2C><04>Z:e3jid-<2D>d"e-fd.<2E><04>Z;e3jqd-<2D>d"e-d)efd/<2F><04>Z<e3j{d0<64>d"e-d%e-d)efd1<64><04>Z>e3j?d0<64>d"e-d%e-fd2<64><04>Z?e3jqd3<64>d"e-d%e-fd4<64><04>Z@e3jqd5<64>d"e-fd6<64><04>ZAe3jqd7<64>d)efd8<64><04>ZBe3jid9<64>d:<3A><00>ZCe3j<33>d;ee&j<><00><<3C>d=<3D>><3E>e3jid?e<13>@<40>dA<64><00>ZFeGdBk(r/ddlHZHeHj<48>dCe&j<>e&j<>dD<64>E<EFBFBD>yy)GuX
TTS Book Service - 小米 MiMo TTS 转换服务
为听书 App 提供音频接入接口
<EFBFBD>N)<01>asynccontextmanager)<01>Path)<04>FastAPI<50> HTTPException<6F>Query<72>Request)<03> FileResponse<73> HTMLResponse<73> JSONResponse)<01> StaticFiles)<08>Column<6D>Integer<65>String<6E>Text<78>DateTime<6D>func<6E>select<63>delete)<03>create_async_engine<6E> AsyncSession<6F>async_sessionmaker)<01>DeclarativeBaseF)<01>echo)<02>class_<73>expire_on_commitc<00> <00>eZdZy)<02>BaseN)<03>__name__<5F>
__module__<EFBFBD> __qualname__<5F><00><00> app/main.pyrrs<00><00>r"rc<00><><00>eZdZdZeedd<02><03>Zeed<04>ddd<02><06>Zeed<07>d<05><08>Z eed <09>d
<EFBFBD> <0B>Z
ee e j<00><00> <0C>Zy )<0E>Book<6F>booksT<73><02> primary_key<65> autoincrement<6E>dF)<03>unique<75>nullable<6C>index<65><78>)r,<00><><00><00><01>default<6C><01>server_defaultN)rrr <00> __tablename__r r<00>idr<00>book_id<69>title<6C>authorrr<00>now<6F>
created_atr!r"r#r%r%#s]<00><00><1B>M<EFBFBD> <0F><07>T<EFBFBD><14> ><3E>B<EFBFBD><14>V<EFBFBD>C<EFBFBD>[<5B><14><05>T<EFBFBD>J<>G<EFBFBD> <12>6<EFBFBD>#<23>;<3B><15> /<2F>E<EFBFBD> <13>F<EFBFBD>3<EFBFBD>K<EFBFBD><12> ,<2C>F<EFBFBD><17><08><18><14><18><18><1A><<3C>Jr"r%c<00><><00>eZdZdZeedd<02><03>Zeed<04>dd<02><06>Zeed<04>dd<02><06>Z eed<04>d<07><08>Z
eed <09>d<07><08>Z ee d<07><08>Z eed <09>d<07><08>Zeed
<EFBFBD>d <0B><08>Zee d<07><08>Zeeej&<00><00> <0C>Zeeej&<00>ej&<00><00> <0A>Zy)<0F>Chapter<65>chaptersTr'r*F)r,r-r0r1r.<00><00>pendingr3)r4<00>onupdateN)rrr r5r rr6rr7<00>
chapter_id<EFBFBD>app_chapter_idr8r<00> text_content<6E>
audio_file<EFBFBD>status<75> error_msgrrr:r;<00>
updated_atr!r"r#r=r=,s<><00><00><1E>M<EFBFBD> <0F><07>T<EFBFBD><14> ><3E>B<EFBFBD><14>V<EFBFBD>C<EFBFBD>[<5B>5<EFBFBD><04>=<3D>G<EFBFBD><17><06>s<EFBFBD> <0B>e<EFBFBD>4<EFBFBD>@<40>J<EFBFBD><1B>F<EFBFBD>3<EFBFBD>K<EFBFBD><12>4<>N<EFBFBD> <12>6<EFBFBD>#<23>;<3B><02> +<2B>E<EFBFBD><19>$<24><02>+<2B>L<EFBFBD><17><06>s<EFBFBD> <0B>R<EFBFBD>0<>J<EFBFBD> <13>F<EFBFBD>2<EFBFBD>J<EFBFBD> <09> 2<>F<EFBFBD><16>t<EFBFBD>R<EFBFBD>(<28>I<EFBFBD><17><08><18><14><18><18><1A><<3C>J<EFBFBD><17><08><18><14><18><18><1A>h<EFBFBD>d<EFBFBD>h<EFBFBD>h<EFBFBD>j<EFBFBD>Q<>Jr"r=<00>text<78>style<6C>returnc <00><00>4K<00>tjs tdd<02><00>|rd|<01>d|<00><00>n|}tjdtjd<06>d|d<08>gd <09>}d
tjd <0B>}t j d <0C> <0A>4<00>d{<00><02><03>}|jtj||<04><0F><00>d{<00><03><03>}ddd<0E><00>d{<00><02><03>jdk7r)tdd|j<00>d|jdd<00><00><04><00>|j<00>}|jd<15>rtdd|d<00><00><02><00> |ddddd}tj|<08>S7<00><>7<00><>7<00><>#1<00>d{<00><03><03>7swY<00><>xYw#tt t"f$r} tdd| <09><00><02><00>d} ~ wwxYw<01>w)u3调用小米 MiMo TTS API返回 WAV 音频字节r.u.MIMO_API_KEY 未配置请设置环境变量z<style>z</style><3E>wav)<02>format<61>voice<63> assistant)<02>role<6C>content)<03>model<65>audio<69>messageszapplication/json)z Content-Typezapi-key<65>x)<01>timeoutN)<02>json<6F>headersr/i<>uMiMo TTS API 错误: HTTP z - <20>,<00>erroruMiMo TTS 错误: <20>choicesr<00>messagerT<00>datauMiMo TTS 响应解析失败: )<12>config<69> MIMO_API_KEYr<00>MIMO_TTS_MODEL<45>
MIMO_VOICE<EFBFBD>httpx<70> AsyncClient<6E>post<73>MIMO_API_ENDPOINT<4E> status_coderIrX<00>get<65>base64<36> b64decode<64>KeyError<6F>
IndexError<EFBFBD> TypeError)
rIrJrR<00>payloadrY<00>client<6E>respr^<00> audio_b64<36>es
r#<00> call_mimo_ttsrs=s<><00><00><><00> <11> <1E> <1E><1B>C<EFBFBD>!Q<>R<>R<>16<31><07><05>w<EFBFBD>h<EFBFBD>t<EFBFBD>f<EFBFBD>-<2D>D<EFBFBD>G<EFBFBD><18>&<26>&<26>!<21>F<EFBFBD>,=<3D>,=<3D>><3E>)<29>g<EFBFBD>><3E>?<3F><06>G<EFBFBD>+<2B><19>&<26>&<26><06>G<EFBFBD>
<15> <20> <20><13>-<2D>Z<01>Z<01><16><1B>[<5B>[<5B><16>!9<>!9<><07>QX<51>[<5B>Y<>Y<><04>Z<01>Z<01> <0C><17><17>3<EFBFBD><1E><1B>C<EFBFBD>#=<3D>d<EFBFBD>>N<>>N<>=O<>s<EFBFBD>SW<53>S\<5C>S\<5C>]a<>^a<>Sb<53>Rc<52>!d<>e<>e<> <0F>9<EFBFBD>9<EFBFBD>;<3B>D<EFBFBD> <0B>x<EFBFBD>x<EFBFBD><07><18><1B>C<EFBFBD>#4<>T<EFBFBD>'<27>]<5D>O<EFBFBD>!D<>E<>E<>F<01><18><19>O<EFBFBD>A<EFBFBD>&<26>y<EFBFBD>1<>'<27>:<3A>6<EFBFBD>B<> <09><15><1F><1F> <09>*<2A>*<2A>Z<01><>Y<><59>Z<01><>Z<01>Z<01>Z<01><> <15>j<EFBFBD>)<29> ,<2C>F<01><1B>C<EFBFBD>#@<40><11><03>!D<>E<>E<><45>F<01>s<00>A?F<01>E<06>F<01>&E<03>+E<06>,E<03>0 F<01>;E<04><A/F<01>,%E-<00>F<01>E<03>F<01>E*<07>E! <0C>E*<07>&F<01>-F<03>F<03>F<03>F<01>wav_path<74>mp3_pathc <00><><00>tjddd|dddd|g dd<08> <09>}|jd
k7rtd |jd d <00><00><02><00>y )u用 ffmpeg 将 WAV 转为 MP3<50>ffmpegz-yz-iz-codec:a<>
libmp3lamez -qscale:a<>2T)<02>capture_outputrIruffmpeg 转换失败: NrZ)<05>
subprocess<EFBFBD>run<75>
returncode<EFBFBD> RuntimeError<6F>stderr)rtru<00>results r#<00>
wav_to_mp3r<EFBFBD>`sa<00><00> <17>^<5E>^<5E> <11>4<EFBFBD><14>x<EFBFBD><1A>\<5C>;<3B>PS<50>U]<5D>^<5E><1B>$<24><06>F<EFBFBD><0E><18><18>A<EFBFBD><1D><1A>2<>6<EFBFBD>=<3D>=<3D><14>#<23>3F<33>2G<32>H<>I<>I<>r"<00>chapter_id_strc<00><00>0K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(<00><00><00>d{<00><03><03>}|j <00>}|s ddd<01><00>d{<00><02><03>y|jj<00>s8d|_ d|_
|j<00><00>d{<00><03><03> ddd<01><00>d{<00><02><03>yd|_ |j<00><00>d{<00><03><03> ttj<00>|jz }|j!dd<05><06>t#||j
<00>d<07>z <00>}t#||j
<00>d<08>z <00>}t%|j<00><00>d{<00><04><03>}t'|d <09>5}|j)|<07>ddd<01>t+j,<00>} | j/dt0||<06><00>d{<00><04><03>t3j4|<05>||_d
|_ d |_
|j<00><00>d{<00><03><03>ddd<01><00>d{<00><02><03>y7<00><02>7<00><01><>7<00><01><>7<00><01>y7<00><01>k7<00><01>N7<00><>#1swY<00><>xYw7<00>w#t8$r$}
d|_ t#|
<EFBFBD>dd |_
Yd}
~
<EFBFBD>sd}
~
wwxYw7<00>g7<00>Y#1<00>d{<00><03><03>7swYyxYw<01>w) u,为指定章节生成音频WAV → MP3Nr[u文本内容为空<E4B8BA>
generatingT<EFBFBD><02>parents<74>exist_ok<6F>.wav<61>.mp3<70>wb<77>readyr0r.)<1D> async_session<6F>executerr=<00>whererB<00>scalar_one_or_nonerD<00>striprFrG<00>commitrr_<00> AUDIO_DIRr7<00>mkdir<69>strrs<00>open<65>write<74>asyncio<69>get_event_loop<6F>run_in_executorr<72><00>os<6F>removerE<00> Exception) r<><00>dbr<62><00>chapter<65> audio_dirrtru<00> wav_bytes<65>f<>looprrs r#<00>generate_chapter_audior<6F>jsO<00><00><><00><1C><EFBFBD>)<1A>)<1A>"<22><19>z<EFBFBD>z<EFBFBD>&<26><17>/<2F>"7<>"7<><07>8J<38>8J<38>n<EFBFBD>8\<5C>"]<5D>^<5E>^<5E><06><18>+<2B>+<2B>-<2D><07><16> <12> )<1A>)<1A>)<1A> <17>#<23>#<23>)<29>)<29>+<2B>$<24>G<EFBFBD>N<EFBFBD> 4<>G<EFBFBD> <1D><14>)<29>)<29>+<2B> <1D> <1D> <12>)<1A>)<1A>)<1A>&<26><07><0E><10>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19> -<2D><1C>V<EFBFBD>-<2D>-<2D>.<2E><17><1F><1F>@<40>I<EFBFBD> <15>O<EFBFBD>O<EFBFBD>D<EFBFBD>4<EFBFBD>O<EFBFBD> 8<><1A>9<EFBFBD>'<27>*<<3C>*<<3C>)=<3D>T<EFBFBD>'B<>B<>C<>H<EFBFBD><1A>9<EFBFBD>'<27>*<<3C>*<<3C>)=<3D>T<EFBFBD>'B<>B<>C<>H<EFBFBD>,<2C>G<EFBFBD>,@<40>,@<40>A<>A<>I<EFBFBD><15>h<EFBFBD><04>%<25> #<23><11><11><07><07> <09>"<22> #<23><1B>)<29>)<29>+<2B>D<EFBFBD><16>&<26>&<26>t<EFBFBD>Z<EFBFBD><18>8<EFBFBD>L<> L<> L<> <0F>I<EFBFBD>I<EFBFBD>h<EFBFBD> <1F>!)<29>G<EFBFBD> <1E>$<24>G<EFBFBD>N<EFBFBD> "<22>G<EFBFBD> <1D>
<11>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19>S)<1A>)<1A>)<1A><>^<5E><>)<1A><> <1E><>)<1A><> <1A><>B<01><> #<23> #<23><>
M<01><><19> -<2D>$<24>G<EFBFBD>N<EFBFBD> #<23>A<EFBFBD><06>t<EFBFBD><03> <0C>G<EFBFBD> <1D> <1D><> -<2D><> <1A><>S)<1A><>)<1A>)<1A>)<1A>s$<00>J<01>H+<06>J<01>AJ<03>H.<06>J<03>/ J<01>:H1<04>;J<01>;J<03>;H4<06><J<03> J<01> H7<04> J<01>J<03>,H:<06>-J<03>2BI <02>9H=<06>:I <02>
H?<05>7I <02>I <06>.I <02>J<03>I=<06>J<03> J<01>%I?<04>&J<01>.J<03>1J<01>4J<03>7J<01>:J<03>=I <02>?I <09>I <02> I:<05>I5<05>0J<03>5I:<05>:J<03>?J<01>J<07>J
<0C>J<07>J<01>appc<00><>K<00>tjtjd<01><02>tjtjj tj d<03>d<01><02>tj<00>4<00>d{<00><02><03>}|jtjj<00><00>d{<00><03><03>ddd<00><00>d{<00><02><03>d<00><04><01>y7<00>K7<00>7<00>#1<00>d{<00><03><03>7swY<00>xYw<01>w)NT)r<>r^) r<><00>makedirsr_r<><00>path<74>join<69>BASE_DIR<49>engine<6E>begin<69>run_syncr<00>metadata<74>
create_all)r<><00>conns r#<00>lifespanr<6E><00>s<><00><00><><00><06>K<EFBFBD>K<EFBFBD><06> <20> <20>4<EFBFBD>0<><06>K<EFBFBD>K<EFBFBD><02><07><07> <0C> <0C>V<EFBFBD>_<EFBFBD>_<EFBFBD>f<EFBFBD>5<><04>E<><15>|<7C>|<7C>~<7E>6<>6<><14><12>m<EFBFBD>m<EFBFBD>D<EFBFBD>M<EFBFBD>M<EFBFBD>4<>4<>5<>5<>5<>6<>6<> <09>6<><36>5<><35>6<><36>6<>6<>6<>sZ<00>BC*<01>C<06>C*<01>-C<03>4C<06>5C<03>9 C*<01>C<04> C*<01>C<03>C*<01>C'<07>C <0C>C'<07>#C*zTTS Book Service)r8r<>z/api/book/{book_id}r7c<00><00>rK<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(<00><00><00>d{<00><03><03>}|j <00>}|stdd|<00>d<04><03><00>|jtt<00>j tj
|k(<00>jtj<00><00><00>d{<00><03><03>}|j<00>j<00>}|j
|j|j|D<00>cgc]T}|j|j |j|j"|j"dk(rd|<00>d|j<00>d<08>ndd <09><05><02>Vc}d
<EFBFBD>cddd<01><00>d{<00><02><03>S7<00><01><>7<00><01>?7<00><>cc}w7<00>#1<00>d{<00><03><03>7swYyxYw<01>w) u8获取书籍信息及章节列表(听书 App 调用N<EFBC89><4E><00>书籍 u
不存在r<E59CA8>z
/api/book/z /chapter/<2F>/audio)rBrCr8rF<00> audio_url)r7r8r9r>)r<>r<>rr%r<>r7r<>rr=<00>order_byr6<00>scalars<72>allr8r9rBrCrF)r7r<><00> book_result<6C>book<6F> ch_resultr><00>chs r#<00> get_book_infor<6F><00>so<00><00><><00><1D><EFBFBD>
<EFBFBD>
<EFBFBD>"<22><1E>J<EFBFBD>J<EFBFBD>v<EFBFBD>d<EFBFBD>|<7C>'9<>'9<>$<24>,<2C>,<2C>'<27>:Q<>'R<>S<>S<> <0B><1A>-<2D>-<2D>/<2F><04><13><1F><03>w<EFBFBD>w<EFBFBD>i<EFBFBD>z<EFBFBD>%B<>C<> C<><1C>*<2A>*<2A> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C> =<3D> F<> F<>w<EFBFBD>z<EFBFBD>z<EFBFBD> R<>
<EFBFBD>
<EFBFBD> <09><1D>$<24>$<24>&<26>*<2A>*<2A>,<2C><08><1C>|<7C>|<7C><19>Z<EFBFBD>Z<EFBFBD><1A>k<EFBFBD>k<EFBFBD>#<23>
<0E><17>#%<25>-<2D>-<2D>&(<28>&7<>&7<><1F>X<EFBFBD>X<EFBFBD> <20>i<EFBFBD>i<EFBFBD><19>y<EFBFBD>y<EFBFBD>G<EFBFBD>+<2B>$.<2E>g<EFBFBD>Y<EFBFBD>i<EFBFBD><02> <0A> <0A><EFBFBD>f<EFBFBD>!U<>15<31> <12>
<0E> 
<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD>S<><53>

<EFBFBD><EFBFBD>
<0E>
<EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>s~<00>F7<01>F<06>F7<01>AF"<03>F<06>BF"<03>F<06>AF"<03>$AF <0C>=F"<03> F7<01> F <06>F7<01>F"<03>F"<03>F"<03> F7<01>"F4<07>(F+ <0C>)F4<07>0F7z./api/book/{book_id}/chapter/{chapter_id}/audiorBc<00><00>|K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(tj |k(<00><00><00>d{<00><03><03>}|j<00>}ddd<01><00>d{<00><02><03>s tdd<03><00>|jdk7s |jstdd|j<00><00><02><00>tjj|j<00>s tdd<06><00>t|jd|<01>d<08><02> <09>S7<00><01>7<00><>7<00><>#1<00>d{<00><03><03>7swY<00><>xYw<01>w)
u/获取章节音频文件(听书 App 调用Nr<4E><00>章节不存在r<E59CA8>u#音频尚未生成,当前状态: u音频文件丢失z
audio/mpegr<67>)<02>
media_type<EFBFBD>filename)r<>r<>rr=r<>r7rBr<>rrFrEr<>r<><00>existsr )r7rBr<>r<>r<>s r#<00>get_chapter_audior<6F><00>s<00><00><><00><1D><EFBFBD>.<2E>.<2E>"<22><19>z<EFBFBD>z<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21><17><0F><0F>7<EFBFBD>*<2A>G<EFBFBD>,><3E>,><3E>*<2A>,L<> <0E>
<EFBFBD>
<EFBFBD><06>
<19>+<2B>+<2B>-<2D><07> .<2E>.<2E> <13><1B>C<EFBFBD>!2<>3<>3<><0E>~<7E>~<7E><17> <20><07>(:<3A>(:<3A><1B>C<EFBFBD>#F<>w<EFBFBD>~<7E>~<7E>FV<46>!W<>X<>X<> <0A>7<EFBFBD>7<EFBFBD>><3E>><3E>'<27>,<2C>,<2C> -<2D><1B>C<EFBFBD>!5<>6<>6<> <17><07>*<2A>*<2A>|<7C>Q[<5B>P\<5C>\`<60>Na<4E> b<>b<>!.<2E><>
<EFBFBD><EFBFBD>.<2E><>.<2E>.<2E>.<2E>sX<00>D<<01>D <06>D<<01>AD'<03>)D#<06>*D'<03>> D<<01> D%<04>
BD<<01>#D'<03>%D<<01>'D9<07>-D0 <0C>.D9<07>5D<z/admin/api/booksc<00><00><>K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
j <00><00><00><00>d{<00><03><03>}|j<00>j<00>}|D<00>cgc]&}|j|j|jd<01><03><02>(c}cddd<00><00>d{<00><02><03>S7<00><>7<00>gcc}w7<00>#1<00>d{<00><03><03>7swYyxYw<01>w)N<>r7r8r9) r<>r<>rr%r<>r6<00>descr<63>r<>r7r8r9)r<>r<>r&<00>bs r#<00>
list_booksr<EFBFBD><00>s<><00><00><><00><1C><EFBFBD>]<01>]<01>"<22><19>z<EFBFBD>z<EFBFBD>&<26><14>,<2C>"7<>"7<><04><07><07> <0C> <0C><0E>"G<>H<>H<><06><16><0E><0E> <20>$<24>$<24>&<26><05>V[<5B>\<5C>QR<51>A<EFBFBD>I<EFBFBD>I<EFBFBD><01><07><07>1<EFBFBD>8<EFBFBD>8<EFBFBD>L<>\<5C>]<01>]<01>]<01><>H<><48>\<5C>]<01><>]<01>]<01>]<01>si<00>C(<01>C<06>C(<01>A C<03>"C
<06>#&C<03> +C <06>4C<03>6 C(<01>C<06>C(<01>
C<03> C<03>C(<01>C%<07>C <0C>C%<07>!C(<01>requestc<00><00><>K<00>|j<00><00>d{<00><02><03>}|jdd<02>j<00>}|jdd<02>j<00>}|jdd<02>j<00>}|r|s tdd<06><00>t <00>4<00>d{<00><02><03>}|j t t<00>jtj|k(<00><00><00>d{<00><03><03>}|j<00>rtdd|<02>d <09><03><00>t|||<04>
<EFBFBD>}|j|<07>|j<00><00>d{<00><03><03>d |d <0C>cddd<00><00>d{<00><02><03>S7<00><01>;7<00><>7<00>v7<00>!7<00>#1<00>d{<00><03><03>7swYyxYw<01>w) Nr7r0r8r9<00><>ubook_id 和 title 不能为空<E4B8BA><E7A9BA>r<><00>
已存在r<E59CA8>T)<02>okr7) rXrhr<>rr<>r<>rr%r<>r7r<><00>addr<64>)r<>r^r7r8r9r<><00>existingr<67>s r#<00> create_bookr<6B><00>s8<00><00><><00><18><1C><1C><1E> <1F>D<EFBFBD><12>h<EFBFBD>h<EFBFBD>y<EFBFBD>"<22>%<25>+<2B>+<2B>-<2D>G<EFBFBD> <10>H<EFBFBD>H<EFBFBD>W<EFBFBD>b<EFBFBD> !<21> '<27> '<27> )<29>E<EFBFBD> <11>X<EFBFBD>X<EFBFBD>h<EFBFBD><02> #<23> )<29> )<29> +<2B>F<EFBFBD> <12>%<25><1B>C<EFBFBD>!A<>B<>B<><1C><EFBFBD>0<>0<>"<22><1B><1A><1A>F<EFBFBD>4<EFBFBD>L<EFBFBD>$6<>$6<>t<EFBFBD>|<7C>|<7C>w<EFBFBD>7N<37>$O<>P<>P<><08> <13> &<26> &<26> (<28><1F><03>w<EFBFBD>w<EFBFBD>i<EFBFBD>z<EFBFBD>%B<>C<> C<><13>G<EFBFBD>5<EFBFBD><16>@<40><04>
<EFBFBD><06><06>t<EFBFBD> <0C><10>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19><1A>w<EFBFBD>/<2F>0<>0<>0<> <20><>0<><30>P<><50> <1A><>0<><30>0<>0<>0<>s~<00>E1<01>E<04>BE1<01>E<06>E1<01>AE<03>E<06> AE<03>6E<06>7E<03>? E1<01> E<06> E1<01>E1<01>E<03>E<03>E1<01>E.<07>"E% <0C>#E.<07>*E1z/admin/api/books/{book_id}c<00><00><>K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(<00><00><00>d{<00><03><03>|jtt <00>j t j
|k(<00><00><00>d{<00><03><03>|j<00><00>d{<00><03><03>ddicddd<00><00>d{<00><02><03>S7<00><>7<00>y7<00>57<00>7<00> #1<00>d{<00><03><03>7swYyxYw<01>w<01>Nr<4E>T)r<>r<>rr=r<>r7r%r<>)r7r<>s r#<00> delete_bookr<6B><00>s<><00><00><><00><1C><EFBFBD><1C><1C>"<22><10>j<EFBFBD>j<EFBFBD><16><07><1F>.<2E>.<2E>w<EFBFBD><EFBFBD><EFBFBD>'<27>/I<>J<>K<>K<>K<><10>j<EFBFBD>j<EFBFBD><16><04><1C>+<2B>+<2B>D<EFBFBD>L<EFBFBD>L<EFBFBD>G<EFBFBD>,C<>D<>E<>E<>E<><10>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19><14>d<EFBFBD>|<7C> <1C><1C><1C><>K<><4B>E<><45><19><><1C><><1C><1C><1C>s|<00>C.<01>C<06>C.<01>AC<03>C<06>AC<03>C<06>C<03>5C<06>6C<03>= C.<01> C<06>
C.<01>C<03>C<03>C<03>C.<01>C+<07>C" <0C> C+<07>'C.z#/admin/api/books/{book_id}/chaptersc <00><00><>K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(<00>j tj<00><00><00>d{<00><03><03>}|j<00>j<00>}|D<00>cgc]<5D>}|j|j|jt|j<00>dkDr|jdddzn |jt|j<00>|j|j |jdk(d<04><08><02><>c}cddd<00><00>d{<00><02><03>S7<00><01>67<00><>cc}w7<00>#1<00>d{<00><03><03>7swYyxYw<01>w)Nr/z...r<>)rBrCr8rD<00> text_lengthrFrG<00> has_audio)r<>r<>rr=r<>r7r<>r6r<>r<>rBrCr8<00>lenrDrFrG)r7r<>r<>r>r<>s r#<00> list_chaptersr<73>
s <00><00><><00><1C><EFBFBD>
<EFBFBD>
<EFBFBD>"<22><19>z<EFBFBD>z<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C> =<3D> F<> F<>w<EFBFBD>z<EFBFBD>z<EFBFBD> R<>
<EFBFBD>
<EFBFBD><06><1A>><3E>><3E>#<23>'<27>'<27>)<29><08><1F> 
<EFBFBD><13>!<21>m<EFBFBD>m<EFBFBD>"$<24>"3<>"3<><1B><18><18>AD<41>R<EFBFBD>_<EFBFBD>_<EFBFBD>AU<41>X[<5B>A[<5B><02><0F><0F><04><13> 5<><05> =<3D>ac<61>ap<61>ap<61>"<22>2<EFBFBD>?<3F>?<3F>3<><1C>)<29>)<29><1F>\<5C>\<5C><1F>Y<EFBFBD>Y<EFBFBD>'<27>1<> <0E> 
<EFBFBD> 
<EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD> 
<EFBFBD> 
<EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>sj<00>E(<01>E<06>E(<01>AE<03>4E
<06>5&E<03>BE <06>3E<03>5 E(<01>E<06>E(<01>
E<03> E<03>E(<01>E%<07>E <0C>E%<07>!E(c<00><00>RK<00>|j<00><00>d{<00><02><03>}|jdd<02>j<00>}|jdd<02>j<00>}|jdd<02>j<00>}|jdd<02>j<00>}|s tdd<07><00>t <00>4<00>d{<00><02><03>}|j t t<00>jtj|k(tj|k(<00><00><00>d{<00><03><03>}|j<00>rtdd |<03>d
<EFBFBD><03><00>t|||xs|||<06> <0B>} |j| <09>|j<00><00>d{<00><03><03>d |d <0A>cddd<00><00>d{<00><02><03>S7<00><01>q7<00><>7<00>|7<00>!7<00>#1<00>d{<00><03><03>7swYyxYw<01>w)NrBr0r8rCrDr<>uchapter_id 不能为空r<E7A9BA>u章节 r<>)r7rBrCr8rDT)r<>rB)rXrhr<>rr<>r<>rr=r<>r7rBr<>r<>r<>)
r7r<>r^rBr8rCrDr<>r<>r<>s
r#<00>create_chapterr<72> sy<00><00><><00><18><1C><1C><1E> <1F>D<EFBFBD><15><18><18>,<2C><02>+<2B>1<>1<>3<>J<EFBFBD> <10>H<EFBFBD>H<EFBFBD>W<EFBFBD>b<EFBFBD> !<21> '<27> '<27> )<29>E<EFBFBD><19>X<EFBFBD>X<EFBFBD>.<2E><02>3<>9<>9<>;<3B>N<EFBFBD><17>8<EFBFBD>8<EFBFBD>N<EFBFBD>B<EFBFBD>/<2F>5<>5<>7<>L<EFBFBD> <15><1B>C<EFBFBD>!:<3A>;<3B>;<3B><1C><EFBFBD>6<>6<>"<22><1B><1A><1A> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C>g<EFBFBD>>P<>>P<>T^<5E>>^<5E> _<>
<EFBFBD>
<EFBFBD><08> <14> &<26> &<26> (<28><1F><03>w<EFBFBD>z<EFBFBD>l<EFBFBD>*<2A>%E<>F<> F<><19><1B>!<21>)<29>7<>Z<EFBFBD><17>%<25> 
<EFBFBD><07> <0B><06><06>w<EFBFBD><0F><10>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19><1A>*<2A>5<>!6<>6<>6<> <20><>6<><36>
<EFBFBD><EFBFBD> <1A><>6<><36>6<>6<>6<>s~<00>F'<01>F<04>B F'<01>7F
<06>8F'<01>;AF<03>F <06>AF<03>,F<06>-F<03>5 F'<01>F<06>F'<01>
F'<01> F<03>F<03>F'<01>F$<07>F <0C>F$<07> F'z0/admin/api/books/{book_id}/chapters/{chapter_id}c<00><00>8K<00>|j<00><00>d{<00><02><03>}t<00>4<00>d{<00><02><03>}|jtt<00>j tj |k(tj|k(<00><00><00>d{<00><03><03>}|j<00>}|s tdd<02><00>d|vr
|d|_
d|vr
|d|_ d|vr
|d|_ |j<00><00>d{<00><03><03>ddicddd<00><00>d{<00><02><03>S7<00><>7<00><>7<00>}7<00>7<00> #1<00>d{<00><03><03>7swYyxYw<01>w)Nr<4E>r<>rDr8rCr<>T)rXr<>r<>rr=r<>r7rBr<>rrDr8rCr<>)r7rBr<>r^r<>r<>r<>s r#<00>update_chapterr<72>>s<00><00><><00><18><1C><1C><1E> <1F>D<EFBFBD><1C><EFBFBD><1C><1C>"<22><19>z<EFBFBD>z<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C>g<EFBFBD>>P<>>P<>T^<5E>>^<5E> _<>
<EFBFBD>
<EFBFBD><06><19>+<2B>+<2B>-<2D><07><16><1F><03>%6<>7<> 7<> <19>T<EFBFBD> !<21>#'<27><0E>#7<>G<EFBFBD> <20> <12>d<EFBFBD>?<3F> <20><17>M<EFBFBD>G<EFBFBD>M<EFBFBD> <1B>t<EFBFBD> #<23>%)<29>*:<3A>%;<3B>G<EFBFBD> "<22><10>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19><14>d<EFBFBD>|<7C>!<1C><1C><1C> <20><><1C><>
<EFBFBD><EFBFBD> <1A><><1C><><1C><1C><1C>sz<00>D<01>C;<04>D<01>C=<06>D<01>AD<03>C?<06>AD<03>!D<06>"D<03>) D<01>5D<06>6D<01>=D<01>?D<03>D<03>D<01>D<07> D <0C> D<07>Dc<00><00>tK<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(tj |k(<00><00><00>d{<00><03><03>|j<00><00>d{<00><03><03>ddicddd<00><00>d{<00><02><03>S7<00><>7<00>37<00>7<00> #1<00>d{<00><03><03>7swYyxYw<01>wr<>)r<>r<>rr=r<>r7rBr<>)r7rBr<>s r#<00>delete_chapterr<72>Ts<><00><00><><00><1C><EFBFBD><1C><1C>"<22><10>j<EFBFBD>j<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C>g<EFBFBD>>P<>>P<>T^<5E>>^<5E> _<>
<EFBFBD>
<EFBFBD>
<EFBFBD><11>i<EFBFBD>i<EFBFBD>k<EFBFBD><19><19><14>d<EFBFBD>|<7C> <1C><1C><1C><>
<EFBFBD><EFBFBD> <1A><> <1C><><1C><1C><1C>si<00>B8<01>B<06>B8<01>AB#<03>)B<06>*B#<03>B<06>B#<03> B8<01>B!<06>B8<01>B#<03>B#<03>!B8<01>#B5<07>)B, <0C>*B5<07>1B8z9/admin/api/books/{book_id}/chapters/{chapter_id}/generatec<00><00><>K<00>t|<01><00>d{<00><02><03>t<00>4<00>d{<00><02><03>}|jtt<00>j tj |k(tj|k(<00><00><00>d{<00><03><03>}|j<00>}ddd<01><00>d{<00><02><03>dj|jd<03>S7<00><>7<00><>7<00>B7<00>$#1<00>d{<00><03><03>7swY<00>4xYw<01>w)u手动生成单章音频NT)r<>rFrG) r<>r<>r<>rr=r<>r7rBr<>rFrG)r7rBr<>r<>r<>s r#<00>generate_audior<6F>`s<><00><00><><00> !<21><1A>
,<2C>,<2C>,<2C><1C><EFBFBD>)<29>)<29>"<22><19>z<EFBFBD>z<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C>g<EFBFBD>>P<>>P<>T^<5E>>^<5E> _<>
<EFBFBD>
<EFBFBD><06><14> &<26> &<26> (<28><02> )<29>)<29>
<17>"<22>)<29>)<29>"<22>,<2C>,<2C> G<>G<> -<2D><>)<29><>
<EFBFBD><EFBFBD>)<29><>)<29>)<29>)<29>sg<00>C<01>B;<04>C<01>B=<06>C<01>AC<03><B?<06>=C<03> C<01>C<04>C<01>=C<01>?C<03>C<01>C<07> C <0C>
C<07>Cz'/admin/api/books/{book_id}/generate-allc<00><00>K<00>t<00>4<00>d{<00><02><03>}|jtt<00>j tj
|k(tj dk7<00><00><00>d{<00><03><03>}|j<00>j<00>}ddd<01><00>d{<00><02><03>D<00>cgc]}|j<00><02>}}|D]}t|<06><00>d{<00><02><03><00>dt|<05>|d<04>S7<00><>7<00>v7<00>J#1<00>d{<00><03><03>7swY<00>ZxYwcc}w7<00>5<EFBFBD>w)u$批量生成书籍所有章节音频Nr<4E>T)r<><00>total<61> chapter_ids) r<>r<>rr=r<>r7rFr<>r<>rBr<>r<>)r7r<>r<>r>r<>r<><00>cids r#<00>generate_all_chaptersr<73>ls<><00><00><><00><1D><EFBFBD>*<2A>*<2A>"<22><19>z<EFBFBD>z<EFBFBD> <12>7<EFBFBD>O<EFBFBD> !<21> !<21>'<27>/<2F>/<2F>W<EFBFBD>"<<3C>g<EFBFBD>n<EFBFBD>n<EFBFBD>PW<50>>W<> X<>
<EFBFBD>
<EFBFBD><06><1A>><3E>><3E>#<23>'<27>'<27>)<29><08> *<2A>*<2A> ,4<>4<>R<EFBFBD>2<EFBFBD>=<3D>=<3D>4<>K<EFBFBD>4<><1A>*<2A><03>$<24>S<EFBFBD>)<29>)<29>)<29>*<2A><17><13>[<5B>!1<>+<2B> N<>N<>*<2A><>
<EFBFBD><EFBFBD>*<2A><>*<2A>*<2A>*<2A><> 5<>)<29>so<00>D<01>C<06>D<01>AC$<03>)C <06>*"C$<03> D<01>C"<04>D<01> C9<04>3D<01>C><06> D<01> C$<03>"D<01>$C6<07>*C- <0C>+C6<07>2 Dz/admin/api/tts/previewc<00><00>*K<00>|j<00><00>d{<00><02><03>}|jdd<03>j<00>}|jdd<03>j<00>}|s tdd<06><00>t ||<03><00>d{<00><02><03>}t t j<00>dz }|jdd<08> <09>tj<00>j<00>d
<EFBFBD>}t|tj<00>j<00>d <0B>z <00>}t||z <00>}t|d <0C>5} | j|<04>ddd<01>tj <00>}
|
j#dt$||<08><00>d{<00><02><03>t'j(|<07>dd |<06><00>d<0E>S7<00><01>i7<00><01>
#1swY<00>`xYw7<00>3<EFBFBD>w)u试听 TTS 效果NrIr0rJr<>u文本不能为空<E4B8BA>_previewTr<54>r<>r<>r<>z/audio/_preview/)r<><00>url)rXrhr<>rrsrr_r<>r<><00>uuid<69>uuid4<64>hexr<78>r<>r<>r<>r<>r<>r<>r<>r<>) r<>r^rIrJr<>r<>r<>rtrur<>r<>s r#<00> tts_previewr<77>~s`<00><00><><00><19><1C><1C><1E> <1F>D<EFBFBD> <0F>8<EFBFBD>8<EFBFBD>F<EFBFBD>B<EFBFBD> <1F> %<25> %<25> '<27>D<EFBFBD> <10>H<EFBFBD>H<EFBFBD>W<EFBFBD>b<EFBFBD> !<21> '<27> '<27> )<29>E<EFBFBD> <0F><1B>C<EFBFBD>!5<>6<>6<>#<23>D<EFBFBD>%<25>0<>0<>I<EFBFBD><14>V<EFBFBD>%<25>%<25>&<26><1A>3<>I<EFBFBD> <0A>O<EFBFBD>O<EFBFBD>D<EFBFBD>4<EFBFBD>O<EFBFBD>0<><16>*<2A>*<2A>,<2C>"<22>"<22>#<23>4<EFBFBD>(<28>H<EFBFBD><12>9<EFBFBD>$<24>*<2A>*<2A>,<2C>"2<>"2<>!3<>4<EFBFBD>8<>8<>9<>H<EFBFBD><12>9<EFBFBD>x<EFBFBD>'<27>(<28>H<EFBFBD> <0A>h<EFBFBD><04> <1D><1B><11> <09><07><07> <09><1A><1B> <13> !<21> !<21> #<23>D<EFBFBD>
<0E>
<1E>
<1E>t<EFBFBD>Z<EFBFBD><18>8<EFBFBD>
D<EFBFBD>D<>D<><06>I<EFBFBD>I<EFBFBD>h<EFBFBD><17><16>!1<>(<28><1A><<3C> =<3D>=<3D>- <20><>1<><31><1B><1B><>E<01>sG<00>F<01>E?<04>A!F<01>8F<04>9BF<01>F<03>&7F<01>F<04>"F<01>F<01>F<07>
Fz/admin/api/configc<00><00><>K<00>tjtjtjtjrtjdddzd<04>Sdd<04>S<00>w)N<>z****u 未配置)<04>endpointrSrO<00>api_key_masked)r_rfrarbr`r!r"r#<00>
get_configr<EFBFBD><00>s[<00><00><><00><1B>,<2C>,<2C><17>&<26>&<26><17>"<22>"<22>>D<>>Q<>>Q<>&<26>-<2D>-<2D>b<EFBFBD>q<EFBFBD>1<>F<EFBFBD>:<3A>  <06><06>Xc<01>  <06><06>s<00>AAr<>)<01> directoryrT)<01>name<6D>/)<01>response_classc<00><00><>K<00>tjjtjdd<02>}t |dd<04><05>5}t |j<00><00>cddd<00>S#1swYyxYw<01>w)N<>staticz
index.html<6D>rzutf-8)<01>encoding)r<>r<>r<>r_r<>r<>r
<00>read)<02> html_pathr<68>s r#<00>frontendr<64><00>sP<00><00><><00><12><07><07> <0C> <0C>V<EFBFBD>_<EFBFBD>_<EFBFBD>h<EFBFBD> <0C>E<>I<EFBFBD> <0A>i<EFBFBD><13>w<EFBFBD> /<2F>&<26>1<EFBFBD><1B>A<EFBFBD>F<EFBFBD>F<EFBFBD>H<EFBFBD>%<25>&<26>&<26>&<26>s<00>>A/<01>A#<03>
A/<01>#A,<07>(A/<01>__main__zmain:appT)<03>host<73>port<72>reload)r0)L<>__doc__r<5F>rXrir{r<>r<><00>
contextlibr<00>pathlibrrc<00>fastapirrrr<00>fastapi.responsesr r
r <00>fastapi.staticfilesr <00>
sqlalchemyr rrrrrrr<00>sqlalchemy.ext.asynciorrr<00>sqlalchemy.ormrr_<00> DATABASE_URLr<4C>r<>rr%r=r<><00>bytesrsr<>r<>r<>r<>rhr<>r<>r<>rer<>r<>r<>r<><00>putr<74>r<>r<>r<>r<>r<><00>mountr<74>r<>r<00>uvicornr|<00> SERVER_HOST<53> SERVER_PORTr!r"r#<00><module>rs<00><01><04>

<EFBFBD> <0B> <0A><11> <0B><0E>*<2A><18> <0C>:<3A>:<3A>F<>F<>+<2B>T<>T<>T<>X<>X<>*<2A> <0A>
<1D>V<EFBFBD>0<>0<>u<EFBFBD> =<3D><06>"<22>6<EFBFBD>,<2C>QV<51>W<> <0A> <09>?<3F> <09>=<3D>4<EFBFBD>=<3D> R<01>d<EFBFBD> R<01>" F<01>c<EFBFBD> F<01>#<23> F<01>u<EFBFBD> F<01>FJ<01><13>J<01><03>J<01>+<1A><13>+<1A>`<15>
<EFBFBD><07>
<EFBFBD><15>
<EFBFBD><0E>&<26><18>:<3A><03>
<05><17><17> <1E><1F>
<EFBFBD><13>
<EFBFBD> <20>
<EFBFBD>><05><17><17> 9<>:<3A>c<01>S<EFBFBD>c<01>c<EFBFBD>c<01>;<3B>c<01>2<05><17><17> <1B><1C>]<01><1D>]<01><05><18><18>
<1C><1D>0<>w<EFBFBD>0<><1E>0<>(<05><1A><1A> (<28>)<29><1C>s<EFBFBD><1C>*<2A><1C><05><17><17> .<2E>/<2F>
<EFBFBD><13>
<EFBFBD>0<>
<EFBFBD>*<05><18><18>
/<2F>0<>6<>#<23>6<><07>6<>1<>6<>:<05><17><17> ;<3B><<3C><1C>#<23><1C>3<EFBFBD><1C><17><1C>=<3D><1C>*<05><1A><1A> ><3E>?<3F><1C>#<23><1C>3<EFBFBD><1C>@<01><1C><05><18><18>
E<EFBFBD>F<>H<01>#<23>H<01>3<EFBFBD>H<01>G<01>H<01><05><18><18>
3<EFBFBD>4<> O<01><13> O<01>5<> O<01>"<05><18><18>
"<22>#<23>><3E>w<EFBFBD>><3E>$<24>><3E>6<05><17><17> <1C><1D><06><1E><06><04> <09> <09>(<28>K<EFBFBD>&<26>*:<3A>*:<3A>;<3B>'<27> <09>J<><05><17><17><13>\<5C><17>*<2A>&<26>+<2B>&<26> <0C>z<EFBFBD><19><12><0F>G<EFBFBD>K<EFBFBD>K<EFBFBD>
<EFBFBD><16>!3<>!3<>&<26>:L<>:L<>UY<55>Z<>r"