Spaces:
Running
Running
FauziIsyrinApridal
commited on
Commit
Β·
e17f2c4
1
Parent(s):
be1430e
back
Browse files- app/chat.py +17 -33
app/chat.py
CHANGED
|
@@ -11,21 +11,20 @@ from app.db import supabase
|
|
| 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,7 +34,6 @@ def save_feedback_to_supabase(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,14 +52,14 @@ def initialize_session_state():
|
|
| 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 |
-
#
|
| 65 |
def text_to_speech(text):
|
| 66 |
cache_dir = "cache_tts"
|
| 67 |
os.makedirs(cache_dir, exist_ok=True)
|
|
@@ -87,24 +85,20 @@ def text_to_speech(text):
|
|
| 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}
|
| 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,16 +106,16 @@ def display_chat_history(chain):
|
|
| 112 |
|
| 113 |
col2, col3 = st.columns([1, 1])
|
| 114 |
|
| 115 |
-
# Tombol
|
| 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
|
| 125 |
with col3:
|
| 126 |
stt_text = speech_to_text(
|
| 127 |
start_prompt="π€ Input Suara",
|
|
@@ -132,6 +126,7 @@ def display_chat_history(chain):
|
|
| 132 |
use_container_width=True,
|
| 133 |
)
|
| 134 |
|
|
|
|
| 135 |
if stt_text:
|
| 136 |
st.session_state.input_text = stt_text
|
| 137 |
st.experimental_rerun()
|
|
@@ -147,30 +142,19 @@ def display_chat_history(chain):
|
|
| 147 |
st.session_state['generated'].append(output)
|
| 148 |
st.session_state.input_text = ""
|
| 149 |
|
| 150 |
-
# Reset flag TTS
|
| 151 |
if st.session_state['should_speak'] and output:
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
st.session_state['tts_played'] = False
|
| 155 |
|
| 156 |
-
# Tampilkan
|
| 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
|
| 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()
|
|
|
|
| 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 |
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 |
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 |
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 |
|
| 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 |
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 |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|