FauziIsyrinApridal commited on
Commit
be1430e
Β·
1 Parent(s): 0ef32f0

tambahkan indikator audio dan audio selalu diputar

Browse files
Files changed (2) hide show
  1. app.py +12 -12
  2. app/chat.py +33 -17
app.py CHANGED
@@ -17,15 +17,15 @@ from langchain_community.document_transformers import LongContextReorder
17
 
18
  load_dotenv()
19
 
20
- # ---------------------------------------------------------
21
- # ⚑️ CONFIG
22
- # ---------------------------------------------------------
23
  BUCKET_NAME = "pnp-bot-storage-archive"
24
  VECTOR_STORE_PREFIX = "vector_store"
25
 
26
- # ---------------------------------------------------------
27
- # ⚑️ UTILITY
28
- # ---------------------------------------------------------
29
  def get_latest_data_timestamp_from_files(bucket_name: str) -> float:
30
  """Get the latest timestamp from files in a Supabase storage bucket."""
31
  files = list_all_files(bucket_name)
@@ -76,9 +76,9 @@ def reorder_embedding(docs):
76
  return reordering.transform_documents(docs)
77
 
78
 
79
- # ---------------------------------------------------------
80
- # ⚑️ RAG CHAIN
81
- # ---------------------------------------------------------
82
  @traceable(name="Create RAG Conversational Chain")
83
  def create_conversational_chain(vector_store):
84
  """Create a Conversational Retrieval Chain for RAG."""
@@ -102,9 +102,9 @@ def get_rag_chain(vector_store):
102
  return create_conversational_chain(vector_store)
103
 
104
 
105
- # ---------------------------------------------------------
106
- # ⚑️ MAIN FUNCTION
107
- # ---------------------------------------------------------
108
  @traceable(name="Main Chatbot RAG App")
109
  def main():
110
  initialize_session_state()
 
17
 
18
  load_dotenv()
19
 
20
+
21
+ # CONFIG
22
+
23
  BUCKET_NAME = "pnp-bot-storage-archive"
24
  VECTOR_STORE_PREFIX = "vector_store"
25
 
26
+
27
+ # UTILITY
28
+
29
  def get_latest_data_timestamp_from_files(bucket_name: str) -> float:
30
  """Get the latest timestamp from files in a Supabase storage bucket."""
31
  files = list_all_files(bucket_name)
 
76
  return reordering.transform_documents(docs)
77
 
78
 
79
+
80
+ # RAG CHAIN
81
+
82
  @traceable(name="Create RAG Conversational Chain")
83
  def create_conversational_chain(vector_store):
84
  """Create a Conversational Retrieval Chain for RAG."""
 
102
  return create_conversational_chain(vector_store)
103
 
104
 
105
+
106
+ # MAIN FUNCTION
107
+
108
  @traceable(name="Main Chatbot RAG App")
109
  def main():
110
  initialize_session_state()
app/chat.py CHANGED
@@ -11,20 +11,21 @@ from app.db import supabase
11
  import os
12
  import glob
13
  import time
 
14
  from dotenv import load_dotenv
15
 
16
  load_dotenv()
17
 
18
- # Bersihkan cache audio lama (opsional)
19
  def clean_old_cache(tts_dir="cache_tts", max_age_hours=12):
20
  now = time.time()
21
  for f in glob.glob(os.path.join(tts_dir, "*.mp3")):
22
  if os.stat(f).st_mtime < now - max_age_hours * 3600:
23
  os.remove(f)
24
 
25
- # Jalankan pembersihan saat startup
26
  clean_old_cache()
27
 
 
28
  def save_feedback_to_supabase(feedback_text):
29
  try:
30
  data = {"message": feedback_text}
@@ -34,6 +35,7 @@ def save_feedback_to_supabase(feedback_text):
34
  st.error(f"Gagal menyimpan feedback: {e}")
35
  return False
36
 
 
37
  def initialize_session_state():
38
  if 'history' not in st.session_state:
39
  st.session_state['history'] = []
@@ -52,14 +54,14 @@ def initialize_session_state():
52
  if 'tts_output' not in st.session_state:
53
  st.session_state['tts_output'] = ""
54
  if 'tts_played' not in st.session_state:
55
- st.session_state['tts_played'] = True # default True supaya tidak main saat awal
56
 
57
- # edge-tts fallback (cadangan)
58
  async def generate_audio_edge(text, path, voice="id-ID-GadisNeural"):
59
  communicate = edge_tts.Communicate(text, voice=voice)
60
  await communicate.save(path)
61
 
62
- # fungsi utama TTS dengan fallback
63
  def text_to_speech(text):
64
  cache_dir = "cache_tts"
65
  os.makedirs(cache_dir, exist_ok=True)
@@ -85,20 +87,24 @@ def text_to_speech(text):
85
  with open(path, "rb") as audio_file:
86
  audio_base64 = base64.b64encode(audio_file.read()).decode()
87
 
 
 
88
  return f"""
89
  <audio autoplay>
90
- <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
91
  </audio>
92
  """
93
  except Exception as e:
94
  print(f"[Error saat membaca audio] {e}")
95
  return ""
96
 
 
97
  def conversation_chat(query, chain, history):
98
  result = chain({"question": query, "chat_history": history})
99
  history.append((query, result["answer"]))
100
  return result["answer"]
101
 
 
102
  def display_chat_history(chain):
103
  reply_container = st.container()
104
 
@@ -106,16 +112,16 @@ def display_chat_history(chain):
106
 
107
  col2, col3 = st.columns([1, 1])
108
 
109
- # Tombol TTS Aktif / Nonaktif
110
  with col2:
111
- if st.button("πŸ”Š Text-to-Speech Aktif" if st.session_state['should_speak'] else "πŸ”‡ Text-to-Speech Nonaktif",
112
- key="toggle_tts",
113
- help="Aktifkan/Nonaktifkan Text-to-Speech",
114
  use_container_width=True):
115
  st.session_state['should_speak'] = not st.session_state['should_speak']
116
  st.experimental_rerun()
117
 
118
- # Tombol Input Suara
119
  with col3:
120
  stt_text = speech_to_text(
121
  start_prompt="🎀 Input Suara",
@@ -126,7 +132,6 @@ def display_chat_history(chain):
126
  use_container_width=True,
127
  )
128
 
129
- # Jika ada STT
130
  if stt_text:
131
  st.session_state.input_text = stt_text
132
  st.experimental_rerun()
@@ -142,19 +147,30 @@ def display_chat_history(chain):
142
  st.session_state['generated'].append(output)
143
  st.session_state.input_text = ""
144
 
145
- # Reset flag supaya TTS siap memutar lagi
146
  if st.session_state['should_speak'] and output:
147
- st.session_state['tts_output'] = output
148
- st.session_state['tts_played'] = False
 
149
 
150
- # Tampilkan Riwayat Chat
151
  if st.session_state['generated']:
152
  with reply_container:
153
  for i in range(len(st.session_state['generated'])):
154
  message(st.session_state["past"][i], is_user=True, key=str(i) + '_user', avatar_style="no-avatar")
155
  message(st.session_state["generated"][i], key=str(i), avatar_style="no-avatar")
156
 
157
- # Pemutaran TTS
158
  if st.session_state.get('tts_output') and not st.session_state.get('tts_played'):
 
 
 
159
  st.markdown(text_to_speech(st.session_state['tts_output']), unsafe_allow_html=True)
160
  st.session_state['tts_played'] = True
 
 
 
 
 
 
 
 
11
  import os
12
  import glob
13
  import time
14
+ import threading
15
  from dotenv import load_dotenv
16
 
17
  load_dotenv()
18
 
19
+ # Bersihkan cache audio lama
20
  def clean_old_cache(tts_dir="cache_tts", max_age_hours=12):
21
  now = time.time()
22
  for f in glob.glob(os.path.join(tts_dir, "*.mp3")):
23
  if os.stat(f).st_mtime < now - max_age_hours * 3600:
24
  os.remove(f)
25
 
 
26
  clean_old_cache()
27
 
28
+ # Simpan feedback ke Supabase
29
  def save_feedback_to_supabase(feedback_text):
30
  try:
31
  data = {"message": feedback_text}
 
35
  st.error(f"Gagal menyimpan feedback: {e}")
36
  return False
37
 
38
+ # Inisialisasi session state
39
  def initialize_session_state():
40
  if 'history' not in st.session_state:
41
  st.session_state['history'] = []
 
54
  if 'tts_output' not in st.session_state:
55
  st.session_state['tts_output'] = ""
56
  if 'tts_played' not in st.session_state:
57
+ st.session_state['tts_played'] = True
58
 
59
+ # edge-tts fallback
60
  async def generate_audio_edge(text, path, voice="id-ID-GadisNeural"):
61
  communicate = edge_tts.Communicate(text, voice=voice)
62
  await communicate.save(path)
63
 
64
+ # Fungsi utama TTS dengan cache-busting
65
  def text_to_speech(text):
66
  cache_dir = "cache_tts"
67
  os.makedirs(cache_dir, exist_ok=True)
 
87
  with open(path, "rb") as audio_file:
88
  audio_base64 = base64.b64encode(audio_file.read()).decode()
89
 
90
+ # πŸ”Ή Cache-busting query string
91
+ ts = int(time.time())
92
  return f"""
93
  <audio autoplay>
94
+ <source src="data:audio/mp3;base64,{audio_base64}?v={ts}" type="audio/mp3">
95
  </audio>
96
  """
97
  except Exception as e:
98
  print(f"[Error saat membaca audio] {e}")
99
  return ""
100
 
101
+ # Fungsi chat utama
102
  def conversation_chat(query, chain, history):
103
  result = chain({"question": query, "chat_history": history})
104
  history.append((query, result["answer"]))
105
  return result["answer"]
106
 
107
+ # Tampilan chat + TTS indikator
108
  def display_chat_history(chain):
109
  reply_container = st.container()
110
 
 
112
 
113
  col2, col3 = st.columns([1, 1])
114
 
115
+ # Tombol toggle TTS
116
  with col2:
117
+ if st.button("πŸ”Š Text-to-Speech Aktif" if st.session_state['should_speak'] else "πŸ”‡ Text-to-Speech Nonaktif",
118
+ key="toggle_tts",
119
+ help="Aktifkan/Nonaktifkan Text-to-Speech",
120
  use_container_width=True):
121
  st.session_state['should_speak'] = not st.session_state['should_speak']
122
  st.experimental_rerun()
123
 
124
+ # Input suara STT
125
  with col3:
126
  stt_text = speech_to_text(
127
  start_prompt="🎀 Input Suara",
 
132
  use_container_width=True,
133
  )
134
 
 
135
  if stt_text:
136
  st.session_state.input_text = stt_text
137
  st.experimental_rerun()
 
147
  st.session_state['generated'].append(output)
148
  st.session_state.input_text = ""
149
 
150
+ # Reset flag TTS setiap ada output baru
151
  if st.session_state['should_speak'] and output:
152
+ if st.session_state.get('tts_output') != output:
153
+ st.session_state['tts_output'] = output
154
+ st.session_state['tts_played'] = False
155
 
156
+ # Tampilkan riwayat chat
157
  if st.session_state['generated']:
158
  with reply_container:
159
  for i in range(len(st.session_state['generated'])):
160
  message(st.session_state["past"][i], is_user=True, key=str(i) + '_user', avatar_style="no-avatar")
161
  message(st.session_state["generated"][i], key=str(i), avatar_style="no-avatar")
162
 
163
+ # Pemutaran TTS + indikator
164
  if st.session_state.get('tts_output') and not st.session_state.get('tts_played'):
165
+ indicator = st.empty()
166
+ indicator.markdown("🎧 **Memutar audio...**")
167
+
168
  st.markdown(text_to_speech(st.session_state['tts_output']), unsafe_allow_html=True)
169
  st.session_state['tts_played'] = True
170
+
171
+ # Hilangkan indikator setelah 3 detik (tidak blok UI)
172
+ def remove_indicator():
173
+ time.sleep(3)
174
+ indicator.empty()
175
+
176
+ threading.Thread(target=remove_indicator).start()