|
|
import gradio as gr |
|
|
import threading |
|
|
import time |
|
|
import os |
|
|
import traceback |
|
|
from services.audio_service import AudioService |
|
|
from services.chat_service import ChatService |
|
|
from services.image_service import ImageService |
|
|
from services.streaming_voice_service import StreamingVoiceService |
|
|
from core.rag_system import EnhancedRAGSystem |
|
|
from core.tts_service import EnhancedTTSService |
|
|
from core.wikipedia_processor import WikipediaProcessor |
|
|
from ui.components import create_audio_components, create_chat_components,create_streaming_voice_components |
|
|
|
|
|
def create_all_tabs(audio_service: AudioService, chat_service: ChatService, |
|
|
image_service: ImageService, rag_system: EnhancedRAGSystem, |
|
|
tts_service: EnhancedTTSService, wikipedia_processor: WikipediaProcessor, |
|
|
streaming_voice_service: StreamingVoiceService): |
|
|
|
|
|
with gr.Tab("🎙️ Streaming Voice (VAD)"): |
|
|
create_streaming_voice_tab(streaming_voice_service) |
|
|
|
|
|
with gr.Tab("🎙️ Audio"): |
|
|
create_audio_tab(audio_service) |
|
|
|
|
|
with gr.Tab("💬 Chat"): |
|
|
create_chat_tab(chat_service) |
|
|
|
|
|
with gr.Tab("🖼️ Image"): |
|
|
create_image_tab(image_service) |
|
|
|
|
|
with gr.Tab("📚 RAG Wikipedia"): |
|
|
create_rag_tab(rag_system, wikipedia_processor) |
|
|
|
|
|
with gr.Tab("🔊 Text-to-Speech"): |
|
|
create_tts_tab(tts_service) |
|
|
|
|
|
with gr.Tab("🌐 Language Info"): |
|
|
create_language_info_tab(rag_system.multilingual_manager) |
|
|
def create_rag_tab(rag_system: EnhancedRAGSystem, wikipedia_processor: WikipediaProcessor): |
|
|
"""Tạo tab RAG với debug chi tiết""" |
|
|
|
|
|
|
|
|
if rag_system is None: |
|
|
rag_system = EnhancedRAGSystem() |
|
|
if wikipedia_processor is None: |
|
|
wikipedia_processor = WikipediaProcessor() |
|
|
|
|
|
with gr.Blocks() as rag_tab: |
|
|
gr.Markdown("## 📚 Upload Dữ Liệu Wikipedia") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### 📤 Upload Dữ Liệu") |
|
|
file_upload = gr.File( |
|
|
label="Tải lên file (TXT, CSV, JSON)", |
|
|
file_types=['.txt', '.csv', '.json'], |
|
|
file_count="single" |
|
|
) |
|
|
upload_btn = gr.Button("📤 Upload Data", variant="primary") |
|
|
upload_status = gr.Textbox( |
|
|
label="Trạng thái Upload", |
|
|
interactive=False, |
|
|
lines=5 |
|
|
) |
|
|
|
|
|
gr.Markdown("### 📊 Thống kê Database") |
|
|
stats_btn = gr.Button("📊 Database Stats", variant="secondary") |
|
|
stats_display = gr.Textbox( |
|
|
label="Thống kê", |
|
|
interactive=False, |
|
|
lines=6 |
|
|
) |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### 🔍 Tìm kiếm & Kiểm tra") |
|
|
search_query = gr.Textbox( |
|
|
label="Tìm kiếm trong database", |
|
|
placeholder="Nhập từ khóa để kiểm tra dữ liệu..." |
|
|
) |
|
|
search_btn = gr.Button("🔍 Tìm kiếm", variant="secondary") |
|
|
rag_results = gr.JSON( |
|
|
label="Kết quả tìm kiếm", |
|
|
show_label=True |
|
|
) |
|
|
|
|
|
def upload_wikipedia_file(file): |
|
|
"""Xử lý upload file với debug đầy đủ""" |
|
|
if file is None: |
|
|
return "❌ Vui lòng chọn file để upload" |
|
|
|
|
|
try: |
|
|
print(f"🔄 Bắt đầu upload file: {file.name}") |
|
|
|
|
|
|
|
|
if not os.path.exists(file.name): |
|
|
return f"❌ File không tồn tại: {file.name}" |
|
|
|
|
|
|
|
|
documents = wikipedia_processor.process_uploaded_file(file.name) |
|
|
|
|
|
if not documents: |
|
|
return "❌ Không thể trích xuất dữ liệu từ file. File có thể trống hoặc định dạng không đúng." |
|
|
|
|
|
print(f"✅ Đã xử lý {len(documents)} documents") |
|
|
|
|
|
|
|
|
metadatas = [] |
|
|
for i, doc in enumerate(documents): |
|
|
metadata = { |
|
|
"source": "uploaded_file", |
|
|
"type": "knowledge", |
|
|
"file_name": os.path.basename(file.name), |
|
|
"language": "vi", |
|
|
"doc_id": i, |
|
|
"length": len(doc) |
|
|
} |
|
|
metadatas.append(metadata) |
|
|
|
|
|
|
|
|
old_stats = rag_system.get_collection_stats() |
|
|
old_count = old_stats['total_documents'] |
|
|
|
|
|
rag_system.add_documents(documents, metadatas) |
|
|
|
|
|
|
|
|
new_stats = rag_system.get_collection_stats() |
|
|
new_count = new_stats['total_documents'] |
|
|
|
|
|
success_msg = f""" |
|
|
✅ UPLOAD THÀNH CÔNG! |
|
|
📁 File: {os.path.basename(file.name)} |
|
|
📄 Documents xử lý: {len(documents)} |
|
|
📊 Documents thêm vào: {new_count - old_count} |
|
|
🏷️ Tổng documents: {new_count} |
|
|
🔤 Embeddings: {new_stats['embedding_count']} |
|
|
🌐 Ngôn ngữ: {new_stats['language_distribution']} |
|
|
💡 Bạn có thể tìm kiếm ngay để kiểm tra dữ liệu! |
|
|
""" |
|
|
return success_msg |
|
|
|
|
|
except Exception as e: |
|
|
error_msg = f"❌ LỖI UPLOAD: {str(e)}" |
|
|
print(f"UPLOAD ERROR: {traceback.format_exc()}") |
|
|
return error_msg |
|
|
|
|
|
def get_rag_stats(): |
|
|
"""Lấy thống kê chi tiết""" |
|
|
try: |
|
|
stats = rag_system.get_collection_stats() |
|
|
return f""" |
|
|
📊 THỐNG KÊ RAG DATABASE: |
|
|
• 📄 Tổng documents: {stats['total_documents']} |
|
|
• 🔤 Số embeddings: {stats['embedding_count']} |
|
|
• 📐 Dimension: {stats['embedding_dimension']} |
|
|
• 🌐 Phân bố ngôn ngữ: {stats['language_distribution']} |
|
|
• ✅ Trạng thái: {stats['status']} |
|
|
• 🏷️ Tên: {stats['name']} |
|
|
💡 Embeddings: {'Có' if stats['has_embeddings'] else 'Không'} |
|
|
""" |
|
|
except Exception as e: |
|
|
return f"❌ Lỗi lấy thống kê: {str(e)}" |
|
|
|
|
|
def search_rag_database(query): |
|
|
"""Tìm kiếm để kiểm tra dữ liệu""" |
|
|
if not query.strip(): |
|
|
return [{"message": "Nhập từ khóa để tìm kiếm"}] |
|
|
|
|
|
try: |
|
|
results = rag_system.semantic_search(query, top_k=3) |
|
|
|
|
|
if not results: |
|
|
return [{"message": "Không tìm thấy kết quả nào", "query": query}] |
|
|
|
|
|
return results |
|
|
|
|
|
except Exception as e: |
|
|
return [{"error": f"Lỗi tìm kiếm: {str(e)}"}] |
|
|
|
|
|
|
|
|
upload_btn.click(upload_wikipedia_file, inputs=[file_upload], outputs=[upload_status]) |
|
|
stats_btn.click(get_rag_stats, inputs=[], outputs=[stats_display]) |
|
|
search_btn.click(search_rag_database, inputs=[search_query], outputs=[rag_results]) |
|
|
|
|
|
return rag_tab |
|
|
def create_audio_tab(audio_service: AudioService): |
|
|
gr.Markdown("## Nói chuyện với AI (Đa ngôn ngữ)") |
|
|
audio_input, transcription_output, response_output, tts_audio_output, process_button = create_audio_components() |
|
|
|
|
|
|
|
|
language_display = gr.Textbox( |
|
|
label="🌐 Ngôn ngữ phát hiện", |
|
|
interactive=False, |
|
|
placeholder="Ngôn ngữ sẽ hiển thị ở đây..." |
|
|
) |
|
|
|
|
|
process_button.click( |
|
|
audio_service.transcribe_audio, |
|
|
inputs=audio_input, |
|
|
outputs=[transcription_output, response_output, tts_audio_output, language_display] |
|
|
) |
|
|
def create_streaming_voice_tab(streaming_service: StreamingVoiceService): |
|
|
"""Tạo tab streaming voice sử dụng Gradio microphone""" |
|
|
|
|
|
|
|
|
(microphone, clear_btn, status_display, state_display, |
|
|
transcription, ai_response, tts_output) = create_streaming_voice_components() |
|
|
|
|
|
def process_audio_stream(audio_data): |
|
|
"""Xử lý audio stream từ microphone""" |
|
|
if audio_data is None: |
|
|
return "❌ Không có âm thanh", "Vui lòng nói lại", None, "Đang chờ...", {} |
|
|
|
|
|
try: |
|
|
print("🎯 Đang xử lý audio stream...") |
|
|
|
|
|
|
|
|
result = streaming_service.process_streaming_audio(audio_data) |
|
|
|
|
|
|
|
|
state = streaming_service.get_conversation_state() |
|
|
status = f"✅ Đã xử lý - {len(result['transcription'])} ký tự" |
|
|
|
|
|
return result['transcription'], result['response'], result['tts_audio'], status, state |
|
|
|
|
|
except Exception as e: |
|
|
error_msg = f"❌ Lỗi xử lý: {str(e)}" |
|
|
print(f"Lỗi: {traceback.format_exc()}") |
|
|
return error_msg, "Xin lỗi, có lỗi xảy ra", None, "❌ Lỗi", {} |
|
|
|
|
|
def clear_conversation(): |
|
|
"""Xóa hội thoại""" |
|
|
streaming_service.clear_conversation() |
|
|
state = streaming_service.get_conversation_state() |
|
|
return "", "", None, "🗑️ Đã xóa hội thoại", state |
|
|
|
|
|
|
|
|
microphone.stream( |
|
|
process_audio_stream, |
|
|
inputs=[microphone], |
|
|
outputs=[transcription, ai_response, tts_output, status_display, state_display] |
|
|
) |
|
|
|
|
|
clear_btn.click( |
|
|
clear_conversation, |
|
|
outputs=[transcription, ai_response, tts_output, status_display, state_display] |
|
|
) |
|
|
|
|
|
|
|
|
def get_initial_state(): |
|
|
state = streaming_service.get_conversation_state() |
|
|
return state |
|
|
|
|
|
|
|
|
def initialize_tab(): |
|
|
state = streaming_service.get_conversation_state() |
|
|
return "Sẵn sàng - nhấn nút microphone để nói", state |
|
|
|
|
|
|
|
|
status_display.value = "Sẵn sàng - nhấn nút microphone để nói" |
|
|
state_display.value = streaming_service.get_conversation_state() |
|
|
def create_image_tab(image_service: ImageService): |
|
|
gr.Markdown("## Phân tích hình ảnh") |
|
|
with gr.Row(): |
|
|
image_input = gr.Image(type="numpy", label="Tải lên hình ảnh") |
|
|
with gr.Row(): |
|
|
image_description = gr.Textbox( |
|
|
label="Mô tả hình ảnh của bạn (tùy chọn)", |
|
|
placeholder="Mô tả ngắn về hình ảnh để AI phân tích chính xác hơn..." |
|
|
) |
|
|
with gr.Row(): |
|
|
image_output = gr.Textbox(label="Kết quả phân tích") |
|
|
analyze_button = gr.Button("Phân tích hình ảnh", variant="primary") |
|
|
analyze_button.click( |
|
|
image_service.analyze_image_with_description, |
|
|
inputs=[image_input, image_description], |
|
|
outputs=[image_output] |
|
|
) |
|
|
def create_chat_tab(chat_service: ChatService): |
|
|
gr.Markdown("## Trò chuyện với AI Assistant (Đa ngôn ngữ)") |
|
|
|
|
|
chatbot, state, user_input, send_button, clear_button, chat_tts_output = create_chat_components() |
|
|
|
|
|
|
|
|
chat_language_display = gr.Textbox( |
|
|
label="🌐 Ngôn ngữ phát hiện", |
|
|
interactive=False, |
|
|
placeholder="Ngôn ngữ sẽ hiển thị ở đây..." |
|
|
) |
|
|
|
|
|
|
|
|
send_button.click( |
|
|
fn=chat_service.respond, |
|
|
inputs=[user_input, state], |
|
|
outputs=[user_input, chatbot, state, chat_tts_output, chat_language_display] |
|
|
) |
|
|
|
|
|
clear_button.click( |
|
|
fn=chat_service.clear_chat_history, |
|
|
inputs=[state], |
|
|
outputs=[chatbot, state] |
|
|
) |
|
|
|
|
|
|
|
|
user_input.submit( |
|
|
fn=chat_service.respond, |
|
|
inputs=[user_input, state], |
|
|
outputs=[user_input, chatbot, state, chat_tts_output, chat_language_display] |
|
|
) |
|
|
|
|
|
def create_language_info_tab(multilingual_manager): |
|
|
"""Tab hiển thị thông tin về hệ thống đa ngôn ngữ""" |
|
|
gr.Markdown("## 🌐 Thông tin Hệ thống Đa ngôn ngữ") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
gr.Markdown("### 🔧 Cấu hình Model") |
|
|
|
|
|
vietnamese_info = multilingual_manager.get_language_info('vi') |
|
|
multilingual_info = multilingual_manager.get_language_info('en') |
|
|
|
|
|
|
|
|
gr.Markdown(f""" |
|
|
**Tiếng Việt:** |
|
|
- Embedding Model: `{vietnamese_info['embedding_model']}` |
|
|
- LLM Model: `{vietnamese_info['llm_model']}` |
|
|
- Trạng thái: {vietnamese_info['embedding_status']} |
|
|
|
|
|
**Đa ngôn ngữ:** |
|
|
- Embedding Model: `{multilingual_info['embedding_model']}` |
|
|
- LLM Model: `{multilingual_info['llm_model']}` |
|
|
- Trạng thái: {multilingual_info['embedding_status']} |
|
|
""") |
|
|
|
|
|
with gr.Column(): |
|
|
gr.Markdown("### 🎯 Ngôn ngữ được hỗ trợ") |
|
|
|
|
|
supported_languages = """ |
|
|
- 🇻🇳 **Tiếng Việt**: Sử dụng model chuyên biệt |
|
|
- 🇺🇸 **English**: Sử dụng model đa ngôn ngữ |
|
|
- 🇫🇷 **French**: Sử dụng model đa ngôn ngữ |
|
|
- 🇪🇸 **Spanish**: Sử dụng model đa ngôn ngữ |
|
|
- 🇩🇪 **German**: Sử dụng model đa ngôn ngữ |
|
|
- 🇯🇵 **Japanese**: Sử dụng model đa ngôn ngữ |
|
|
- 🇰🇷 **Korean**: Sử dụng model đa ngôn ngữ |
|
|
- 🇨🇳 **Chinese**: Sử dụng model đa ngôn ngữ |
|
|
""" |
|
|
gr.Markdown(supported_languages) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
gr.Markdown("### 🔍 Kiểm tra Ngôn ngữ") |
|
|
test_text = gr.Textbox( |
|
|
label="Nhập văn bản để kiểm tra ngôn ngữ", |
|
|
placeholder="Nhập văn bản bằng bất kỳ ngôn ngữ nào..." |
|
|
) |
|
|
test_button = gr.Button("🔍 Kiểm tra", variant="primary") |
|
|
|
|
|
test_result = gr.JSON(label="Kết quả phát hiện ngôn ngữ") |
|
|
|
|
|
test_button.click( |
|
|
lambda text: { |
|
|
'detected_language': multilingual_manager.detect_language(text), |
|
|
'language_info': multilingual_manager.get_language_info(multilingual_manager.detect_language(text)), |
|
|
'embedding_model': multilingual_manager.get_embedding_model(multilingual_manager.detect_language(text)) is not None, |
|
|
'llm_model': multilingual_manager.get_llm_model(multilingual_manager.detect_language(text)) |
|
|
}, |
|
|
inputs=[test_text], |
|
|
outputs=[test_result] |
|
|
) |
|
|
def create_tts_tab(tts_service: EnhancedTTSService): |
|
|
gr.Markdown("## 🎵 Chuyển văn bản thành giọng nói nâng cao") |
|
|
gr.Markdown("Nhập văn bản và chọn ngôn ngữ để chuyển thành giọng nói") |
|
|
|
|
|
with gr.Group(): |
|
|
with gr.Row(): |
|
|
tts_text_input = gr.Textbox( |
|
|
label="Văn bản cần chuyển thành giọng nói", |
|
|
lines=4, |
|
|
placeholder="Nhập văn bản tại đây..." |
|
|
) |
|
|
with gr.Row(): |
|
|
tts_language = gr.Dropdown( |
|
|
choices=["vi", "en", "fr", "es", "de", "ja", "ko", "zh"], |
|
|
value="vi", |
|
|
label="Ngôn ngữ" |
|
|
) |
|
|
tts_provider = gr.Dropdown( |
|
|
choices=["auto", "gtts", "edgetts"], |
|
|
value="auto", |
|
|
label="Nhà cung cấp TTS" |
|
|
) |
|
|
with gr.Row(): |
|
|
tts_output_audio = gr.Audio( |
|
|
label="Kết quả giọng nói", |
|
|
interactive=False |
|
|
) |
|
|
tts_button = gr.Button("🔊 Chuyển thành giọng nói", variant="primary") |
|
|
|
|
|
def text_to_speech_standalone(text, language, tts_provider): |
|
|
if not text: |
|
|
return None |
|
|
|
|
|
try: |
|
|
tts_audio_bytes = tts_service.text_to_speech(text, language, tts_provider) |
|
|
if tts_audio_bytes: |
|
|
temp_audio_file = tts_service.save_audio_to_file(tts_audio_bytes) |
|
|
return temp_audio_file |
|
|
except Exception as e: |
|
|
print(f"❌ Lỗi TTS: {e}") |
|
|
|
|
|
return None |
|
|
|
|
|
tts_button.click( |
|
|
text_to_speech_standalone, |
|
|
inputs=[tts_text_input, tts_language, tts_provider], |
|
|
outputs=[tts_output_audio] |
|
|
) |
|
|
|
|
|
|