Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -2,171 +2,97 @@
|
|
2 |
# Step 0: Import required libraries
|
3 |
##########################################
|
4 |
import streamlit as st # For building the web application
|
5 |
-
from transformers import (
|
6 |
-
pipeline,
|
7 |
-
SpeechT5Processor,
|
8 |
-
SpeechT5ForTextToSpeech,
|
9 |
-
SpeechT5HifiGan,
|
10 |
-
AutoModelForCausalLM,
|
11 |
-
AutoTokenizer
|
12 |
) # For emotion analysis, text-to-speech, and text generation
|
13 |
from datasets import load_dataset # For loading datasets (e.g., speaker embeddings)
|
14 |
import torch # For tensor operations
|
15 |
import soundfile as sf # For saving audio as .wav files
|
16 |
-
import sentencepiece # Required by SpeechT5Processor for tokenization
|
17 |
|
18 |
##########################################
|
19 |
# Streamlit application title and input
|
20 |
##########################################
|
21 |
-
|
22 |
st.title("🚀 Just Comment") # Application title displayed to users
|
23 |
st.write("I'm listening to you, my friend~") # Application description for users
|
24 |
text = st.text_area("Enter your comment", "") # Text area for user input of comments
|
25 |
|
26 |
-
|
27 |
##########################################
|
28 |
# Step 1: Sentiment Analysis Function
|
29 |
##########################################
|
30 |
def analyze_dominant_emotion(user_review):
|
31 |
-
"""
|
32 |
-
|
33 |
-
"""
|
34 |
-
emotion_classifier = pipeline(
|
35 |
-
"text-classification",
|
36 |
-
model="Thea231/jhartmann_emotion_finetuning",
|
37 |
-
return_all_scores=True
|
38 |
-
) # Load our fine-tuned emotion classification model
|
39 |
-
|
40 |
emotion_results = emotion_classifier(user_review)[0] # Get emotion scores for the review
|
41 |
dominant_emotion = max(emotion_results, key=lambda x: x['score']) # Find the emotion with the highest confidence
|
42 |
-
return dominant_emotion
|
43 |
|
44 |
##########################################
|
45 |
# Step 2: Response Generation Function
|
46 |
##########################################
|
47 |
def response_gen(user_review):
|
48 |
-
"""
|
49 |
-
|
50 |
-
"""
|
51 |
-
# Get dominant emotion for the input
|
52 |
-
dominant_emotion = analyze_dominant_emotion(user_review) # Get the dominant emotion
|
53 |
emotion_label = dominant_emotion['label'].lower() # Extract emotion label
|
54 |
-
|
55 |
-
# Define response templates for each emotion
|
56 |
emotion_prompts = {
|
57 |
-
"anger":
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
),
|
65 |
-
"joy": (
|
66 |
-
"Customer review: '{review}'\n\n"
|
67 |
-
"As a customer service representative, write a positive response that:\n"
|
68 |
-
"- Thanks the customer for their feedback\n"
|
69 |
-
"- Acknowledges both positive and constructive comments\n"
|
70 |
-
"- Invites them to explore loyalty programs\n\n"
|
71 |
-
"Response:"
|
72 |
-
),
|
73 |
-
"disgust": (
|
74 |
-
"Customer quality concern: '{review}'\n\n"
|
75 |
-
"As a customer service representative, craft a response that:\n"
|
76 |
-
"- Immediately acknowledges the product issue.\n"
|
77 |
-
"- Explains measures taken in quality control.\n"
|
78 |
-
"- Provides clear return/replacement instructions.\n"
|
79 |
-
"- Offers a goodwill gesture (1-3 sentences).\n\n"
|
80 |
-
"Response:"
|
81 |
-
),
|
82 |
-
"fear": (
|
83 |
-
"Customer safety concern: '{review}'\n\n"
|
84 |
-
"As a customer service representative, craft a reassuring response that:\n"
|
85 |
-
"- Directly addresses the safety worries.\n"
|
86 |
-
"- References relevant certifications or standards.\n"
|
87 |
-
"- Offers a dedicated support contact.\n"
|
88 |
-
"- Provides a satisfaction guarantee (1-3 sentences).\n\n"
|
89 |
-
"Response:"
|
90 |
-
),
|
91 |
-
"neutral": (
|
92 |
-
"Customer feedback: '{review}'\n\n"
|
93 |
-
"As a customer service representative, craft a balanced response that:\n"
|
94 |
-
"- Provides additional relevant product information.\n"
|
95 |
-
"- Highlights key service features.\n"
|
96 |
-
"- Politely requests more detailed feedback.\n"
|
97 |
-
"- Maintains a professional tone (1-3 sentences).\n\n"
|
98 |
-
"Response:"
|
99 |
-
),
|
100 |
-
"sadness": (
|
101 |
-
"Customer disappointment: '{review}'\n\n"
|
102 |
-
"As a customer service representative, craft an empathetic response that:\n"
|
103 |
-
"- Shows genuine understanding of the issue.\n"
|
104 |
-
"- Proposes a personalized recovery solution.\n"
|
105 |
-
"- Offers extended support options.\n"
|
106 |
-
"- Maintains a positive outlook (1-3 sentences).\n\n"
|
107 |
-
"Response:"
|
108 |
-
),
|
109 |
-
"surprise": (
|
110 |
-
"Customer enthusiastic feedback: '{review}'\n\n"
|
111 |
-
"As a customer service representative, craft a response that:\n"
|
112 |
-
"- Matches the customer's positive energy.\n"
|
113 |
-
"- Highlights unexpected product benefits.\n"
|
114 |
-
"- Invites the customer to join community events or programs.\n"
|
115 |
-
"- Maintains the brand's voice (1-3 sentences).\n\n"
|
116 |
-
"Response:"
|
117 |
-
),
|
118 |
-
|
119 |
-
|
120 |
}
|
121 |
-
|
122 |
# Format the prompt with the user's review
|
123 |
prompt = emotion_prompts.get(emotion_label, "Neutral").format(review=user_review)
|
124 |
-
|
125 |
-
# Load a pre-trained text generation model
|
126 |
-
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen1.5-0.5B")
|
127 |
-
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen1.5-0.5B")
|
128 |
inputs = tokenizer(prompt, return_tensors="pt") # Tokenize the prompt
|
|
|
129 |
outputs = model.generate(**inputs, max_new_tokens=100) # Generate a response
|
130 |
-
|
131 |
-
|
132 |
-
response = tokenizer.decode(outputs[0][input_length:], skip_special_tokens=True) # Decode the generated text
|
133 |
-
return response
|
134 |
|
135 |
##########################################
|
136 |
# Step 3: Text-to-Speech Conversion Function
|
137 |
##########################################
|
138 |
def sound_gen(response):
|
139 |
-
"""
|
140 |
-
Convert the generated response to speech and save as a .wav file.
|
141 |
-
"""
|
142 |
# Load the pre-trained TTS models
|
143 |
-
processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
|
144 |
-
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
|
145 |
-
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
|
146 |
-
|
147 |
# Load speaker embeddings (e.g., neutral female voice)
|
148 |
-
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
|
149 |
-
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
|
150 |
-
|
151 |
# Process the input text and generate a spectrogram
|
152 |
-
inputs = processor(text=response, return_tensors="pt")
|
153 |
-
spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings)
|
154 |
-
|
155 |
# Use the vocoder to generate a waveform
|
156 |
with torch.no_grad():
|
157 |
-
speech = vocoder(spectrogram)
|
158 |
-
|
159 |
# Save the generated speech as a .wav file
|
160 |
-
sf.write("customer_service_response.wav", speech.numpy(), samplerate=16000)
|
161 |
st.audio("customer_service_response.wav") # Play the audio in Streamlit
|
162 |
|
163 |
##########################################
|
164 |
# Main Function
|
165 |
##########################################
|
166 |
def main():
|
167 |
-
"""
|
168 |
-
Main function to orchestrate the workflow of sentiment analysis, response generation, and text-to-speech.
|
169 |
-
"""
|
170 |
if text: # Check if the user entered a comment
|
171 |
response = response_gen(text) # Generate a response
|
172 |
st.write(f"Generated response: {response}") # Display the generated response
|
@@ -174,4 +100,4 @@ def main():
|
|
174 |
|
175 |
# Run the main function
|
176 |
if __name__ == "__main__":
|
177 |
-
main()
|
|
|
2 |
# Step 0: Import required libraries
|
3 |
##########################################
|
4 |
import streamlit as st # For building the web application
|
5 |
+
from transformers import (
|
6 |
+
pipeline,
|
7 |
+
SpeechT5Processor,
|
8 |
+
SpeechT5ForTextToSpeech,
|
9 |
+
SpeechT5HifiGan,
|
10 |
+
AutoModelForCausalLM,
|
11 |
+
AutoTokenizer
|
12 |
) # For emotion analysis, text-to-speech, and text generation
|
13 |
from datasets import load_dataset # For loading datasets (e.g., speaker embeddings)
|
14 |
import torch # For tensor operations
|
15 |
import soundfile as sf # For saving audio as .wav files
|
|
|
16 |
|
17 |
##########################################
|
18 |
# Streamlit application title and input
|
19 |
##########################################
|
|
|
20 |
st.title("🚀 Just Comment") # Application title displayed to users
|
21 |
st.write("I'm listening to you, my friend~") # Application description for users
|
22 |
text = st.text_area("Enter your comment", "") # Text area for user input of comments
|
23 |
|
|
|
24 |
##########################################
|
25 |
# Step 1: Sentiment Analysis Function
|
26 |
##########################################
|
27 |
def analyze_dominant_emotion(user_review):
|
28 |
+
""" Analyze the dominant emotion in the user's review using a text classification model. """
|
29 |
+
emotion_classifier = pipeline("text-classification", model="Thea231/jhartmann_emotion_finetuning", return_all_scores=True) # Load emotion classification model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
emotion_results = emotion_classifier(user_review)[0] # Get emotion scores for the review
|
31 |
dominant_emotion = max(emotion_results, key=lambda x: x['score']) # Find the emotion with the highest confidence
|
32 |
+
return dominant_emotion # Return the dominant emotion (as a dict with label and score)
|
33 |
|
34 |
##########################################
|
35 |
# Step 2: Response Generation Function
|
36 |
##########################################
|
37 |
def response_gen(user_review):
|
38 |
+
""" Generate a response based on the sentiment of the user's review. """
|
39 |
+
dominant_emotion = analyze_dominant_emotion(user_review) # Get dominant emotion for the input
|
|
|
|
|
|
|
40 |
emotion_label = dominant_emotion['label'].lower() # Extract emotion label
|
41 |
+
|
42 |
+
# Define response templates for each emotion
|
43 |
emotion_prompts = {
|
44 |
+
"anger": "I appreciate your feedback and apologize for the inconvenience caused by '{review}'. We're committed to resolving this issue promptly and will ensure it doesn't happen again. Thank you for your patience.",
|
45 |
+
"joy": "Thank you for your positive feedback on '{review}'! We're thrilled to hear you had a great experience and hope to serve you again soon.",
|
46 |
+
"disgust": "We regret that your experience with '{review}' did not meet our standards. We will take immediate steps to address this issue and appreciate your understanding.",
|
47 |
+
"fear": "Your safety is our priority. Regarding your concern about '{review}', we ensure that all our products meet strict safety standards. Please feel free to reach out for further assistance.",
|
48 |
+
"neutral": "Thank you for your feedback on '{review}'. We value your input and would love to hear more about your experience to improve our services.",
|
49 |
+
"sadness": "I'm sorry to hear that you were disappointed with '{review}'. We're here to help and would like to offer you a solution tailored to your needs.",
|
50 |
+
"surprise": "We're glad to hear that '{review}' exceeded your expectations! Thank you for sharing your excitement with us."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|
52 |
+
|
53 |
# Format the prompt with the user's review
|
54 |
prompt = emotion_prompts.get(emotion_label, "Neutral").format(review=user_review)
|
55 |
+
|
56 |
+
# Load a pre-trained text generation model
|
57 |
+
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen1.5-0.5B") # Load tokenizer
|
58 |
+
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen1.5-0.5B") # Load model
|
59 |
inputs = tokenizer(prompt, return_tensors="pt") # Tokenize the prompt
|
60 |
+
|
61 |
outputs = model.generate(**inputs, max_new_tokens=100) # Generate a response
|
62 |
+
response = tokenizer.decode(outputs[0], skip_special_tokens=True) # Decode the generated text
|
63 |
+
return response.strip()[:200] # Return a response trimmed to 200 characters
|
|
|
|
|
64 |
|
65 |
##########################################
|
66 |
# Step 3: Text-to-Speech Conversion Function
|
67 |
##########################################
|
68 |
def sound_gen(response):
|
69 |
+
""" Convert the generated response to speech and save as a .wav file. """
|
|
|
|
|
70 |
# Load the pre-trained TTS models
|
71 |
+
processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts") # Load processor
|
72 |
+
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts") # Load TTS model
|
73 |
+
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan") # Load vocoder
|
74 |
+
|
75 |
# Load speaker embeddings (e.g., neutral female voice)
|
76 |
+
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation") # Load dataset
|
77 |
+
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0) # Get speaker embeddings
|
78 |
+
|
79 |
# Process the input text and generate a spectrogram
|
80 |
+
inputs = processor(text=response, return_tensors="pt") # Process the text
|
81 |
+
spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings) # Generate spectrogram
|
82 |
+
|
83 |
# Use the vocoder to generate a waveform
|
84 |
with torch.no_grad():
|
85 |
+
speech = vocoder(spectrogram) # Generate speech waveform
|
86 |
+
|
87 |
# Save the generated speech as a .wav file
|
88 |
+
sf.write("customer_service_response.wav", speech.numpy(), samplerate=16000) # Save audio
|
89 |
st.audio("customer_service_response.wav") # Play the audio in Streamlit
|
90 |
|
91 |
##########################################
|
92 |
# Main Function
|
93 |
##########################################
|
94 |
def main():
|
95 |
+
""" Main function to orchestrate the workflow of sentiment analysis, response generation, and text-to-speech. """
|
|
|
|
|
96 |
if text: # Check if the user entered a comment
|
97 |
response = response_gen(text) # Generate a response
|
98 |
st.write(f"Generated response: {response}") # Display the generated response
|
|
|
100 |
|
101 |
# Run the main function
|
102 |
if __name__ == "__main__":
|
103 |
+
main() # Execute the main function
|