From 01f9e9f05ea7a38adf70bb6d95668b5505c175a4 Mon Sep 17 00:00:00 2001 From: Robin COuret Date: Thu, 5 Mar 2026 20:08:10 +0100 Subject: [PATCH] replace loadenv by pydantic-settings --- server/.env.example | 4 ++-- server/requirements.txt | 6 +++--- .../app/__pycache__/config.cpython-311.pyc | Bin 0 -> 1075 bytes .../app/__pycache__/database.cpython-311.pyc | Bin 1241 -> 1108 bytes .../src/app/__pycache__/main.cpython-311.pyc | Bin 1639 -> 1528 bytes server/src/app/config.py | 19 ++++++++++++++++++ server/src/app/database.py | 9 ++------- server/src/app/main.py | 7 ++----- .../services/__pycache__/auth.cpython-311.pyc | Bin 4742 -> 4615 bytes .../language_generation.cpython-311.pyc | Bin 2084 -> 1903 bytes server/src/app/services/auth.py | 11 +++------- .../src/app/services/language_generation.py | 10 +++------ 12 files changed, 34 insertions(+), 32 deletions(-) create mode 100644 server/src/app/__pycache__/config.cpython-311.pyc create mode 100644 server/src/app/config.py diff --git a/server/.env.example b/server/.env.example index 373fcc5..e3ca509 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,6 +1,6 @@ DATABASE_URI="sqlite:///database.db" LANGUAGE_MODEL_API="http://localhost:8080/v1" -MODEL_NAME="SmolLM3-Q4_K_M.gguf" +LANGUAGE_MODEL_NAME="SmolLM3-Q4_K_M.gguf" ORIGIN="http://localhost:5173" -SECRET_SIGN="xxxx" #generate secure random secret key: openssl rand -hex 32 +SECRET_KEY="xxxx" #generate secure random secret key: openssl rand -hex 32 ACCESS_TOKEN_EXPIRE_MINUTES=10080 \ No newline at end of file diff --git a/server/requirements.txt b/server/requirements.txt index b750282..a0ccd53 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -1,9 +1,9 @@ fastapi==0.128.6 sqlmodel==0.0.32 -python-dotenv==1.2.1 openai==2.21.0 spacy==3.8.11 PyJWT>=2.11.0 -argon2-cffi>=25.1.0 # python -m spacy download en_core_web_sm -# python -m spacy download fr_core_news_sm \ No newline at end of file +# python -m spacy download fr_core_news_sm +argon2-cffi>=25.1.0 +pydantic-settings==2.13.1 diff --git a/server/src/app/__pycache__/config.cpython-311.pyc b/server/src/app/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0182d12a3c44cbb5ac2de8dca6a88daef329171 GIT binary patch literal 1075 zcmZuwyHDFd7{9YG!K4YVguWPPC6-horfr5aLX}Lgq9`QLIFVW}CpR{UCC5%}g9Pf3 zN*$=wrCs1JphEmJj=DsiDs^HD3KLWBoCgB>-FKgV-{bCn_wcV+ECPsJ{65ovLID0! zXDp!+7;F%53{;>(1GJzFAz(lrsLWTOvKl;P0XQdpC^EwUjX5RG`8Wh*Rz(s>hAwC% z3H|7X;%JiQy1LnL>XR}8(8w8>1RMhm$WR3`Qv({SAr-EZsLIHpz+(ds$>G2YQ7=H@ z37QJf6dB1;6p)@Kq$8&cp-1{qWKMlR=tX^Q%*l^#3RPi4kVIUo6b>IZUALX(dBdtJ zM$>ZKY-TO9#_zxM7q*0Qz9!^FT-x3gx3I8NIE+gz%h)QtUVWFwMO;cX8hg8b{7zw6 zD2aY}yHdy(%6>!=a}}|Qi{b}=Nyz0yNy63bqFBb_`<+6COkOD0s-kr3sK{*vGFTv= zo1;=8Ic8peJEZRoVI7EGfNE}njsSwj=A%s2f!n>_~Gy@68 c`{wBLC5>L)q@ICj;wbYi`#sy?XbZ^x10bmd_IWI340}y0gUYS`ikyo-l0mzxokiw9{n8T3E7{$m4Vl(A1zk9STY%-*q9hnSyLIa*g-~sKnhDL+Zxto%nS^xffxd!I8xYJ7@{~+*nuQh z3P&)5Cg)3#lqTaXj^fmklFYpHVol~-?7^wU#S`DlZkA%?Wn>isDqx?i!=%9|FgcW| z%aR+UfvJcENEPuxG_w~2HDu=J6*B_)3PplI@)mb`YDqj)yhs!%!Zlffd8)9VCigAA z;-X}|#DW67z=Km^Ew zUmP~M`6;D2sdhz@KrYDU;szk`ftit!@dktP1ynRSfJI(GKzTvv1%B-Yo*SHE9kLTD du88YwFg;LnfivVHXUG-Kkjbl9v{^tl0053lU2OmW delta 543 zcmY*V&r2IY6rMM`*<`XiiCPdmC_)J|OoOgbummF-xVg!+`^%G@>)o@8jbgk@6BKbWVbGNf)0HDp~z zE!F&Vcv|A#e08NdS6yDHufALSc3XhV3(WMA9=w9l&D6r0)RT=?W4#fp z`iAzk`QzajZT1*8(jx|q8e=B?%DoLExe=%tJ&Dw;5Pw1Q!vcUlVeR4Rld10iw@+So z%}ste+V0xP(jBk#c%|(PMqZw+c8iGmYOK%zK#z8iG?;uLS@t^P-!s1ZVMA+m&=*mlW;6tJ^miZtkAMII z8Q>5@=(EHmjxY)sF_|k^30P(!u3|M{g@t(pM*!=G4JPT zez3NvmNPY0m0~(PFDw+eNQ)-KC7LIL^+j_zQxlYZke?A@&?NgX1yYlC) Py;r4)Qa2mkM(F4dwiRq) delta 613 zcmZ9Ize^)Q6vyYy{>c8wBr!%4eO9VlYgX7pj z;To$I(L#~?KfJ>tEC_ao-IZtO?1W(S&Afe|nfIMHZ}z|cH%-n7@sP4VKQEd$KgdL9 z4-h&*3^5Q$0tHAI3rw+!hA^Z_O}%FdOWM@dY>AX~sH52yuJov@GeJ- zN^kSxRW4Fbxm4aaTH>X%iNR_(^1`dKlO$AmyfrzHoJ|dAII@w~L&-j!=F<(JWpznq zST|tq@G{G@(FP=bRfsIrobtY@2jkDEHuhvD>u?*2xuqJ!z6jRX7Z$X6Ywz|5$^fM> z!gEe+FRv`t7ni~Zyil!GV{ap9wfWb!Xs+)Vsz8i`-PrD*3+u)+NvQ(OouCyP4c-px z=EwP2B}@Lz?xFhrGXS86KHR;XJ>+)v=%LEp+Zp~cBmWWkU4Ne(kS+;Vt(C0*ZSs5N RxN_?Jc4zM0nef{B^a5~2dtLwl diff --git a/server/src/app/config.py b/server/src/app/config.py new file mode 100644 index 0000000..130233b --- /dev/null +++ b/server/src/app/config.py @@ -0,0 +1,19 @@ +from pydantic_settings import BaseSettings + +class Settings(BaseSettings): + # Database + DATABASE_URI: str + + # Language model + LANGUAGE_MODEL_API: str = "http://localhost:8080/v1" + LANGUAGE_MODEL_NAME: str = "SmolLM3-Q4_K_M.gguf" + + # Security + ORIGIN: str + SECRET_KEY : str + ACCESS_TOKEN_EXPIRE_MINUTES: int + + class Config: + env_file = ".env" + +settings = Settings() \ No newline at end of file diff --git a/server/src/app/database.py b/server/src/app/database.py index 31406b5..80582f2 100644 --- a/server/src/app/database.py +++ b/server/src/app/database.py @@ -1,13 +1,8 @@ -import os -from dotenv import load_dotenv +from src.app.config import settings from sqlmodel import Session, SQLModel, create_engine -load_dotenv() - -database_uri=os.environ.get("DATABASE_URI") - connect_args = {"check_same_thread": False} -engine = create_engine(database_uri, echo=False, connect_args=connect_args) +engine = create_engine(settings.DATABASE_URI, echo=False, connect_args=connect_args) def create_db_and_tables(): SQLModel.metadata.create_all(engine) diff --git a/server/src/app/main.py b/server/src/app/main.py index cb0d9f9..8f99323 100644 --- a/server/src/app/main.py +++ b/server/src/app/main.py @@ -1,6 +1,5 @@ +from src.app.config import settings from contextlib import asynccontextmanager -import os -from dotenv import load_dotenv from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware @@ -18,8 +17,6 @@ from .api import router #Test from src.app.faker_seed import faker -load_dotenv() - #TODO : alternative @app.on_event("startup") ? @asynccontextmanager async def lifespan(app: FastAPI): @@ -31,7 +28,7 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) app.include_router(router) -origin = os.environ.get("ORIGIN") +origin = settings.ORIGIN origins = [origin] app.add_middleware( diff --git a/server/src/app/services/__pycache__/auth.cpython-311.pyc b/server/src/app/services/__pycache__/auth.cpython-311.pyc index 81a240e436e247d88150e02582627fd063e7f6e4..32ec1d064f52d81cbef0f6502e8374aea30bd16a 100644 GIT binary patch delta 1265 zcmZWnO>7%g5PomHS=+l_|0YiC*va}QByL&%xp5PAoWz$K_Ew;nigs00@fQX+DQR^nXobKnZ%z|5u*DvWkN&3xa?)6Beg zcjm*o`K4*<1nlNd_j})eVitz?C?TH`PB?XlOBto;D~{quSj1JB;;Kvyxrj63YD^1# z)rq<>77P6mC+_M@cMWE^36=;s%`x31ONM^bNwE~18FSKZhGjx7?quB@%Yi>6Tz5v@ zF*fGrS>7FI<6(l~Ot=MB2>papbSK#)B?_^V-25te04+a&|I}Cs_}l>m56&pU$~?uU zc$!Tskgv4aTYz<+AYLT$)%Addb|tne|r%JX)$t@80ZDy#7chzsx+?Rs0| zlfcdJlKo6u;brh=F&8wuOW8!ccCiZ!Z{I1(Dr5%60D6qLezp?t_8>{PEuddz{ z&jZm=#YOo;`~t1WKjUR>5h$-KOZs}@`tkWIKQ15UH;(cf$N7zW#!0Gp7%K`(-qqiE zb`BCn0}r4A7vSMbdosA$ZF${)r+OKbWtlT-)RIevMK8%s<5qrG13EN6dFBx!kBl)I zlaGxBnv>&+8Xc9F6Xg_M@j*^30TV>L{cUIgF9PP&%!N9RDXt>md_kmR z`={4vB9}v`%XM?UiZy}m4{q80E#C55;ye%@wgp!RCMxm^Gq0}$v4YAs@{zfcx_(?= z`fm9!yLOaaJI=02BYC@&y0%CjEt=P^L>lLUq$hTot-ZbG&Y<7!b>wHsUx(qgupMz3 z0mnJ*DSUYNDgt$TFmS?~4OHIS@x@D+gu4^i!G9j+U$GT;!1o>d1+fh(F5lZw2>ByI kDLo;z!>2x_b|T+RkIG?MlULI}%ejp8@U6@&RV}Fd2ktrxX8-^I delta 1382 zcmZWnUuYaf7@yhQ`?q_WyKHDg_P2$^=OHOnu=v;X?+q@P#+ZYB!L9-a4bFwQbF)RMAQernIuZ<9P`_6zTfYg z`@Z?U*GFC}+aKDtiD2E_{}f>9($-zwGl=2oME4>j zqI`xM^?0bJ}*ad%1*ldUY_JJ(h$=&p@!SC5Ve%gq4u4QO(^F! z?EOUwpzXd_O9mLaHh8GeZWYA`R?nJqUto!*$Pn!$!y2k0n%+RPizPO7xE%Juvi8>X>!Vs2^zf>KMGVO!Yd*fD@3Q@0RE|1pQ92QmuCqNh^J#W za8!h`pR^z&w&M>v@HmOOyV&H7;Hp${1GV+&7ir&mTR;g)cFKB{3rl44%U9}QV?I8Z*dO&+i%@dpqP=;uf&Rds^k3E z=f0TUNmqB%)xC68d~2^}t(i&m&7?gutyd;Pt?7r+gCQjyKd;Fb3}Y~|4c=Vl7vaRu zNRTbz(-PFgs@YQ0C`TnUt~8sjYIkVR#(cmZlgh^>$b9ab)<5H?ye4hA>@;V<${zWv z8bZJ7*uuDt66@+GeshkCADy;|taa-Zd&6G0#h0m4m+ibw-nsnd<@cZ1wa51Cv30Zk M=?|$R*pRdO5Anw^x&QzG diff --git a/server/src/app/services/__pycache__/language_generation.cpython-311.pyc b/server/src/app/services/__pycache__/language_generation.cpython-311.pyc index 7511e8b2ac18b1dbdcc922ac07a667ffa6d999ad..c72f82217d215ead72f5124922a0fb34bef737a1 100644 GIT binary patch delta 602 zcmZ1?@Scx%IWI340}$|ES(%wXkyo<53CNkwkiw9{n8OeSqM33SbD5%;7(s029Ohh> zC>AiAC5JVaEsBkifr%lNC6y_Q9b^m$q_D1GTgJq|uo{RVAc_O1h9Qd+#!q2i#t4)L zVyHY<3P&ni8dC~qixEo{cM4-LgC^HYker_;<1LQj)RL0Sy!2uqo6Wx0EfJjD$0W-rJXwHQQlGts zEeq^tkOeLbu`;zBHS7zxK|FL&!;!^4c>=Q}vup`SuPP(YWHV+{M()Wu%r}{Ni})sc zu*gXjF$1;T683TQa}RZNca8V;cX9QJ_jB}hom|9X#K<{$DT@Q6%;aY*bGWpCD*1r8 zSbA~~s}+mb6+W%W$624L^4wxAE=WwSyv0{sl&qInP@tEbpO==I4l$Z7AL!}C%*hwn zRO^M%tZ@wRED{0P&ytg$m{KGKWEO#JS;!7F-&S7Y)ec0U%7tpM6Q Bi5UO@ delta 783 zcmZWn&ubGw6rS1NyU8|b)0Rftij^XzR;z-QAi+pO6`K?kFDo@HoiQYCcEfI}6cQT2 zgA_sP2)*>sgG8lX{2K~hylkQ1vZtJ+p7d%@&Ll=?ee>R%_q}=FyqRHs_PvYi?{!@R zRIH`#(%ze!R$jCmLGE{ z@ssNUp*sl0)CdEV(@EqEy$AY1c|CWLcVAm$Ch{K9T-%AEx2di4o3uZ1Z9g%0keKtqKoHSirCz5u(*CJS`;pm$ V$ZS( str: @@ -69,7 +64,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> Use headers={"WWW-Authenticate": "Bearer"}, ) try: - payload = jwt.decode(token, secret_key, algorithms=[algorithm]) + payload = jwt.decode(token, settings.SECRET_KEY, algorithm=algorithm) username = payload.get("sub") if username is None: raise credentials_exception diff --git a/server/src/app/services/language_generation.py b/server/src/app/services/language_generation.py index 4f41604..a4335a0 100644 --- a/server/src/app/services/language_generation.py +++ b/server/src/app/services/language_generation.py @@ -1,15 +1,11 @@ -import os import spacy +from src.app.config import settings from openai import OpenAI -from pydantic import BaseModel from src.app.models.knowledge import Knowledge -language_model_api=os.environ.get("LANGUAGE_MODEL_API") -model_name=os.environ.get("LANGUAGE_MODEL_NAME") - client = OpenAI( - base_url=language_model_api, + base_url=settings.LANGUAGE_MODEL_API, api_key = "sk-no-key-required" ) @@ -23,7 +19,7 @@ def questions_generation(knowledge: Knowledge): #SLM processing response = client.responses.create( - model=model_name, + model=settings.LANGUAGE_MODEL_NAME, input=[ {"role": "system", "content": "Question Generation"}, {"role": "user", "content": prompt}],