tonneli commited on
Commit
059b43a
·
1 Parent(s): 4039b5b

update code

Browse files
app.py CHANGED
@@ -41,24 +41,29 @@ def click_proof(lien):
41
  if stemed_fn == Path(lien).stem:
42
  path_to_file = Path(f["internal-link"])
43
  if path_to_file and path_to_file.is_file():
44
- show_pdf(path_to_file)
 
 
 
 
 
45
  else:
46
  print(f"File {path_to_file} not found")
47
  with column_proof:
48
  update_proofs(st.session_state.proofs)
49
 
50
- def show_pdf(link):
51
- pdf_images = convert_from_path(link)[0]
52
  tmp_f_name = NamedTemporaryFile(delete=False)
53
- print(f"Tmp file is {tmp_f_name.name}")
54
  pdf_images.save(tmp_f_name.name, 'PNG')
55
  st.session_state.messages.append({"role": "ai", "content": tmp_f_name.name})
56
- print("Successfully converted PDF to images")
57
 
58
  def update_proofs(proofs):
59
  if len(proofs):
60
  proofs = proofs[-1]
61
  for it, (proof, source) in enumerate(zip(proofs["justifications"], proofs["sources"])):
 
62
  limited_content = f"[{it+1}] - {proof[:min(PROOF_LIMIT_SIZE, len(proof))]} ..."
63
  st.button(limited_content, on_click=click_proof, use_container_width=True, kwargs={"lien": source})
64
 
@@ -108,7 +113,7 @@ with column_chat:
108
  with st.chat_message("user"):
109
  st.markdown(prompt)
110
  placeholder = st.empty()
111
- placeholder.status("Wow c'est chaud ! Gros 2s je réfléchis...", expanded=False)
112
  response = get_llm_response(prompt)
113
  st.session_state.messages.append({"role": "assistant", "content": response["content"]})
114
  st.session_state.proofs.append({"justifications": response["justifications"], "sources": response["sources"]})
 
41
  if stemed_fn == Path(lien).stem:
42
  path_to_file = Path(f["internal-link"])
43
  if path_to_file and path_to_file.is_file():
44
+ page_num = lien.split("PAGENUMBER")
45
+ if len(page_num) == 2:
46
+ page_num = int(page_num[1])
47
+ else:
48
+ page_num = 0
49
+ show_pdf(path_to_file, page_num)
50
  else:
51
  print(f"File {path_to_file} not found")
52
  with column_proof:
53
  update_proofs(st.session_state.proofs)
54
 
55
+ def show_pdf(link, page_num):
56
+ pdf_images = convert_from_path(link)[page_num]
57
  tmp_f_name = NamedTemporaryFile(delete=False)
 
58
  pdf_images.save(tmp_f_name.name, 'PNG')
59
  st.session_state.messages.append({"role": "ai", "content": tmp_f_name.name})
60
+ print(f"Successfully converted PDF ({link} page {page_num}) to images ({tmp_f_name.name})")
61
 
62
  def update_proofs(proofs):
63
  if len(proofs):
64
  proofs = proofs[-1]
65
  for it, (proof, source) in enumerate(zip(proofs["justifications"], proofs["sources"])):
66
+ print(source)
67
  limited_content = f"[{it+1}] - {proof[:min(PROOF_LIMIT_SIZE, len(proof))]} ..."
68
  st.button(limited_content, on_click=click_proof, use_container_width=True, kwargs={"lien": source})
69
 
 
113
  with st.chat_message("user"):
114
  st.markdown(prompt)
115
  placeholder = st.empty()
116
+ placeholder.status("Veuillez patienter ...", expanded=False)
117
  response = get_llm_response(prompt)
118
  st.session_state.messages.append({"role": "assistant", "content": response["content"]})
119
  st.session_state.proofs.append({"justifications": response["justifications"], "sources": response["sources"]})
chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/data_level0.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8ae79625c27cd89b5988ac75f2d945a859ecf7437cdd55c429bff55bb6250c21
3
+ size 4236000
chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/header.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d23badaeebfac293e1198b40bc8264c0e5f9ed2167be6396afab0aa4ad1ebdd1
3
+ size 100
chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/index_metadata.pickle ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aae650aec0e8056432ec91d10d2f604a9fe3a3e85a3639926254a784801967e7
3
+ size 55974
chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/length.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd0a1b11ae57eaf76b9d48df0a272d3f4d73424bf9fdc27fdd8865843e5c587f
3
+ size 4000
chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/link_lists.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:507b234e54872bade578cb7e03f0f97376a20c2df98490aab4e945b2d479f160
3
+ size 8148
chroma_db/chroma.sqlite3 CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:83a6a141f2dc2946d859c73c75757c467074fd8f2e8b44dd4e11c1194f2e7320
3
- size 18763776
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0863eeca4875e96dffff8ba34525e16a348f06f4a7fc45bd99cfd96e3dbb233c
3
+ size 15695872
core.py CHANGED
@@ -4,25 +4,18 @@ os.environ["REQUESTS_CA_BUNDLE"] = ""
4
  from llama_index.core import (
5
  VectorStoreIndex,
6
  )
7
- import io
8
 
9
  import chromadb
10
- from tqdm import tqdm
11
  from llama_index.llms.mistralai import MistralAI
12
  from llama_index.embeddings.mistralai import MistralAIEmbedding
13
  from llama_index.vector_stores.chroma import ChromaVectorStore
14
  from llama_index.core.storage.storage_context import StorageContext
15
  from llama_index.core import ServiceContext
16
- from llama_index.core import Document
17
  from llama_index.core.retrievers import VectorIndexRetriever
18
- from pathlib import Path
19
 
20
- import pandas as pd
21
  import tenacity
22
- from pdfminer.high_level import extract_pages
23
- from pdfminer.layout import LTChar, LTTextLine
24
  from typing import List, Union
25
-
26
  import dspy
27
  from dsp.utils import dotdict
28
  from dsp.modules.lm import LM
@@ -33,57 +26,6 @@ EMBEDDING_MODEL_NAME = "mistral-embed"
33
  COMPLETION_MODEL_NAME = "mistral-medium"
34
  PERSISTANT_DB_PATH = "./chroma_db"
35
 
36
- def parse_df(dataframe: pd.DataFrame, source_name: str) -> List:
37
- docs = []
38
-
39
- for _, row in dataframe.iterrows():
40
- strs = []
41
- for k, v in row.items():
42
- if k is None or v is None:
43
- continue
44
- strs.append(f"{str(k).strip()}: {str(v).strip()}")
45
- content = ", ".join(strs)
46
-
47
- doc = Document(text=content, extra_info={"source_name": source_name})
48
- docs.append(doc)
49
-
50
- return docs
51
-
52
- def parse_elem_list(elem) -> List:
53
- if isinstance(elem, LTTextLine) or isinstance(elem, LTChar):
54
- return [elem]
55
- try:
56
- return sum((parse_elem_list(x) for x in elem), [])
57
- except TypeError:
58
- return []
59
-
60
-
61
- def sort_elem_list(elem_list):
62
- return sorted(elem_list, key=lambda x: (-x.y0, x.x0))
63
-
64
-
65
- def get_text(elem_list) -> str:
66
- return "".join(elem.get_text() for elem in elem_list)
67
-
68
-
69
- def parse_pages(f: io.IOBase) -> List[str]:
70
- data = extract_pages(f)
71
- pages = [get_text(sort_elem_list(parse_elem_list(page))) for page in data]
72
-
73
- return pages
74
-
75
- def parse_pdf(pdf_path: Path, source_name: str=None):
76
- with open(pdf_path, "rb") as fd:
77
- pages = parse_pages(fd)
78
-
79
- docs = []
80
- for page in pages:
81
- sub_pages = page.split("\n \n")
82
- for sub_page in sub_pages:
83
- docs.append(Document(text=sub_page.replace("\n", " "), extra_info={"source_name": source_name}))
84
-
85
- return docs
86
-
87
  def deduplicate_with_sources(seq: list[str], sources: list[str]) -> list[str]:
88
  final_context = []
89
  final_sources = []
@@ -130,7 +72,6 @@ class SimplifiedBaleen(dspy.Module):
130
 
131
  for hop in range(self.max_hops):
132
  query = self.generate_query[hop](contexte=context, question=question).requete
133
- print(f"\t hop {hop} query => ", query)
134
  retriever_output = self.retrieve(query)
135
  passages, current_sources = retriever_output
136
  passages = passages.passages
@@ -180,22 +121,6 @@ class DspyMistralWrapper(LM):
180
 
181
  def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs):
182
  return [self.basic_request(prompt=prompt)]
183
-
184
- def index_data_files(index):
185
- # create client and a new collection
186
- docs = []
187
- print("Parsing docs...")
188
- for doc_path in tqdm(Path(r"./").glob("**/*.pdf")):
189
- docs.extend(parse_pdf(doc_path, doc_path.name))
190
- print("done")
191
-
192
- print(len(docs), docs[0].extra_info)
193
- print("Indexing docs...")
194
- for doc in tqdm(docs):
195
- index.insert(doc)
196
- print("done")
197
- print("Database created")
198
-
199
 
200
  def init_llm(persistant_db_path=PERSISTANT_DB_PATH):
201
  llm = MistralAI(api_key=MISTRAL_API_KEY, model=COMPLETION_MODEL_NAME, temperature=0, max_tokens=10000)
@@ -214,9 +139,6 @@ def init_llm(persistant_db_path=PERSISTANT_DB_PATH):
214
  [], service_context=service_context, storage_context=storage_context
215
  )
216
 
217
- if not Path(persistant_db_path).is_dir():
218
- index_data_files(index)
219
-
220
  retriever = ChromaDBRetriever(vector_store_index=index)
221
 
222
  dspy_llm = DspyMistralWrapper(llm_model=llm)
@@ -224,20 +146,20 @@ def init_llm(persistant_db_path=PERSISTANT_DB_PATH):
224
  dspy.settings.configure(lm=dspy_llm, rm=retriever)
225
 
226
  def invoke(input_prompt:str):
227
- # uncompiled_baleen = SimplifiedBaleen(passages_per_hop=5, max_hops=2)
228
- # predictions, justifications, sources = uncompiled_baleen(input_prompt)
229
- # content = " ".join(textwrap.wrap(predictions.answer))
230
- import time
231
- time.sleep(0.2)
232
- content = "Le numéro d'identification d'un bovin en France est composé de 12 chiffres. Les deux premiers chiffres représentent le code pays "FR" ([1]). Les deux chiffres suivants correspondent au numéro de code INSEE du département où se trouve l'animal au moment de son identification ([2]). Les huit chiffres restants sont attribués sous la responsabilité de l'établissement de l'élevage ([2]). Pour les bovins identifiés en France après le 1er septembre 1998, le numéro de travail est composé des 4 derniers chiffres du numéro national ([1])."
233
- justifications = [
234
- "Pour les bovins identifiés en France (naissance ou import), le code pays est 'FR'. 2.3.1.2 Numéro national Le numéro national est défini par l’article 23 du présent arrêté. 2.3.1.3 Numéro de travail Pour les bovins identifiés en France après le 1er septembre 1998, le numéro de travail est composé obligatoirement des 4 derniers chiffres du numéro national.",
235
- "26/02/2024 11:45 Arrêté du 6 août 2013 relatif à l'identification des animaux de l'espèce bovine - Légifrance Le numéro national d'identification porté par la marque auriculaire agréée est un numéro national exclusif qui n'a pas encore été attribué et ne sera ultérieurement attribué à aucun autre animal. Il est attribué pour toute la vie de l'animal et ne peut pas être modifié. Il est composé de dix chiffres et précédé, pour les animaux identifiés en France, du code pays FR ; les deux premiers chiffres de gauche représentent le numéro de code INSEE du département où se trouve l'animal au moment de son identification ; l'attribution des huit chiffres suivants est effectuée sous la responsabilité de l'établissement de l'élevage. Article 24 L'établissement de l'élevage est chargé : ― de la gestion de l'attribution et de l'unicité des numéros nationaux d'identification attribués au sein de sa circonscription ; de la gestion des commandes des marques auriculaires agréées pour sa circonscription ; ― de la gestion de la livraison des marques auriculaires agréées ; ― de l'attribution à chaque éleveur-naisseur d'un lot de marques auriculaires agréées et du suivi de l'utilisation de ce lot ; de la vérification du stock de marques auriculaires agréées détenu par un détenteur ; de l'attribution à chaque agent identificateur habilité d'un lot de marques auriculaires agréées et du suivi de l'utilisation de ce lot ; ― de la vérification du stock de marques auriculaires agréées détenu par un agent identificateur habilité. Le maître d'œuvre de l'identification est tenu d'assurer un suivi de toutes les marques auriculaires agréées commandées, gardées en stock dans son organisme, délivrées à chaque détenteur et à chaque agent identificateur habilité, utilisées, récupérées, inutilisables, perdues ou détruites. Toute anomalie lors de ce suivi doit faire l'objet d'un rapport détaillé du maître d'œuvre de l'identification, transmis au directeur en charge de la protection des populations et au directeur départemental en charge des territoires. Sans préjudice des actions encourues au titre de du code pénal, tout dysfonctionnement constaté dans ce suivi peut donner lieu à la suspension ou au retrait de l'agrément de l'établissement de l'élevage, tel que prévu à l'article R. 653-43 du code rural et de la pêche maritime. Modifié par Arrêté du 3 avril 2023 - art. 1 Article 25 Les détenteurs d'animaux sont autorisés à obtenir à l'avance, s'ils le souhaitent, une quantité de marques auriculaires agréés proportionnée à leurs besoins pour une période maximale d'un an. Dans ce cas, le maître d'œuvre de l'identification valide les commandes de chaque détenteur après avoir vérifié le caractère proportionné de la demande. Chapitre IV : Modalités de notification (Articles 26 à 28) Article 26 Tout détenteur, à l'exclusion des transporteurs, ainsi que tout collecteur de cadavres de bovins est tenu de notifier : 1. Pour les exploitations d'élevage au maître d'œuvre de l'identification : les naissances ; tous les déplacements à destination et en provenance de l'exploitation ; toutes les morts d'animaux. 2. Pour les détenteurs autres que les éleveurs, selon des modalités définies en annexe du présent arrêté, au maître d'œuvre de l'identification ou au gestionnaire de la base de données nationale d'identification : 2.1. Le maître d'œuvre de l'identification assure la traçabilité de la procédure utilisée pour chacune de ses interventions. Dans le cas où cette vérification n'apporte pas les preuves de l'identité du bovin, tout autre moyen apportant la preuve de son identité peut être retenu, le résultat de cette vérification est dans ce cas validé par le responsable administratif de l'établissement de l'élevage qui informe le directeur départemental en charge de la protection des populations du moyen utilisé et du résultat de la vérification. Si les preuves de l'identité du bovin ne sont pas établies, l'agent identificateur habilité en informe l'établissement de l'élevage qui en informe le directeur départemental en charge de la protection des populations et le directeur départemental en charge des territoires. Article 20 https://www.legifrance.gouv.fr/loda/id/JORFTEXT000027876223 6/15 Depuis la mise en application du décret 98-764 du 28/08/1998 agréé est  Le marquage l’apposition, à chaque oreille, d’une boucle plastique saumon agréée comportant le même numéro national d’identification (code FR et un numéro à 10 chiffres pour un bovin français). identifié  Toutefois un bovin avant la mise en œuvre du décret 98-764 du 28/08/1998 et présenté aux échanges intra- communautaires doit être conforme au règlement (CE) n° 1760/2000 du 17/07/2000 relatif à l’identification bovine. Il doit donc présenter 2 marques auriculaires agréées comportant le même numéro national d’identification. Ainsi un « surbouclage » et une réédition de passeport peuvent être nécessaires pour ces bovins destinés à être échangés avec un autre pays de l’Union européenne."
236
- ]
237
- sources = [
238
- "Dossier-PAC-2022_notice_aides-couplees.pdf",
239
- "lien2.html",
240
- ]
241
  if not len(justifications) == len(sources):
242
  raise RuntimeError(f"Justifications ({len(justifications)}) and sources ({len(sources)}) does not have the same size")
243
  return {
 
4
  from llama_index.core import (
5
  VectorStoreIndex,
6
  )
 
7
 
8
  import chromadb
 
9
  from llama_index.llms.mistralai import MistralAI
10
  from llama_index.embeddings.mistralai import MistralAIEmbedding
11
  from llama_index.vector_stores.chroma import ChromaVectorStore
12
  from llama_index.core.storage.storage_context import StorageContext
13
  from llama_index.core import ServiceContext
 
14
  from llama_index.core.retrievers import VectorIndexRetriever
 
15
 
 
16
  import tenacity
 
 
17
  from typing import List, Union
18
+ import textwrap
19
  import dspy
20
  from dsp.utils import dotdict
21
  from dsp.modules.lm import LM
 
26
  COMPLETION_MODEL_NAME = "mistral-medium"
27
  PERSISTANT_DB_PATH = "./chroma_db"
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def deduplicate_with_sources(seq: list[str], sources: list[str]) -> list[str]:
30
  final_context = []
31
  final_sources = []
 
72
 
73
  for hop in range(self.max_hops):
74
  query = self.generate_query[hop](contexte=context, question=question).requete
 
75
  retriever_output = self.retrieve(query)
76
  passages, current_sources = retriever_output
77
  passages = passages.passages
 
121
 
122
  def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs):
123
  return [self.basic_request(prompt=prompt)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
  def init_llm(persistant_db_path=PERSISTANT_DB_PATH):
126
  llm = MistralAI(api_key=MISTRAL_API_KEY, model=COMPLETION_MODEL_NAME, temperature=0, max_tokens=10000)
 
139
  [], service_context=service_context, storage_context=storage_context
140
  )
141
 
 
 
 
142
  retriever = ChromaDBRetriever(vector_store_index=index)
143
 
144
  dspy_llm = DspyMistralWrapper(llm_model=llm)
 
146
  dspy.settings.configure(lm=dspy_llm, rm=retriever)
147
 
148
  def invoke(input_prompt:str):
149
+ uncompiled_baleen = SimplifiedBaleen(passages_per_hop=5, max_hops=2)
150
+ predictions, justifications, sources = uncompiled_baleen(input_prompt)
151
+ content = " ".join(textwrap.wrap(predictions.answer))
152
+ # import time
153
+ # time.sleep(0.2)
154
+ # content = "Le numéro d'identification d'un bovin en France est composé de 12 chiffres. Les deux premiers chiffres représentent le code pays "FR" ([1]). Les deux chiffres suivants correspondent au numéro de code INSEE du département où se trouve l'animal au moment de son identification ([2]). Les huit chiffres restants sont attribués sous la responsabilité de l'établissement de l'élevage ([2]). Pour les bovins identifiés en France après le 1er septembre 1998, le numéro de travail est composé des 4 derniers chiffres du numéro national ([1])."
155
+ # justifications = [
156
+ # "Page 20 sur 47 IDENTIFICATION Vv. BOVINE Annexe de l’arrêté du 6 août 2013 relatif à l’identification des animaux de l’espèce bovine Notification des informations 10. Notifier chaque événement dans les sept jours, à (nom du maître d'oeuvre de l'identification) : – soit en transmettant l’exemplaire du « DOCUMENT DE NOTIFICATION – REGISTRE BOVIN » prévu à cet effet ; – soit en transmettant ces informations par voie électronique, selon les modalités techniques définies par (nom du maître d'oeuvre de l'identification). 11. Notifier toute anomalie constatée sur tout document (passeport, livre des bovins, document de notification….) à (nom du maître d'oeuvre de l'identification). Pertes de marques auriculaires agréées numérotées 12. En cas de perte, de détérioration ou d’illisibilité d'une seule marque auriculaire agréée, commander à (nom du maître d'oeuvre de l'identification) une marque auriculaire agréée permettant d'avoir toujours le même numéro national sur ce bovin et l’apposer au plus vite, dans un délai maximum de trente jours après la livraison. 13. En cas de perte de détérioration ou d’illisibilité de deux marques auriculaires agréées, isoler l'animal et faire appel à (nom du maître d'oeuvre de l'identification) pour la vérification de l’identité de l'animal et le remplacement éventuel de ses marques auriculaires agréées à l'identique. En cas d'impossibilité de reconnaissance de l’identité de l'animal, ce dernier pourra être détruit sans compensation financière, conformément à la réglementation communautaire en vigueur. Circulation des animaux 14. Ne laisser entrer dans mon exploitation un bovin, ou en sortir, que correctement identifié (deux marques auriculaires agréées numérotées, passeport correctement renseigné et correspondant aux caractéristiques de l'animal). Cessation d’activité 15. Informer (nom du maître d'oeuvre de l'identification) de ma cessation d'activité. Restitution du matériel d'identification 16. Restituer à (nom du maître d'oeuvre de l'identification), en cas de cessation d'activité, ou à sa demande, la totalité des marques d'identification et des passeports dont je dispose. Dispositions générales 17. Sur demande d'un agent mandaté par l'établissement de l'élevage ou par (nom du maître d'oeuvre de l'identification) le cas échéant ou de tout agent mandaté de la direction départementale en charge de la protection de la population ou de la direction départementale des territoires, communiquer toute information utile et présenter tous mes animaux, toutes les marques auriculaires agréées en stock ainsi que tous les documents d'identification dont je dispose. 18. En cas d’intervention de ces agents, faciliter l'accès à mes animaux en assurant notamment leur contention. 19. Payer à (nom du maître d'oeuvre de l'identification) les sommes dont je suis redevable pour les opérations d'identification. En cas de non-paiement, (nom du maître d’oeuvre de l’identification) peut me refuser la délivrance des passeports. 20. En cas de non-respect de mes obligations, je dois avoir recours à un agent mandaté par (nom du maître d'oeuvre de l'identification) à mes frais, pour la réalisation de l'identification des animaux de mon exploitation. 21. Je suis informé que le non-respect de mes obligations peut se traduire par la perte des primes, voire l'obligation de paiement de pénalités financières complémentaires. Date et signature. Vu le détenteur. un exemplaire signé est retourné à (nom du maître d'oeuvre de l'identification) un exemplaire est conservé par le détenteur",
157
+ # "Page 21 sur 47 IDENTIFICATION Vv. BOVINE Annexe de l’arrêté du 6 août 2013 relatif à l’identification des animaux de lespèce bovine 7.1.2 I-B. - Déclaration du détenteur-opérateur commercial auprès de l'établissement départemental/interdépartemental de l'élevage *** Préciser dans le texte l'organisme qui assure la maîtrise d'oeuvre de l'identification*** Je soussigné, M. ..., détenteur, agissant en mon nom propre / agissant en tant que responsable de (nom de la personne morale)…………… déclare avoir pris connaissance de l'obligation qui m'est faite d'accomplir les opérations d'identification des bovins, détenus sur mon exploitation ……....., telles que prévues par la réglementation communautaire et nationale en vigueur. Ces obligations portent plus particulièrement sur les points suivants : Gestion des marques auriculaires agréées numérotées et des documents d'identification 1. Notifier à (nom du maître d'oeuvre de l'identification) toute perte de documents d'identification. 2. Ne déboucler sous aucun prétexte quelque animal que ce soit. Tenue du registre 3. Inscrire sur le registre des bovins chaque événement : naissance, entrée, sortie ou mort. Remarque : dans le cas particulier d’une naissance, l’apposition des marques auriculaires sur l’animal, réalisée par l’EdE, s’effectue avant l’enregistrement de la naissance sur le registre. Le registre des bovins peut être tenu : ou en utilisant les documents de notification mis à disposition par (nom du maître d'oeuvre de l'identification) ; ou en utilisant le registre fiscal, ou sur support électronique. Dans ce dernier cas, le registre doit pouvoir être présenté sur demande d’un agent identificateur désigné par l’EdE, d’un agent mandaté par la direction départementale de la protection de la population ou d’un agent mandaté par la direction départementale des territoires. 4. Vérifier que le registre des bovins contient l'ensemble des informations d'identification, tenues à jour, concernant mon exploitation. 5. Conserver dans le registre des bovins au minimum, les informations des trois dernières années. Notification des informations 6. Notifier chaque événement dans les sept jours : soit en transmettant à (nom du maître d'oeuvre de l'identification) un exemplaire du support papier du registre ; soit en transmettant ces informations par voie électronique, selon les modalités techniques définies par (nom du maître d'oeuvre de l'identification). 7. Notifier toute anomalie constatée sur tout document (passeport, livre des bovins, document de notification….) à (nom du maître d'oeuvre de l'identification). Pertes de marques auriculaires agréées numérotées 8. Notifier toute perte, détérioration ou illisibilité de marques auriculaires agréées à (nom du maître d'oeuvre de l'identification). Un agent identificateur habilité vérifiera l'identité de l'animal et effectuera le remplacement éventuel des marques auriculaires agréées à l'identique. En cas d'impossibilité de reconnaissance de l'identité de l'animal, ce dernier pourra être détruit sans compensation financière, conformément à la réglementation communautaire en vigueur. z- | Liberd + Egalté » Fraternlté REPUBLIQUE FRANCAISE Annexe v1.2"
158
+ # ]
159
+ # sources = [
160
+ # "Dossier-PAC-2022_notice_ICHN.pdfPAGENUMBER2",
161
+ # "lien2.html",
162
+ # ]
163
  if not len(justifications) == len(sources):
164
  raise RuntimeError(f"Justifications ({len(justifications)}) and sources ({len(sources)}) does not have the same size")
165
  return {