| 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 với VAD""" |
| |
| with gr.Blocks() as streaming_tab: |
| gr.Markdown("## 🎤 Trò chuyện giọng nói thời gian thực với VAD") |
| gr.Markdown(""" |
| ### 🎯 Chế độ VAD (Voice Activity Detection) |
| - **Tự động phát hiện** khi bạn bắt đầu nói |
| - **Không cần giữ nút** - hệ thống tự nhận diện |
| - **Loại bỏ tiếng ồn** - chỉ xử lý giọng nói thật |
| """) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| |
| with gr.Row(): |
| start_vad_btn = gr.Button("🎙️ Bắt đầu VAD", variant="primary") |
| stop_vad_btn = gr.Button("🛑 Dừng VAD", variant="secondary") |
| |
| |
| microphone = gr.Microphone( |
| label="🎤 Hoặc nhấn để nói thủ công", |
| type="numpy", |
| streaming=True, |
| show_download_button=False |
| ) |
| |
| |
| clear_btn = gr.Button("🗑️ Xóa hội thoại", variant="secondary") |
| |
| |
| status_display = gr.Textbox( |
| label="Trạng thái", |
| value="Chưa bắt đầu - nhấn 'Bắt đầu VAD'", |
| interactive=False |
| ) |
| |
| |
| state_display = gr.JSON( |
| label="Thông tin hệ thống", |
| value={} |
| ) |
| |
| with gr.Column(scale=2): |
| |
| realtime_transcription = gr.Textbox( |
| label="📝 Bạn vừa nói", |
| lines=2, |
| interactive=False, |
| placeholder="Văn bản được chuyển đổi sẽ xuất hiện ở đây..." |
| ) |
| |
| |
| ai_response = gr.Textbox( |
| label="🤖 Phản hồi AI", |
| lines=3, |
| interactive=False, |
| placeholder="Phản hồi của AI sẽ xuất hiện ở đây..." |
| ) |
| |
| |
| tts_output = gr.Audio( |
| label="🔊 Phản hồi bằng giọng nói", |
| interactive=False, |
| autoplay=True |
| ) |
| |
| def start_vad(): |
| """Bắt đầu VAD listening""" |
| def vad_callback(result): |
| """Callback khi VAD phát hiện speech""" |
| |
| |
| print(f"VAD Result: {result}") |
| |
| success = streaming_service.start_listening(vad_callback) |
| status = "✅ Đang lắng nghe với VAD..." if success else "❌ Lỗi khởi động VAD" |
| state = streaming_service.get_conversation_state() |
| return status, state |
| |
| def stop_vad(): |
| """Dừng VAD listening""" |
| streaming_service.stop_listening() |
| state = streaming_service.get_conversation_state() |
| return "🛑 Đã dừng VAD", state |
| |
| def process_manual_audio(audio_data): |
| """Xử lý audio manual (không dùng VAD)""" |
| if audio_data is None: |
| return "❌ Không có âm thanh", "Vui lòng nói lại", None, "Đang chờ...", {} |
| |
| try: |
| result = streaming_service.process_streaming_audio(audio_data) |
| state = streaming_service.get_conversation_state() |
| status = "✅ Đã xử lý manual audio" |
| return result['transcription'], result['response'], result['tts_audio'], status, state |
| except Exception as e: |
| error_msg = f"❌ Lỗi: {str(e)}" |
| 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 |
| |
| |
| start_vad_btn.click( |
| start_vad, |
| outputs=[status_display, state_display] |
| ) |
| |
| stop_vad_btn.click( |
| stop_vad, |
| outputs=[status_display, state_display] |
| ) |
| |
| microphone.stream( |
| process_manual_audio, |
| inputs=[microphone], |
| outputs=[realtime_transcription, ai_response, tts_output, status_display, state_display] |
| ) |
| |
| clear_btn.click( |
| clear_conversation, |
| outputs=[realtime_transcription, ai_response, tts_output, status_display, state_display] |
| ) |
| |
| return streaming_tab |
| 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] |
| ) |
|
|
| |