Spaces:
Running
Running
Commit
·
6c15782
1
Parent(s):
44b1492
.....
Browse files- app.py +36 -10
- style.css +12 -0
- tabs/chatbot_tab.py +218 -131
- tabs/intro.py +6 -3
- translate_app.py +3 -1
app.py
CHANGED
|
@@ -17,6 +17,7 @@ else:
|
|
| 17 |
st.set_page_config (
|
| 18 |
page_title=config.TITLE,
|
| 19 |
page_icon= "assets/faviconV2.png",
|
|
|
|
| 20 |
initial_sidebar_state=st.session_state.sidebar_state
|
| 21 |
)
|
| 22 |
|
|
@@ -58,32 +59,40 @@ st.markdown(f"<style>{style}</style>", unsafe_allow_html=True)
|
|
| 58 |
TABS = OrderedDict(
|
| 59 |
[
|
| 60 |
(tr(intro.sidebar_name), intro),
|
| 61 |
-
(tr(sentence_similarity_tab.sidebar_name), sentence_similarity_tab),
|
| 62 |
-
(tr(speech2text_tab.sidebar_name), speech2text_tab),
|
| 63 |
(tr(chatbot_tab.sidebar_name), chatbot_tab),
|
|
|
|
|
|
|
| 64 |
]
|
| 65 |
)
|
| 66 |
|
| 67 |
-
# Utilisation du module translate
|
| 68 |
-
# lang_tgt = ['fr','en','af','ak','sq','de','am','en','ar','hy','as','az','ba','bm','eu','bn','be','my','bs','bg','ks','ca','ny','zh','si','ko','co','ht','hr','da','dz','gd','es','eo','et','ee','fo','fj','fi','fr','fy','gl','cy','lg','ka','el','gn','gu','ha','he','hi','hu','ig','id','iu','ga','is','it','ja','kn','kk','km','ki','rw','ky','rn','ku','lo','la','lv','li','ln','lt','lb','mk','ms','ml','dv','mg','mt','mi','mr','mn','nl','ne','no','nb','nn','oc','or','ug','ur','uz','ps','pa','fa','pl','pt','ro','ru','sm','sg','sa','sc','sr','sn','sd','sk','sl','so','st','su','sv','sw','ss','tg','tl','ty','ta','tt','cs','te','th','bo','ti','to','ts','tn','tr','tk','tw','uk','vi','wo','xh','yi']
|
| 69 |
-
# label_lang = ['Français', 'Anglais / English','Afrikaans','Akan','Albanais','Allemand / Deutsch','Amharique','Anglais','Arabe','Arménien','Assamais','Azéri','Bachkir','Bambara','Basque','Bengali','Biélorusse','Birman','Bosnien','Bulgare','Cachemiri','Catalan','Chichewa','Chinois','Cingalais','Coréen','Corse','Créolehaïtien','Croate','Danois','Dzongkha','Écossais','Espagnol / Español','Espéranto','Estonien','Ewe','Féroïen','Fidjien','Finnois','Français','Frisonoccidental','Galicien','Gallois','Ganda','Géorgien','Grecmoderne','Guarani','Gujarati','Haoussa','Hébreu','Hindi','Hongrois','Igbo','Indonésien','Inuktitut','Irlandais','Islandais','Italien / Italiano','Japonais','Kannada','Kazakh','Khmer','Kikuyu','Kinyarwanda','Kirghiz','Kirundi','Kurde','Lao','Latin','Letton','Limbourgeois','Lingala','Lituanien','Luxembourgeois','Macédonien','Malais','Malayalam','Maldivien','Malgache','Maltais','MaorideNouvelle-Zélande','Marathi','Mongol','Néerlandais / Nederlands','Népalais','Norvégien','Norvégienbokmål','Norvégiennynorsk','Occitan','Oriya','Ouïghour','Ourdou','Ouzbek','Pachto','Pendjabi','Persan','Polonais','Portugais','Roumain','Russe','Samoan','Sango','Sanskrit','Sarde','Serbe','Shona','Sindhi','Slovaque','Slovène','Somali','SothoduSud','Soundanais','Suédois','Swahili','Swati','Tadjik','Tagalog','Tahitien','Tamoul','Tatar','Tchèque','Télougou','Thaï','Tibétain','Tigrigna','Tongien','Tsonga','Tswana','Turc','Turkmène','Twi','Ukrainien','Vietnamien','Wolof','Xhosa','Yiddish']
|
| 70 |
-
|
| 71 |
# Utilisation du module deep_translator
|
| 72 |
-
lang_tgt = ['fr', 'en',
|
| 73 |
-
label_lang = ['Français',
|
|
|
|
| 74 |
|
| 75 |
-
@st.cache_data
|
| 76 |
def find_lang_label(lang_sel):
|
| 77 |
global lang_tgt, label_lang
|
| 78 |
return label_lang[lang_tgt.index(lang_sel)]
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
def run():
|
| 81 |
|
| 82 |
st.sidebar.image(
|
| 83 |
"assets/value_props_logo.png",
|
| 84 |
width=270,
|
| 85 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
with st.sidebar:
|
|
|
|
| 87 |
tab_name = option_menu(None, list(TABS.keys()),
|
| 88 |
# icons=['house', 'bi-binoculars', 'bi bi-graph-up', 'bi-chat-right-text','bi-book', 'bi-body-text'], menu_icon="cast", default_index=0,
|
| 89 |
icons=['house', 'binoculars', 'graph-up', 'search','book', 'chat-right-text','controller'], menu_icon="cast", default_index=0,
|
|
@@ -101,7 +110,24 @@ def run():
|
|
| 101 |
st.sidebar.markdown(member.sidebar_markdown(), unsafe_allow_html=True)
|
| 102 |
|
| 103 |
with st.sidebar:
|
| 104 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
tab = TABS[tab_name]
|
| 107 |
tab.run()
|
|
|
|
| 17 |
st.set_page_config (
|
| 18 |
page_title=config.TITLE,
|
| 19 |
page_icon= "assets/faviconV2.png",
|
| 20 |
+
layout="wide",
|
| 21 |
initial_sidebar_state=st.session_state.sidebar_state
|
| 22 |
)
|
| 23 |
|
|
|
|
| 59 |
TABS = OrderedDict(
|
| 60 |
[
|
| 61 |
(tr(intro.sidebar_name), intro),
|
|
|
|
|
|
|
| 62 |
(tr(chatbot_tab.sidebar_name), chatbot_tab),
|
| 63 |
+
(tr(sentence_similarity_tab.sidebar_name), sentence_similarity_tab),
|
| 64 |
+
# (tr(speech2text_tab.sidebar_name), speech2text_tab),
|
| 65 |
]
|
| 66 |
)
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
# Utilisation du module deep_translator
|
| 69 |
+
lang_tgt = ['fr', 'en','de','es', 'it', 'nl']
|
| 70 |
+
label_lang = ['Français','English','Deutsch','Español','Italiano','Nederlands']
|
| 71 |
+
label_lang_en = ['French', 'English', 'German', 'Spanish', 'Italian', 'Dutch']
|
| 72 |
|
| 73 |
+
# @st.cache_data
|
| 74 |
def find_lang_label(lang_sel):
|
| 75 |
global lang_tgt, label_lang
|
| 76 |
return label_lang[lang_tgt.index(lang_sel)]
|
| 77 |
|
| 78 |
+
# @st.cache_data
|
| 79 |
+
def find_lang_label_en(lang_sel):
|
| 80 |
+
global lang_tgt, label_lang_en
|
| 81 |
+
return label_lang_en[lang_tgt.index(lang_sel)]
|
| 82 |
+
|
| 83 |
def run():
|
| 84 |
|
| 85 |
st.sidebar.image(
|
| 86 |
"assets/value_props_logo.png",
|
| 87 |
width=270,
|
| 88 |
)
|
| 89 |
+
with st.sidebar.expander(tr("Développez moi")):
|
| 90 |
+
st.markdown(tr("""
|
| 91 |
+
Cette application vous permet de tester les futures fonctionnalités de la plateforme Value Props, et plus particulièrement « Sales Coaching ».
|
| 92 |
+
Amusez vous bien !
|
| 93 |
+
"""))
|
| 94 |
with st.sidebar:
|
| 95 |
+
|
| 96 |
tab_name = option_menu(None, list(TABS.keys()),
|
| 97 |
# icons=['house', 'bi-binoculars', 'bi bi-graph-up', 'bi-chat-right-text','bi-book', 'bi-body-text'], menu_icon="cast", default_index=0,
|
| 98 |
icons=['house', 'binoculars', 'graph-up', 'search','book', 'chat-right-text','controller'], menu_icon="cast", default_index=0,
|
|
|
|
| 110 |
st.sidebar.markdown(member.sidebar_markdown(), unsafe_allow_html=True)
|
| 111 |
|
| 112 |
with st.sidebar:
|
| 113 |
+
st.write("")
|
| 114 |
+
llm_choice = st.selectbox("LLM:",["Mistral large","OpenAI 3.5","OpenAI 4o"], label_visibility="visible")
|
| 115 |
+
if (llm_choice == "OpenAI 3.5") : st.session_state.model = "gpt-3.5-turbo"
|
| 116 |
+
elif (llm_choice == "OpenAI 4o") : st.session_state.model = "gpt-4o"
|
| 117 |
+
else: st.session_state.model = "mistral-large-latest"
|
| 118 |
+
|
| 119 |
+
if (llm_choice in ["OpenAI 3.5","OpenAI 4o"]) and ('OPENAI_API_KEY' not in st.session_state):
|
| 120 |
+
# Set OpenAI API key
|
| 121 |
+
st.sidebar.subheader("OpenAI API Key")
|
| 122 |
+
openai_api_key = st.sidebar.text_input("Enter your OpenAI API Key:", type='password')
|
| 123 |
+
if openai_api_key:
|
| 124 |
+
os.environ['OPENAI_API_KEY'] = openai_api_key
|
| 125 |
+
st.session_state['OPENAI_API_KEY'] = openai_api_key
|
| 126 |
+
st.sidebar.success("OpenAI API Key set successfully.")
|
| 127 |
+
|
| 128 |
+
with st.sidebar:
|
| 129 |
+
l = st.selectbox("langue:",lang_tgt, format_func = find_lang_label, key="Language", label_visibility="hidden")
|
| 130 |
+
st.session_state.language_label = find_lang_label_en(l)
|
| 131 |
|
| 132 |
tab = TABS[tab_name]
|
| 133 |
tab.run()
|
style.css
CHANGED
|
@@ -8,6 +8,11 @@ h2 {
|
|
| 8 |
padding-bottom: 0.5rem;
|
| 9 |
}
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
/* La ligne suivante est nécessaire à cause du module streamlit_option_menu qui "casse" les CSS suivants */
|
| 12 |
@media (prefers-color-scheme: dark) {
|
| 13 |
.st-cc {
|
|
@@ -99,6 +104,13 @@ section[data-testid="stSidebar"] .stSelectbox .st-bk {
|
|
| 99 |
background-color: #a0d3de;
|
| 100 |
}
|
| 101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
section[data-testid="stSidebar"] .stSelectbox .st-cc {
|
| 103 |
color: rgb(255, 75, 75);
|
| 104 |
font-weight: bold;
|
|
|
|
| 8 |
padding-bottom: 0.5rem;
|
| 9 |
}
|
| 10 |
|
| 11 |
+
h3 {
|
| 12 |
+
padding-bottom: 0.0rem;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
|
| 16 |
/* La ligne suivante est nécessaire à cause du module streamlit_option_menu qui "casse" les CSS suivants */
|
| 17 |
@media (prefers-color-scheme: dark) {
|
| 18 |
.st-cc {
|
|
|
|
| 104 |
background-color: #a0d3de;
|
| 105 |
}
|
| 106 |
|
| 107 |
+
.st-emotion-cache-1h9usn1{
|
| 108 |
+
font-weight: bold!important;
|
| 109 |
+
background-color: #a0d3de;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
section[data-testid="stSidebar"] .stSelectbox .st-cc {
|
| 115 |
color: rgb(255, 75, 75);
|
| 116 |
font-weight: bold;
|
tabs/chatbot_tab.py
CHANGED
|
@@ -22,6 +22,7 @@ from langchain_core.messages import BaseMessage, SystemMessage, HumanMessage, AI
|
|
| 22 |
from langgraph.graph.message import add_messages
|
| 23 |
from typing_extensions import Annotated, TypedDict
|
| 24 |
from dotenv import load_dotenv
|
|
|
|
| 25 |
|
| 26 |
import warnings
|
| 27 |
warnings.filterwarnings('ignore')
|
|
@@ -38,21 +39,14 @@ if st.session_state.Cloud != 0:
|
|
| 38 |
load_dotenv()
|
| 39 |
os.getenv("LANGCHAIN_API_KEY")
|
| 40 |
os.getenv("MISTRAL_API_KEY")
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
model = ChatMistralAI(model="mistral-large-latest")
|
| 47 |
-
# model = ChatOpenAI(model="gpt-3.5-turbo")
|
| 48 |
|
| 49 |
|
| 50 |
-
language = "French"
|
| 51 |
prompt = ChatPromptTemplate.from_messages(
|
| 52 |
[
|
| 53 |
(
|
| 54 |
"system",
|
| 55 |
-
"Répond à toutes les questions du mieux possible
|
| 56 |
),
|
| 57 |
MessagesPlaceholder(variable_name="messages"),
|
| 58 |
]
|
|
@@ -81,51 +75,117 @@ app = workflow.compile(checkpointer=memory)
|
|
| 81 |
|
| 82 |
# @st.cache_data
|
| 83 |
def init():
|
| 84 |
-
global config,thread_id, context,human_message1,ai_message1,language, app, model_speech
|
| 85 |
|
| 86 |
thread_id = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 87 |
config = {"configurable": {"thread_id": thread_id}}
|
| 88 |
model_speech = whisper.load_model("base")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
|
|
|
|
|
|
| 93 |
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
Répond à mes questions en tant que Directeur commercial désorganisé, connaissant mal le concept de proposition de valeur,
|
| 120 |
et mon équipe de vente n'est pas performante.
|
| 121 |
|
| 122 |
-
Attention: Ce n'est pas toi qui m'aide, c'est moi qui t'aide avec ma solution.
|
| 123 |
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
ai_message1 = st.text_area(label=tr("Réponse du prospect"), value=ai_message1)
|
| 129 |
messages = [
|
| 130 |
SystemMessage(content=context),
|
| 131 |
HumanMessage(content=human_message1),
|
|
@@ -134,19 +194,13 @@ Attention: Ce n'est pas toi qui m'aide, c'est moi qui t'aide avec ma solution.
|
|
| 134 |
]
|
| 135 |
|
| 136 |
|
| 137 |
-
|
| 138 |
app.invoke(
|
| 139 |
{"messages": messages, "language": language},
|
| 140 |
config,
|
| 141 |
)
|
| 142 |
-
|
| 143 |
-
st.write("**Contexte:** "+context)
|
| 144 |
-
st.write("")
|
| 145 |
-
st.write("**Human Message:** "+human_message1)
|
| 146 |
-
st.write("")
|
| 147 |
-
st.write("**AI Message:** "+ai_message1)
|
| 148 |
-
'''
|
| 149 |
st.write("")
|
|
|
|
| 150 |
return config, thread_id
|
| 151 |
|
| 152 |
# Fonction pour générer et jouer le texte en speech
|
|
@@ -175,24 +229,41 @@ def play_audio(custom_sentence, Lang_target, speed=1.0):
|
|
| 175 |
new_audio_stream_bytesio.seek(0)
|
| 176 |
|
| 177 |
# Lire l'audio dans Streamlit
|
| 178 |
-
|
|
|
|
| 179 |
|
| 180 |
|
| 181 |
|
| 182 |
def run():
|
| 183 |
-
global thread_id, config, model_speech
|
| 184 |
|
| 185 |
st.write("")
|
| 186 |
st.write("")
|
| 187 |
st.title(tr(title))
|
| 188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
chosen_id = tab_bar(data=[
|
| 190 |
TabBarItemData(id="tab1", title=tr("Initialisation"), description=tr("d'une nouvelle conversation")),
|
| 191 |
-
TabBarItemData(id="tab2", title=tr("Conversation"), description=tr("avec le prospect"))
|
|
|
|
| 192 |
default="tab1")
|
| 193 |
|
| 194 |
|
| 195 |
if (chosen_id == "tab1"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
config,thread_id = init()
|
| 197 |
query = ""
|
| 198 |
st.button(label=tr("Validez"), type="primary")
|
|
@@ -202,87 +273,103 @@ def run():
|
|
| 202 |
# On ne fait rien
|
| 203 |
except NameError:
|
| 204 |
config,thread_id = init()
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
#
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
# Read the WAV stream using wavio
|
| 223 |
-
wav = wavio.read(audio_stream_bytesio)
|
| 224 |
-
|
| 225 |
-
# Extract the audio data from the wavio.Wav object
|
| 226 |
-
audio_data = wav.data
|
| 227 |
-
|
| 228 |
-
# Convert the audio data to a NumPy array
|
| 229 |
-
audio_input = np.array(audio_data, dtype=np.float32)
|
| 230 |
-
audio_input = np.mean(audio_input, axis=1)/32768
|
| 231 |
-
|
| 232 |
-
result = model_speech.transcribe(audio_input)
|
| 233 |
-
Lang_detected = result["language"]
|
| 234 |
-
query = result["text"]
|
| 235 |
-
st.write(tr("Langue détectée")+" : "+Lang_detected)
|
| 236 |
-
|
| 237 |
-
else:
|
| 238 |
-
# Avec l'aide de la bibliothèque speech_recognition de Google
|
| 239 |
-
Lang_detected = "fr"
|
| 240 |
-
# Transcription google
|
| 241 |
-
audio_stream = sr.AudioData(audio_bytes, 32000, 2)
|
| 242 |
-
r = sr.Recognizer()
|
| 243 |
-
query = r.recognize_google(audio_stream, language = Lang_detected)
|
| 244 |
-
|
| 245 |
-
# Transcription
|
| 246 |
-
st.write("**Vendeur :** "+query)
|
| 247 |
-
st.write("")
|
| 248 |
|
| 249 |
-
if
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
# Joue l'audio
|
| 260 |
-
if language=="French": Lang_target = "fr" # Langue de la réponse
|
| 261 |
-
play_audio(custom_sentence, Lang_target, 1)
|
| 262 |
-
|
| 263 |
-
st.write("**Prospect :** "+custom_sentence)
|
| 264 |
-
|
| 265 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
|
| 273 |
-
'''
|
| 274 |
-
# Créer un espace réservé pour afficher les tokens
|
| 275 |
-
placeholder = st.empty()
|
| 276 |
-
|
| 277 |
-
for chunk, metadata in app.stream(
|
| 278 |
-
{"messages": input_messages, "language": language},
|
| 279 |
-
config,
|
| 280 |
-
stream_mode="messages",
|
| 281 |
-
):
|
| 282 |
-
if isinstance(chunk, AIMessage): # Filter to just model responses
|
| 283 |
-
# st.markdown("<span style='white-space: nowrap;'>"+"/"+chunk.content+"/"+"</span>", unsafe_allow_html=True)
|
| 284 |
-
placeholder.markdown(f"<p style='display: inline;'>{chunk.content}</p>", unsafe_allow_html=True)
|
| 285 |
-
'''
|
| 286 |
st.write("")
|
| 287 |
st.write("")
|
| 288 |
st.write("")
|
|
|
|
| 22 |
from langgraph.graph.message import add_messages
|
| 23 |
from typing_extensions import Annotated, TypedDict
|
| 24 |
from dotenv import load_dotenv
|
| 25 |
+
import time
|
| 26 |
|
| 27 |
import warnings
|
| 28 |
warnings.filterwarnings('ignore')
|
|
|
|
| 39 |
load_dotenv()
|
| 40 |
os.getenv("LANGCHAIN_API_KEY")
|
| 41 |
os.getenv("MISTRAL_API_KEY")
|
| 42 |
+
os.getenv("OPENAI_API_KEY")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
|
|
|
|
| 45 |
prompt = ChatPromptTemplate.from_messages(
|
| 46 |
[
|
| 47 |
(
|
| 48 |
"system",
|
| 49 |
+
"Répond à toutes les questions du mieux possible dans la langue {language}, même si la question est posée dans une autre langue",
|
| 50 |
),
|
| 51 |
MessagesPlaceholder(variable_name="messages"),
|
| 52 |
]
|
|
|
|
| 75 |
|
| 76 |
# @st.cache_data
|
| 77 |
def init():
|
| 78 |
+
global config,thread_id, context,human_message1,ai_message1,language, app, model_speech,language,prompt,model
|
| 79 |
|
| 80 |
thread_id = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 81 |
config = {"configurable": {"thread_id": thread_id}}
|
| 82 |
model_speech = whisper.load_model("base")
|
| 83 |
+
|
| 84 |
+
options = ["Directeur Commercial", "Directeur Général", "Directeur Marketing"]
|
| 85 |
+
translated_options = [tr(o) for o in options]
|
| 86 |
+
selected_option = st.selectbox(tr("Interlocuteur"),translated_options)
|
| 87 |
+
selected_index = translated_options.index(selected_option)
|
| 88 |
|
| 89 |
+
options2 = ["Entreprise qui commercialise des solutions (produits et ou services) B2B innovantes avec une équipe commerciale de plus de 15 personnes",
|
| 90 |
+
"Entreprise qui commercialise des solutions (produits et ou services) B2B innovantes avec une équipe commerciale de plus de 100 personnes"]
|
| 91 |
+
translated_options2 = [tr(o) for o in options2]
|
| 92 |
+
selected_option2 = st.selectbox(tr("Activité"),translated_options2)
|
| 93 |
+
selected_index2 = translated_options2.index(selected_option2)
|
| 94 |
|
| 95 |
+
options3 = ["Logiciels informatiques et d’application SaaS",
|
| 96 |
+
"Équipements et solutions industrielles",
|
| 97 |
+
"Services et conseil spécialisés"]
|
| 98 |
+
translated_options3 = [tr(o) for o in options3]
|
| 99 |
+
selected_option3 = st.selectbox(tr("Domaine d'activité"),translated_options3)
|
| 100 |
+
selected_index3 = translated_options3.index(selected_option3)
|
| 101 |
+
|
| 102 |
+
context = tr(f"""Tu es un {options[selected_index]}, mal organisé, d'une {options2[selected_index2]}.
|
| 103 |
+
Cette entreprise propose des {options3[selected_index3]}.
|
| 104 |
+
""")
|
| 105 |
+
context = st.text_area(label=tr("Résumé du Contexte (modifiable):"), value=context)
|
| 106 |
+
st.markdown('''
|
| 107 |
+
------------------------------------------------------------------------------------
|
| 108 |
+
''')
|
| 109 |
+
|
| 110 |
+
options4 = ["Il est difficile pour les forces de vente d'articuler clairement les messages de la proposition de valeur",
|
| 111 |
+
"Il est difficile d’affiner une proposition de valeur unique et pertinente de l'offre face à la concurrence qui évolue rapidement",
|
| 112 |
+
"Il est chronophage de former les forces de ventes sur la proposition de valeur et ses évolutions"
|
| 113 |
+
]
|
| 114 |
+
selected_options4 = st.multiselect(tr("Problématiques"),[tr(o) for o in options4])
|
| 115 |
+
problematique = [tr(o) for o in selected_options4]
|
| 116 |
+
markdown_text4 = tr("""
|
| 117 |
+
Les problématiques rencontrés par notre prospect (problèmes à résoudre) sont:""")
|
| 118 |
+
markdown_text4 = markdown_text4+"".join(f"\n- {o}" for o in problematique)
|
| 119 |
+
st.write(markdown_text4)
|
| 120 |
+
|
| 121 |
+
options5 = ["Former la force de ventes sur l'articulation de la proposition de valeur",
|
| 122 |
+
"Aligner les messages marketing et commerciaux",
|
| 123 |
+
"Affiner et modéliser la proposition de valeur",
|
| 124 |
+
"Mettre en oeuvre des meilleures pratiques commerciales"
|
| 125 |
+
]
|
| 126 |
+
selected_options5 = st.multiselect(tr("Processus"),[tr(o) for o in options5])
|
| 127 |
+
processus = [tr(o) for o in selected_options5]
|
| 128 |
+
markdown_text5 = tr("""
|
| 129 |
+
\nLes processus adressés par le prospect (cas d’usages) sont:""")
|
| 130 |
+
markdown_text5 = markdown_text5+"".join(f"\n- {o}" for o in processus)
|
| 131 |
+
st.write(markdown_text5)
|
| 132 |
+
|
| 133 |
+
options6 = ["Augmenter les performances commerciales",
|
| 134 |
+
"Croissance du chiffre d’affaires",
|
| 135 |
+
"Réduire les cycles de vente",
|
| 136 |
+
"Augmenter taux de conversion d’affaires gagnées",
|
| 137 |
+
"Améliorer l’efficience et la confiance des forces de ventes",
|
| 138 |
+
"Réduire temps de monté en compétence des nouvelles embauches",
|
| 139 |
+
"Fidéliser les clients"
|
| 140 |
+
]
|
| 141 |
+
selected_options6 = st.multiselect(tr("Objectifs d'amélioration"),[tr(o) for o in options6])
|
| 142 |
+
objectifs = [tr(o) for o in selected_options6]
|
| 143 |
+
markdown_text6 = tr("""
|
| 144 |
+
\nLes objectifs d’amélioration opérationnelle du prospect (Valeur ajoutée) sont:""")
|
| 145 |
+
markdown_text6 = markdown_text6+"".join(f"\n- {o}" for o in objectifs)
|
| 146 |
+
st.write(markdown_text6)
|
| 147 |
+
|
| 148 |
+
options7 = ["Gestion de contenu commercial avec logiciel Microsoft sharePoint ou GoogleDrive",
|
| 149 |
+
"Playbook développé en interne sur outils génériques tels que logiciel Notion, Powerpoint, Excel, Word, Docs",
|
| 150 |
+
"Outils de sales enablement tels que application Seismic",
|
| 151 |
+
"Outils de gestion des présentations clients tels que Logiciel Powerpoint ou Google slide",
|
| 152 |
+
"Conseil externe en positionnement marché & produit",
|
| 153 |
+
"Services externes de formation des équipes commerciales"
|
| 154 |
+
]
|
| 155 |
+
selected_options7 = st.multiselect(tr("Solutions utilisées"),[tr(o) for o in options7])
|
| 156 |
+
solutions_utilisees = [tr(o) for o in selected_options7]
|
| 157 |
+
markdown_text7 = tr("""
|
| 158 |
+
\nLes principales Solutions utilisées par nos prospects pour traiter les cas d’usages (Catégories de solutions du marché) sont:""")
|
| 159 |
+
markdown_text7 = markdown_text7+"".join(f"\n- {o}" for o in solutions_utilisees)
|
| 160 |
+
st.write(markdown_text7)
|
| 161 |
+
st.write("")
|
| 162 |
+
col1, col2, col3 = st.columns(3)
|
| 163 |
+
with col1:
|
| 164 |
+
virulence = st.slider(tr("Virulence (choisissez une valeur entre 1 et 5)"), min_value=1, max_value=5, step=1)
|
| 165 |
+
markdown_text8 = tr(f"""\nTu vas utiliser une échelle de 1 à 5 de virulence. Pour cette simulation utilise le niveaux {virulence}""")
|
| 166 |
+
|
| 167 |
+
human_message1 = tr("""Je souhaites que nous ayons une conversation verbale entre un commercial de mon entreprise, et toi que je prospecte.
|
| 168 |
+
Mon entreprise propose une solution logicielle pour gérer la proposition de valeur d’entreprises B2B qui commercialises des solutions technologiques.
|
| 169 |
+
""")+markdown_text4+markdown_text5+markdown_text6+markdown_text7+tr("""
|
| 170 |
+
|
| 171 |
+
Je suis le vendeur.
|
| 172 |
Répond à mes questions en tant que Directeur commercial désorganisé, connaissant mal le concept de proposition de valeur,
|
| 173 |
et mon équipe de vente n'est pas performante.
|
| 174 |
|
| 175 |
+
Attention: Ce n'est pas toi qui m'aide, c'est moi qui t'aide avec ma solution.
|
| 176 |
+
|
| 177 |
+
""")+markdown_text8
|
| 178 |
+
|
| 179 |
+
human_message1 = st.text_area(label=tr("Consigne"), value=tr(human_message1),height=300)
|
| 180 |
+
st.markdown('''
|
| 181 |
+
------------------------------------------------------------------------------------
|
| 182 |
+
''')
|
| 183 |
+
|
| 184 |
+
ai_message1 = tr(f"J'ai bien compris, je suis un {options[selected_index]} prospecté et je réponds seulement à tes questions. Je réponds à une seule question à la fois, sans commencer mes réponses par 'En tant que {options[selected_index]}'")
|
| 185 |
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
# ai_message1 = st.text_area(label=tr("Réponse du prospect"), value=ai_message1)
|
| 189 |
messages = [
|
| 190 |
SystemMessage(content=context),
|
| 191 |
HumanMessage(content=human_message1),
|
|
|
|
| 194 |
]
|
| 195 |
|
| 196 |
|
|
|
|
| 197 |
app.invoke(
|
| 198 |
{"messages": messages, "language": language},
|
| 199 |
config,
|
| 200 |
)
|
| 201 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
st.write("")
|
| 203 |
+
st.session_state.messages = []
|
| 204 |
return config, thread_id
|
| 205 |
|
| 206 |
# Fonction pour générer et jouer le texte en speech
|
|
|
|
| 229 |
new_audio_stream_bytesio.seek(0)
|
| 230 |
|
| 231 |
# Lire l'audio dans Streamlit
|
| 232 |
+
time.sleep(2)
|
| 233 |
+
st.audio(new_audio_stream_bytesio, start_time=0, autoplay=True)
|
| 234 |
|
| 235 |
|
| 236 |
|
| 237 |
def run():
|
| 238 |
+
global thread_id, config, model_speech, language,prompt,model
|
| 239 |
|
| 240 |
st.write("")
|
| 241 |
st.write("")
|
| 242 |
st.title(tr(title))
|
| 243 |
|
| 244 |
+
if 'language_label' in st.session_state:
|
| 245 |
+
language = st.session_state['language_label']
|
| 246 |
+
else: language = "French"
|
| 247 |
+
|
| 248 |
chosen_id = tab_bar(data=[
|
| 249 |
TabBarItemData(id="tab1", title=tr("Initialisation"), description=tr("d'une nouvelle conversation")),
|
| 250 |
+
TabBarItemData(id="tab2", title=tr("Conversation"), description=tr("avec le prospect")),
|
| 251 |
+
TabBarItemData(id="tab3", title=tr("Evaluation"), description=tr("de l'acte de vente"))],
|
| 252 |
default="tab1")
|
| 253 |
|
| 254 |
|
| 255 |
if (chosen_id == "tab1"):
|
| 256 |
+
if 'model' in st.session_state and (st.session_state.model[:3]=="gpt") and ("OPENAI_API_KEY" in st.session_state):
|
| 257 |
+
model = ChatOpenAI(model=st.session_state.model,
|
| 258 |
+
temperature=0.8, # Adjust creativity level
|
| 259 |
+
max_tokens=150 # Define max output token limit
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
else:
|
| 263 |
+
st.session_state.model = "mistral-large-latest"
|
| 264 |
+
model = ChatMistralAI(model=st.session_state.model)
|
| 265 |
+
|
| 266 |
+
|
| 267 |
config,thread_id = init()
|
| 268 |
query = ""
|
| 269 |
st.button(label=tr("Validez"), type="primary")
|
|
|
|
| 273 |
# On ne fait rien
|
| 274 |
except NameError:
|
| 275 |
config,thread_id = init()
|
| 276 |
+
with st.container():
|
| 277 |
+
# Diviser l'écran en deux colonnes
|
| 278 |
+
col1, col2 = st.columns(2)
|
| 279 |
+
# with col1:
|
| 280 |
+
# st.markdown(
|
| 281 |
+
# """
|
| 282 |
+
# <div style="height: 400px;">
|
| 283 |
+
# </div>
|
| 284 |
+
# """,
|
| 285 |
+
# unsafe_allow_html=True,
|
| 286 |
+
# )
|
| 287 |
+
with col1:
|
| 288 |
+
st.write("**thread_id:** "+thread_id)
|
| 289 |
+
query = ""
|
| 290 |
+
audio_bytes = audio_recorder (pause_threshold=2.0, sample_rate=16000, auto_start=False, text=tr("Cliquez pour parler, puis attendre 2sec."), \
|
| 291 |
+
recording_color="#e8b62c", neutral_color="#1ec3bc", icon_size="6x",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
|
| 293 |
+
if audio_bytes:
|
| 294 |
+
# st.write("**"+tr("Vendeur")+" :**\n")
|
| 295 |
+
# Fonction pour générer et jouer le texte en speech
|
| 296 |
+
st.audio(audio_bytes, format="audio/wav", autoplay=False)
|
| 297 |
+
try:
|
| 298 |
+
detection = False
|
| 299 |
+
if detection:
|
| 300 |
+
# Create a BytesIO object from the audio stream
|
| 301 |
+
audio_stream_bytesio = io.BytesIO(audio_bytes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
|
| 303 |
+
# Read the WAV stream using wavio
|
| 304 |
+
wav = wavio.read(audio_stream_bytesio)
|
| 305 |
+
|
| 306 |
+
# Extract the audio data from the wavio.Wav object
|
| 307 |
+
audio_data = wav.data
|
| 308 |
+
|
| 309 |
+
# Convert the audio data to a NumPy array
|
| 310 |
+
audio_input = np.array(audio_data, dtype=np.float32)
|
| 311 |
+
audio_input = np.mean(audio_input, axis=1)/32768
|
| 312 |
+
|
| 313 |
+
result = model_speech.transcribe(audio_input)
|
| 314 |
+
Lang_detected = result["language"]
|
| 315 |
+
query = result["text"]
|
| 316 |
+
|
| 317 |
+
else:
|
| 318 |
+
# Avec l'aide de la bibliothèque speech_recognition de Google
|
| 319 |
+
Lang_detected = st.session_state['Language']
|
| 320 |
+
# Transcription google
|
| 321 |
+
audio_stream = sr.AudioData(audio_bytes, 32000, 2)
|
| 322 |
+
r = sr.Recognizer()
|
| 323 |
+
query = r.recognize_google(audio_stream, language = Lang_detected)
|
| 324 |
+
|
| 325 |
+
# Transcription
|
| 326 |
+
# st.write("**"+tr("Vendeur :")+"** "+query)
|
| 327 |
+
with st.chat_message("user"):
|
| 328 |
+
st.markdown(query)
|
| 329 |
+
st.write("")
|
| 330 |
|
| 331 |
+
if query != "":
|
| 332 |
+
input_messages = [HumanMessage(query)]
|
| 333 |
+
output = app.invoke(
|
| 334 |
+
{"messages": input_messages, "language": language},
|
| 335 |
+
config,
|
| 336 |
+
)
|
| 337 |
+
#with st.chat_message("user"):
|
| 338 |
+
# Add user message to chat history
|
| 339 |
+
st.session_state.messages.append({"role": "user", "content": query})
|
| 340 |
+
|
| 341 |
+
# Récupération de la réponse
|
| 342 |
+
custom_sentence = output["messages"][-1].content
|
| 343 |
+
|
| 344 |
+
# Joue l'audio
|
| 345 |
+
l = st.session_state['Language']
|
| 346 |
+
play_audio(custom_sentence,l , 1)
|
| 347 |
+
|
| 348 |
+
# st.write("**"+tr("Prospect :")+"** "+custom_sentence)
|
| 349 |
+
with st.chat_message("assistant"):
|
| 350 |
+
st.markdown(custom_sentence)
|
| 351 |
+
|
| 352 |
+
# Add user message to chat history
|
| 353 |
+
st.session_state.messages.append({"role": "assistant", "content": custom_sentence})
|
| 354 |
+
|
| 355 |
|
| 356 |
+
|
| 357 |
+
except KeyboardInterrupt:
|
| 358 |
+
st.write(tr("Arrêt de la reconnaissance vocale."))
|
| 359 |
+
except:
|
| 360 |
+
st.write(tr("Problème, essayer de nouveau.."))
|
| 361 |
+
st.write("")
|
| 362 |
+
# Ajouter un espace pour séparer les zones
|
| 363 |
+
# st.divider()
|
| 364 |
+
with col2:
|
| 365 |
+
# with st.container():
|
| 366 |
+
if query:
|
| 367 |
+
# Display chat messages from history on app rerun
|
| 368 |
+
|
| 369 |
+
for message in st.session_state.messages:
|
| 370 |
+
with st.chat_message(message["role"]):
|
| 371 |
+
st.markdown(message["content"])
|
| 372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
st.write("")
|
| 374 |
st.write("")
|
| 375 |
st.write("")
|
tabs/intro.py
CHANGED
|
@@ -24,12 +24,15 @@ def run():
|
|
| 24 |
st.title(tr(title))
|
| 25 |
st.markdown('''
|
| 26 |
## **'''+tr("Système d'aide à la mise en oeuvre d'une Proposition de Valeur en entreprise")+'''**
|
| 27 |
-
|
| 28 |
''')
|
| 29 |
-
st.header("**"+tr("A propos")+"**")
|
| 30 |
st.markdown(tr(
|
| 31 |
"""
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
""")
|
| 34 |
, unsafe_allow_html=True)
|
| 35 |
|
|
|
|
| 24 |
st.title(tr(title))
|
| 25 |
st.markdown('''
|
| 26 |
## **'''+tr("Système d'aide à la mise en oeuvre d'une Proposition de Valeur en entreprise")+'''**
|
| 27 |
+
------------------------------------------------------------------------------------
|
| 28 |
''')
|
|
|
|
| 29 |
st.markdown(tr(
|
| 30 |
"""
|
| 31 |
+
<h4>
|
| 32 |
+
Bienvenue dans le fabuleux univers de Value Props.<br>
|
| 33 |
+
Decouvrez et testez ici les futures fonctionnalités que la plateforme souhaite vous proposer.<br>
|
| 34 |
+
N'hesitez pas à nous faire part de vos commentaires en les envoyant à [email protected]<br>
|
| 35 |
+
</h4>
|
| 36 |
""")
|
| 37 |
, unsafe_allow_html=True)
|
| 38 |
|
translate_app.py
CHANGED
|
@@ -18,7 +18,9 @@ def trad(message,l):
|
|
| 18 |
return "Problème de traduction.."
|
| 19 |
|
| 20 |
def tr(message):
|
| 21 |
-
if 'Language' not in st.session_state:
|
|
|
|
|
|
|
| 22 |
else: l= st.session_state['Language']
|
| 23 |
if l == 'fr': return message
|
| 24 |
else: message = message.replace(":red[**","").replace("**]","")
|
|
|
|
| 18 |
return "Problème de traduction.."
|
| 19 |
|
| 20 |
def tr(message):
|
| 21 |
+
if 'Language' not in st.session_state:
|
| 22 |
+
l = 'fr'
|
| 23 |
+
st.session_state['Language'] = l
|
| 24 |
else: l= st.session_state['Language']
|
| 25 |
if l == 'fr': return message
|
| 26 |
else: message = message.replace(":red[**","").replace("**]","")
|