diff --git a/public/index.html b/public/index.html index f5e5312a..51ba41fa 100644 --- a/public/index.html +++ b/public/index.html @@ -1,24 +1,44 @@ - - - + + + - - + + - - - - + + + - Vapi Web Quickstart - - - -
- - + + + LegalScout AI + + +
+ +
+ +
+
+

✨ Legal Help, Simplified ✨

+

Don't navigate the legal system alone! 😓 LegalScout AI is your guide. Tell us about your case, and we'll connect you with the perfect attorney.

+

Get matched with lawyers who are experienced, available, and eager to take your case. 💪

+

See our Terms & Conditions.

+ +
+
+ + + + \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 3c74ab38..c4ab9f20 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -6,7 +6,7 @@ import Vapi from "@vapi-ai/web"; import { isPublicKeyMissingError } from "./utils"; // Put your Vapi Public Key below. -const vapi = new Vapi("0000XXXX-XXXX-XXXX-XXXX-XXXXXXXX0000"); +const vapi = new Vapi("310f0d43-27c2-47a5-a76d-e55171d024f7"); // Replace with your actual public key const App = () => { const [connecting, setConnecting] = useState(false); @@ -14,55 +14,96 @@ const App = () => { const [assistantIsSpeaking, setAssistantIsSpeaking] = useState(false); const [volumeLevel, setVolumeLevel] = useState(0); + const [microphoneAllowed, setMicrophoneAllowed] = useState(false); // Add state for microphone permission const { showPublicKeyInvalidMessage, setShowPublicKeyInvalidMessage } = usePublicKeyInvalid(); // hook into Vapi events useEffect(() => { - vapi.on("call-start", () => { + const handleCallStart = () => { setConnecting(false); setConnected(true); setShowPublicKeyInvalidMessage(false); - }); + }; - vapi.on("call-end", () => { + const handleCallEnd = () => { setConnecting(false); setConnected(false); setShowPublicKeyInvalidMessage(false); - }); + }; - vapi.on("speech-start", () => { + const handleSpeechStart = () => { setAssistantIsSpeaking(true); - }); + }; - vapi.on("speech-end", () => { + const handleSpeechEnd = () => { setAssistantIsSpeaking(false); - }); + }; - vapi.on("volume-level", (level) => { + const handleVolumeLevel = (level) => { setVolumeLevel(level); - }); + }; - vapi.on("error", (error) => { + const handleError = (error) => { console.error(error); setConnecting(false); if (isPublicKeyMissingError({ vapiError: error })) { setShowPublicKeyInvalidMessage(true); } - }); - - // we only want this to fire on mount + }; + + // Add event listeners + vapi.on("call-start", handleCallStart); + vapi.on("call-end", handleCallEnd); + vapi.on("speech-start", handleSpeechStart); + vapi.on("speech-end", handleSpeechEnd); + vapi.on("volume-level", handleVolumeLevel); + vapi.on("error", handleError); + + // Clean up event listeners on unmount + return () => { + vapi.off("call-start", handleCallStart); + vapi.off("call-end", handleCallEnd); + vapi.off("speech-start", handleSpeechStart); + vapi.off("speech-end", handleSpeechEnd); + vapi.off("volume-level", handleVolumeLevel); + vapi.off("error", handleError); + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // call start handler - const startCallInline = () => { + const startCallInline = async () => { setConnecting(true); - vapi.start(assistantOptions); + + try { + // Request microphone access + await navigator.mediaDevices.getUserMedia({ audio: true }); + setMicrophoneAllowed(true); + + const assistantOverrides = { + transcriber: { + provider: "deepgram", + model: "nova-2", + language: "en-US", + }, + recordingEnabled: true, + // Add any other overrides you need here, like: + // endCallOnNoSpeech: false, // Disable automatic end on no speech + // maxDuration: 3600, // Set a longer max duration (in seconds) + }; + + vapi.start('e3fff1dd-2e82-4cce-ac6c-8c3271eb0865', assistantOverrides); + } catch (error) { + console.error("Error accessing microphone:", error); + setConnecting(false); + // Handle microphone access errors (e.g., display an error message) + } }; + const endCall = () => { vapi.stop(); }; @@ -79,9 +120,11 @@ const App = () => { > {!connected ? ( + {label} +

+ ); + + return ( +
+ +
); }; diff --git a/src/index.css b/src/index.css index 677ec824..595a0a86 100644 --- a/src/index.css +++ b/src/index.css @@ -1,8 +1,10 @@ +/* index.css */ + body { margin: 0; - background-color: #010810; - font-family: "Inter", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", - "Helvetica Neue", sans-serif; + background-color: #000000; + font-family: "Inter", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", + "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -11,3 +13,131 @@ p { margin: 0; padding: 0; } + +header { + display: flex; + flex-direction: column; + align-items: center; + padding: 0px 0px; + width: 100%; + position: fixed; /* Keep the header in view */ + top: 0; /* Position it at the top */ + left: 0; /* Position it at the left */ + width: 100%; /* Make it span the full width */ + z-index: 100; /* Ensure it's on top of other elements */ + background-color: #171717; /* Add background color to the header */ +} + + +nav { + display: flex; /* Make the nav a flex container */ + align-items: center; /* Vertically align items */ + width: 100%; + /* background-color: #171717; Remove background color from nav */ + padding: 15px 20px; /* Add padding for height */ +} + +.logo-container { + margin-right: auto; /* Push logo to the left */ +} + +.logo { + max-width: 150px; /* Adjust logo size as needed */ + height: auto; +} + +.nav-links { + display: flex; /* Make the links a flex container */ + justify-content: center; /* Center the links horizontally */ + width: 100%; /* Make the links container take full width */ +} + +.nav-links a { + color: white; + text-decoration: none; + margin-left: 15px; /* Spacing between links */ + font-size: 1rem; + padding: 8px 15px; /* Add padding to the links */ + border-radius: 20px; /* Rounded corners for the button style */ + transition: background-color 0.3s ease; /* Smooth transition for hover effect */ +} + +.nav-links a:hover { + background-color: #333; /* Darker background on hover */ +} + +.hero { + text-align: center; + padding: 70px 10px 10px 10px; /* Adjusted padding */ + color: white; +} + +.hero img { + max-width: auto; + height: auto; + margin-top: 20px; +} + +.statement { + font-size: 1.5em; + text-align: center; + margin: 30px auto; + margin-top: 20px; +margin-bottom: -350px; + width: 80%; + display: flex; /* Make the statement a flex container */ + flex-direction: column; /* Align items vertically */ + align-items: center; /* Center items horizontally */ +} + +.statement p { + display: flex; + flex-direction: column; /* Arrange lines vertically */ + align-items: center; /* Center each line horizontally */ +} + +/* Add more specific styles for each line if needed */ +.statement p span:nth-child(1) { + /* Styles for the first line */ +} + +.statement p span:nth-child(2) { + /* Styles for the second line */ +} + +.statement p span:nth-child(3) { + /* Styles for the third line */ +} + +.button-container { + display: flex; + + align-items: center; +} + +.statement #root { + margin-top: 10px; +} + +/* index.css */ + +/* ... other styles ... */ + +.button-container { + display: flex; + justify-content: center; /* Add this to center horizontally */ + align-items: center; + +} +@keyframes ripple { + 0% { + box-shadow: 0 0 40px 10px rgba(0, 0, 100, 0.7); + } + 50% { + box-shadow: 0 0 60px 20px rgba(0, 0, 100, 0.9); + } + 100% { + box-shadow: 0 0 40px 10px rgba(0, 0, 100, 0.7); + } +} + diff --git a/src/index.js b/src/index.js index f67c1704..35c085d6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,13 @@ +// src/index.js import "./index.css"; import App from "./App"; import React from "react"; import ReactDOM from "react-dom/client"; -// render application -const root = ReactDOM.createRoot(document.getElementById("root")); +// Render application +const root = ReactDOM.createRoot(document.getElementById("root")); // Changed to "root" + root.render(