Customers commited on
Commit
1f32b76
·
verified ·
1 Parent(s): fd68e95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -147
app.py CHANGED
@@ -15,13 +15,10 @@ from google.oauth2 import service_account
15
  from googleapiclient.discovery import build
16
  from datetime import datetime
17
  from google.oauth2.service_account import Credentials
18
- from gtts import gTTS # Text-to-speech
19
- import speech_recognition as sr # Speech-to-text
20
  import tempfile
21
  import base64
22
- from io import BytesIO# For temporary audio files
23
-
24
-
25
 
26
 
27
 
@@ -138,21 +135,6 @@ BATTERY_COLORS = {
138
  SPONSOR = "default" # Set this to the sponsor name or leave as "default" for default branding
139
  TRAINER_SHEET_ID = "1GiA8pxZn04aUA-OKwcANvfJ_CpChooF2mUQxiJ_i2-s"
140
 
141
- def text_to_speech(text):
142
- """Convert text to speech and return base64 encoded audio data"""
143
- try:
144
- # Create speech from text
145
- tts = gTTS(text=text, lang='en')
146
-
147
- # Save to temporary file
148
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
149
- tts.save(fp.name)
150
- return fp.name
151
-
152
- except Exception as e:
153
- print(f"Error in text-to-speech: {str(e)}")
154
- return None
155
-
156
  def record_trainer_info(email, client_email, freelancer_email, freelancer_link, seal):
157
  """Record trainer information to Google Sheet"""
158
  try:
@@ -2889,43 +2871,70 @@ button:active {
2889
  .progress-bar {
2890
  display: none !important;
2891
  }
2892
-
2893
- .voice-btn {
2894
- min-width: 40px !important;
2895
- height: 40px !important;
2896
- border-radius: 50% !important;
2897
- padding: 0 !important;
2898
- margin-left: 5px !important;
2899
- background: linear-gradient(135deg, #6e8efb, #a777e3) !important;
2900
- color: white !important;
2901
  }
2902
- .voice-btn:hover {
2903
- transform: scale(1.05) !important;
 
 
 
 
2904
  }
2905
- /* Audio player styling */
2906
- .gradio-audio {
2907
- margin-top: 10px;
2908
- background: rgba(255, 255, 255, 0.7) !important;
2909
- border-radius: 8px !important;
2910
- padding: 10px !important;
2911
  }
2912
-
2913
- /* Voice button styling */
2914
- .voice-btn {
2915
- min-width: 40px !important;
2916
- height: 40px !important;
2917
- border-radius: 50% !important;
2918
- padding: 0 !important;
2919
- margin-left: 5px !important;
2920
- background: linear-gradient(135deg, #6e8efb, #a777e3) !important;
2921
- color: white !important;
2922
  }
2923
- .voice-btn:hover {
2924
- transform: scale(1.05) !important;
2925
  }
 
2926
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2927
  """
2928
-
 
 
 
 
 
 
 
 
 
 
 
 
 
2929
  def respond(message, history, max_tokens, temperature, top_p):
2930
  email = OWNER_EMAIL
2931
 
@@ -2933,12 +2942,10 @@ def respond(message, history, max_tokens, temperature, top_p):
2933
  save_chat_history(email, message, "")
2934
 
2935
  try:
2936
- # Save to BATTERY_SHEET_ID (using our multi-sheet function)
2937
  sheet = get_or_create_sheet(BATTERY_SHEET_ID, "ChatHistory")
2938
-
2939
  now_str = datetime.now().strftime("%m/%d/%Y %H:%M:%S")
2940
  sheet.append_row([now_str, email, message, ""])
2941
-
2942
  except Exception as e:
2943
  print(f"Error saving to battery sheet: {str(e)}")
2944
 
@@ -2946,7 +2953,7 @@ def respond(message, history, max_tokens, temperature, top_p):
2946
  temp_response = f"""<a href="https://flutterwave.com/pay/gossapp" target="_blank">
2947
  <img src='https://i.imgur.com/PznT4qo.png' width='20'>
2948
  </a>"""
2949
- yield [(message, temp_response)], None # Add None for audio output
2950
 
2951
  try:
2952
  # Build prompt
@@ -2955,13 +2962,12 @@ def respond(message, history, max_tokens, temperature, top_p):
2955
  for user_msg, bot_msg in history:
2956
  if user_msg:
2957
  messages.append({"role": "user", "content": user_msg})
2958
- if bot_msg and not str(bot_msg).startswith("<img"): # Convert to string before checking
2959
  messages.append({"role": "assistant", "content": str(bot_msg)})
2960
  messages.append({"role": "user", "content": message})
2961
 
2962
- # Get the current inference client
2963
  inference_client = get_inference_client()
2964
-
2965
  response = ""
2966
  for chunk in inference_client.chat_completion(
2967
  messages,
@@ -2974,36 +2980,33 @@ def respond(message, history, max_tokens, temperature, top_p):
2974
  if token:
2975
  response += token
2976
  clean_response = response.split("(Note:")[0].strip()
2977
- yield [(message, clean_response)], None # Add None for audio output
2978
 
2979
  clean_response = response.split("(Note:")[0].strip()
2980
-
2981
- # Generate audio for the response
2982
- audio_file = text_to_speech(clean_response)
2983
 
2984
- # Save full bot response to chat history
 
 
 
2985
  save_chat_history(email, message, clean_response)
2986
 
2987
- # Update response in battery sheet
2988
  try:
2989
  scope = ['https://www.googleapis.com/auth/spreadsheets',
2990
  'https://www.googleapis.com/auth/drive']
2991
  creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
2992
- gspread_client = gspread.authorize(creds) # Renamed to avoid conflict
2993
 
2994
  spreadsheet = gspread_client.open_by_key(BATTERY_SHEET_ID)
2995
 
2996
- # Search all sheets for our record to update
2997
  for worksheet in spreadsheet.worksheets():
2998
  try:
2999
  records = worksheet.get_all_records()
3000
- for i, record in enumerate(records, start=2): # start=2 because header is row 1
3001
  if (str(record.get('Email', '')).lower() == email.lower() and
3002
  str(record.get('User Message', '')).strip() == message.strip() and
3003
  (not record.get('Bot Message') or str(record.get('Bot Message', '')).strip() == "")):
3004
-
3005
- # Update the bot response
3006
- worksheet.update_cell(i, 4, clean_response) # Column D is index 4
3007
  break
3008
  except Exception as e:
3009
  print(f"Error searching sheet {worksheet.title}: {str(e)}")
@@ -3012,7 +3015,7 @@ def respond(message, history, max_tokens, temperature, top_p):
3012
  except Exception as e:
3013
  print(f"Error updating battery sheet with response: {str(e)}")
3014
 
3015
- yield [(message, clean_response)], audio_file if audio_file else None
3016
 
3017
  except Exception as e:
3018
  if "402" in str(e):
@@ -3022,8 +3025,8 @@ def respond(message, history, max_tokens, temperature, top_p):
3022
  Please:<br>
3023
  1. <a href="https://flutterwave.com/pay/gossapp" target="_blank">Reload AI-time</a><br>
3024
  2. Try again later,or<br>
3025
- 3. Contact <a href="https://wa.link/x2wdpl" target="_blank">Support </a> if this persists.
3026
- Tired of Manual Chatbot reset delays? Consider a Subscription to have your chatbot last upto 20 times longer and fewer/ zero reset delays (Auto-reset)</div>
3027
  """)
3028
  else:
3029
  custom_error = gr.HTML(f"""
@@ -3316,52 +3319,34 @@ with gr.Blocks(
3316
 
3317
 
3318
 
3319
- with gr.Column(scale=3, elem_classes="chat-container"):
3320
- # Create the HTML component separately
3321
- greeting_html = gr.HTML(get_chatbot_greeting())
3322
-
3323
- chatbot = gr.Chatbot(
3324
- elem_id="chatbot",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3325
  show_label=False,
3326
- avatar_images=(None, user_data['avatar_url']),
3327
- show_copy_button=False,
3328
- show_share_button=False,
3329
- layout="panel",
3330
- value=[(None, greeting_html)],
3331
- height=600,
3332
  )
3333
-
3334
- with gr.Row():
3335
- with gr.Column(scale=6):
3336
- msg = gr.Textbox(
3337
- show_label=False,
3338
- placeholder="Let's GossApp! Type or say something...",
3339
- container=False,
3340
- autofocus=True
3341
- )
3342
-
3343
- with gr.Column(scale=1, min_width=50):
3344
- voice_btn = gr.Button("🎤", elem_classes="voice-btn")
3345
-
3346
- submit = gr.Button("", elem_classes="send-btn")
3347
-
3348
- # Audio output for TTS responses
3349
- audio_output = gr.Audio(visible=True, label="Chatbot Response", autoplay=True)
3350
-
3351
- clear = gr.ClearButton([msg, chatbot], variant="secondary")
3352
-
3353
- with gr.Accordion("🔊 Alternative: Upload Audio", open=False):
3354
- audio_upload = gr.Audio(
3355
- sources=["upload"], # Allow file upload
3356
- type="filepath",
3357
- label="Or upload an audio file"
3358
- )
3359
-
3360
- # Process uploaded audio
3361
- audio_upload.change(
3362
- fn=lambda audio: listen_microphone(audio), # Reuse speech-to-text
3363
- outputs=msg
3364
- )
3365
 
3366
  # Add Business, Family, Friends chatbots right below the button row
3367
  business_html_display = gr.HTML(f"""
@@ -5347,17 +5332,30 @@ with gr.Blocks(
5347
  outputs=[save_status, bio_display, chatbot]
5348
  )
5349
 
5350
- submit.click(
 
5351
  respond,
5352
- inputs=[msg, chatbot, max_tokens, temperature],
5353
- outputs=[chatbot, audio_output],
5354
- ).then(clear_input, outputs=[msg])
 
 
 
 
 
 
5355
 
5356
- msg.submit(
5357
  respond,
5358
- inputs=[msg, chatbot, max_tokens, temperature],
5359
- outputs=[chatbot, audio_output],
5360
- ).then(clear_input, outputs=[msg])
 
 
 
 
 
 
5361
 
5362
  # Add these at the end of your existing event handlers
5363
  submit_complaint_btn.click(
@@ -5372,7 +5370,24 @@ with gr.Blocks(
5372
  outputs=[status_display]
5373
  )
5374
 
5375
- # Certificate generation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5376
  def generate_certificate(name, email):
5377
  """Generate certificate HTML with centered name on background image"""
5378
 
@@ -5415,28 +5430,6 @@ with gr.Blocks(
5415
  outputs=[cert_display]
5416
  )
5417
 
5418
- def listen_microphone():
5419
- r = sr.Recognizer()
5420
- try:
5421
- with sr.Microphone() as source:
5422
- print("Listening...")
5423
- audio = r.listen(source, timeout=5)
5424
- user_text = r.recognize_google(audio)
5425
- return user_text
5426
- except Exception as e:
5427
- raise gr.Error(f"Error: {str(e)}. Try typing instead.")
5428
-
5429
- voice_btn.click(
5430
- listen_microphone,
5431
- outputs=[msg]
5432
- )
5433
-
5434
- def speak_response(text):
5435
- with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as fp:
5436
- tts = gTTS(text=text, lang="en")
5437
- tts.save(fp.name)
5438
- return fp.name
5439
-
5440
  def auto_refresh():
5441
  while True:
5442
  # Check for inactive accounts once per day
 
15
  from googleapiclient.discovery import build
16
  from datetime import datetime
17
  from google.oauth2.service_account import Credentials
18
+ from gtts import gTTS
 
19
  import tempfile
20
  import base64
21
+ from io import BytesIO
 
 
22
 
23
 
24
 
 
135
  SPONSOR = "default" # Set this to the sponsor name or leave as "default" for default branding
136
  TRAINER_SHEET_ID = "1GiA8pxZn04aUA-OKwcANvfJ_CpChooF2mUQxiJ_i2-s"
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  def record_trainer_info(email, client_email, freelancer_email, freelancer_link, seal):
139
  """Record trainer information to Google Sheet"""
140
  try:
 
2871
  .progress-bar {
2872
  display: none !important;
2873
  }
2874
+ """
2875
+ audio_player_css = """
2876
+ .audio-player-container {
2877
+ display: flex;
2878
+ align-items: center;
2879
+ gap: 5px;
2880
+ margin-left: 5px;
 
 
2881
  }
2882
+ .audio-player-btn {
2883
+ background: none;
2884
+ border: none;
2885
+ cursor: pointer;
2886
+ font-size: 16px;
2887
+ padding: 5px;
2888
  }
2889
+ .audio-player-btn:hover {
2890
+ color: #4CAF50;
 
 
 
 
2891
  }
2892
+ .download-btn {
2893
+ background: none;
2894
+ border: none;
2895
+ cursor: pointer;
2896
+ font-size: 16px;
2897
+ padding: 5px;
2898
+ color: #666;
 
 
 
2899
  }
2900
+ .download-btn:hover {
2901
+ color: #4CAF50;
2902
  }
2903
+ """
2904
 
2905
+ # Add this JavaScript for audio control
2906
+ audio_player_js = """
2907
+ function createAudioPlayer(audioData) {
2908
+ if (!audioData) return '';
2909
+
2910
+ const audioId = 'audio-' + Math.random().toString(36).substr(2, 9);
2911
+ const downloadUrl = 'data:audio/mp3;base64,' + audioData;
2912
+
2913
+ return `
2914
+ <div class="audio-player-container">
2915
+ <audio id="${audioId}" src="${downloadUrl}"></audio>
2916
+ <button class="audio-player-btn" onclick="document.getElementById('${audioId}').play()">▶️</button>
2917
+ <button class="audio-player-btn" onclick="document.getElementById('${audioId}').pause()">⏸️</button>
2918
+ <button class="audio-player-btn" onclick="document.getElementById('${audioId}').currentTime = 0; document.getElementById('${audioId}').pause()">⏹️</button>
2919
+ <a class="download-btn" href="${downloadUrl}" download="response.mp3">💾</a>
2920
+ </div>
2921
+ `;
2922
+ }
2923
  """
2924
+
2925
+ def text_to_speech(text):
2926
+ """Convert text to speech and return base64 encoded audio"""
2927
+ try:
2928
+ tts = gTTS(text=text, lang='en', slow=False)
2929
+ with tempfile.NamedTemporaryFile(delete=True, suffix='.mp3') as fp:
2930
+ tts.save(fp.name)
2931
+ with open(fp.name, 'rb') as audio_file:
2932
+ audio_bytes = audio_file.read()
2933
+ return base64.b64encode(audio_bytes).decode('utf-8')
2934
+ except Exception as e:
2935
+ print(f"Error in text-to-speech: {str(e)}")
2936
+ return None
2937
+
2938
  def respond(message, history, max_tokens, temperature, top_p):
2939
  email = OWNER_EMAIL
2940
 
 
2942
  save_chat_history(email, message, "")
2943
 
2944
  try:
2945
+ # Save to BATTERY_SHEET_ID
2946
  sheet = get_or_create_sheet(BATTERY_SHEET_ID, "ChatHistory")
 
2947
  now_str = datetime.now().strftime("%m/%d/%Y %H:%M:%S")
2948
  sheet.append_row([now_str, email, message, ""])
 
2949
  except Exception as e:
2950
  print(f"Error saving to battery sheet: {str(e)}")
2951
 
 
2953
  temp_response = f"""<a href="https://flutterwave.com/pay/gossapp" target="_blank">
2954
  <img src='https://i.imgur.com/PznT4qo.png' width='20'>
2955
  </a>"""
2956
+ yield [(message, temp_response)], None # None for initial audio
2957
 
2958
  try:
2959
  # Build prompt
 
2962
  for user_msg, bot_msg in history:
2963
  if user_msg:
2964
  messages.append({"role": "user", "content": user_msg})
2965
+ if bot_msg and not str(bot_msg).startswith("<img"):
2966
  messages.append({"role": "assistant", "content": str(bot_msg)})
2967
  messages.append({"role": "user", "content": message})
2968
 
2969
+ # Get response
2970
  inference_client = get_inference_client()
 
2971
  response = ""
2972
  for chunk in inference_client.chat_completion(
2973
  messages,
 
2980
  if token:
2981
  response += token
2982
  clean_response = response.split("(Note:")[0].strip()
2983
+ yield [(message, clean_response)], None # No audio during streaming
2984
 
2985
  clean_response = response.split("(Note:")[0].strip()
 
 
 
2986
 
2987
+ # Generate audio
2988
+ audio_data = text_to_speech(clean_response)
2989
+
2990
+ # Save to chat history
2991
  save_chat_history(email, message, clean_response)
2992
 
2993
+ # Update battery sheet
2994
  try:
2995
  scope = ['https://www.googleapis.com/auth/spreadsheets',
2996
  'https://www.googleapis.com/auth/drive']
2997
  creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
2998
+ gspread_client = gspread.authorize(creds)
2999
 
3000
  spreadsheet = gspread_client.open_by_key(BATTERY_SHEET_ID)
3001
 
 
3002
  for worksheet in spreadsheet.worksheets():
3003
  try:
3004
  records = worksheet.get_all_records()
3005
+ for i, record in enumerate(records, start=2):
3006
  if (str(record.get('Email', '')).lower() == email.lower() and
3007
  str(record.get('User Message', '')).strip() == message.strip() and
3008
  (not record.get('Bot Message') or str(record.get('Bot Message', '')).strip() == "")):
3009
+ worksheet.update_cell(i, 4, clean_response)
 
 
3010
  break
3011
  except Exception as e:
3012
  print(f"Error searching sheet {worksheet.title}: {str(e)}")
 
3015
  except Exception as e:
3016
  print(f"Error updating battery sheet with response: {str(e)}")
3017
 
3018
+ yield [(message, clean_response)], audio_data if audio_data else None
3019
 
3020
  except Exception as e:
3021
  if "402" in str(e):
 
3025
  Please:<br>
3026
  1. <a href="https://flutterwave.com/pay/gossapp" target="_blank">Reload AI-time</a><br>
3027
  2. Try again later,or<br>
3028
+ 3. Contact <a href="https://wa.link/x2wdpl" target="_blank">Support </a> if this persists.<br><br>
3029
+ Tired of Manual Chatbot reset delays? <br>Consider a Subscription to have your chatbot last upto 20 times longer and fewer/ zero reset delays (Auto-reset)</div>
3030
  """)
3031
  else:
3032
  custom_error = gr.HTML(f"""
 
3319
 
3320
 
3321
 
3322
+ with gr.Column(scale=3, elem_classes="chat-container"):
3323
+ # Create the HTML component separately
3324
+ greeting_html = gr.HTML(get_chatbot_greeting())
3325
+
3326
+ chatbot = gr.Chatbot(
3327
+ elem_id="chatbot",
3328
+ show_label=False,
3329
+ avatar_images=(None, user_data['avatar_url']),
3330
+ show_copy_button=False,
3331
+ show_share_button=False,
3332
+ layout="panel",
3333
+ value=[(None, greeting_html)],
3334
+ height=600,
3335
+ # Add these to ensure proper centering in the container
3336
+ elem_classes=["centered-chatbot"]
3337
+ )
3338
+
3339
+ # Replace the existing button row and clear button code with this:
3340
+ with gr.Row():
3341
+ msg = gr.Textbox(
3342
  show_label=False,
3343
+ placeholder="Let's GossApp...",
3344
+ container=False,
3345
+ autofocus=True,
3346
+ scale=6
 
 
3347
  )
3348
+ submit = gr.Button("", elem_classes="send-btn")
3349
+ audio_output = gr.HTML(visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3350
 
3351
  # Add Business, Family, Friends chatbots right below the button row
3352
  business_html_display = gr.HTML(f"""
 
5332
  outputs=[save_status, bio_display, chatbot]
5333
  )
5334
 
5335
+ # Update your submit/msg handlers
5336
+ msg.submit(
5337
  respond,
5338
+ inputs=[msg, chatbot, max_tokens, temperature, top_p],
5339
+ outputs=[chatbot, audio_output]
5340
+ ).then(
5341
+ lambda: gr.HTML(visible=True),
5342
+ outputs=[audio_output]
5343
+ ).then(
5344
+ clear_input,
5345
+ outputs=[msg]
5346
+ )
5347
 
5348
+ submit.click(
5349
  respond,
5350
+ inputs=[msg, chatbot, max_tokens, temperature, top_p],
5351
+ outputs=[chatbot, audio_output]
5352
+ ).then(
5353
+ lambda: gr.HTML(visible=True),
5354
+ outputs=[audio_output]
5355
+ ).then(
5356
+ clear_input,
5357
+ outputs=[msg]
5358
+ )
5359
 
5360
  # Add these at the end of your existing event handlers
5361
  submit_complaint_btn.click(
 
5370
  outputs=[status_display]
5371
  )
5372
 
5373
+ # Add the audio player update function
5374
+ def update_audio_player(audio_data):
5375
+ if audio_data:
5376
+ return f"""
5377
+ <script>
5378
+ {audio_player_js}
5379
+ document.currentScript.parentNode.innerHTML = createAudioPlayer('{audio_data}');
5380
+ </script>
5381
+ """
5382
+ return ""
5383
+
5384
+ audio_output.change(
5385
+ update_audio_player,
5386
+ inputs=[audio_output],
5387
+ outputs=[audio_output]
5388
+ )
5389
+
5390
+ # Certificate generation
5391
  def generate_certificate(name, email):
5392
  """Generate certificate HTML with centered name on background image"""
5393
 
 
5430
  outputs=[cert_display]
5431
  )
5432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5433
  def auto_refresh():
5434
  while True:
5435
  # Check for inactive accounts once per day