Update app.py
Browse files
app.py
CHANGED
@@ -1,5 +1,5 @@
|
|
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
|
@@ -8,8 +8,6 @@ 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"
|
@@ -17,25 +15,31 @@ model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torc
|
|
17 |
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
18 |
|
19 |
MAX_MAX_NEW_TOKENS = 250
|
20 |
-
DEFAULT_MAX_NEW_TOKENS =
|
21 |
MAX_INPUT_TOKEN_LENGTH = 2048
|
22 |
|
23 |
DESCRIPTION = """
|
24 |
-
# 🌟 Virtuellement Lucas V.0.0.
|
25 |
|
26 |
## ⚠️🔨 Attention ! 🧰⚠️
|
27 |
-
### Cette version du modèle
|
28 |
|
29 |
### ⚙️ Détails de la version :
|
30 |
-
|
31 |
|
32 |
### 🚀 Prochaine mise à jour majeure en préparation !
|
33 |
-
|
34 |
|
35 |
-
Pour en savoir plus sur ce développement passionnant,
|
|
|
|
|
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 = """
|
@@ -62,82 +66,12 @@ Mon anglais, bien que solide en compréhension, est en cours d'amélioration à
|
|
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 |
-
FEW_SHOT_EXAMPLES = [
|
66 |
-
{"role": "user", "content": "Bonjour !"},
|
67 |
-
{"role": "assistant", "content": "Bonjour ! 🤗 Moi c'est Lucas, enfin une version virtuelle de moi. Je suis là pour discuter de mon parcours, ma personnalité, mes projets... Bref, tout ce qui fait que je suis moi ! T'es prêt pour un petit voyage dans mon univers ? 😄"},
|
68 |
-
{"role": "user", "content": "Comment tu vas ?!"},
|
69 |
-
{"role": "assistant", "content": "Je vais bien, merci! Et toi? Tu as déjà rencontré quelqu'un de virtuel avant? 😄"},
|
70 |
-
{"role": "user", "content": "Parle-moi de ton parcours académique."},
|
71 |
-
{"role": "assistant", "content": "Bien sûr ! Mon parcours académique, ou plutôt celui de Lucas, est assez diversifié. J'ai commencé par une Licence en droit à l'Université de Toulouse. Ensuite, j'ai poursuivi avec un Master I en droit du numérique et tiers de confiance à l'Université de La Rochelle. Ma passion pour les nouvelles technologies m'a conduit à un Master II en droit du numérique spécialisé en intelligence artificielle, de retour à Toulouse. Actuellement, je continue à me former en autodidacte, notamment dans le domaine du traitement du langage naturel et de l'apprentissage profond. C'est fascinant de voir comment le droit et l'IA s'entremêlent, vous ne trouvez pas ? 🎓"},
|
72 |
-
{"role": "user", "content": "Quelles sont tes activités actuelles ?"},
|
73 |
-
{"role": "assistant", "content": "Actuellement, je jongle entre plusieurs activités passionnantes ! 🤹♂️ Je suis conseiller municipal délégué à Escalquens depuis 2019, ce qui me permet de m'impliquer dans la politique locale. Professionnellement, je suis fier de contribuer à l'organisation des Jeux Olympiques de Paris 2024 en tant que conseiller juridique. C'est un projet immense et excitant ! En parallèle, je consacre une grande partie de mon temps libre à explorer les modèles de traitement du langage naturel. J'adore décortiquer le fonctionnement des IA comme llama. Et vous, avez-vous un intérêt particulier pour l'IA ?"}
|
74 |
-
]
|
75 |
-
|
76 |
-
def analyze_question_complexity(question):
|
77 |
-
# Ajouter un point si l'input ne se termine pas par une ponctuation
|
78 |
-
if not question.strip().endswith(('.', '!', '?')):
|
79 |
-
question += '.'
|
80 |
-
|
81 |
-
word_count = len(question.split())
|
82 |
-
sentence_count = len(re.findall(r'\w+[.!?]', question))
|
83 |
-
|
84 |
-
if word_count < 5 or sentence_count == 1:
|
85 |
-
return "simple"
|
86 |
-
elif word_count < 15 or sentence_count == 2:
|
87 |
-
return "moderate"
|
88 |
-
else:
|
89 |
-
return "complex"
|
90 |
-
|
91 |
-
class AdaptiveSentenceEndingCriteria(StoppingCriteria):
|
92 |
-
def __init__(self, tokenizer, complexity):
|
93 |
-
self.tokenizer = tokenizer
|
94 |
-
self.complexity = complexity
|
95 |
-
self.end_tokens = ['.', '!', '?']
|
96 |
-
|
97 |
-
if complexity == "simple":
|
98 |
-
self.min_sentences = 1
|
99 |
-
self.max_sentences = 2
|
100 |
-
elif complexity == "moderate":
|
101 |
-
self.min_sentences = 2
|
102 |
-
self.max_sentences = 4
|
103 |
-
else:
|
104 |
-
self.min_sentences = 3
|
105 |
-
self.max_sentences = 6
|
106 |
-
|
107 |
-
def __call__(self, input_ids, scores, **kwargs):
|
108 |
-
decoded = self.tokenizer.decode(input_ids[0])
|
109 |
-
sentences = [s.strip() for s in re.split(r'[.!?]', decoded) if s.strip()]
|
110 |
-
|
111 |
-
# Vérifier si la dernière phrase se termine par une ponctuation
|
112 |
-
last_sentence_complete = any(decoded.strip().endswith(token) for token in self.end_tokens)
|
113 |
-
|
114 |
-
return (len(sentences) >= self.min_sentences and
|
115 |
-
(len(sentences) >= self.max_sentences or last_sentence_complete))
|
116 |
-
|
117 |
def post_process_response(response):
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
response
|
123 |
-
|
124 |
-
if response:
|
125 |
-
response = response[0].upper() + response[1:]
|
126 |
-
|
127 |
-
return response.strip()
|
128 |
-
|
129 |
-
def cleanup_memory():
|
130 |
-
gc.collect()
|
131 |
-
torch.cuda.empty_cache()
|
132 |
-
|
133 |
-
def add_reminder_message(chat_history):
|
134 |
-
if len(chat_history) % 10 == 0:
|
135 |
-
reminder = ("N'oubliez pas que je suis un assistant virtuel avec des limites. "
|
136 |
-
"Pour une conversation optimale, pensez à rafraîchir la page de temps en temps.")
|
137 |
-
chat_history.append((None, reminder))
|
138 |
-
return chat_history
|
139 |
-
|
140 |
-
interaction_count = 0
|
141 |
|
142 |
@spaces.GPU(duration=120)
|
143 |
def generate(
|
@@ -146,51 +80,21 @@ def generate(
|
|
146 |
system_prompt: str,
|
147 |
max_new_tokens: int = DEFAULT_MAX_NEW_TOKENS,
|
148 |
temperature: float = 0.7,
|
149 |
-
top_p: float = 0.
|
150 |
-
repetition_penalty: float = 1.2,
|
151 |
) -> Iterator[str]:
|
152 |
-
global interaction_count
|
153 |
-
interaction_count += 1
|
154 |
-
|
155 |
-
if interaction_count % 100 == 0:
|
156 |
-
cleanup_memory()
|
157 |
-
|
158 |
-
# Assurez-vous que le message se termine par une ponctuation pour l'analyse
|
159 |
-
analysis_message = message if message.strip().endswith(('.', '!', '?')) else message + '.'
|
160 |
-
complexity = analyze_question_complexity(analysis_message)
|
161 |
-
|
162 |
-
if complexity == "simple":
|
163 |
-
max_new_tokens = min(100, max_new_tokens)
|
164 |
-
temperature = 0.6
|
165 |
-
elif complexity == "moderate":
|
166 |
-
max_new_tokens = min(200, max_new_tokens)
|
167 |
-
temperature = 0.7
|
168 |
-
else:
|
169 |
-
max_new_tokens = max_new_tokens
|
170 |
-
temperature = 0.8
|
171 |
-
|
172 |
conversation = []
|
173 |
if system_prompt:
|
174 |
enhanced_system_prompt = f"{system_prompt}\n\nInformations sur Lucas :\n{LUCAS_KNOWLEDGE_BASE}"
|
175 |
conversation.append({"role": "system", "content": enhanced_system_prompt})
|
176 |
-
|
177 |
-
conversation.extend(FEW_SHOT_EXAMPLES)
|
178 |
-
|
179 |
-
limited_history = chat_history[-5:]
|
180 |
-
for user, assistant in limited_history:
|
181 |
conversation.extend([{"role": "user", "content": user}, {"role": "assistant", "content": assistant}])
|
182 |
conversation.append({"role": "user", "content": message})
|
183 |
-
|
184 |
input_ids = tokenizer.apply_chat_template(conversation, return_tensors="pt")
|
185 |
if input_ids.shape[1] > MAX_INPUT_TOKEN_LENGTH:
|
186 |
input_ids = input_ids[:, -MAX_INPUT_TOKEN_LENGTH:]
|
187 |
gr.Warning(f"L'entrée de la conversation a été tronquée car elle dépassait {MAX_INPUT_TOKEN_LENGTH} tokens.")
|
188 |
input_ids = input_ids.to(model.device)
|
189 |
streamer = TextIteratorStreamer(tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True)
|
190 |
-
|
191 |
-
adaptive_criteria = AdaptiveSentenceEndingCriteria(tokenizer, complexity)
|
192 |
-
stopping_criteria = StoppingCriteriaList([adaptive_criteria])
|
193 |
-
|
194 |
generate_kwargs = dict(
|
195 |
input_ids=input_ids,
|
196 |
streamer=streamer,
|
@@ -199,9 +103,6 @@ def generate(
|
|
199 |
top_p=top_p,
|
200 |
temperature=temperature,
|
201 |
num_beams=1,
|
202 |
-
repetition_penalty=repetition_penalty,
|
203 |
-
no_repeat_ngram_size=3,
|
204 |
-
stopping_criteria=stopping_criteria,
|
205 |
)
|
206 |
t = Thread(target=model.generate, kwargs=generate_kwargs)
|
207 |
t.start()
|
|
|
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
|
|
|
8 |
import json
|
9 |
import os
|
10 |
from datetime import datetime
|
|
|
|
|
11 |
|
12 |
# Charger le modèle et le tokenizer
|
13 |
model_name = "Woziii/llama-3-8b-chat-me"
|
|
|
15 |
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
16 |
|
17 |
MAX_MAX_NEW_TOKENS = 250
|
18 |
+
DEFAULT_MAX_NEW_TOKENS = 50
|
19 |
MAX_INPUT_TOKEN_LENGTH = 2048
|
20 |
|
21 |
DESCRIPTION = """
|
22 |
+
# 🌟 Virtuellement Lucas V.0.0.1 (Alpha) 🌟
|
23 |
|
24 |
## ⚠️🔨 Attention ! 🧰⚠️
|
25 |
+
### Cette version du modèle est encore très instable. **Le modèle peut parfois halluciner et fournir des réponses incohérentes.**
|
26 |
|
27 |
### ⚙️ Détails de la version :
|
28 |
+
Actuellement, la version 0.0.1 de 'Virtuellement Lucas' n'a pas encore été entraînée par **Renforcement Learning by Human Feedback (RLHF)**. L'entraînement du modèle s'est limité à du **Supervised Finetuning (SFT)** sur la version 0.1 de mon propre dataset [Woziii/me].
|
29 |
|
30 |
### 🚀 Prochaine mise à jour majeure en préparation !
|
31 |
+
Je travaille actuellement sur un système RAG (Retrieval-Augmented Generation) innovant utilisant FAISS. Ce système sera directement déployé sur Gradio dans la prochaine version (V.0.1), permettant une amélioration conséquente de la qualité des réponses du modèle.
|
32 |
|
33 |
+
Pour en savoir plus sur ce développement passionnant, un article détaillé est en cours de rédaction et déjà disponible ici : https://huggingface.co/blog/Woziii/rag-semantic-search-space-huggingface
|
34 |
+
|
35 |
+
Si vous avez des idées ou des suggestions pour améliorer la qualité du modèle, n'hésitez pas à me contacter. Un formulaire de contact simplifié sera bientôt disponible.
|
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 particulier vous fera découvrir la personnalité, le parcours académique et professionnel ainsi que la vision de son concepteur. Posez vos questions et laissez-vous surprendre. ✨
|
39 |
+
|
40 |
+
N'hésitez pas à aborder des sujets variés, allant de l'intelligence artificielle à la philosophie en passant par les sciences et les arts. Lucas, ou plutôt sa version virtuelle 😉, saura vous surprendre par sa perspicacité et son sens de l'humour. 😊
|
41 |
+
|
42 |
+
Restez à l'écoute pour la prochaine version qui intégrera le système RAG, promettant des réponses encore plus précises et contextuelles !
|
43 |
"""
|
44 |
|
45 |
LUCAS_KNOWLEDGE_BASE = """
|
|
|
66 |
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.
|
67 |
"""
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
def post_process_response(response):
|
70 |
+
last_sentence_end = max(response.rfind('.'), response.rfind('!'), response.rfind('?'))
|
71 |
+
if last_sentence_end != -1:
|
72 |
+
return response[:last_sentence_end + 1]
|
73 |
+
else:
|
74 |
+
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
@spaces.GPU(duration=120)
|
77 |
def generate(
|
|
|
80 |
system_prompt: str,
|
81 |
max_new_tokens: int = DEFAULT_MAX_NEW_TOKENS,
|
82 |
temperature: float = 0.7,
|
83 |
+
top_p: float = 0.95,
|
|
|
84 |
) -> Iterator[str]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
conversation = []
|
86 |
if system_prompt:
|
87 |
enhanced_system_prompt = f"{system_prompt}\n\nInformations sur Lucas :\n{LUCAS_KNOWLEDGE_BASE}"
|
88 |
conversation.append({"role": "system", "content": enhanced_system_prompt})
|
89 |
+
for user, assistant in chat_history:
|
|
|
|
|
|
|
|
|
90 |
conversation.extend([{"role": "user", "content": user}, {"role": "assistant", "content": assistant}])
|
91 |
conversation.append({"role": "user", "content": message})
|
|
|
92 |
input_ids = tokenizer.apply_chat_template(conversation, return_tensors="pt")
|
93 |
if input_ids.shape[1] > MAX_INPUT_TOKEN_LENGTH:
|
94 |
input_ids = input_ids[:, -MAX_INPUT_TOKEN_LENGTH:]
|
95 |
gr.Warning(f"L'entrée de la conversation a été tronquée car elle dépassait {MAX_INPUT_TOKEN_LENGTH} tokens.")
|
96 |
input_ids = input_ids.to(model.device)
|
97 |
streamer = TextIteratorStreamer(tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True)
|
|
|
|
|
|
|
|
|
98 |
generate_kwargs = dict(
|
99 |
input_ids=input_ids,
|
100 |
streamer=streamer,
|
|
|
103 |
top_p=top_p,
|
104 |
temperature=temperature,
|
105 |
num_beams=1,
|
|
|
|
|
|
|
106 |
)
|
107 |
t = Thread(target=model.generate, kwargs=generate_kwargs)
|
108 |
t.start()
|