Spaces:
Sleeping
Sleeping
import streamlit as st # type: ignore | |
import os | |
from datetime import datetime | |
from extra_streamlit_components import tab_bar, TabBarItemData | |
import io | |
from gtts import gTTS | |
import soundfile as sf | |
import wavio | |
from audio_recorder_streamlit import audio_recorder | |
import speech_recognition as sr | |
import whisper | |
import numpy as np | |
from translate_app import tr | |
import getpass | |
from langchain_mistralai import ChatMistralAI | |
from langchain_openai import ChatOpenAI | |
from langgraph.checkpoint.memory import MemorySaver | |
from langgraph.graph import START, END, MessagesState, StateGraph | |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder | |
from typing import Sequence | |
from langchain_core.messages import BaseMessage, SystemMessage, HumanMessage, AIMessage, trim_messages | |
from langgraph.graph.message import add_messages | |
from typing_extensions import Annotated, TypedDict | |
from dotenv import load_dotenv | |
import warnings | |
warnings.filterwarnings('ignore') | |
title = "Sales coaching" | |
sidebar_name = "Sales coaching" | |
dataPath = st.session_state.DataPath | |
os.environ["LANGCHAIN_TRACING_V2"] = "true" | |
os.environ["LANGCHAIN_ENDPOINT"]="https://api.smith.langchain.com" | |
os.environ["LANGCHAIN_HUB_API_URL"]="https://api.smith.langchain.com" | |
os.environ["LANGCHAIN_PROJECT"] = "Sales Coaching Chatbot" | |
if st.session_state.Cloud != 0: | |
load_dotenv() | |
os.getenv("LANGCHAIN_API_KEY") | |
os.getenv("MISTRAL_API_KEY") | |
# os.getenv("OPENAI_API_KEY") | |
model = ChatMistralAI(model="mistral-large-latest") | |
# model = ChatOpenAI(model="gpt-3.5-turbo") | |
language = "French" | |
prompt = ChatPromptTemplate.from_messages( | |
[ | |
( | |
"system", | |
"Répond à toutes les questions du mieux possible en {language}.", | |
), | |
MessagesPlaceholder(variable_name="messages"), | |
] | |
) | |
class State(TypedDict): | |
messages: Annotated[Sequence[BaseMessage], add_messages] | |
language: str | |
def call_model(state: State): | |
chain = prompt | model | |
response = chain.invoke(state) | |
return {"messages": [response]} | |
# Define a new graph | |
workflow = StateGraph(state_schema=State) | |
# Define the (single) node in the graph | |
workflow.add_edge(START, "model") | |
workflow.add_node("model", call_model) | |
workflow.add_edge("model", END) | |
# Add memory | |
memory = MemorySaver() | |
app = workflow.compile(checkpointer=memory) | |
# @st.cache_data | |
def init(): | |
global config,thread_id, context,human_message1,ai_message1,language, app, model_speech | |
thread_id = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
config = {"configurable": {"thread_id": thread_id}} | |
model_speech = whisper.load_model("base") | |
context = """Tu es un Directeur Commercial, mal organisé, d'une entreprise qui commercialise une solution technologique B2B. """ | |
human_message1 = """Je souhaites que nous ayons une conversation verbale entre un commercial de mon entreprise, Marc (moi), et toi que je prospecte. | |
Mon entreprise propose une solution logicielle pour gérer la proposition de valeur d’entreprises B2B qui commercialises des solutions technologiques. | |
Les problématiques adressées par ma solution sont: | |
- Il est difficile pour les startups de concevoir et formaliser une proposition de valeur unique et pertinente | |
- Il est difficile pour les forces de vente d'articuler clairement les messages de la proposition de valeur | |
- Il est chronophage pour les scale-ups de former leur forces de ventes sur les évolutions de la proposition de valeur et de ses messages Valeur ajoutée de ma solution | |
- Augmenter les performances commerciales | |
- Réduction du cycle de vente | |
- Accelerer la croissance du chiffre d'affaires | |
- Concentrer les ressources sur les opportunités qualifiées | |
- Réduction temps de monté en compétence des nouvelles embauches | |
- Augmenter le taux de conversion d'affaires gagnées | |
- Améliorer l'efficacité globale des ventes | |
- Améliorer l'efficience et la confiance des forces de ventes | |
- Optimiser les processus commerciaux pour réduire les cycles de vente, fidéliser les clients et augmenter la productivité | |
- Favoriser le développement personnel des forces de vente | |
Les cas d’usages adressés par ma solution sont : | |
- Affiner et modéliser la proposition de valeur | |
- Décliner les messages marketing & commerciaux | |
- Former la force de vente sur la proposition de valeur | |
- Orchestrer les conversations clients | |
- Partager les retours terrain | |
- Mettre en oeuvre des meilleures pratiques commerciales | |
- Identifier et reproduire les messages de vente gagnants | |
Je suis Marc, le vendeur. | |
Répond à mes questions en tant que Directeur commercial désorganisé, connaissant mal le concept de proposition de valeur, | |
et mon équipe de vente n'est pas performante. | |
Attention: Ce n'est pas toi qui m'aide, c'est moi qui t'aide avec ma solution. | |
""" | |
ai_message1 = "J'ai bien compris, je suis un Directeur Commercial 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 Directeur Commercial'" | |
context = st.text_area(label=tr("Contexte:"), value=context) | |
human_message1 = st.text_area(label=tr("Consigne"), value=human_message1,height=300) | |
ai_message1 = st.text_area(label=tr("Réponse du prospect"), value=ai_message1) | |
messages = [ | |
SystemMessage(content=context), | |
HumanMessage(content=human_message1), | |
AIMessage(content=ai_message1), | |
HumanMessage(content="") | |
] | |
app.invoke( | |
{"messages": messages, "language": language}, | |
config, | |
) | |
''' | |
st.write("**Contexte:** "+context) | |
st.write("") | |
st.write("**Human Message:** "+human_message1) | |
st.write("") | |
st.write("**AI Message:** "+ai_message1) | |
''' | |
st.write("") | |
return config, thread_id | |
# Fonction pour générer et jouer le texte en speech | |
def play_audio(custom_sentence, Lang_target, speed=1.0): | |
# Générer le speech avec gTTS | |
audio_stream_bytesio_src = io.BytesIO() | |
tts = gTTS(custom_sentence, lang=Lang_target) | |
# Revenir au début du flux audio | |
audio_stream_bytesio_src.seek(0) | |
audio_stream_bytesio_src.truncate(0) | |
tts.write_to_fp(audio_stream_bytesio_src) | |
audio_stream_bytesio_src.seek(0) | |
# Charger l'audio dans un tableau numpy | |
data, samplerate = sf.read(audio_stream_bytesio_src) | |
# Modifier la vitesse de lecture en ajustant le taux d'échantillonnage | |
new_samplerate = int(samplerate * speed) | |
new_audio_stream_bytesio = io.BytesIO() | |
# Enregistrer l'audio avec la nouvelle fréquence d'échantillonnage | |
sf.write(new_audio_stream_bytesio, data, new_samplerate, format='wav') | |
new_audio_stream_bytesio.seek(0) | |
# Lire l'audio dans Streamlit | |
st.audio(new_audio_stream_bytesio, autoplay=True) | |
def run(): | |
global thread_id, config, model_speech | |
st.write("") | |
st.write("") | |
st.title(tr(title)) | |
chosen_id = tab_bar(data=[ | |
TabBarItemData(id="tab1", title=tr("Initialisation"), description=tr("d'une nouvelle conversation")), | |
TabBarItemData(id="tab2", title=tr("Conversation"), description=tr("avec le prospect"))], | |
default="tab1") | |
if (chosen_id == "tab1"): | |
config,thread_id = init() | |
query = "" | |
st.button(label=tr("Validez"), type="primary") | |
else: # tab2 | |
try: | |
config | |
# On ne fait rien | |
except NameError: | |
config,thread_id = init() | |
st.write("**thread_id:** "+thread_id) | |
# query = st.text_area(label=tr("Vendeur:"), value="") | |
query = "" | |
audio_bytes = audio_recorder (pause_threshold=2.0, sample_rate=16000, text=tr("Cliquez pour parler, puis attendre 2sec."), \ | |
recording_color="#e8b62c", neutral_color="#1ec3bc", icon_size="6x",) | |
if audio_bytes: | |
st.write("**"+tr("Vendeur")+" :**\n") | |
# Fonction pour générer et jouer le texte en speech | |
st.audio(audio_bytes, format="audio/wav", autoplay=False) | |
try: | |
detection = False | |
if detection: | |
# Create a BytesIO object from the audio stream | |
audio_stream_bytesio = io.BytesIO(audio_bytes) | |
# Read the WAV stream using wavio | |
wav = wavio.read(audio_stream_bytesio) | |
# Extract the audio data from the wavio.Wav object | |
audio_data = wav.data | |
# Convert the audio data to a NumPy array | |
audio_input = np.array(audio_data, dtype=np.float32) | |
audio_input = np.mean(audio_input, axis=1)/32768 | |
result = model_speech.transcribe(audio_input) | |
Lang_detected = result["language"] | |
query = result["text"] | |
st.write(tr("Langue détectée")+" : "+Lang_detected) | |
else: | |
# Avec l'aide de la bibliothèque speech_recognition de Google | |
Lang_detected = "fr" | |
# Transcription google | |
audio_stream = sr.AudioData(audio_bytes, 32000, 2) | |
r = sr.Recognizer() | |
query = r.recognize_google(audio_stream, language = Lang_detected) | |
# Transcription | |
st.write("**Vendeur :** "+query) | |
st.write("") | |
if query != "": | |
input_messages = [HumanMessage(query)] | |
output = app.invoke( | |
{"messages": input_messages, "language": language}, | |
config, | |
) | |
# Récupération de la réponse | |
custom_sentence = output["messages"][-1].content | |
# Joue l'audio | |
if language=="French": Lang_target = "fr" # Langue de la réponse | |
play_audio(custom_sentence, Lang_target, 1) | |
st.write("**Prospect :** "+custom_sentence) | |
except KeyboardInterrupt: | |
st.write(tr("Arrêt de la reconnaissance vocale.")) | |
except: | |
st.write(tr("Problème, essayer de nouveau..")) | |
''' | |
# Créer un espace réservé pour afficher les tokens | |
placeholder = st.empty() | |
for chunk, metadata in app.stream( | |
{"messages": input_messages, "language": language}, | |
config, | |
stream_mode="messages", | |
): | |
if isinstance(chunk, AIMessage): # Filter to just model responses | |
# st.markdown("<span style='white-space: nowrap;'>"+"/"+chunk.content+"/"+"</span>", unsafe_allow_html=True) | |
placeholder.markdown(f"<p style='display: inline;'>{chunk.content}</p>", unsafe_allow_html=True) | |
''' | |
st.write("") | |
st.write("") | |
st.write("") | |
st.write("") |