Dify एलएलएम वर्कफ़्लो ऑनलाइन बनाने के लिए एक ओपन-सोर्स SaaS प्लेटफ़ॉर्म है। मैं अपने ऐप पर संवादात्मक एआई अनुभव बनाने के लिए एपीआई का उपयोग कर रहा हूं। मैं एपीआई प्रतिक्रिया के रूप में टीटीएस स्ट्रीम प्राप्त करने और इसे चलाने के लिए संघर्ष कर रहा था। यहां मैं दर्शाता हूं कि ऑडियो स्ट्रीम को कैसे संसाधित किया जाए और इसे सही तरीके से कैसे चलाया जाए।
मैं टेक्स्ट चैट के लिए एपीआई एंडपॉइंट https://api.dify.ai/v1/chat-messages का उपयोग कर रहा हूं। यदि हम अपने Dify ऐप्स में टेक्स्ट टू स्पीच सुविधा सक्षम करते हैं तो यह टेक्स्ट प्रतिक्रिया के समान स्ट्रीम में ऑडियो डेटा लौटाता है।
फीचर जोड़ें बटन दबाएं और टेक्स्ट टू स्पीच फीचर जोड़ें।
आप निम्नलिखित कर्ल कमांड के साथ एपीआई से प्रतिक्रिया की जांच कर सकते हैं।
curl -X POST 'https://api.dify.ai/v1/chat-messages' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --data-raw '{ "inputs": {}, "query": "What are the specs of the iPhone 13 Pro Max?", "response_mode": "streaming", "conversation_id": "", "user": "abc-123", "files": [] }'
मैं टाइपस्क्रिप्ट/जावास्क्रिप्ट में प्रदर्शित करता हूं लेकिन आप अपनी प्रोग्रामिंग भाषा में वही तर्क लागू कर सकते हैं।
सबसे पहले, आइए समझें कि Dify स्ट्रीम के लिए किस प्रकार का डेटा उपयोग कर रहा है।
Dify निम्नलिखित टेक्स्ट डेटा प्रारूप का उपयोग कर रहा है। यह JSON लाइनों की तरह है लेकिन यह बिल्कुल वैसा नहीं है।
data: {"event": "workflow_started", "conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "message_id": "3f0fe3cf-5aa1-4f7c-8abe-2505bf07ae8f", "created_at": 1724478014, "task_id": "dacb2d5c-a6f5-44b5-b5a6-de000f24aeba", "workflow_run_id": "50100b30-e458-4632-ad7d-8dd383823376", "data": {"id": "50100b30-e458-4632-ad7d-8dd383823376", "workflow_id": "debdb4fa-dcab-4233-9413-fd6d17b9e36a", "sequence_number": 334, "inputs": {"sys.query": "What are the specs of the iPhone 13 Pro Max?", "sys.files": [], "sys.conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "sys.user_id": "abc-123"}, "created_at": 1724478014}} data: {"event": "node_started", "conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "message_id": "3f0fe3cf-5aa1-4f7c-8abe-2505bf07ae8f", "created_at": 1724478014, "task_id": "dacb2d5c-a6f5-44b5-b5a6-de000f24aeba", "workflow_run_id": "50100b30-e458-4632-ad7d-8dd383823376", "data": {"id": "bf912f43-29dd-4ee2-aefa-0fabdf379257", "node_id": "1721365917005", "node_type": "start", "title": "\u958b\u59cb", "index": 1, "predecessor_node_id": null, "inputs": null, "created_at": 1724478013, "extras": {}}} data: {"event": "node_finished", "conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "message_id": "3f0fe3cf-5aa1-4f7c-8abe-2505bf07ae8f", "created_at": 1724478014, "task_id": "dacb2d5c-a6f5-44b5-b5a6-de000f24aeba", "workflow_run_id": "50100b30-e458-4632-ad7d-8dd383823376", "data": {"id": "bf912f43-29dd-4ee2-aefa-0fabdf379257", "node_id": "1721365917005", "node_type": "start", "title": "\u958b\u59cb", "index": 1, "predecessor_node_id": null, "inputs": {"sys.query": "What are the specs of the iPhone 13 Pro Max?", "sys.files": [], "sys.conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "sys.user_id": "abc-123", "sys.dialogue_count": 1}, "process_data": null, "outputs": {"sys.query": "What are the specs of the iPhone 13 Pro Max?", "sys.files": [], "sys.conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "sys.user_id": "abc-123", "sys.dialogue_count": 1}, "status": "succeeded", "error": null, "elapsed_time": 0.001423838548362255, "execution_metadata": null, "created_at": 1724478013, "finished_at": 1724478013, "files": []}} data: {"event": "node_started", "conversation_id": "065fb118-35d4-4524-a067-a70338ece575", "message_id": "3f0fe3cf-5aa1-4f7c-8abe-2505bf07ae8f", "created_at": 1724478014, "task_id": "dacb2d5c-a6f5-44b5-b5a6-de000f24aeba", "workflow_run_id": "50100b30-e458-4632-ad7d-8dd383823376", "data": {"id": "89ed58ab-6157-499b-81b2-92b1336969a5", "node_id": "llm", "node_type": "llm", "title": "LLM", "index": 2, "predecessor_node_id": "1721365917005", "inputs": null, "created_at": 1724478013, "extras": {}}} ...
प्रतिक्रिया में, Dify टेक्स्ट उत्तर और ऑडियो डेटा को आगे बढ़ाता है।
पाठ उत्तर की उदाहरण पंक्ति
data: {"event": "message", "conversation_id": "aa13eb24-e90a-4c5d-a36b-756f0e3be8f8", "message_id": "5be739a9-09ba-4444-9905-a2f37f8c7a21", "created_at": 1724301648, "task_id": "0643f770-e9d3-408f-b771-bb2e9430b4f9", "id": "5be739a9-09ba-4444-9905-a2f37f8c7a21", "answer": "MP"}
ऑडियो डेटा की उदाहरण पंक्ति
data: {"event": "tts_message", "conversation_id": "aa13eb24-e90a-4c5d-a36b-756f0e3be8f8", "message_id": "5be739a9-09ba-4444-9905-a2f37f8c7a21", "created_at": 1724301648, "task_id": "0643f770-e9d3-408f-b771-bb2e9430b4f9", "audio": "//PkxABhvDm0DVp4ACUUfvWc1CFlh0tR9Oh7LxzHRsGBuGx155x3JqTJiwKKZf8wIcxpMzJU0h4zhgyQwwwIsgWQMAALQMkanBTjfCPgZwFsDOGGIYJoJoJoJoPQPQLYEgAOwM4SMXMW8TcNWGrEPEME0HoIQTg0DQNA0C5k7IOLeJuDnDVi5nWyJwgghAagQwTQQgJAGrDVibiFhqw1YR8HOEjBUA5AcgagQwTQTQQgJAAtgLYKsQ8hZc0PV7OrE4SgQgFIAsAQAwA6H0Uv4t4m4m49Yt4uYOQHIBkAyAqAkAuB0Mm6UeKxDGRrIODkByBqBNBCA1ARwHIEgBVg5wkY41W2GgdEVDFBNe HicQw0ydk7HrHrIWXM62d48ePNfCkNATcTcNWGrCRhqxDxcwMYBwBkByCGC4EILgoJTQUDeW8W8TcTchZ1qBWIYchOBbBCA1AhgSMJGGrFzLmh6fL LeBkAyAZAcgSAXAhB0Kxnj4YDkJwXA6FAzwj8IIJoJoPQXA6EPOcg4R8FOBnCRljRAwlwoh4EUwLhFTCVA MR0R8wyxOhgAwwDgJjBUABMM0hMxBgnTPtMrMBEEcwJQCzIXIdMZMG821DmjDKHJAwLDKHRMQsJkwbwVRoFs//PkxEx5dDnwAZ7wANHgEUFJHGCUCQp3LWCQQYGAATI5QzwHBJF4UFktpfATT2l0goAGNADLOU64HAMCQCK50szABAIkDS2/j8gl6l6Di7QgBEiAfMEADBnyZBgeAWCMK4xvBbhoRZj1M ktsNMTrMNcHEwHQEzAjAHMGQAQwRQZTBHALMGMDkzhh2jGhLtMgsMMwfhOzCnGLMMcKgwOw8pqHMoGtvdDzos0AIAiXIsBAmGsRFtYcBABmB0AUYjQfhhDAfjoCrETAGArMOAJ4iAAMCMFkwXwh5fffuhpYMhyP2bl3MVAJQrSYQDsna7G2 fx/GvyAwUQbTAdAFCAHVKyIAduTXHZZXDjNS57/VeVJ5 JBJ 0kATkCSells8/NBt/2/5Dj1s chDBYSINutNS9FQwDwBWHjgASKRgAAJOyYC4Ao0CMNAKBgB6KK1hYBkAAHROM9mLsknb8avTcB0MerV6jl7llE70egOerRh9WcP/FoHqtVsO/In2f G2tsdnH L/KSSvBQB4OATam27Yi4jiBgBFOpq15bTQU6k1G4LoWo1mMAwDQwlBEzEnKsMkA7c5JYuTOzK2MvAbEysSPTM dOOn1XEzGgIzXzmPODVvs1cyNTJxQ9MsAWwy//PkxDlz7DIMAd7gAek5EwnjcjX9QVN1N0czFyijQKOmMi4IYw8RvzFvCHMHYBQwdQlTRxVNvm8ycGjLYlMTAQ=="}
हम इवेंट प्रॉपर्टी की जांच करके ऑडियो डेटा की JSON लाइनों को अलग कर सकते हैं। ऑडियो JSON का मान tts_message है। ऑडियो एमपी3 बाइनरी को JSONs की ऑडियो प्रॉपर्टी में बेस64 प्रारूप में संग्रहीत किया जाता है।
जब हम टीटीएस ऑडियो रीयल-टाइम चलाते हैं तो पहली समस्या यह होती है कि JSON लाइनें पैकेट में विभाजित हो जाती हैं और प्रत्येक पैकेट वैध JSON डेटा नहीं होता है।
उदाहरण पैकेट जो बीच में कटा हुआ है
euimRrhsPMZiMAl BqSZMDmIkQEcDb/8 TEtHm8MhwA3p/p8dA0CCpAxwMMPABoYMIWwUDG6BRmiYZg2G6gRidGanOm5i5iaIYmfkH8Z/FmEopqJGZKXihYEIRxCKYKtlQuMvPjPQIwUVFFECDRnRCYEimGmA6cji41yQMImMEmhaHrVKpCxo2OYx6Q5RcJKAKkah4X6MckHEqdwKgHGHltDUjCy46HMgTCpwodAM8KijREwSSEk5hB4gRGFfC0ouYoeDiYtNREDgKQsTT6EI4egmMMBxpQZmoUJmAAg6YPDmQISgSECAZQOLfAUEQAG/dgxAVkxfFHGorEHB4CS Yugwk2gq8akIwMsZIuIzUSrCAGm1iBnoYA8lcoYSlaIJ5RjCblwbsh8sB3skA7Gcx3zmSOKnXNJO6ObKklhuYjlVL1dSMhgwVJtFzMeWFufNKy3ODmCExBTUUzLjEwMKqqqqqqqqqqqqqqqqqqCIEWFIAA4DAWKkMDDIBA4lBqGDdmZwzAkGJFoYiwEV0IQOQHg1AATJiUM6F0z2fDE6PMvlc6DhTMJ MNH4xWwzBwKMMCgHAwwUFQwjGEgMgovgIBMIMECYxYSDKAwSoMOBC4Ez682pEZIB8kBuiawZEaSnFAjIEwSFRxGUJIXMGRMmfNCPApcKL/8 TEiVdEKlJm5pM9gz0MyScwo04BgqjEFh489MGKVw=="}
पैकेट JSON लाइन के मध्य से प्रारंभ हो रहा है। वैध JSON लाइन प्राप्त करने के लिए हमें कई पैकेटों को संयोजित करना होगा।
दूसरी समस्या यह है कि JSON में ऑडियो डेटा खंड वैध ऑडियो डेटा नहीं है। डेटा को एमपी3 फ्रेम के बीच में काटा जाता है।
JSON और mp3 के स्प्लिट डेटा को संभालने के लिए हमें कुछ स्मार्ट तरीके अपनाने होंगे। प्रक्रिया का प्रवाह इस प्रकार है:
सबसे पहले, हमें वैध JSON डेटा प्राप्त करना होगा और पैकेट प्राप्त करते समय JSON में विभाजित करना होगा। जब हमें अंत में \n वाला एक पैकेट मिलता है, तो हम कह सकते हैं कि अब तक प्राप्त पैकेटों का संयोजन बीच में नहीं काटा गया है। छद्म कोड इस प्रकार है।
let packets = [] stream.on('data', (bytes) => { const text = bytes.toString() packets.push(text) if (text.endsWith('\n')) { // Extract audio data from the packets. const audioChunks = extractAudioChunks(packets.join('')) // Clear the packet array packets = [] } })
दूसरा, हमें ऑडियो हिस्सों को एमपी3 फ्रेम में विभाजित करना होगा। हम ऑडियो खंडों को एक बाइनरी में जोड़ते हैं और उसमें प्रत्येक एमपी3 फ़्रेम ढूंढते हैं।
const mp3Frames = [] const binaryToProcess = Buffer.concat([...audioChunks]) let frameStartIndex = 0 for (let i = 0; iयह एमपी3 फ्रेम में विभाजन का पूर्ण कार्यान्वयन नहीं है। वास्तविक प्रक्रिया में, हमें उन मामलों पर विचार करना होगा जब हमने ऑडियो बाइनरी से एमपी3 फ्रेम निकाले थे और शेष बाइट्स को अगले पुनरावृत्ति में ऑडियो बाइट्स की शुरुआत के रूप में उपयोग किया था। पूर्ण कार्यान्वयन के लिए कृपया मेरा जीथब रेपो जांचें।
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3