improved docs and code

This commit is contained in:
Andriy 2023-05-20 20:02:26 -06:00
parent fb4d2f0d9f
commit c15b582e3a
3 changed files with 49 additions and 82 deletions

View File

@ -1,16 +1,36 @@
## Tu Tutor
## Research Project Creating AI Ravikant
Weekend project where I learned how to use open ai chatpot, eleven labs, prompt engineering to have an ai tutor to speak with and improve my spanish! I took some inspiration & code from Aleem's [Espanol Love Repo](https://github.com/aleemrehmtulla/espanol-love) :-)
This is a weekend project where I learned how to use open ai chatbot, langchain-js, elevenlabs, prompt engineering & using extra information like books to improve the experience when talking to chatbot.
I used the book, "ALMANACK OF NAVAL RAVIKANT" to create a vector database and index the data.
**This project is not related to real Naval Ravikant and is a research project only**
The way this app works is when the user asks a question, we look through the vector database and provide 4 most relevant context snippets from the book that are each 2,000 characters long and send it to open ai as additional context so that it can provide a better response
For more content, you can follow me on twitter [here](https://twitter.com/emergingbits)
### Setup
1. Grab an openai api key from [here](https://beta.openai.com/) and add it to your .env file
1. Grab an openai api key from [here](https://beta.openai.com/) and add it to your `.env` file that you will want to create in root folder
2. Grab an ElevenLabs api key from [here](https://beta.elevenlabs.io/speech-synthesis) and add it to your .env file
3. Clone a voice with ElevenLabs and add the model id to your .env file
4. Hit `npm install` to grab the necessary packages
5. Run `npm run dev` to start your server on `http://localhost:3000`
5. Go to [pinecone](https://www.pinecone.io/) and create an index with these parameters:
- euclidian algo
- 1536 dimensions
When you finish that, you need to add vars with those values `PINECONE_ENVIRONMENT=`, `PINECONE_API_KEY=`
and `PINECONE_INDEX={name of index you created}`
6. If you don't have `ts-node` or `pdf-parse` installed, please install globally so you can run script to add indexing to pinecone
`npm install -g ts-node pdf-parse`
7. I ran the script to add indexing to pinecone `ts-node scripts/createIndex.ts`. Feel free to adjust it for your needs. You can use all kinds of file types including txt, pdf, etc.
8. Run `npm run dev` to start your server on `http://localhost:3000`
### Deploy to the world
@ -20,11 +40,15 @@ For more content, you can follow me on twitter [here](https://twitter.com/emergi
### Other Useful Notes
When setting up eleven labs, you need to configure voices to get the proper `ELEVENLABS_VOICE_ID`
1. Langchain docs: https://js.langchain.com/docs/
- great documentation for interacting with pinecone
2. When setting up eleven labs, you need to configure voices to get the proper `ELEVENLABS_VOICE_ID`
- https://docs.elevenlabs.io/api-reference/voices
Open AI has rate limits. This repo is using open ai 3.5. if you have access to 4.0, you can switch the model!
3. Open AI has rate limits. This repo is using open ai 3.5. if you have access to 4.0, you can switch the model!
- https://platform.openai.com/account/rate-limits
@ -32,7 +56,7 @@ To properly configure open ai for best experience, refer to deep learning course
- improve prompting with: https://learn.deeplearning.ai/chatgpt-prompt-eng/lesson/8/chatbot
Open AI does a fairly good job with translating but it's not perfect. Here is another provider for more precise translation:
4. Open AI does a fairly good job with translating but it's not perfect. Here is another provider for more precise translation:
- https://www.deepl.com/translator
@ -42,8 +66,5 @@ Open AI does a fairly good job with translating but it's not perfect. Here is an
## To Do
- create a JS script for embedding vector dbs
- update docs
- update voice
- rename api
- had to install `npm install pdf-parse`

View File

@ -88,7 +88,11 @@ async function askOpenAI({
messages: [
{
role: "system",
content: `Imagine you are Naval Ravikant and you want to give advice to the user you're interacting with that may ask you questions or advice. The user's name is ${userName}. I will provide you context snippets from "The Almanack of Naval Ravikant" from a vecor database to help you answer the user's questions. Introduce youself to ${userName}"`,
content: `
Imagine you are Naval Ravikant and you want to give advice to the user you're interacting with that may ask you questions or advice. The user's name is ${userName}.
I will provide you context snippets from "The Almanack of Naval Ravikant" from a vecor database to help you answer the user's questions.
Introduce youself to ${userName}. Don't mention context snippets when replying.
`,
},
...(messages || [
{

View File

@ -1,6 +1,6 @@
import { useState, useEffect, useRef } from "react";
import Head from "next/head";
import { FaMicrophone, FaTwitter } from "react-icons/fa";
import { FaTwitter } from "react-icons/fa";
import Beatloader from "react-spinners/BeatLoader";
import base64ToBlob from "@/utils/basetoblob";
import {
@ -19,18 +19,8 @@ import {
import { handleEnterKeyPress } from "@/utils";
import NameInput from "@/components/NameInput";
import { Message } from "@/types";
import useIsChrome from "@/hooks/useIsChrome";
let SpeechRecognition: { new (): SpeechRecognition };
if (typeof window !== "undefined") {
SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition;
}
function Home() {
const isChrome = useIsChrome();
const micRef = useRef<SpeechRecognition>();
const audioRef = useRef<HTMLAudioElement | null>(null);
const [messages, setMessages] = useState<Message[]>([]);
@ -40,13 +30,8 @@ function Home() {
};
const toast = useToast();
const [isListening, setIsListening] = useState(false);
const [text, setText] = useState("");
const [loading, setLoading] = useState(false);
const [isRecording, setIsRecording] = useState<boolean>(false);
const [speechRecognition, setSpeechRecognition] =
useState<SpeechRecognition | null>(null);
// on the first translate, we need to get the user's name
// on subsequent translates, we can use the name from state
@ -76,7 +61,7 @@ function Home() {
setLoading(true);
// response for chat gpt
const response = await fetch("/api/translate", {
const response = await fetch("/api/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -114,47 +99,11 @@ function Home() {
await audioRef.current.play();
};
// testing
const handleListen = async (mic: any) => {
if (!SpeechRecognition)
return alert("Speech recognition is not available in your browser.");
mic.continuous = true;
mic.interimResults = true;
mic.lang = "es-ES";
if (isListening) mic.start();
if (!isListening) mic.stop();
mic.onresult = (event: SpeechRecognitionEvent) => {
const transcript = Array.from(event.results)
.map((result) => result[0])
.map((result) => result.transcript)
.join("");
setText(transcript);
mic.onerror = (event: SpeechRecognitionErrorEvent) => {
console.log(event.error);
};
};
};
useEffect(() => {
const mic = new SpeechRecognition();
micRef.current = mic;
const audio = new Audio();
audioRef.current = audio;
return () => {
mic.stop();
};
}, []);
useEffect(() => {
handleListen(micRef.current);
}, [isListening]);
const userBgColor = useColorModeValue("blue.500", "blue.300");
const assistantBgColor = useColorModeValue("gray.100", "gray.700");
const userColor = "white";
@ -169,7 +118,7 @@ function Home() {
<Head>
<title>Naval AI Bot</title>
</Head>
<VStack pt={40} px={4} spacing={4} h="100vh" maxW="600px" mx="auto">
<VStack pt={40} px={4} mb={100} spacing={4} maxW="600px" mx="auto">
<Heading as="h1" color="black">
AI Naval That Gives Advice
</Heading>
@ -185,9 +134,6 @@ function Home() {
<Icon as={FaTwitter} fontSize="md" />
</Link>
</Text>
<Text color="black" as="i">
<b> Microphone works well in Google Chrome only (for now).</b>
</Text>
{!userName ? (
<NameInput
@ -243,26 +189,22 @@ function Home() {
variant="outline"
onClick={() => {
translate();
console.log(
"document.body.scrollHeight",
document.body.scrollHeight
);
window.scrollTo({
left: 0,
top: document.body.scrollHeight,
behavior: "smooth",
});
}}
isLoading={loading}
spinner={<Beatloader size={8} />}
>
Send
</Button>
{isChrome && (
<Icon
as={FaMicrophone}
cursor="pointer"
color={isListening ? "red.500" : "gray.500"}
onClick={() => {
if (isListening === true) {
translate();
}
setIsListening(!isListening);
setText("");
}}
/>
)}
</HStack>
</>
)}