v0.0.2
Openai-Whisper-Talk เป็นแอพพลิเคชั่นการสนทนาด้วยเสียงที่ขับเคลื่อนด้วยเทคโนโลยี OpenAI เช่น Whisper ระบบการรู้จำเสียงพูดอัตโนมัติ (ASR) การแชทเสร็จสมบูรณ์อินเตอร์เฟสที่จำลองการสนทนากับโมเดลที่มีบทบาทของผู้ช่วยฝังข้อความ แอปพลิเคชันถูกสร้างขึ้นโดยใช้ Nuxt ซึ่งเป็นเฟรมเวิร์ก JavaScript ตาม Vue.js.
แอปพลิเคชันมีคุณสมบัติใหม่สองประการ: การจัดการตารางเวลาและหน่วยความจำระยะยาว ด้วยการจัดการตารางเวลาคุณสามารถสั่ง chatbot เพื่อเพิ่มแก้ไขลบและดึงเหตุการณ์ที่กำหนดเวลา คุณสมบัติหน่วยความจำระยะยาวช่วยให้คุณสามารถเก็บข้อมูลตัวอย่างที่ chatbot จะจดจำสำหรับการอ้างอิงในอนาคต คุณสามารถรวมฟังก์ชั่นทั้งสองเข้ากับการสนทนาของคุณได้อย่างราบรื่นโดยการโต้ตอบกับ chatbot
อัปเดต: อัปเดตโมดูล OpenAI เป็นเวอร์ชันล่าสุดและแทนที่โมเดลการฝังจาก
text-embedding-ada-002เป็นรุ่น V3 รุ่นใหม่ที่ทำtext-embedding-3-small
Openai-Whisper-talk は、 Whisper (ASR))))、 การแชทเสร็จสมบูรณ์ (アシスタントの役割を果たすモデルとの会話をシミュレートするインターフェース)、、、、、 (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する)) (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する (セマンティック検索などのタスクで使用できるベクターデータにテキストを変換する に基づいたに基づいたに基づいた Javascript フレームワークである nuxt を使用して構築されています。 (テキストをリアルな話し言葉のオーディオに変える の技術を駆使したサンプル音声会話アプリケーションです。このアプリケーションは、 の技術を駆使したサンプル音声会話アプリケーションです。このアプリケーションは、 の技術を駆使したサンプル音声会話アプリケーションです。このアプリケーションは、 の技術を駆使したサンプル音声会話アプリケーションです。このアプリケーションは、
このアプリケーションには、「スケジュール管理」と「永続メモリ」の 2 つの新機能があります。スケジュール管理を使用すると、チャットボットにスケジュールイベントの追加、変更、削除、取得を指示できます。永続メモリ機能を使用すると、将来の参照のためにチャットボットが覚えておく情報のスニペットを保存できます。これらの機能をチャットボットとの対話を通じてシームレスに統合することができます。将来的に、いくつかの機能強化、たとえばメールやメッセージング機能を追加することで、完全な個人アシスタントになるかもしれません。

จากหน้าหลักคุณสามารถเลือก chatbot ที่จะมีส่วนร่วมด้วย chatbot แต่ละคนมีบุคลิกที่แตกต่างพูดภาษาที่แตกต่างและมีเสียงที่เป็นเอกลักษณ์ คุณสามารถเปลี่ยนชื่อและบุคลิกภาพของ chatbot ใด ๆ ได้โดยคลิกที่ปุ่ม แก้ไข ที่อยู่ติดกับชื่อ ปัจจุบันอินเทอร์เฟซผู้ใช้ไม่สนับสนุนการเพิ่ม chatbots ใหม่โดยตรง อย่างไรก็ตามคุณสามารถเพิ่ม chatbot ด้วยตนเองและปรับแต่งการตั้งค่าเสียงและภาษาสำหรับแต่ละรายการโดยการแก้ไขไฟล์สินทรัพย์/ผู้ติดต่อ json

นอกจากนี้คุณสามารถปรับแต่งโปรไฟล์ของคุณได้โดยคลิกที่ไอคอน Avatar ที่มุมขวาบน สิ่งนี้ช่วยให้คุณสามารถป้อนชื่อของคุณและแบ่งปันรายละเอียดเกี่ยวกับตัวคุณเองทำให้แชทบ็อตสามารถโต้ตอบกับคุณในลักษณะที่เป็นส่วนตัวมากขึ้น


ข้อมูลเสียงจะถูกบันทึกโดยอัตโนมัติหากตรวจพบเสียง มีการตั้งค่าเกณฑ์เพื่อป้องกันไม่ให้เสียงรบกวนจากพื้นหลังทริกเกอร์การจับเสียง โดยค่าเริ่มต้นจะถูกตั้งค่าเป็น -45DB (พร้อม -10dB แสดงถึงเสียงที่ดังที่สุด) คุณสามารถปรับเกณฑ์นี้ได้โดยการปรับเปลี่ยนตัวแปร MIN_DECIBELS 1 ตามความต้องการของคุณ
เมื่อเปิดใช้งานการบันทึกและไม่พบเสียงเป็นเวลา 3 วินาที ข้อมูลเสียงจะถูกอัปโหลดและส่งไปยังแบ็กเอนด์สำหรับการถอดความ เป็นที่น่าสังเกตว่าในการสนทนาทั่วไปช่องว่างเฉลี่ยระหว่างแต่ละเทิร์นอยู่ที่ประมาณ 2 วินาที ในทำนองเดียวกันการหยุดชั่วคราวระหว่างประโยคเมื่อพูดประมาณเดียวกัน ดังนั้นฉันจึงเลือกระยะเวลาที่ยาวพอที่จะรอการตอบกลับ คุณสามารถปรับระยะเวลานี้ได้โดยการแก้ไขตัวแปร MAX_COUNT 1
ระบบสามารถบันทึกข้อมูลเสียงได้อย่างต่อเนื่องจนกว่าจะได้รับการตอบกลับ เมื่อการตอบกลับจากเสียงจาก chatbot ได้รับและเล่นการบันทึกเสียงจะถูกปิดใช้งานเพื่อป้องกันการบันทึกการตอบสนองของ chatbot โดยไม่ตั้งใจ
นอกจากนี้ยังมีการป้อนข้อมูลข้อความหากคุณต้องการเขียนข้อความของคุณ
ข้อมูลเสียงที่บันทึกไว้ทั้งหมดจะถูกอัปโหลดไปยังไดเรกทอรี public/upload ในรูปแบบไฟล์ webm ก่อนที่จะส่งไฟล์เสียงไปยัง Whisper API จำเป็นต้องลบส่วนเงียบทั้งหมดออก ขั้นตอนนี้ช่วยป้องกันปัญหาภาพหลอนที่รู้จักกันดีที่เกิดจาก Whisper ด้วยเหตุผลเดียวกันนี้ขอแนะนำให้ตั้งค่า MIN_DECIBELS ให้สูงที่สุดเท่าที่จะทำได้เพื่อให้มั่นใจว่ามีการบันทึกคำพูดเท่านั้น
ในการลบชิ้นส่วนเงียบออกจากเสียงเราจะใช้ ffmpeg ให้แน่ใจว่าได้ติดตั้ง
ffmpeg -i sourceFile -af silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-50dB outputFileในคำสั่งนี้:
-1 sourceFile ระบุไฟล์อินพุต-af silenceremove ใช้ตัวกรอง silencerremovestop_periods=-1 ลบช่วงเวลาทั้งหมดของความเงียบstop_duration=1 ตั้งค่าช่วงเวลาใด ๆ ของความเงียบนานกว่า 1 วินาทีเป็นความเงียบstop_threshold=-50dB ตั้งค่าระดับเสียงรบกวนใด ๆ ต่ำกว่า -50db เป็นความเงียบoutputFile ในการเรียกใช้คำสั่งเชลล์นี้ในเส้นทาง API ของเราเราจะใช้ exec จากโมดูล child-process
หลังจากลบชิ้นส่วนที่เงียบควรตรวจสอบขนาดไฟล์ ขนาดไฟล์สุดท้ายมักจะเล็กกว่าต้นฉบับมาก ในระหว่างการตรวจสอบนี้ไฟล์ที่มีขนาดเล็กกว่า 16 KB จะถูกละเว้นโดยสมมติว่าไฟล์ขนาดนี้มีความลึก 16 บิตเท่ากับเสียงประมาณหนึ่งวินาที สิ่งใดที่สั้นกว่านั้นไม่ได้ยิน
// simple file size formula
const audio_file_size = duration_in_seconds * bitrateกระบวนการทั้งหมดจากการกำจัดชิ้นส่วนที่เงียบไปจนถึงการตรวจสอบขนาดไฟล์ได้รับการออกแบบมาเพื่อให้แน่ใจว่ามีการส่งข้อมูลเสียงที่ทำงานได้เท่านั้นที่ส่งไปยัง Whisper API เป้าหมายของเราคือการหลีกเลี่ยงภาพหลอนและการส่งข้อมูลที่ไม่จำเป็น
หลังจากได้รับการยืนยันถึงความมีชีวิตของข้อมูลเสียงของเราจากนั้นเราจะโทรหา Whisper API ต่อไป
const transcription = await openai . audio . transcriptions . create ( {
file : fs . createReadStream ( filename ) ,
language : lang ,
response_format : 'text' ,
temperature : 0 ,
} ) โดยที่ lang เป็นรหัส ISO 639-1 ของภาษาที่ระบุของ chatbot ของเรา โปรดตรวจสอบรายการภาษาที่รองรับในปัจจุบัน
เราเลือกรูปแบบ text อย่างง่ายเนื่องจากไม่จำเป็นต้องใช้การประทับเวลาและเราตั้งค่าพารามิเตอร์ temperature เป็นศูนย์เพื่อให้ได้ผลลัพธ์ที่กำหนด
หลังจากได้รับการถอดเสียงจาก Whisper เราจะส่งไปยัง API การแชทเสร็จสมบูรณ์ด้วยการเรียกใช้ฟังก์ชั่น เราใช้โมดูล openai node.js ล่าสุด (เวอร์ชัน 4) ที่เผยแพร่เมื่อวานนี้ (2023/11/07) ซึ่งรวมถึงรูปแบบการเรียกใช้ฟังก์ชั่นที่อัปเดต การทำซ้ำใหม่ล่าสุดนี้ช่วยให้การเรียกใช้หลายฟังก์ชั่นในคำขอเดียว
let messages = [ { role : 'system' , content : system_prompt } ]
let all_history = await mongoDb . getMessages ( )
if ( all_history . length > 0 ) {
const history_context = trim_array ( all_history , 20 )
messages = messages . concat ( history_context )
}
messages . push ( { role : 'user' , content : user_query } )
let response = await openai . chat . completions . create ( {
temperature : 0.3 ,
messages ,
tools : [
{ type : 'function' , function : add_calendar_entry } ,
{ type : 'function' , function : get_calendar_entry } ,
{ type : 'function' , function : edit_calendar_entry } ,
{ type : 'function' , function : delete_calendar_entry } ,
{ type : 'function' , function : save_new_memory } ,
{ type : 'function' , function : get_info_from_memory }
]
} )ลองตัดองค์ประกอบต่าง ๆ ของการโทรนี้ในส่วนที่ตามมา
ระบบแจ้งเตือนมีบทบาทสำคัญในการให้ชีวิตกับแชทบ็อตของเรา ที่นี่เป็นที่ที่เราสร้างชื่อและตัวตนตามแชทบ็อตที่ผู้ใช้เลือก เราให้คำแนะนำเฉพาะเกี่ยวกับวิธีการตอบกลับพร้อมกับรายการฟังก์ชั่นที่สามารถดำเนินการได้ นอกจากนี้เรายังแจ้งเกี่ยวกับตัวตนของผู้ใช้และรายละเอียดส่วนบุคคล ในที่สุดเราตั้งค่าวันที่และเวลาปัจจุบันซึ่งเป็นสิ่งจำเป็นสำหรับการเปิดใช้งานฟังก์ชั่นปฏิทิน
const today = new Date ( )
let system_prompt = `In this session, we will simulate a voice conversation between two friends.nn` +
`# Personan` +
`You will act as ${ selPerson . name } .n` +
` ${ selPerson . prompt } nn` +
`Please ensure that your responses are consistent with this persona.nn` +
`# Instructionsn` +
`The user is talking to you over voice on their phone, and your response will be read out loud with realistic text-to-speech (TTS) technology.n` +
`Use natural, conversational language that are clear and easy to follow (short sentences, simple words).n` +
`Keep the conversation flowing.n` +
`Sometimes the user might just want to chat. Ask them relevant follow-up questions.nn` +
`# Functionsn` +
`You have the following functions that you can call depending on the situation.n` +
`add_calendar_entry, to add a new event.n` +
`get_calendar_entry, to get the event at a particular date.n` +
`edit_calendar_entry, to edit or update existing event.n` +
`delete_calendar_entry, to delete an existing event.n` +
`save_new_memory, to save new information to memory.n` +
`get_info_from_memory, to retrieve information from memory.nn` +
`When you present the result from the function, only mention the relevant details for the user query.n` +
`Omit information that is redundant and not relevant to the query.n` +
`Always be concise and brief in your replies.nn` +
`# Usern` +
`As for me, in this simulation I am known as ${ user_info . name } .n` +
` ${ user_info . prompt } nn` +
`# Todayn` +
`Today is ${ today } .n` ข้อความทั้งหมดจะถูกเก็บไว้ใน MongoDB
ในการจัดการโทเค็นและหลีกเลี่ยงการเกินขีด จำกัด สูงสุดของโมเดลเราจะส่งการโต้ตอบ 20 ครั้งล่าสุดเท่านั้น ฟังก์ชั่น trim_array ได้รับการออกแบบมาเพื่อตัดแต่งประวัติข้อความหากเกิน 20 รอบ เกณฑ์นี้สามารถปรับได้เพื่อตอบสนองความต้องการเฉพาะของคุณ
// allow less than or equal to 15 turns
const history_context = trim_array ( all_history , 15 ) จากหน้าจอหลักคุณมีตัวเลือกในการลบประวัติก่อนหน้านี้สำหรับแต่ละ chatbot

โปรดทราบว่าเราได้แยกการจัดการการเรียกใช้ฟังก์ชัน (function_call.js) ออกจากการเรียกร้องการแชทหลัก API (transcribe.php) ความแตกต่างนี้เกิดขึ้นกับที่อยู่อินสแตนซ์เมื่อมีเนื้อหาข้อความอยู่ในขณะที่การเรียกใช้ฟังก์ชันจะถูกเรียกใช้ซึ่งโดยทั่วไปจะเป็นโมฆะ การแยกนี้ช่วยให้แอปสามารถแสดงข้อความในขณะที่การประมวลผลการเรียกใช้ฟังก์ชันพร้อมกัน ฉันได้แนบกระบวนการภายในลูปในกรณีที่การโทร API ครั้งที่สองส่งผลในการเรียกใช้ฟังก์ชันอื่น สิ่งนี้อาจได้รับการจัดการอย่างสง่างามมากขึ้นโดยการใช้ สตรีมมิ่ง แต่ฉันยังไม่ได้เรียนรู้วิธีการใช้สตรีมมิ่งกับ Nuxt
ฟังก์ชั่นของเราถูกจัดหมวดหมู่ภายใต้คุณสมบัติใหม่สองประการ: การจัดการตารางเวลา และ หน่วยความจำระยะยาว
ก่อนอื่นมาตรวจสอบวิธีที่เราจัดการการเรียกใช้ฟังก์ชั่นด้วยรูปแบบใหม่ เราต้องใช้พารามิเตอร์ เครื่องมือ ใหม่แทนพารามิเตอร์ ฟังก์ชั่น ที่ได้รับการพิจารณาในขณะนี้เพื่อเปิดใช้งานการเรียกใช้การเรียกใช้ฟังก์ชันหลายรายการ
let response = await openai . chat . completions . create ( {
temperature : 0.3 ,
messages ,
tools : [
{ type : 'function' , function : add_calendar_entry } ,
{ type : 'function' , function : get_calendar_entry } ,
{ type : 'function' , function : edit_calendar_entry } ,
{ type : 'function' , function : delete_calendar_entry } ,
{ type : 'function' , function : save_new_memory } ,
{ type : 'function' , function : get_info_from_memory }
]
} ) ตรวจสอบ สคีมา JSON ของแต่ละฟังก์ชั่นจาก lib/ ไดเรกทอรี นี่คือ add_calendar_entry :
{
"name" : "add_calendar_entry" ,
"description" : "Adds a new entry to the calendar" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"event" : {
"type" : "string" ,
"description" : "The name or title of the event"
} ,
"date" : {
"type" : "string" ,
"description" : "The date of the event in 'YYYY-MM-DD' format"
} ,
"time" : {
"type" : "string" ,
"description" : "The time of the event in 'HH:MM' format"
} ,
"additional_detail" : {
"type" : "string" ,
"description" : "Any additional details or notes related to the event"
}
} ,
"required" : [ "event" , "date" , "time" , "additional_detail" ]
}
}หากต้องการ dicuss วิธีการทำงานทั้งหมดเหล่านี้ลองไปที่ส่วนถัดไป
สำหรับ การจัดการกำหนดเวลา เรามีฟังก์ชั่นดังต่อไปนี้:
รายการปฏิทินทั้งหมดจะถูกเก็บไว้ใน MongoDB โปรดทราบว่ารายการทั้งหมดจะสามารถเข้าถึงได้สำหรับ chatbots ทั้งหมด
ลองมาดูการสนทนาตัวอย่างแชทเพื่อแสดงให้เห็นว่าองค์ประกอบเหล่านี้มีปฏิสัมพันธ์กันอย่างไร:
ผู้ใช้: สวัสดีตอนเช้า Jeeves วันนี้ของฉันคืออะไร?
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [ {
id : 'call_4cCtmNlgYN5o4foVOQM9MIdA' ,
type : 'function' ,
function : { name : 'get_calendar_entry' , arguments : '{"date":"2023-11-10"}' }
} ]
}การตอบสนองของฟังก์ชั่น:
[
{
tool_call_id : 'call_4cCtmNlgYN5o4foVOQM9MIdA' ,
role : 'tool' ,
name : 'get_calendar_entry' ,
content : '{n' +
' "message": "Found 3 entries",n' +
' "items": [n' +
' {n' +
' "_id": "654b2805e51fcd815dea8e2d",n' +
' "event": "Project presentation",n' +
' "date": "2023-11-10",n' +
' "time": "10:00",n' +
' "additional_detail": "Important project presentation",n' +
' "__v": 0n' +
' },n' +
' {n' +
' "_id": "654d7b53ff0bf31de6c2af29",n' +
' "event": "Meet Tony",n' +
' "date": "2023-11-10",n' +
' "time": "19:00",n' +
' "additional_detail": "Electric Sheep Bar",n' +
' "__v": 0n' +
' },n' +
' {n' +
' "_id": "654d7d868751ea8704fc9f11",n' +
' "event": "Dinner with Anna",n' +
' "date": "2023-11-10",n' +
' "time": "19:00",n' +
' "additional_detail": "Electric Sheep Bar",n' +
' "__v": 0n' +
' }n' +
' ]n' +
'}'
}
]สรุปการแชท:
{ role : 'assistant' ,
content : 'Good morning, Jerry. Today, you have a project presentation at 10:00 AM and a dinner meeting with Anna at 7:00 PM at the Electric Sheep Bar. You also have a meeting with Tony at 7:00 PM at the same location.'
}ผู้ใช้: ดูเหมือนว่าซ้ำซ้อนที่จะมีรายการแยกต่างหากสำหรับเหตุการณ์เดียวกัน คุณสามารถแก้ไขกิจกรรมกับ Anna เพื่อรวมการประชุม Tony และลบกิจกรรมอื่น ๆ ได้หรือไม่?
การเรียกใช้ฟังก์ชัน (เรียกใช้ edit_calendar_entry และ delete_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_ZVAwO5YsXMuWr8876tyCIPIX' ,
type : 'function' ,
function : {
name : 'edit_calendar_entry' ,
arguments : '{"event": "Dinner Meeting with Anna", "date": "2023-11-10", "time": "19:00", "additional_detail": "Meeting with Tony included."}'
}
} ,
{
id : 'call_eMGuI8LxLbXFsLp8FduCrxgp' ,
type : 'function' ,
function : {
name : 'delete_calendar_entry' ,
arguments : '{"delete_type": "event_name", "event": "Meeting with Tony"}'
}
}
]
}การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_ZVAwO5YsXMuWr8876tyCIPIX' ,
role : 'tool' ,
name : 'edit_calendar_entry' ,
content : '{n "message": "Entry edited",n "name": "Dinner Meeting with Anna"n}'
} ,
{
tool_call_id : 'call_eMGuI8LxLbXFsLp8FduCrxgp' ,
role : 'tool' ,
name : 'delete_calendar_entry' ,
content : '{n "name": "Meeting with Tony",n "message": "Entry deleted"n}'
}
]สรุปการแชท:
{ role : 'assistant' ,
content : 'The event "Dinner Meeting with Anna" has been updated to include the meeting with Tony, and the separate event "Meeting with Tony" has been deleted.'
}ผู้ใช้: โอเคเพียงเพื่อให้แน่ใจคุณช่วยบอกตารางเวลาของฉันอีกครั้งสำหรับวันนี้ได้ไหม
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_liqFn24Ds4qp0cy2V5NBg62v' ,
type : 'function' ,
function : { name : 'get_calendar_entry' , arguments : '{"date":"2023-11-10"}' }
}
]
}การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_liqFn24Ds4qp0cy2V5NBg62v' ,
role : 'tool' ,
name : 'get_calendar_entry' ,
content : '{n' +
' "message": "Found 2 entries",n' +
' "items": [n' +
' {n' +
' "_id": "654b2805e51fcd815dea8e2d",n' +
' "event": "Project presentation",n' +
' "date": "2023-11-10",n' +
' "time": "10:00",n' +
' "additional_detail": "Important project presentation",n' +
' "__v": 0n' +
' },n' +
' {n' +
' "_id": "654d7d868751ea8704fc9f11",n' +
' "event": "Dinner with Anna",n' +
' "date": "2023-11-10",n' +
' "time": "19:00",n' +
' "additional_detail": "Meeting with Tony included.",n' +
' "__v": 0n' +
' }n' +
' ]n' +
'}'
}
]สรุปการแชท:
{ role : 'assistant' ,
content : 'Your schedule for today is as follows:n' +
'- Project presentation at 10:00 AMn' +
'- Dinner with Anna at 7:00 PM, which includes a meeting with Tony.'
}ผู้ใช้: อ่าคุณลืมเพิ่มตำแหน่งในมื้อค่ำ ขออภัยคุณสามารถอัปเดตอีกครั้งได้หรือไม่?
การเรียกใช้ฟังก์ชัน (เรียกใช้ edit_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_eRTFMcz2l8qHO7nhp3msI3v8' ,
type : 'function' ,
function : {
name : 'edit_calendar_entry' ,
arguments : '{"event":"Dinner with Anna","date":"2023-11-10","time":"19:00","additional_detail":"Meeting with Tony at the Electric Sheep Bar."}'
}
}
]
}การตอบสนองของฟังก์ชั่น:
{
tool_call_id : 'call_eRTFMcz2l8qHO7nhp3msI3v8' ,
role : 'tool' ,
name : 'edit_calendar_entry' ,
content : '{n "message": "Entry edited",n "name": "Dinner with Anna"n}'
}สรุปการแชท:
{ role : 'assistant' ,
content : 'The event "Dinner with Anna" has been updated to include the meeting with Tony at the Electric Sheep Bar.'
}ผู้ใช้: โอเคฉันต้องการยืนยันอีกครั้งคุณช่วยบอกตารางเวลาของฉันสำหรับวันนี้ได้ไหม
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_HYlAj4BTeWcu2CxSp4zBYPuC' ,
type : 'function' ,
function : { name : 'get_calendar_entry' , arguments : '{"date":"2023-11-10"}' }
}
]
}การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_HYlAj4BTeWcu2CxSp4zBYPuC' ,
role : 'tool' ,
name : 'get_calendar_entry' ,
content : '{n' +
' "message": "Found 2 entries",n' +
' "items": [n' +
' {n' +
' "_id": "654b2805e51fcd815dea8e2d",n' +
' "event": "Project presentation",n' +
' "date": "2023-11-10",n' +
' "time": "10:00",n' +
' "additional_detail": "Important project presentation",n' +
' "__v": 0n' +
' },n' +
' {n' +
' "_id": "654d7d868751ea8704fc9f11",n' +
' "event": "Dinner with Anna",n' +
' "date": "2023-11-10",n' +
' "time": "19:00",n' +
' "additional_detail": "Meeting with Tony at the Electric Sheep Bar.",n' +
' "__v": 0n' +
' }n' +
' ]n' +
'}'
}
]สรุปการแชท:
{ role : 'assistant' ,
content : 'Your schedule for today is as follows:n' +
'- Project presentation at 10:00 AMn' +
'- Dinner with Anna at 7:00 PM, which includes a meeting with Tony at the Electric Sheep Bar.'
}สำหรับ หน่วยความจำระยะยาว เรามีฟังก์ชั่นต่อไปนี้
ฟังก์ชั่นก่อนหน้าทั้งหมดทั้งหมดมุ่งเน้นไปที่การดึงข้อมูลทั่วไปและการตั้งค่างาน แต่สำหรับการดึงหน่วยความจำระยะยาวเราไม่สามารถเพียงแค่ค้นหาคำหลัก เราต้องพิจารณาบริบทของการสืบค้น เราต้องทำการค้นหาความหมาย และในเรื่องนี้เราจะใช้ Embeddings API ให้เราดำเนินการต่อไปยังส่วนถัดไปเพื่อหารือเกี่ยวกับเรื่องนี้เพิ่มเติม
อัปเดต : ฉันได้แทนที่
text-embedding-ada-002ด้วยtext-embedding-3-smallจากการทดสอบของฉันหลังทำงานได้ดีพอ คะแนนความคล้ายคลึงกันของโคไซน์ระหว่างคำตอบที่เกี่ยวข้องอย่างใกล้ชิดและคำตอบที่ไม่เกี่ยวข้องนั้นแตกต่างกันอย่างชัดเจน นอกจากนี้ค่าใช้จ่ายของรุ่นขนาดเล็ก V3 ซึ่งมีราคาอยู่ที่โทเค็น $ 0.00002/1K อย่างไรก็ตามคุณต้องแปลงข้อมูลเวกเตอร์ของคุณจาก ADA เป็น V3 ขนาดเล็กเนื่องจากไม่สามารถใช้งานได้ โปรดทราบว่าเรายังลดเกณฑ์จาก 0.72 เป็น 0.3
เพื่อให้ง่าย Embeddings วัดความเกี่ยวข้องของสตริงข้อความ หากเราเรียก API มันจะให้ข้อมูลเวกเตอร์ของหมายเลขลอยตัวที่เกี่ยวข้องกับข้อความอินพุต
const embedding = await openai . embeddings . create ( {
model : "text-embedding-3-small" , //"text-embedding-ada-002",
input : "The quick brown fox jumped over the lazy dog" ,
encoding_format : "float" ,
} )ในการใช้สิ่งนี้ในแอปพลิเคชันของเราเราจะใช้สิ่งที่พวกเขาเรียกว่า การค้นพบการจู่โจม หรือผ้าขี้ริ้วง่ายๆ
เริ่มแรกเมื่อได้รับข้อมูลใหม่จากฟังก์ชั่น SAVE_NEW_MEMORY เราเรียกว่า EMBEDDINGS API เพื่อสร้างการแสดงเวกเตอร์ ข้อมูลเวกเตอร์นี้จะถูกเก็บไว้ใน MongoDB เพื่อใช้ในอนาคต
ต่อจากนั้นเมื่อผู้ใช้ส่งแบบสอบถามที่ต้องใช้การดึงหน่วยความจำฟังก์ชัน GET_INFO_FROM_MEMORY จะถูกเรียกใช้ เราเรียกว่า Embeddings API สำหรับพารามิเตอร์การค้นหาและเปรียบเทียบกับข้อมูลเวกเตอร์ที่เก็บไว้โดยใช้ความคล้ายคลึงกันของโคไซน์อย่างง่าย การเปรียบเทียบนี้มักจะให้ผลการแข่งขันหลายรายการที่มีคะแนนแตกต่างกัน เราได้กำหนดเกณฑ์ของเราเป็นคะแนน 0.3 (0.72 สำหรับโมเดล ADA) หรือสูงกว่าและเรา จำกัด ผลลัพธ์ให้สูงสุด 10
ผลลัพธ์จะถูกส่งผ่านไปยัง API การแชทเสร็จสิ้นขั้นสุดท้ายซึ่งกำหนดการตอบสนองที่เหมาะสมที่สุดสำหรับแบบสอบถามของผู้ใช้ AI มีความสามารถในการเลือกผลลัพธ์หนึ่งรายการขึ้นไปเป็นพื้นฐานสำหรับการตอบสนองขึ้นอยู่กับลักษณะของการสืบค้น นี่คือที่แสดงให้เห็นถึงพลังที่แท้จริงของ AI แทนที่จะสำรอกข้อมูลทั้งหมดที่ได้รับ AI วิเคราะห์ข้อมูลและกำหนดการตอบสนองที่เหมาะสม หากผลลัพธ์จากผ้าขี้ริ้วถือว่าเพียงพอมันจะสร้างการตอบสนองข้อความเชิงบวก
เพื่อช่วยอำนวยความสะดวกในการจัดเก็บข้อมูลเวกเตอร์และการดำเนินการเวกเตอร์อื่น ๆ ใน MongoDB ฉันใช้โมดูล Mongoose จนถึงตอนนี้นี่เป็นวิธีแก้ปัญหาที่ไม่เจ็บปวดที่สุดในการจัดการการจัดเก็บและดึงข้อมูลเวกเตอร์
ก่อนอื่นเรากำหนดสคีมาของเรา:
const memoryVectorsSchema = new mongoose . Schema ( {
chunks : [ {
embedding : [ Number ] ,
text : String
} ]
} ) จากนั้นเราจะแนบฟังก์ชั่น getScore ซึ่งดำเนินการ ความคล้ายคลึงกันของโคไซน์ ระหว่างโมเดลเอกสารและสตริงแบบสอบถามฝังตัว:
memoryVectorsSchema . methods . getScore = function getScore ( query_embedding ) {
return this . chunks . map ( ( chunk ) => {
const dot_product = chunk . embedding . reduce ( ( sum , val , i ) => sum + val * query_embedding [ i ] , 0 )
const magnitude = ( vec ) => Math . sqrt ( vec . reduce ( ( sum , val ) => sum + val * val , 0 ) )
const cosine_similarity = dot_product / ( magnitude ( chunk . embedding ) * magnitude ( query_embedding ) )
return { text : chunk . text , score : cosine_similarity }
} )
}ต่อไปเรารวบรวมสคีมาของเราเป็นแบบจำลอง:
const MemoryVectors = mongoose . model ( 'MemoryVectors' , memoryVectorsSchema )เพื่อบันทึกข้อมูลเวกเตอร์:
const newVector = new MemoryVectors ( {
chunks
} )
newVector . save ( )เพื่อค้นหาข้อมูลเวกเตอร์ที่เก็บไว้ด้วยการฝังตัวของแบบสอบถามผู้ใช้
const cosineSimThreshold = 0.3 // Note: for text-embedding-ada-002, 0.72 but for v3 embed models, use 0.3
const maxResults = 10
const maxFilesLength = 2000 * 3
const vectors = await MemoryVectors . find ( )
const vector_result = vectors . map ( ( v ) => {
return v . getScore ( search_query )
} ) . flat ( ) . sort ( ( a , b ) => b . score - a . score ) . filter ( ( chunk ) => chunk . score > cosineSimThreshold ) . slice ( 0 , maxResults )
const query_result = vector_result . length > 0 ? vector_result . map ( ( v ) => v . text ) . join ( "n" ) . slice ( 0 , maxFilesLength ) : ''แค่นั้นแค่นั้น เรียบร้อยเหรอ?
เพื่อแสดงให้เห็นว่างานเหล่านี้ทั้งหมดให้ตรวจสอบการสนทนาตัวอย่าง
ผู้ใช้: เฮ้บอกฉันว่าเบอร์เกอร์ที่คุณชอบคืออะไร? ชีส? เบคอน? เห็ด?
BOT: โอ้แน่นอน! ฉันทั้งหมดเกี่ยวกับเบอร์เกอร์เบคอนคุณรู้ไหม? เบคอนกรอบเพียงแค่นำไปสู่ระดับใหม่ทั้งหมด แล้วคุณล่ะ
ผู้ใช้: เห็ด! ด้วยชีส! โอ้ฉันรักมัน
บอท: ทั้งหมด! เห็ดและชีสเป็นคู่ที่ทำในสวรรค์เบอร์เกอร์ คุณเคยลองทำเห็ดและเบอร์เกอร์ชีสของคุณเองที่บ้านหรือไม่? มันคุ้มค่า!
ผู้ใช้: ยังไม่ คุณลองอะโวคาโดแล้วหรือยัง?
BOT: โอ้ทั้งหมด! อะโวคาโดบนเบอร์เกอร์เหมือนเชอร์รี่อยู่ด้านบนคุณรู้ไหม? มันเพิ่มความดีของเนยแข็งและเนยที่นำทุกสิ่งไปสู่ระดับต่อไป คุณได้ลองแล้วหรือยัง?
ผู้ใช้: ใช่ มีเรื่องตลกที่เกี่ยวข้องกับเรื่องนี้ ฉันเคยมีเบอร์เกอร์อะโวคาโดมาก่อน แล้วครั้งหนึ่งฉันและเพื่อนของฉันไปเที่ยวเล่นสกี ระหว่างทางที่เราหยุดโดยร้านเบอร์เกอร์ ในขณะที่ฉันกำลังเรียกดูเมนูฉันเห็นอะโวคาโดและฉันชี้ไปเมื่อฉันสั่ง คุณรู้หรือไม่ว่าเกิดอะไรขึ้นต่อไป?
บอท: ไม่มีทาง! เกิดอะไรขึ้น พวกเขาให้เบอร์เกอร์กับคุณเช่นอะโวคาโดทั้งหมดหรือไม่? นั่นจะเฮฮา!
ผู้ใช้: ไม่ แต่ปิด. พวกเขาให้เบอร์เกอร์กับอะโวคาโดชิ้น ไม่มีอะไรอื่น ปรากฎว่าสิ่งที่ฉันเลือกในเมนูคือตัวเลือกมังสวิรัติ!
บอท: โอ้เอ้ยมันตลกเกินไป! ดังนั้นคุณจึงลงเอยด้วยเบอร์เกอร์อะโวคาโดธรรมดาแทนที่จะเป็นสิ่งที่คุณคาดหวัง นั่นเป็นเหมือนการผสมผสานตรงจากหนังตลก! คุณได้เพลิดเพลินกับเบอร์เกอร์อะโวคาโดหรือไม่?
ผู้ใช้: ฉันกินมันไม่เป็นไร แต่ก็ไม่พอใจแน่นอน เฮ้คุณช่วยบันทึกความทรงจำที่ตลกนี้ได้ไหมมันจะเป็นการดีที่จะจำได้ในบางครั้ง
การเรียกใช้ฟังก์ชัน (เรียกใช้ save_new_memory):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_2TIYJOo9WJcprD7ozQsERoo4' ,
type : 'function' ,
function : {
name : 'save_new_memory' ,
arguments : '{"memory_title":"Avocado Burger Mix-Up","memory_detail":"Ordered an avocado burger at a ski trip burger shop, but got a plain avocado burger instead. Turns out, the one I picked on the menu was the vegan option! Hilarious mix-up.","memory_date":"2023-11-10","memory_tags":["funny","food","burger"]}'
}
}
]
}ณ จุดนี้เราเรียกว่า Embeddings API และรับข้อมูลเวกเตอร์สำหรับอาร์กิวเมนต์ทั้งหมดและบันทึกด้วยข้อความไปยัง MongoDB
การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_2TIYJOo9WJcprD7ozQsERoo4' ,
role : 'tool' ,
name : 'save_new_memory' ,
content : '{n "message": "New memory saved"n}'
}
]บอท: บันทึกความทรงจำ! ตอนนี้คุณมีเรื่องราวการผสมผสานที่ตลกที่จะมองย้อนกลับไปทุกครั้งที่คุณต้องการหัวเราะที่ดี มันเหมือนชีวิตเล็กน้อยคุณรู้ไหม?
ตอนนี้สำหรับการดึงข้อมูลจากหน่วยความจำ
ผู้ใช้: โดยวิธีการที่คุณรู้จักข้อต่อเบอร์เกอร์ที่ปิดในเดือนนี้หรือไม่? หนึ่งในชิบูย่า? ชื่ออะไร?
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_calendar_entry):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_3PNs56LMrmDViZUnrxdBScGz' ,
type : 'function' ,
function : { name : 'get_calendar_entry' , arguments : '{"date":"2023-11-30"}' }
}
]
}การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_3PNs56LMrmDViZUnrxdBScGz' ,
role : 'tool' ,
name : 'get_calendar_entry' ,
content : '{n "message": "No entries found"n}'
}
]บอท: ฉันไม่พบข้อมูลใด ๆ เกี่ยวกับการปิดการร่วมเบอร์เกอร์ในชิบูย่าในเดือนนี้ อาจเป็นแค่ข่าวลือคุณรู้ไหม? แต่ถ้าคุณพบชื่อโปรดแจ้งให้เราทราบ!
ผู้ใช้: คุณสามารถตรวจสอบหน่วยความจำของคุณได้ไหมฉันคิดว่าฉันอาจจะบอกคุณก่อนหน้านี้
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_info_from_memory):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_WVBvjR0MKgaaTzik7QBwk3Ei' ,
type : 'function' ,
function : {
name : 'get_info_from_memory' ,
arguments : '{"search":["burger","Shibuya","closing"]}'
}
}
]
} ที่นี่เราได้รับการฝังสำหรับคำ ค้นหา แทนแบบสอบถามผู้ใช้จริง จากนั้นใช้ข้อมูลเวกเตอร์ผลลัพธ์เราเรียก mongoDb.searchEntry เพื่อค้นหาข้อมูลเวกเตอร์ที่เก็บไว้ใน MongoDB
การตอบสนองของฟังก์ชั่น:
[ {
tool_call_id : 'call_WVBvjR0MKgaaTzik7QBwk3Ei' ,
role : 'tool' ,
name : 'get_info_from_memory' ,
content : '{n' +
' "message": "Retrieved related info for burger,Shibuya,closing",n' +
` "result": "score: 0.8513867910905064\n title: Becker's ハンバーガーショップ閉店 detail: 千葉の人気なバーガーショップ「Becker's」が閉店するらしい。 tags: 閉店,ハンバーガー,千葉\nscore: 0.8506170963709474\n title: トリキバーガーの渋谷店閉店情報 detail: 渋谷のトリキバーガーの店舗が閉店することが決まりました。最後の日は今月の20日です。お店は渋谷の井の頭通りにあります。 date: 2023-11-10 tags: トリキバーガー,渋谷,閉店情報\nscore: 0.8307398914702265\n title: Becker's閉店情報 detail: 千葉の人気なバーガーショップBecker'sが閉店する。最後の日は今月の22日。 date: 2023-11-22 tags: 閉店情報,Becker's...n` +
'}'
}
]ฉันเพียงแสดงผลลัพธ์บางส่วนของเนื้อหา แต่มันมีการโจมตีหลายครั้งจากฐานข้อมูลที่เกี่ยวข้องกับคำค้นหา เราส่งผลลัพธ์ทั้งหมดไปยัง API การแชทเสร็จสมบูรณ์และปล่อยให้ AI ตัดสินใจว่าจะทำอย่างไร
บอท: โอ้ใช่แล้ว! ข้อต่อเบอร์เกอร์ที่ปิดใน Shibuya คือ Triki Burger สถานที่ Shibuya ของพวกเขาปิดตัวลงในวันที่ 20 ของเดือนนี้ เป็นเรื่องน่าเศร้าที่เห็นพวกเขาไปคุณรู้ไหม?
หากคุณสังเกตเห็นผลลัพธ์บางส่วนที่แสดงเป็นภาษาญี่ปุ่น! ดังนั้นแน่นอนว่านี่แสดงให้เห็นว่าเราไม่ได้ทำการค้นหาคำหลักง่ายๆที่นี่ คุณสามารถเพิ่มข้อมูลภาษาผสมและสอบถามหน่วยความจำโดยใช้ภาษาและโอกาสที่แตกต่างกันคุณจะยังคงได้รับคำตอบ ลองใช้บอทรัสเซียของเรา Vitaly ฉันจะใช้ Google Translate เนื่องจากฉันไม่พูดภาษารัสเซีย
ผู้ใช้: виталий, можешвспомнитьназваниемоихимыхкартофелныхипипсов? (Vitaly คุณจำชื่อมันฝรั่งทอดที่ฉันชอบได้ไหม?)
การเรียกใช้ฟังก์ชัน (เรียกใช้ get_info_from_memory):
{ role : 'assistant' ,
content : null ,
tool_calls : [
{
id : 'call_8fXETNlDMuKEXsitUuqt5PlE' ,
type : 'function' ,
function : {
name : 'get_info_from_memory' ,
arguments : '{"search":["картофельные чипсы"]}'
}
}
]
}ดังนั้นอีกครั้งเราได้รับ embeddings สำหรับคำ ค้นหา และใช้กับข้อมูลเวกเตอร์แต่ละรายการที่เก็บไว้ใน MongoDB
ฟังก์ชั่นผลลัพธ์:
[ {
tool_call_id : 'call_8fXETNlDMuKEXsitUuqt5PlE' ,
role : 'tool' ,
name : 'get_info_from_memory' ,
content : '{n' +
' "message": "Retrieved related info for картофельные чипсы",n' +
` "result": "score: 0.7718838658905126\n title: トムさんのお気に入りのパン detail: トムさんのお気に入りのパンはカレーパンとあんドーナツです。カレーパンはスパイシーなカレーとサクサクの生地が絶妙に合い、あんドーナツは甘さともちもち感が魅力です。\nscore: 0.7560670627592779\n title: Crisp Bacon Potato Chips detail: Brand: Dice tags: snack,potato chips,brand\nscore: 0.7354783965092787\n title: あまとうのあんみつ detail: 小樽のあまとうで食べるあんみつは絶品。...n` +
'}'
}
]คุณจะเห็นได้ว่าผลลัพธ์ที่แสดงข้อมูลนั้นผสมกับข้อความภาษาญี่ปุ่นและภาษาอังกฤษ
BOT: твоиимыекартофелныечипсы - มันฝรั่งเบคอนมันฝรั่งกรอบ (มันฝรั่งทอดที่คุณชื่นชอบคือมันฝรั่งทอดเบคอนที่คมชัด)
โอเคเรามาสู่ขั้นตอนสุดท้าย
เมื่อได้รับการตอบกลับข้อความจากขั้นตอนก่อนหน้านี้เราจะโทรไปที่ API ข้อความเป็นคำพูด เพื่อเปิดใช้งาน chatbot ของเราเพื่อเปล่งเสียงตอบกลับ
try {
const mp3 = await openai . audio . speech . create ( {
model : 'tts-1' ,
voice : 'alloy' ,
input : 'The quick brown fox jumps over the lazy dog.' ,
} )
const buffer = Buffer . from ( await mp3 . arrayBuffer ( ) )
await fs . promises . writeFile ( filename , buffer )
} catch ( error ) {
throw error
} เนื่องจากเอกสารไม่ได้ให้คำอธิบายเฉพาะสำหรับแต่ละเสียงดังนั้นฉันจึงขอให้ Chatgpt ทำการคาดเดาการศึกษาตามชื่อของพวกเขา:
อัลลอย (f): หลากหลายและอาจเหมาะสำหรับเนื้อหาทางเทคนิคหรือการเรียนการสอนเช่นแบบฝึกหัดสื่อการศึกษาหรือเนื้อหาใด ๆ ที่มีความชัดเจนและความแม่นยำเป็นสิ่งจำเป็น
Echo (M): อาจเหมาะกับการเล่าเรื่องหนังสือเสียงหรือเนื้อหาที่ต้องใช้น้ำเสียงที่น่าทึ่งหรือเล่าเรื่องมากขึ้น
Fable (F): อาจเหมาะสำหรับเรื่องราวของเด็กเนื้อหาแฟนตาซีหรือการเล่าเรื่องใด ๆ ที่ต้องใช้น้ำเสียงที่ขี้เล่นหรือจินตนาการมากขึ้น
Onyx (M): อาจเหมาะสำหรับการอ่านวรรณกรรมที่จริงจังส่งเนื้อหาข่าวหรือเนื้อหาใด ๆ ที่ต้องมีการส่งมอบที่ร้ายแรงหรือเป็นทางการมากขึ้น
Nova (f): เหมาะสำหรับโฆษณาเนื้อหาที่สร้างแรงบันดาลใจหรือวัสดุใด ๆ ที่ต้องมีการส่งมอบในเชิงบวกและกระตือรือร้น
Shimmer (F): เหมาะสำหรับเนื้อหาไลฟ์สไตล์พอดคาสต์หรืออะไรก็ตามที่ต้องใช้น้ำเสียงที่น่าดึงดูดเป็นมิตรและเชิญชวน
ข้อมูลเสียงที่สร้างขึ้นจะถูกบันทึกลงในไดเรกทอรี public/upload ในรูปแบบไฟล์ MP3 จากนั้นเราจะส่งลิงค์ไปยังฝั่งไคลเอ็นต์ที่ HTMLaudioElement แบบไดนามิกจะโหลดและเล่น
const audioDomRef = new Audio ( )
audioDomRef . type = 'audio/mpeg'
audioDomRef . addEventListener ( 'loadedmetadata' , handleAudioLoad )
audioDomRef . addEventListener ( 'ended' , handleAudioEnded )
audioDomRef . addEventListener ( 'error' , handleAudioError )
audioDomRef . src = audio_url
function handleAudioLoad ( ) {
audioDomRef . value . play ( )
}โปรดทราบว่าการบันทึกเสียงจะถูกปิดใช้งานในขณะที่การตอบกลับเสียงกำลังเล่นอยู่ สิ่งนี้ทำให้มั่นใจได้ว่าแอปพลิเคชันจะไม่บันทึกการตอบสนองของบอท
FFMPEG ใช้เพื่อลบชิ้นส่วนเงียบในไฟล์เสียง
ในการติดตั้งเครื่องมือบรรทัดคำสั่ง ffmpeg
# on Ubuntu or Debian
sudo apt update && sudo apt install ffmpeg
# on Arch Linux
sudo pacman -S ffmpeg
# on MacOS using Homebrew (https://brew.sh/)
brew install ffmpeg
# on Windows using Chocolatey (https://chocolatey.org/)
choco install ffmpeg
# on Windows using Scoop (https://scoop.sh/)
scoop install ffmpeg
MongoDB จะใช้ในการจัดเก็บรายการปฏิทินและข้อมูลเวกเตอร์สำหรับฟังก์ชั่นหน่วยความจำระยะยาว
ในการติดตั้ง MongoDB Community Edition โปรดตรวจสอบหน้านี้ คุณอาจต้องการติดตั้งเชลล์ MongoDB เพื่อดูฐานข้อมูล
ก่อนอื่นต้องแน่ใจว่าติดตั้ง FFMPEG และ MongoDB ในระบบของคุณ
เพื่อโคลนพื้นที่เก็บข้อมูลโครงการและติดตั้งการอ้างอิง
$ git clone https://github.com/supershaneski/openai-whisper-talk.git myproject
$ cd myproject
$ npm install คัดลอกไฟล์ .env.example และเปลี่ยนชื่อเป็น .env จากนั้นเปิดและแก้ไขรายการที่มีค่าจริง สำหรับรายการ MongoDB คุณอาจไม่จำเป็นต้องแก้ไขเว้นแต่คุณจะมีการตั้งค่าที่แตกต่างกัน
NUXT_OPENAI_API_KEY=your-openai-api-key
NUXT_MONGODB_HOST_NAME=localhost
NUXT_MONGODB_PORT=27017
NUXT_MONGODB_DB_NAME=embeddingvectorsdb
จากนั้นเรียกใช้แอป
$ npm run dev เปิดเบราว์เซอร์ของคุณเป็น http://localhost:5000/ (หมายเลขพอร์ตขึ้นอยู่กับความพร้อมใช้งาน) เพื่อโหลดหน้าแอปพลิเคชัน
หมายเหตุ: ฉันยังไม่ได้ทดสอบด้วยการอัปเดตล่าสุด
คุณอาจต้องการเรียกใช้แอพนี้โดยใช้โปรโตคอล https สิ่งนี้จำเป็นสำหรับการเปิดใช้งานการจับเสียงโดยใช้อุปกรณ์แยกต่างหากเช่นสมาร์ทโฟน
ในการทำเช่นนั้นให้เตรียม certificate ที่เหมาะสมและไฟล์ key และแก้ไข server.mjs ที่ไดเรกทอรีรูท
จากนั้นสร้างโครงการ
$ npm run buildในที่สุดเรียกใช้แอป
$ node server.mjs ตอนนี้เปิดเบราว์เซอร์ของคุณเป็น https://localhost:3000/ (หมายเลขพอร์ตขึ้นอยู่กับความพร้อมใช้งาน) หรือใช้ที่อยู่ IP ในพื้นที่ของคุณเพื่อโหลดหน้าเว็บ
คุณสามารถค้นหาตัวแปรเหล่านี้ได้ในหน้า/talk/[id] .vue ไฟล์ ↩ 2
หากตามวันที่รายการจะต้องเป็นหนึ่งเดียวภายใต้วันที่มิฉะนั้นจะมีการส่งคืนข้อผิดพลาด