Skip to content

Commit

Permalink
feat: refacto
Browse files Browse the repository at this point in the history
  • Loading branch information
leoguillaumegouv committed Oct 11, 2024
1 parent 82e84a9 commit c646b82
Show file tree
Hide file tree
Showing 32 changed files with 308 additions and 471 deletions.
10 changes: 10 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
LANGUAGE_MODEL=AgentPublic/llama3-instruct-8b
EMBEDDINGS_MODEL=BAAI/bge-m3
ALBERT_BASE_URL=https://albert.api.dev.etalab.gouv.fr/v1
#ALBERT_BASE_URL=http://localhost:8080/v1
#ALBERT_API_KEY=spp-prod-V3QLrqTTmzd5jrZSiAAdHnFw9ijyc7m2DZDK97nAq4md34DMpvQYmCZj7wQYwkta
ALBERT_API_KEY=leo-qQVK5cFW4R7QbCxx5V33gKE9qzER32tesNb4DTrPeg7sqVrRsUdprJfArwMtAxui
REDIS_HOST=albert.bdd.001.etalab.gouv.fr
REDIS_PORT=36379
REDIS_PASSWORD=gaYauVqErKgFtAgDZrgJt4ZKohjoJ7FXkgQAEU3gMVSAwHwY2TqeaeTwofroeJnk
COLLECTION_ID=5080b4bc-71a3-49af-acfc-c27f56079f0c
14 changes: 6 additions & 8 deletions .github/workflows/build_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ on:
push:
branches:
- main
- staging
- dev

env:
IMAGE_NAME: ghcr.io/${{ github.repository }}/albert-spp
APP_IMAGE_NAME: ghcr.io/${{ github.repository }}/app
IMAGE_TAG: ${{ github.sha }}
application_name: albert-spp
deployment_environment: staging
Expand All @@ -35,18 +33,19 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./app/Dockerfile
push: true
tags: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }},${{ env.IMAGE_NAME }}:latest
tags: ${{ env.APP_IMAGE_NAME }}:${{ env.IMAGE_TAG }},${{ env.APP_IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max

deploy-dev:
deploy-staging:
name: Deploy from ${{ github.ref_name }}/${{ github.sha }}
runs-on: ubuntu-latest
needs: build-and-push
if: github.ref_name == 'dev'
if: github.ref_name == 'main'
steps:
- name: Trigger dev deployment
- name: Trigger staging deployment
run: |
RESPONSE="$(curl --request POST \
--form token=${{ secrets.GITLAB_CI_TOKEN }} \
Expand All @@ -64,4 +63,3 @@ jobs:
echo $RESPONSE
exit 1
fi
47 changes: 0 additions & 47 deletions .gitlab-ci.yml

This file was deleted.

16 changes: 0 additions & 16 deletions Dockerfile

This file was deleted.

22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Albert - Services Publics Plus

1. Envoi du prompt au modèle

```sh
curl -XPOST https://spp.etalab.gouv.fr/api/spp/anonymize -H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"id":"123", "text":"Merci pour service"}'
```
```sh
curl -XPOST https://spp.etalab.gouv.fr/api/spp/anonymize -H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"id":"123", "text":"Merci pour service."}'
```

2. Récupération de la réponse du modèle

```sh
curl -XPOST https://spp.etalab.gouv.fr/api/spp/prod/run/ditp-get-data -H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"id":"123"}'
```
```sh
curl -XPOST https://spp.etalab.gouv.fr/api/spp/prod/run/ditp-get-data -H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"id":"123"}'
```
69 changes: 0 additions & 69 deletions app.py

This file was deleted.

File renamed without changes.
12 changes: 12 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.12-slim

RUN groupadd --gid 1100 albert
RUN useradd --home /home/albert --gid 1100 --uid 1100 albert
USER albert

WORKDIR /home/albert
ADD ./pyproject.toml ./pyproject.toml
RUN pip install .
ADD ./app /home/albert/app
ENV PYTHONPATH="/home/albert/app:${PYTHONPATH}"

Check warning on line 11 in app/Dockerfile

View workflow job for this annotation

GitHub Actions / Build and push from main/c646b82e5868b09a4f6c551e9c6c1933b42d63c7

Variables should be defined before their use

UndefinedVar: Usage of undefined variable '$PYTHONPATH' More info: https://docs.docker.com/go/dockerfile/rule/undefined-var/
ENV PATH="/home/albert/.local/bin:${PATH}"
File renamed without changes.
3 changes: 2 additions & 1 deletion config.py → app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
REDIS_HOST = os.environ.get("REDIS_HOST", "redis")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", None)

LANGUAGE_MODEL = os.environ["LANGUAGE_MODEL"]
EMBEDDINGS_MODEL = os.environ["EMBEDDINGS_MODEL"]
ALBERT_BASE_URL = os.environ["ALBERT_BASE_URL"]
ALBERT_API_KEY = os.environ["ALBERT_API_KEY"]
COLLECTION = os.getenv("COLLECTION", "plus-transformation-gouv-fr")
COLLECTION_ID = os.environ["COLLECTION_ID"]
2 changes: 1 addition & 1 deletion deps.py → app/deps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from redis import Redis

from config import REDIS_HOST, REDIS_PASSWORD, REDIS_PORT
from app.config import REDIS_HOST, REDIS_PASSWORD, REDIS_PORT


def get_redis(finally_close=True) -> Redis:
Expand Down
6 changes: 3 additions & 3 deletions llm.py → app/llm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import requests

from config import ALBERT_BASE_URL, ALBERT_API_KEY, LANGUAGE_MODEL, EMBEDDINGS_MODEL, COLLECTION
from app.config import ALBERT_API_KEY, ALBERT_BASE_URL, COLLECTION_ID, EMBEDDINGS_MODEL, LANGUAGE_MODEL


def few_shots(prompt: str):
Expand Down Expand Up @@ -34,7 +34,7 @@ def few_shots(prompt: str):
Veuillez apporter une réponse circonstanciée à cette question en respectant scrupuleusement les directives énoncées ci-dessus.
"""
data = {
"collections": [COLLECTION],
"collections": [COLLECTION_ID],
"model": EMBEDDINGS_MODEL,
"k": 4,
"prompt": prompt,
Expand All @@ -44,7 +44,7 @@ def few_shots(prompt: str):
response = response.json()

context = "\n\n\n".join([
f"Question: {result['chunk']['metadata'].get('question', 'N/A')}\n" f"Réponse: {result['chunk']['metadata'].get('answer', 'N/A')}"
f"Question: {result["chunk"]["metadata"].get("question", "N/A")}\n" f"Réponse: {result["chunk"]["metadata"].get("answer", "N/A")}"
for result in response["data"]
])

Expand Down
108 changes: 108 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from contextlib import asynccontextmanager
import datetime as dt
import json
from typing import List, Union
import uuid

from fastapi import Body, Depends, FastAPI, HTTPException, Response, Security
from redis import Redis
import requests
from starlette.middleware.cors import CORSMiddleware

from app.config import (
ALBERT_API_KEY,
ALBERT_BASE_URL,
APP_NAME,
APP_VERSION,
EMBEDDINGS_MODEL,
ENV,
LANGUAGE_MODEL,
)
from app.deps import get_redis
from app.schemas import ExpId, ExpIdWithText
from app.security import check_api_key
from app.subscriptions import Listener


def init_redis(r: Redis):
app.state.listener = Listener(r, ["spp-exp-channel"])
app.state.listener.start()


@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup code
if ENV != "unittest":
r = next(get_redis(finally_close=False))
init_redis(r)

request = requests.get(f"{ALBERT_BASE_URL}/models", headers={"Authorization": f"Bearer {ALBERT_API_KEY}"})
request.raise_for_status()
models = [model["id"] for model in request.json()["data"]]
assert LANGUAGE_MODEL in models, f"Model {LANGUAGE_MODEL} not found"
assert EMBEDDINGS_MODEL in models, f"Model {EMBEDDINGS_MODEL} not found"

yield

# Shutdown code
app.state.listener.stop()


app = FastAPI(title=APP_NAME, version=APP_VERSION, lifespan=lifespan)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])


@app.get("/health")
def healt() -> dict[str, str]:
return Response(status_code=200)


@app.post("/anonymize")
def anonymize(
form_data: Union[ExpIdWithText, List[ExpIdWithText]] = Body(...),
redis: Redis = Depends(get_redis),
api_key: str = Security(check_api_key),
):
if not isinstance(form_data, list):
form_data = [form_data]

for data in form_data:
if not data.id:
# see https://tchap.gouv.fr/#/room/!ZyhOfCwElHmyNMSlcw:agent.dinum.tchap.gouv.fr/$XMeXbIDhGtXBycZu-9Px2frsczn_iU7xiJ5xvjbs-pQ?via=agent.dinum.tchap.gouv.fr&via=agent.externe.tchap.gouv.fr&via=agent.tchap.gouv.fr
data.id = str(uuid.uuid4())

data = data.model_dump()

data["time"] = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%d %H:%M:%S.%f%z")
print(f"anonymize - {data["id"]}: {data["time"]}") # TODO: replace with logger later
redis.publish("spp-exp-channel", json.dumps(data))

if len(form_data) == 1:
responseOutput = {"id": form_data[0].id}
else:
# The spec is ill-defined !!
responseOutput = [{"id": x.id} for x in form_data]

return {"body": responseOutput}


@app.post("/prod/run/ditp-get-data")
def ditp_get_data(form_data: Union[ExpId, List[ExpId]] = Body(...), redis: Redis = Depends(get_redis), api_key: str = Security(check_api_key)):
if not isinstance(form_data, list):
form_data = [form_data]

answers = []
for data in form_data:
data = data.model_dump()
answer = redis.get(data["id"])
answers.append(answer)

if len(form_data) == 1:
if answers[0] is None:
raise HTTPException(status_code=400, detail="ID not found")
responseOutput = {"generated_answer": answers[0]}
else:
# The spec is ill-defined !!
responseOutput = [{"generated_answer": x} for x in answers]

return {"body": responseOutput}
File renamed without changes.
Loading

0 comments on commit c646b82

Please sign in to comment.