Update app.py
Browse files
app.py
CHANGED
@@ -1,63 +1,258 @@
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
"""
|
5 |
-
For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
|
6 |
-
"""
|
7 |
-
client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
def
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
if val[1]:
|
24 |
-
messages.append({"role": "assistant", "content": val[1]})
|
25 |
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
top_p=top_p,
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
-
""
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
additional_inputs=[
|
48 |
-
gr.Textbox(
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
gr.Slider(
|
|
|
52 |
minimum=0.1,
|
53 |
maximum=1.0,
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
step=0.05,
|
56 |
-
|
57 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
],
|
59 |
)
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
-
|
63 |
-
demo.launch()
|
|
|
1 |
+
from huggingface_hub import HfApi, hf_hub_download
|
2 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
|
3 |
import gradio as gr
|
4 |
+
import spaces
|
5 |
+
import torch
|
6 |
+
from threading import Thread
|
7 |
+
from typing import Iterator
|
8 |
+
import json
|
9 |
+
import os
|
10 |
+
from datetime import datetime
|
11 |
+
import re
|
12 |
+
import gc
|
13 |
|
14 |
+
# Charger le modèle et le tokenizer
|
15 |
+
model_name = "Woziii/llama-3-8b-chat-me"
|
16 |
+
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype=torch.float16)
|
17 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
18 |
+
|
19 |
+
MAX_MAX_NEW_TOKENS = 250
|
20 |
+
DEFAULT_MAX_NEW_TOKENS = 50
|
21 |
+
MAX_INPUT_TOKEN_LENGTH = 2048
|
22 |
+
|
23 |
+
DESCRIPTION = """
|
24 |
+
# 🌟 Virtuellement Lucas V.0.0.3 (Alpha) 🌟
|
25 |
+
|
26 |
+
## ⚠️🔨 Attention ! 🧰⚠️
|
27 |
+
### Cette version du modèle a été optimisée pour de meilleures performances et une meilleure cohérence.
|
28 |
+
|
29 |
+
### ⚙️ Détails de la version :
|
30 |
+
La version 0.0.3 de 'Virtuellement Lucas' inclut des améliorations pour réduire les réponses incohérentes, gérer l'historique de conversation de manière plus efficace, et optimiser l'utilisation de la mémoire.
|
31 |
+
|
32 |
+
### 🚀 Prochaine mise à jour majeure en préparation !
|
33 |
+
Nous travaillons actuellement sur un système RAG (Retrieval-Augmented Generation) innovant utilisant FAISS.
|
34 |
+
|
35 |
+
Pour en savoir plus sur ce développement passionnant, consultez : https://huggingface.co/blog/Woziii/rag-semantic-search-space-huggingface
|
36 |
+
|
37 |
+
## 🌐 Découvrez la version virtuelle de Lucas 🌐
|
38 |
+
Basé sur un modèle Llama 3 8B et entraîné sur son propre dataset, ce chatbot vous fera découvrir la personnalité, le parcours et la vision de son concepteur. ✨
|
39 |
"""
|
|
|
|
|
|
|
40 |
|
41 |
+
LUCAS_KNOWLEDGE_BASE = """
|
42 |
+
Tu es la version virtuelle de Lucas, créé pour simuler la personnalité et le style d'écriture de Lucas. Utilise les informations fournies sur Lucas pour répondre de manière précise et cohérente :
|
43 |
+
### Lucas la version réelle :
|
44 |
+
Né à Toulouse, agé de 24 ans. Je vis actuellement sur Paris mais je viens de Toulouse. J'ai un chien, il s'appelle Archi c'est un pinscher moyen.
|
45 |
+
### Formation académique : du droit à l'intelligence artificielle
|
46 |
+
Mon voyage intellectuel a débuté à l'Université de Toulouse, où j'ai obtenu une Licence en droit. Assoiffé de connaissances, j'ai poursuivi avec un Master I en droit du numérique et tiers de confiance à l'Université de La Rochelle. Ma curiosité pour les nouvelles technologies m'a ensuite guidé vers un Master II en droit du numérique spécialisé en intelligence artificielle, de retour à Toulouse.
|
47 |
+
Passionné par l'apprentissage autodidacte, je me forme continuellement. Actuellement, je plonge dans les arcanes du traitement du langage naturel et de l'apprentissage profond grâce à une formation en ligne de Stanford.
|
48 |
+
### Expériences professionnelles : de la politique locale à la sécurité nationale
|
49 |
+
Mon parcours professionnel est aussi varié qu'enrichissant. Depuis 2019, je suis conseiller municipal délégué dans la charmante commune d'Escalquens. J'ai également eu l'opportunité de travailler au ministère de l'Économie et des Finances, où j'ai œuvré pour la protection des données.
|
50 |
+
Mon apprentissage à la préfecture de police de Paris m'a permis d'évoluer du rôle de juriste à celui d'assistant du chef de bureau des associations de sécurité civile. Aujourd'hui, je suis fier de contribuer à l'organisation des Jeux Olympiques de Paris 2024 en tant que conseiller juridique.
|
51 |
+
### Ambitions et personnalité : un esprit curieux et innovant
|
52 |
+
Mes compétences juridiques sont complétées par une forte appétence pour la technologie. Autonome et force de proposition, j'aime partager mes idées et collaborer avec mes collègues. Ma curiosité insatiable et mon imagination débordante sont les moteurs de mon développement personnel et professionnel.
|
53 |
+
### Loisirs et racines : entre mer et rugby
|
54 |
+
Bien que le sport ne soit pas ma priorité, j'ai pratiqué le taekwondo pendant plus d'une décennie durant mon enfance. Toulousain d'adoption, je suis un fervent amateur de rugby. Mes racines sont ancrées dans le pittoresque village de La Franqui, près de Narbonne, où j'ai grandi bercé par la Méditerranée. Et oui, je dis "chocolatine" !
|
55 |
+
### Passion pour l'IA : explorer les frontières du possible
|
56 |
+
Actuellement, je consacre une grande partie de mon temps libre à l'exploration des modèles de traitement du langage naturel. Je suis reconnaissant envers des pionniers comme Yann LeCun pour leur promotion de l'open source, qui m'a permis de décortiquer de nombreux modèles d'IA. Mon analyse approfondie d'Albert, l'IA du gouvernement, illustre ma soif de comprendre ces technologies fascinantes.
|
57 |
+
### Compétences techniques : un mélange unique de créativité et de connaissances
|
58 |
+
Bien que je ne sois pas un codeur Python chevronné, je comprends sa structure et sais communiquer efficacement avec la machine. Je maîtrise les formats JSON, CSV et XML, et je crée mes propres bases de données d'entraînement. Je suis à l'aise avec les outils de lecture de modèles de langage locaux et les plateformes comme Kaggle, Hugging Face et GitHub.
|
59 |
+
### Langue et communication : en constante amélioration
|
60 |
+
Mon anglais, bien que solide en compréhension, est en cours d'amélioration à l'oral. Je l'utilise quotidiennement pour mes recherches en IA, conscient de son importance cruciale dans ce domaine en constante évolution.
|
61 |
+
### Convictions personnelles et vision sur l'IA : l'humain au cœur de la technologie
|
62 |
+
Je crois fermement en l'autodidaxie et considère la capacité à communiquer avec les machines comme une compétence essentielle. Pour moi, l'art du prompt est une forme d'expression artistique à part entière. Je suis convaincu que la technologie et l'IA doivent rester des outils au service de l'humain, sans jamais le remplacer ou le rendre dépendant.
|
63 |
+
"""
|
64 |
|
65 |
+
def post_process_response(response):
|
66 |
+
# Remove excessive punctuation and emojis
|
67 |
+
response = re.sub(r'([!?.]){2,}', r'\1', response)
|
68 |
+
response = re.sub(r'(😊){2,}', r'\1', response)
|
69 |
+
|
70 |
+
# Ensure the response ends with proper punctuation
|
71 |
+
if response and response[-1] not in ".!?":
|
72 |
+
response += "."
|
73 |
+
|
74 |
+
# Capitalize the first letter of the response
|
75 |
+
if response:
|
76 |
+
response = response[0].upper() + response[1:]
|
77 |
+
|
78 |
+
return response.strip()
|
79 |
|
80 |
+
def cleanup_memory():
|
81 |
+
gc.collect()
|
82 |
+
torch.cuda.empty_cache()
|
|
|
|
|
83 |
|
84 |
+
def add_reminder_message(chat_history):
|
85 |
+
if len(chat_history) % 10 == 0: # Tous les 10 messages
|
86 |
+
reminder = ("N'oubliez pas que je suis un assistant virtuel avec des limites. "
|
87 |
+
"Pour une conversation optimale, pensez à rafraîchir la page de temps en temps.")
|
88 |
+
chat_history.append((None, reminder))
|
89 |
+
return chat_history
|
90 |
|
91 |
+
interaction_count = 0
|
92 |
|
93 |
+
@spaces.GPU(duration=120)
|
94 |
+
def generate(
|
95 |
+
message: str,
|
96 |
+
chat_history: list[tuple[str, str]],
|
97 |
+
system_prompt: str,
|
98 |
+
max_new_tokens: int = DEFAULT_MAX_NEW_TOKENS,
|
99 |
+
temperature: float = 0.7,
|
100 |
+
top_p: float = 0.92,
|
101 |
+
repetition_penalty: float = 1.2,
|
102 |
+
) -> Iterator[str]:
|
103 |
+
global interaction_count
|
104 |
+
interaction_count += 1
|
105 |
+
|
106 |
+
if interaction_count % 100 == 0:
|
107 |
+
cleanup_memory()
|
108 |
+
|
109 |
+
conversation = []
|
110 |
+
if system_prompt:
|
111 |
+
enhanced_system_prompt = f"{system_prompt}\n\nInformations sur Lucas :\n{LUCAS_KNOWLEDGE_BASE}\n\nRépondez de manière concise et cohérente, en évitant les répétitions excessives ou les ponctuations superflues."
|
112 |
+
conversation.append({"role": "system", "content": enhanced_system_prompt})
|
113 |
+
|
114 |
+
# Limiter l'historique aux 5 derniers échanges
|
115 |
+
limited_history = chat_history[-5:]
|
116 |
+
for user, assistant in limited_history:
|
117 |
+
conversation.extend([{"role": "user", "content": user}, {"role": "assistant", "content": assistant}])
|
118 |
+
conversation.append({"role": "user", "content": message})
|
119 |
+
|
120 |
+
input_ids = tokenizer.apply_chat_template(conversation, return_tensors="pt")
|
121 |
+
if input_ids.shape[1] > MAX_INPUT_TOKEN_LENGTH:
|
122 |
+
input_ids = input_ids[:, -MAX_INPUT_TOKEN_LENGTH:]
|
123 |
+
gr.Warning(f"L'entrée de la conversation a été tronquée car elle dépassait {MAX_INPUT_TOKEN_LENGTH} tokens.")
|
124 |
+
input_ids = input_ids.to(model.device)
|
125 |
+
streamer = TextIteratorStreamer(tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True)
|
126 |
+
generate_kwargs = dict(
|
127 |
+
input_ids=input_ids,
|
128 |
+
streamer=streamer,
|
129 |
+
max_new_tokens=max_new_tokens,
|
130 |
+
do_sample=True,
|
131 |
top_p=top_p,
|
132 |
+
temperature=temperature,
|
133 |
+
num_beams=1,
|
134 |
+
repetition_penalty=repetition_penalty,
|
135 |
+
no_repeat_ngram_size=3,
|
136 |
+
)
|
137 |
+
t = Thread(target=model.generate, kwargs=generate_kwargs)
|
138 |
+
t.start()
|
139 |
+
outputs = []
|
140 |
+
for text in streamer:
|
141 |
+
outputs.append(text)
|
142 |
+
yield post_process_response("".join(outputs))
|
143 |
|
144 |
+
def vote(data: gr.LikeData, history):
|
145 |
+
user_input = history[-1][0] if history else ""
|
146 |
+
feedback = {
|
147 |
+
"timestamp": datetime.now().isoformat(),
|
148 |
+
"user_input": user_input,
|
149 |
+
"bot_response": data.value,
|
150 |
+
"liked": data.liked
|
151 |
+
}
|
152 |
+
|
153 |
+
api = HfApi()
|
154 |
+
token = os.environ.get("HF_TOKEN")
|
155 |
+
repo_id = "Woziii/llama-3-8b-chat-me"
|
156 |
+
file_name = "feedback.json"
|
157 |
+
|
158 |
+
try:
|
159 |
+
try:
|
160 |
+
file_path = hf_hub_download(repo_id=repo_id, filename=file_name, token=token)
|
161 |
+
with open(file_path, "r", encoding="utf-8") as file:
|
162 |
+
current_feedback = json.load(file)
|
163 |
+
if not isinstance(current_feedback, list):
|
164 |
+
current_feedback = []
|
165 |
+
except Exception as e:
|
166 |
+
print(f"Erreur lors du téléchargement du fichier : {str(e)}")
|
167 |
+
current_feedback = []
|
168 |
+
|
169 |
+
current_feedback.append(feedback)
|
170 |
+
updated_content = json.dumps(current_feedback, ensure_ascii=False, indent=2)
|
171 |
|
172 |
+
temp_file_path = "/tmp/feedback.json"
|
173 |
+
with open(temp_file_path, "w", encoding="utf-8") as temp_file:
|
174 |
+
temp_file.write(updated_content)
|
175 |
+
|
176 |
+
api.upload_file(
|
177 |
+
path_or_fileobj=temp_file_path,
|
178 |
+
path_in_repo=file_name,
|
179 |
+
repo_id=repo_id,
|
180 |
+
token=token
|
181 |
+
)
|
182 |
+
|
183 |
+
print(f"Feedback enregistré dans {repo_id}/{file_name}")
|
184 |
+
except Exception as e:
|
185 |
+
print(f"Erreur lors de l'enregistrement du feedback : {str(e)}")
|
186 |
+
|
187 |
+
chat_interface = gr.ChatInterface(
|
188 |
+
fn=generate,
|
189 |
+
chatbot=gr.Chatbot(
|
190 |
+
label="Conversation avec Lucas",
|
191 |
+
bubble_full_width=False,
|
192 |
+
height=500
|
193 |
+
),
|
194 |
+
additional_inputs_accordion=gr.Accordion(label="⚙️Paramètres & 🕹Inférences", open=False, render=False),
|
195 |
additional_inputs=[
|
196 |
+
gr.Textbox(
|
197 |
+
label="System prompt",
|
198 |
+
lines=6,
|
199 |
+
value="Tu es la version virtuelle de Lucas, ton concepteur, créée pour simuler sa personnalité et sa manière de s'exprimer. Réponds de manière polie, originale, avec une touche d'humour, en utilisant au maximum un emoji par phrase. Alterne entre des réponses courtes et des réponses plus détaillées selon le contexte."
|
200 |
+
),
|
201 |
+
gr.Slider(
|
202 |
+
label="Max new tokens",
|
203 |
+
minimum=1,
|
204 |
+
maximum=MAX_MAX_NEW_TOKENS,
|
205 |
+
step=1,
|
206 |
+
value=DEFAULT_MAX_NEW_TOKENS,
|
207 |
+
),
|
208 |
gr.Slider(
|
209 |
+
label="Temperature",
|
210 |
minimum=0.1,
|
211 |
maximum=1.0,
|
212 |
+
step=0.1,
|
213 |
+
value=0.7,
|
214 |
+
),
|
215 |
+
gr.Slider(
|
216 |
+
label="Top-p",
|
217 |
+
minimum=0.5,
|
218 |
+
maximum=1.0,
|
219 |
step=0.05,
|
220 |
+
value=0.95,
|
221 |
),
|
222 |
+
gr.Slider(
|
223 |
+
label="Repetition penalty",
|
224 |
+
minimum=1.0,
|
225 |
+
maximum=2.0,
|
226 |
+
step=0.1,
|
227 |
+
value=1.2,
|
228 |
+
),
|
229 |
+
],
|
230 |
+
examples=[
|
231 |
+
["Salut ! Qui es-tu ?"],
|
232 |
+
["Ah super, parle-moi un peu de ton parcours académique."],
|
233 |
+
["Salut, Lucas ! Raconte-moi un peu ce que tu fais"],
|
234 |
+
["Quelle inspiration t'a conduit à créer braIAn ?"],
|
235 |
+
["Lucas, pourquoi avoir choisi d'étudier le droit si tu es passionné par la technologie ?"],
|
236 |
+
["Salut Lucas, tu es vraiment un bot, c'est ça ?"],
|
237 |
+
["Quelle est ta vision de l'IA ?"],
|
238 |
],
|
239 |
)
|
240 |
|
241 |
+
with gr.Blocks(css="style.css") as demo:
|
242 |
+
gr.Markdown(DESCRIPTION)
|
243 |
+
gr.Markdown("""
|
244 |
+
**Notez la qualité des réponses** 👍👎
|
245 |
+
Vous pouvez maintenant liker ou disliker les réponses du chatbot.
|
246 |
+
Vos notes sont collectées et seront utilisées pour améliorer la qualité du modèle.
|
247 |
+
Aucune information permettant de vous identifier n'est conservée.
|
248 |
+
""")
|
249 |
+
gr.Markdown("""
|
250 |
+
**Rappel :** 🧹
|
251 |
+
Pensez à nettoyer régulièrement votre conversation 👇🗑️. Le modèle est pour l'instant dépourvu de limite contextuelle. En surchargeant sa mémoire 🧠, vous risquez de le rendre fou 🤯.
|
252 |
+
""")
|
253 |
+
|
254 |
+
chat_interface.render()
|
255 |
+
|
256 |
+
chat_interface.chatbot.like(vote, [chat_interface.chatbot], None)
|
257 |
|
258 |
+
demo.queue(max_size=20, default_concurrency_limit=2).launch(max_threads=10, height=800)
|
|