自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用LLaMA 3.1、Firebase和Node.js,構(gòu)建一個(gè)音控的智能廚房應(yīng)用程序

譯文 精選
人工智能
我在本教程中將介紹從設(shè)置Firebase、配置LLaMA以操控語音命令到實(shí)時(shí)存儲(chǔ)和管理購物清單的整個(gè)過程。

譯者 | 布加迪

審校 | 重樓

這篇指南逐步介紹了創(chuàng)建一個(gè)自動(dòng)化的廚房助理的過程,附有語音命令、實(shí)時(shí)購物清單管理以及食譜建議。

我在本教程中將介紹創(chuàng)建一個(gè)智能廚房應(yīng)用程序(Chent),它可以根據(jù)個(gè)性化偏好簡化雜貨清單管理。該應(yīng)用程序通過語音命令操作,簡化了人機(jī)交互和添加商品。對于那些只需說出需求就能快速創(chuàng)建購物清單的用戶來說,這是理想的選擇。

該項(xiàng)目使用LLaMA 3.1用于自然語言處理(NLP)以解釋語音輸入、使用Firebase用于實(shí)時(shí)數(shù)據(jù)庫存儲(chǔ)和用戶驗(yàn)證,并使用Node.js處理后端邏輯和集成。用戶可以輸入命令以添加商品,設(shè)置飲食偏好,甚至指定數(shù)量,該應(yīng)用程序可以智能化生成滿足這些要求的購物清單。

我在本教程中將介紹從設(shè)置Firebase、配置LLaMA以操控語音命令到實(shí)時(shí)存儲(chǔ)和管理購物清單的整個(gè)過程。

搭建開發(fā)環(huán)境

在開始為smart-kitchen-app應(yīng)用程序編寫代碼之前,我們需要搭建好工作環(huán)境。

1. 安裝Node.js和npm

第一步是安裝Node.js和npm。訪問Node.js網(wǎng)站:https://nodejs.org/en,獲取你電腦的運(yùn)行系統(tǒng)所需的長期支持版本。然后,按照安裝步驟操作。

2. 使用Next.js創(chuàng)建項(xiàng)目

啟動(dòng)終端,進(jìn)入到你想要?jiǎng)?chuàng)建項(xiàng)目的位置。之后,運(yùn)行這些命令:

  • npx create-next-app@latestsmart-kitchen app(使用@latest標(biāo)志,npm可獲得最新版本的Next.js啟動(dòng)設(shè)置。)
  • cd smart-kitchen-app

它將創(chuàng)建一個(gè)新的Next.js項(xiàng)目,并將你帶到項(xiàng)目路徑。在安裝過程中,你會(huì)看到許多配置選擇,設(shè)置如下:

  • 你想使用TypeScript嗎?
  • 你想使用ESLint嗎?
  • 你想使用Tailwind CSS嗎?
  • 你想使用src/目錄嗎?
  • 你想使用App Router(應(yīng)用路由器)嗎?
  • 你想定制默認(rèn)導(dǎo)入別名嗎?

3. 安裝Firebase和Material-UI

在項(xiàng)目目錄下,執(zhí)行以下命令:

Shell
1 npm install @mui/material @emotion/react @emotion/styled firebase

設(shè)置Firebase

  • 在Firebase控制臺(tái)上啟動(dòng)一個(gè)新項(xiàng)目。
  • 項(xiàng)目創(chuàng)建完畢后,點(diǎn)擊“添加應(yīng)用程序”,選擇web平臺(tái)(</>)。
  • 當(dāng)你注冊應(yīng)用程序時(shí)給它取個(gè)名字,比如“smart-kitchen-app”。
  • 復(fù)制Firebase設(shè)置文件。之后,這個(gè)副本很有用。

4. 創(chuàng)建Firebase配置文件

在項(xiàng)目的根目錄下創(chuàng)建一個(gè)名為Firebase .js的新文件,并添加以下代碼,將占位符換成你項(xiàng)目的真實(shí)Firebase設(shè)置:

JavaScript
1 import { initializeApp } from "firebase/app";
2 import { getAnalytics } from "firebase/analytics";
3 import { getAuth } from "firebase/auth";
4 import { getFirestore } from "firebase/firestore";
5 
6 const firebaseConfig = {
7 apiKey: "YOUR_API_KEY",
8 authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
9 projectId: "YOUR_PROJECT_ID",
10 storageBucket: "YOUR_PROJECT_ID.appspot.com",
11 messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
12 appId: "YOUR_APP_ID"
13 };
14
15 const app = initializeApp(firebaseConfig);
16 const analytics = getAnalytics(app);
17 export const auth = getAuth(app);
18 export const db = getFirestore(app);

如何在OpenRouter中創(chuàng)建API令牌?

我們將使用來自O(shè)penRouter的免費(fèi)版本LLaMA 3.1,為此,我們需要獲得API令牌。以下是獲得API令牌的幾個(gè)步驟:

第1步:注冊或登錄到OpenRouter

  • 訪問OpenRouter的官方網(wǎng)站:進(jìn)入到OpenRouter.ai。
  • 如果你還沒有帳戶,創(chuàng)建一個(gè)帳戶。你可以用電子郵件注冊,也可以使用谷歌、GitHub或其他OAuth提供商。
  • 如果你已經(jīng)有了OpenRouter帳戶,請登錄。

第2步:導(dǎo)航進(jìn)入到API密鑰設(shè)置

  • 登錄后,進(jìn)入到儀表板。
  • 在儀表板中,查找API或開發(fā)人員工具部分。
  • 點(diǎn)擊API密鑰或令牌選項(xiàng)。

第3步:生成新的API密鑰

  • 在API密鑰部分,你應(yīng)該看到“生成新API密鑰”的按鈕或鏈接。
  • 點(diǎn)擊“生成”按鈕來創(chuàng)建一個(gè)新的API密鑰。
  • 可能會(huì)要求你給API密鑰取一個(gè)名字。如果你有多個(gè)不同項(xiàng)目的API密鑰(比如“Smart-Kitchen App Key”),這有助于你井然有序地組織密鑰。

第4步:復(fù)制API密鑰

  • 生成API密鑰后,它將顯示在屏幕上。立即復(fù)制API密鑰,因?yàn)橐恍┓?wù)在你離開頁面后可能不會(huì)再次顯示它。
  • 將API密鑰安全地存儲(chǔ)在環(huán)境配置文件中(比如.env.local)。

第5步:將API Key添加到.env.local文件

  • 在Next.js項(xiàng)目中,打開.env.local文件(如果沒有,創(chuàng)建一個(gè))。
  • 添加下面這行:

OPENROUTER_API_KEY = your-generated-api-key-here

確保將your-generated-api-key-here換成你復(fù)制的實(shí)際的API密鑰。

第6步:在應(yīng)用程序中使用API密鑰

  • 現(xiàn)在你已經(jīng)將API密鑰存儲(chǔ)在.env. local文件中,就可以在應(yīng)用程序中使用它。
  • 通過服務(wù)器端代碼中的process.env.OPENROUTER_API_KEY或發(fā)出API請求時(shí)訪問密鑰。確保密鑰安全,避免將其暴露給生產(chǎn)級應(yīng)用程序中的客戶端。

構(gòu)建核心邏輯,導(dǎo)入LLaMa 3.1以創(chuàng)建智能廚房應(yīng)用程序響應(yīng)

創(chuàng)建一個(gè)名為app的新文件夾,并在其下創(chuàng)建一個(gè)名為Extract的子文件夾,文件名為route.ts,按照下面給出的代碼操作:

TypeScript
1 import { NextRequest, NextResponse } from 'next/server';
2
3 export async function POST(req: NextRequest) {
4  const { prompt } = await req.json();
5
6  // Check if the API key is available
7  const apiKey = process.env.OPENROUTER_API_KEY;
8  if (!apiKey) {
9    console.error('API key not found');
10   return NextResponse.json({ error: "API key is missing" }, { status: 500 });
11  }
12
13  const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
14    method: "POST",
15    headers: {
16      "Authorization": `Bearer ${apiKey}`,
17      "Content-Type": "application/json",
18    },
19    body: JSON.stringify({
20      model: "meta-llama/llama-3.1-8b-instruct",
21      messages: [
22        { role: "system", content: "You are an assistant that extracts information and outputs only valid JSON. Do not include any explanation or extra information. Only respond with a JSON object that has the following structure: {\"itemName\": \"string\", \"quantity\": \"number\"}." },
23        { role: "user", content: `Extract the item name and quantity from the following command: "${prompt}"` }
24      ],
25    })
26  });
27
28  if (!response.ok) {
29    console.error('LLaMA API request failed with status:', response.status);
30    return NextResponse.json({ error: "Failed to process command with LLaMA" }, { status: 500 });
31  }
32
33  const completion = await response.json();
34  const rawJson = completion.choices[0].message.content;
35  console.log('Raw response from LLaMA:', rawJson); // Detailed logging of the raw response
36
37  // Extracting JSON from the response content
38  const startIndex = rawJson.indexOf('{');
39  const endIndex = rawJson.lastIndexOf('}') + 1;
40
41  if (startIndex === -1 || endIndex === -1) {
42    console.error('Failed to find valid JSON in LLaMA response');
43    return NextResponse.json({ error: "Failed to extract JSON from LLaMA response" }, { status: 500 });
44  }
45
46  const jsonString = rawJson.substring(startIndex, endIndex);
47  console.log('Extracted JSON string:', jsonString); // Logging extracted JSON string
48
49  try {
50    const parsedData = JSON.parse(jsonString);
51    console.log('Parsed data:', parsedData); // Logging the parsed data
52
53    const { itemName, quantity } = parsedData;
54
55    if (!itemName || !quantity) {
56      console.error('Missing fields in parsed data:', parsedData);
57      return NextResponse.json({ error: "Invalid data received from LLaMA" }, { status: 500 });
58    }
59
60    return NextResponse.json({ itemName, quantity });
61  } catch (error) {
62    console.error('Error parsing JSON from LLaMA response:', error);
63    return NextResponse.json({ error: "Failed to parse JSON from LLaMA response" }, { status: 500 });
64  }
65}
66

這段代碼定義了一個(gè)POST API端點(diǎn),該端點(diǎn)使用LLaMA 3.1模型從用戶的語音命令中提取特定信息(商品名稱和數(shù)量),專注于提供JSON格式的結(jié)構(gòu)化數(shù)據(jù)。

首先,它接收一個(gè)含有提示的請求,并檢查是否有所需的API密鑰(OPENROUTER_API_KEY)。如果缺少API密鑰,它會(huì)給出錯(cuò)誤響應(yīng)。然后將請求發(fā)送到OpenRouter AI API,要求AI僅返回有效的JSON,其中包含從用戶輸入中提取的字段itemName和quantity。

記錄并檢查來自AI的響應(yīng),以確保返回有效的JSON對象。如果響應(yīng)包含有效的JSON,則解析字符串,并檢查字段的完整性。如果itemName和quantity都存在,數(shù)據(jù)則以JSON格式返回給用戶;否則,將記錄并返回相應(yīng)的錯(cuò)誤。這段代碼確保AI助理提供結(jié)構(gòu)化、可操作的響應(yīng),適合智能廚房應(yīng)用程序中的購物清單創(chuàng)建。

在app文件夾下,創(chuàng)建一個(gè)名為Llama的子文件夾,文件名為route.ts,按照下面給出的代碼操作:

TypeScript
1 import { NextRequest, NextResponse } from 'next/server';
2
3 const systemPrompt = `
4 You are a helpful and friendly AI kitchen assistant. Your role is to assist users in their kitchen tasks, providing guidance, suggestions, and support in a clear and concise manner. Follow these guidelines:
5
6 1. Provide friendly, helpful, and respectful responses to all user inquiries, ensuring a positive experience.
7 2. When asked for a recipe, suggest simple and delicious recipes based on the ingredients the user has available. Keep the instructions clear and easy to follow.
8 3. Assist with creating grocery lists by accurately adding items mentioned by the user. Confirm each addition and offer to help with more items.
9 4. Handle common kitchen-related tasks such as suggesting recipes, checking pantry items, offering cooking tips, and more.
10 5. If the user is unsure or needs help deciding, offer suggestions or ask clarifying questions to better assist them.
11 6. Recognize when the user is trying to end the conversation and respond politely, offering a warm closing message.
12 7. Avoid overly technical language or complex instructions. Keep it simple, friendly, and approachable.
13 8. Provide accurate and practical information, such as cooking times, ingredient substitutions, or food storage tips.
14 9. Tailor responses to the user's preferences and dietary restrictions whenever mentioned.
15 10. Ensure every interaction feels personal, supportive, and designed to help the user enjoy their cooking experience.
16
17 Remember, your goal is to make cooking and kitchen tasks easier, more enjoyable, and stress-free for the user.
18 `;
19
20 export async function POST(req: NextRequest) {
21   try {
22     const { command } = await req.json();
23     console.log('Received command:', command);
24
25     const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
26      method: "POST",
27      headers: {
28        "Authorization": `Bearer ${process.env.OPENROUTER_API_KEY}`,
29        "Content-Type": "application/json",
30      },
31      body: JSON.stringify({
32        model: "meta-llama/llama-3.1-8b-instruct",
33        messages: [
34          { role: "system", content: systemPrompt },
35          { role: "user", content: command }
36        ],
37      })
38    });
39
40    if (!response.ok) {
41      throw new Error(`Failed to fetch from OpenRouter AI: ${response.statusText}`);
42    }
43
44    const completion = await response.json();
45    const responseMessage = completion.choices[0].message.content;
46    console.log('Received response:', responseMessage);
47
48    return NextResponse.json({ response: responseMessage });
49  } catch (error) {
50    console.error("Error processing request:", error);
51    return NextResponse.json({ error: "Error processing request" }, { status: 500 });
52  }
53}

這段代碼使用Next.js為廚房助理應(yīng)用程序設(shè)置了POST API端點(diǎn),使其能夠利用OpenRouter AI和LLaMA 3.1模型通過語音輸入處理用戶命令。終端先建立一個(gè)引導(dǎo)AI行為的系統(tǒng)提示,確保交互友好、清晰、得到支持,特別是與食譜建議、購物清單創(chuàng)建和烹飪技巧等廚房任務(wù)相關(guān)方面。一收到POST請求,系統(tǒng)從請求主體部分提取用戶的命令,并將其與系統(tǒng)提示一起轉(zhuǎn)發(fā)給OpenRouter AI API。

來自AI的響應(yīng)根據(jù)命令予以定制,隨后以JSON格式提供給用戶。如果在過程中發(fā)生錯(cuò)誤,將記錄錯(cuò)誤消息,并返回500狀態(tài)碼,確保無縫的用戶體驗(yàn)。

在app文件夾下,創(chuàng)建一個(gè)名為Recipe的子文件夾,文件名為route.ts,并按照下面給出的代碼操作:

TypeScript
1 import { NextRequest, NextResponse } from 'next/server';
2
3 export async function POST(req: NextRequest) {
4   const { availableItems } = await req.json();
5
6   // Check if the API key is available
7   const apiKey = process.env.OPENROUTER_API_KEY;
8   if (!apiKey) {
9     console.error('API key not found');
10    return NextResponse.json({ error: "API key is missing" }, { status: 500 });
11  }
12
13   const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
14    method: "POST",
15    headers: {
16      "Authorization": `Bearer ${apiKey}`,
17      "Content-Type": "application/json",
18    },
19    body: JSON.stringify({
20      model: "meta-llama/llama-3.1-8b-instruct",
21      messages: [
22        { role: "system", content: "You are an assistant that provides specific recipe suggestions based on available ingredients. Only respond with a recipe or cooking instructions based on the provided ingredients." },
23        { role: "user", content: `Here are the ingredients I have: ${availableItems}. Can you suggest a recipe using these ingredients?` }
24      ],
25    })
26  });
27
28  if (!response.ok) {
29    console.error('LLaMA API request failed with status:', response.status);
30    return NextResponse.json({ error: "Failed to process recipe request with LLaMA" }, { status: 500 });
31  }
32
33  const completion = await response.json();
34  const recipe = completion.choices[0].message.content.trim();
35
36  return NextResponse.json({ recipe });
37 }
38

這段代碼建立了一個(gè)POST API端點(diǎn),該端點(diǎn)利用LLaMA 3.1模型生成適合用戶手頭配料的食譜建議。請求包括系統(tǒng)提示指示AI充當(dāng)廚房助手,特別是根據(jù)給定的配料推薦食譜。AI會(huì)收到消息,包括現(xiàn)有配料列表,并請求食譜建議。

一收到成功的API請求,來自AI的響應(yīng)(包括配方)將被提取并以JSON格式提供。如果操作失敗,代碼將記錄錯(cuò)誤并提供表明出現(xiàn)失敗的消息。這段代碼保證了AI根據(jù)用戶在智能廚房應(yīng)用程序中手頭的配料提供量身定制的食譜建議。

構(gòu)建智能廚房應(yīng)用程序的核心組件

第1步:導(dǎo)入和狀態(tài)設(shè)置

導(dǎo)入必要的依賴項(xiàng)并設(shè)置狀態(tài)變量,以管理用戶輸入和Firebase集成。

TypeScript
1 "use client";
2 import React, { useState } from 'react';
3 import { db } from './firebase';
4 import { collection, updateDoc, arrayUnion, doc, getDoc } from 'firebase/firestore';
5

第2步:組件聲明和初始狀態(tài)

定義KitchenAssistant組件,并為用戶命令、響應(yīng)和語音識別初始化狀態(tài)。

TypeScript
1 export default function KitchenAssistant() {
2   const [command, setCommand] = useState('');
3   const [response, setResponse] = useState('');
4   const [recognition, setRecognition] = useState<SpeechRecognition | null>(null);
5

第3步:處理語音命令

這段代碼處理用戶的語音命令。它驗(yàn)證命令是否有結(jié)束語句(比如“thank you”)來結(jié)束對話,或者它是否有諸如“建議食譜”或“向食品儲(chǔ)藏室添加商品”之類的短語。根據(jù)給定的命令,它激活相關(guān)的操作(比如“建議食譜”或“發(fā)聲朗讀”)。

TypeScript
1 const handleVoiceCommand = async (commandText: string) => {
2   setCommand(commandText.toLowerCase());
3   const closingStatements = ["no thank you", "thank you", "that's all", "goodbye", "i'm done"];
4 const isClosingStatement = closingStatements.some(statement => commandText.includes(statement));
5
6   if (isClosingStatement) {
7     const closingResponse = "Thank you! If you need anything else, just ask. Have a great day!";
8     setResponse(closingResponse);
9     speak(closingResponse);
10    return;
11  }
12
13   if (commandText.includes("suggest a recipe")) {
14    await suggestRecipe();
15  } else if (commandText.includes("add items to pantry")) {
16    setResponse("Sure, start telling me the items you'd like to add.");
17    speak("Sure, start telling me the items you'd like to add.");
18  }
19 };
20

第4步:一般命令處理

該函數(shù)使用發(fā)送到/api/llama端點(diǎn)的POST請求來處理一般命令,端點(diǎn)通過LLaMA模型處理命令。來自AI的響應(yīng)被設(shè)置為response狀態(tài),并使用speak函數(shù)大聲朗讀。

TypeScript
1 const handleGeneralCommand = async (commandText: string) => {
2   try {
3     const res = await fetch('/api/llama', {
4     method: 'POST',
5     headers: { 'Content-Type': 'application/json' },
6     body: JSON.stringify({ command: commandText }),
7    });
8    const data = await res.json();
9    setResponse(data.response);
10    speak(data.response);
11  } catch (error) {
12    setResponse("Sorry, I couldn't process your request.");
13    speak("Sorry, I couldn't process your request.");
14  }
15 }; 
16

第5步:為購物清單添加商品

該函數(shù)將商品添加到Firebase中的購物清單中。它估算過期日期,更新Firestore文檔,并通過設(shè)置響應(yīng)并大聲朗讀響應(yīng)來確認(rèn)已添加給用戶。

TypeScript
1 const addToGroceryList = async (itemName: string, quantity: number) => {
2   try {
3     const expiryDate = new Date();
4     expiryDate.setDate(expiryDate.getDate() + 7);
5     const docRef = doc(db, 'grocery-list', 'Available Grocery Items');
6     await updateDoc(docRef, {
7       items: arrayUnion({
8         itemName,
9         quantity,
10        expiryDate: expiryDate.toISOString(),
11      }),
12    });
13    const responseText = `Grocery list updated. You now have: ${itemName} (${quantity}).`;
14    setResponse(responseText);
15    speak(responseText);
16  } catch (error) {
17    setResponse("Sorry, I couldn't add the item to the list.");
18    speak("Sorry, I couldn't add the item to the list.");
19  }
20 };
21

第6步:語音識別

該函數(shù)初始化瀏覽器的語音識別API,監(jiān)聽用戶輸入,并使用handleVoiceCommand處理已識別的文本。它設(shè)置了語言,確保持續(xù)監(jiān)聽。

在這段代碼中,我使用WebSpeech API的SpeechRecognition接口來啟用應(yīng)用程序中的語音命令功能。

TypeScript
1 const startRecognition = () => {
2 const SpeechRecognition = window.SpeechRecognition || (window as any).webkitSpeechRecognition;
3  const newRecognition = new SpeechRecognition();
4  newRecognition.lang = 'en-US';
5  newRecognition.onresult = (event: any) => {
6    const speechToText = event.results[0][0].transcript;
7    handleVoiceCommand(speechToText);
8  };
9  newRecognition.start();
10  setRecognition(newRecognition);
11 };
12

這一行檢查瀏覽器中是否存在原生SpeechRecognition API,或者對于像Chrome這樣通過webkit前綴支持它的瀏覽器,退回到webkitSpeechRecognition。這個(gè)API允許應(yīng)用程序監(jiān)聽用戶的語音輸入,將其轉(zhuǎn)換成文本,然后將其作為命令來處理。

JavaScript
1 const SpeechRecognition = window.SpeechRecognition || (window as any).webkitSpeechRecognition;

使用這個(gè)API,該應(yīng)用程序可以通過語音命令與用戶進(jìn)行交互,支持諸多功能,比如將商品添加到購物清單、建議食譜或檢索食品儲(chǔ)藏室的食材,使體驗(yàn)更自動(dòng)化、交互式。

你可以使用Whisper或所選擇的任何其他語音識別機(jī)制。

創(chuàng)建前端組件

這個(gè)TSX布局為你的智能廚房應(yīng)用程序定義了用戶界面的結(jié)構(gòu)。該設(shè)計(jì)使用了Tailwind CSS類,以實(shí)現(xiàn)迅即響應(yīng)、又不失美感的樣式。

TypeScript
1 return (
2   <div className="flex min-h-screen">
3     <div className="w-1/2 background-image"></div>
4     <div className="w-1/2 flex flex-col justify-center p-8 bg-white bg-opacity-80">
5       <h1 className="text-4xl font-bold mb-8 text-indigo-500">Welcome to Chent</h1>
6       <div className="button-group flex justify-between mb-8">
7        <button onClick={startRecognition} className="bg-green-500">Start Listening</button>
8       <button onClick={interruptSpeech} className="bg-yellow-500">Interrupt</button>
9      </div>
10      <div className="transcript">{command}</div>
11      <div className="response">{response}</div>
12    </div>
13  </div>
14
  • 布局是兩欄設(shè)計(jì):左側(cè)顯示背景圖像,右側(cè)包含應(yīng)用程序的主要功能。
  • 右邊部分包括一個(gè)標(biāo)題、兩個(gè)操作按鈕和兩個(gè)顯示動(dòng)態(tài)文本的區(qū)域:一個(gè)用于用戶的語音命令(Transcript),另一個(gè)用于AI助理的響應(yīng)(Response)。
  • 界面干凈、簡潔、響應(yīng)迅速,允許用戶與智能廚房應(yīng)用程序高效交互,同時(shí)保持外觀漂亮的設(shè)計(jì)。

一旦你完成了它,就會(huì)有一個(gè)類似下面的界面:

以上就是我們創(chuàng)建智能廚房應(yīng)用程序的整個(gè)過程。我在本例中使用了LLaMA 3.1語言模型,不過你可以隨意試用自己選擇的任何其他模型。

原文標(biāo)題Building a Voice-Powered Smart Kitchen App Using LLaMA 3.1, Firebase, and Node.js,作者:Vaibhavi Tiwari

責(zé)任編輯:姜華 來源: 51CTO內(nèi)容精選
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號