|
import gradio as gr |
|
from openai import OpenAI |
|
import os |
|
import random |
|
import zipfile |
|
import json |
|
from gtts import gTTS |
|
from pydub import AudioSegment, effects |
|
from vosk import Model, KaldiRecognizer |
|
import wave |
|
|
|
|
|
client = OpenAI(api_key=os.getenv("sk-tHjndptHgYkaZY6RTPZh-sWkkd318Nqor5qPsyPoqWT3BlbkFJQgnwmTeMnI0VhKOmYv-XLXTWSll-Nan80ZlQiEbT0A")) |
|
|
|
|
|
def unzip_random_background_music(zip_path="background_music.mp3.zip", extract_folder="audio_files"): |
|
if not os.path.exists(extract_folder): |
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref: |
|
zip_ref.extractall(extract_folder) |
|
music_files = [f for f in os.listdir(extract_folder) if f.endswith(".mp3")] |
|
if not music_files: |
|
raise FileNotFoundError("解壓後未找到 MP3 音樂檔案。") |
|
return os.path.join(extract_folder, random.choice(music_files)) |
|
|
|
|
|
def generate_response(input_text, language="zh"): |
|
system_prompt = ( |
|
"你是一個根據非暴力溝通和人際溝通理論提供建議的溫暖助理," |
|
"請用同理心和鼓勵的語氣,分析情況並給出撫慰人心的建議,促進理解和情緒表達。" |
|
"請使用輸入語言回應,並讓回應充滿關懷和支持。" |
|
) |
|
response = client.chat.completions.create( |
|
model="gpt-3.5-turbo", |
|
messages=[ |
|
{"role": "system", "content": system_prompt}, |
|
{"role": "user", "content": input_text} |
|
] |
|
) |
|
return response.choices[0].message.content |
|
|
|
|
|
def generate_audio_with_music(input_text, language="zh"): |
|
try: |
|
|
|
background_music_path = unzip_random_background_music() |
|
|
|
|
|
text_response = generate_response(input_text, language) |
|
|
|
|
|
tts = gTTS(text=text_response, lang=language) |
|
tts.save("response.mp3") |
|
response_audio = AudioSegment.from_file("response.mp3") |
|
response_audio = effects.normalize(response_audio) |
|
|
|
|
|
background_music = AudioSegment.from_file(background_music_path) |
|
background_music = background_music.set_channels(1).set_frame_rate(16000) |
|
background_music = background_music - 10 |
|
|
|
|
|
extended_music = background_music[:] |
|
if len(background_music) < len(response_audio): |
|
extended_music = background_music * (len(response_audio) // len(background_music) + 1) |
|
extended_music = extended_music[:len(response_audio)] |
|
combined_audio = response_audio.overlay(extended_music, position=0) |
|
|
|
|
|
final_audio_path = "final_audio.mp3" |
|
combined_audio.export(final_audio_path, format="mp3") |
|
return text_response, final_audio_path |
|
except Exception as e: |
|
return f"Error: {str(e)}", None |
|
|
|
|
|
def transcribe_speech(audio_file): |
|
try: |
|
model_path = "model/vosk-model-small-zh" |
|
if not os.path.exists(model_path): |
|
return "Vosk 模型未找到,請確認模型已下載並存放於正確目錄。" |
|
|
|
|
|
audio = AudioSegment.from_file(audio_file) |
|
audio = audio.set_channels(1).set_frame_rate(16000) |
|
audio.export("temp.wav", format="wav") |
|
|
|
wf = wave.open("temp.wav", "rb") |
|
model = Model(model_path) |
|
recognizer = KaldiRecognizer(model, wf.getframerate()) |
|
|
|
while True: |
|
data = wf.readframes(4000) |
|
if len(data) == 0: |
|
break |
|
recognizer.AcceptWaveform(data) |
|
|
|
result = json.loads(recognizer.Result()) |
|
return result.get("text", "") |
|
except Exception as e: |
|
return f"語音辨識出錯: {str(e)}" |
|
|
|
|
|
def generate_lucky_item(happiness, energy, focus): |
|
colors = ["紅色", "藍色", "綠色", "黃色", "紫色"] |
|
items = ["手環", "水晶", "書籍", "杯子", "植物"] |
|
foods = ["巧克力", "咖啡", "水果", "餅乾", "堅果"] |
|
numbers = list(range(1, 100)) |
|
|
|
lucky_color = random.choice(colors) |
|
lucky_item = random.choice(items) |
|
lucky_food = random.choice(foods) |
|
lucky_number = random.choice(numbers) |
|
|
|
return { |
|
"顏色": lucky_color, |
|
"物品": lucky_item, |
|
"食物": lucky_food, |
|
"數字": lucky_number |
|
} |
|
|
|
|
|
def main(): |
|
with gr.Blocks(css=""" |
|
body { |
|
background: url('https://www.transparenttextures.com/patterns/asfalt-light.png'); |
|
background-color: #F5F0E6; |
|
} |
|
.gr-button { |
|
background-color: #E8C1A0; |
|
color: #5A4A42; |
|
border-radius: 10px; |
|
} |
|
.gr-button:hover { |
|
background-color: #D1A582; |
|
color: #FFF; |
|
} |
|
""") as demo: |
|
gr.Markdown(""" |
|
# 🌸 心靈對話※情感療癒平台 🌸 |
|
### 🌟 讓我們攜手解開心繫,聽聽您心底的聲音-請你相信沒有人是座孤島 🌟 |
|
""") |
|
with gr.Row(): |
|
input_text = gr.Textbox(label="💼 請輸入問題或心情") |
|
audio_input = gr.Audio(label="🎤 說出您的心聲", type="filepath") |
|
submit_button = gr.Button("💖 傳遞您的心聲 💖") |
|
|
|
output_text = gr.Textbox(label="📜 回應內容") |
|
output_audio = gr.Audio(label="🎵 播放療癒語音") |
|
|
|
def process_input(text, audio): |
|
detected_language = "zh" |
|
if audio: |
|
text = transcribe_speech(audio) |
|
if not text: |
|
return "辨識失敗,請重新錄音", None |
|
detected_language = "zh" |
|
return generate_audio_with_music(text, detected_language) |
|
|
|
submit_button.click(fn=process_input, inputs=[input_text, audio_input], outputs=[output_text, output_audio]) |
|
|
|
gr.Markdown(""" |
|
## 調整您的心情指數來生成今日幸運小物! |
|
""") |
|
with gr.Row(): |
|
happiness_slider = gr.Slider(0, 100, label="💖 快樂指數") |
|
energy_slider = gr.Slider(0, 100, label="⚡ 能量指數") |
|
focus_slider = gr.Slider(0, 100, label="🎯 專注指數") |
|
lucky_button = gr.Button("🔮 生成今日幸運小物!") |
|
|
|
lucky_output = gr.Textbox(label="🎁 今日幸運小物") |
|
|
|
def process_lucky(happiness, energy, focus): |
|
lucky_item = generate_lucky_item(happiness, energy, focus) |
|
return json.dumps(lucky_item, ensure_ascii=False, indent=2) |
|
|
|
lucky_button.click(fn=process_lucky, inputs=[happiness_slider, energy_slider, focus_slider], outputs=lucky_output) |
|
|
|
demo.launch() |
|
|
|
if __name__ == "__main__": |
|
main() |