update code
Browse files- app.py +11 -6
- chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/data_level0.bin +3 -0
- chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/header.bin +3 -0
- chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/index_metadata.pickle +3 -0
- chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/length.bin +3 -0
- chroma_db/246e3555-7483-4eb9-8062-437e88c1bf46/link_lists.bin +3 -0
- chroma_db/chroma.sqlite3 +2 -2
- core.py +15 -93
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)[
|
| 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("
|
| 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:
|
| 3 |
-
size
|
|
|
|
| 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 |
-
|
| 228 |
-
|
| 229 |
-
|
| 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 |
-
|
| 235 |
-
|
| 236 |
-
]
|
| 237 |
-
sources = [
|
| 238 |
-
|
| 239 |
-
|
| 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 l’espè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 n° ……....., 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 {
|