diff --git a/.env b/.env new file mode 100644 index 0000000000000000000000000000000000000000..20e6e6dcfbdc26faec2e911493cf3219e6224389 --- /dev/null +++ b/.env @@ -0,0 +1,10 @@ +NEXT_PUBLIC_SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImlpZWhrb2xzaXRicGlqamh0amZ1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQ5NTg0OTEsImV4cCI6MjAxMDUzNDQ5MX0.arr0B4gUCabegTVk439G7IFm1kG0AEA9xbOLmlEFDP8 +NEXT_PUBLIC_SUPABASE_URL=https://iiehkolsitbpijjhtjfu.supabase.co +GOOGLE_CLIENT_ID=146606603734-cp01g76uroirlstlasvbp6ihb9at18ki.apps.googleusercontent.com +GOOGLE_CLIENT_SECRET=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 +NEXTAUTH_URL=http://localhost:3001 +NEXTAUTH_URL_INTERNAL=http://localhost:3001 +NEXTAUTH_SECRET=B6J21rBJZIrkLK1Kgqro3eJ4g1j2ibKPxTW9m77cG6s= +API_KEY=AIzaSyA6B01DPsXtGIhUQjckCshbD1E99Edd2Tg +OPENAI_API_KEY=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 +SMTP_PASS=soudishtiaq \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9b1913ec73c273709045201fb5a56008d250f12c --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Provider/Provider.jsx b/Provider/Provider.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e1dc5ada5720727d948a14a7a9a3be2e2228a273 --- /dev/null +++ b/Provider/Provider.jsx @@ -0,0 +1,27 @@ +"use client"; + +import { SessionProvider, useSession } from "next-auth/react"; +import { createContext, useContext, useEffect, useState } from "react"; + +export async function getUser () { + try { + let body = await fetch( "/api/auth/session" ); + let user = await body.json(); + if ( Object.keys( user ).length && Object.keys( user.user ).length ) { + return { session: user, signedIn: true }; + } + return { session: null, signedIn: false }; + } catch ( e ) { + console.log( e ); + } +} + +const Provider = ( { children, session } ) => { + return ( + + { children } + + ); +}; + +export default Provider; \ No newline at end of file diff --git a/README.md b/README.md index 05c86a5ff9a4cbeb91dfdfca9708764472b482ee..e5f733efcbeee50f6a7e0d1a3e7d1d795a52dec6 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,34 @@ ---- -title: Ai -emoji: 🏃 -colorFrom: blue -colorTo: indigo -sdk: docker -pinned: false ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/app/(beta)/api-access/page.jsx b/app/(beta)/api-access/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..9e35b4bb77428621220f5ea2bf841c041985ecbb --- /dev/null +++ b/app/(beta)/api-access/page.jsx @@ -0,0 +1,83 @@ +"use client"; + +import { exists, insertData } from "@/app/Supabase/Supabase"; +import styles from "./page.module.css"; +import { useState } from "react"; + + +const ApiPage = () => { + + const [ disabled, setDisabled ] = useState( false ); + const [ email, setEmail ] = useState( "" ); + + + + const handleButtonClick = async () => { + if ( email.trim().length && email.includes( "@" ) ) { + try { + setDisabled( true ); + + const userExists = await exists( { + table: "Early_Access", + where: { + email: email + } + } ); + + if ( !userExists ) { + + await insertData( { + table: "Early_Access", + object: { + email + } + } ); + + const response = await fetch( "/api/api-access", { + method: "POST", + body: JSON.stringify( { + email + } ) + } ); + + if ( response.ok ) { + console.log( await response.json() ); + } + + } else { + alert( "User has already signed up for Early Access!" ); + } + + } catch ( e ) { + console.log( e ); + } finally { + setDisabled( false ); + } + + } + }; + + const handleInputClick = e => { + if ( e.key == "Enter" && !e.shiftKey && !disabled ) { + handleButtonClick(); + } + }; + + return ( +
+
+

API under Development

+

COMING SOON!

+
+
+

Unlock the future – be among the first to access our API with early access

+
+ setEmail( e.target.value ) } placeholder='Enter your Email' /> + +
+
+
+ ); +}; + +export default ApiPage; \ No newline at end of file diff --git a/app/(beta)/api-access/page.module.css b/app/(beta)/api-access/page.module.css new file mode 100644 index 0000000000000000000000000000000000000000..416f0a51a2ea7445990e55548c4f1ceca2d87843 --- /dev/null +++ b/app/(beta)/api-access/page.module.css @@ -0,0 +1,139 @@ +section.api { + background: url("/bg.svg") center no-repeat; + background-size: cover; + width: 100vw; + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + gap: 15vh; + font-family: Montserrat; +} + +div.heading { + display: flex; + flex-direction: column; + gap: 3vh; +} + +section.api div.heading p.note { + color: rgba(255, 255, 255, 0.50); + font-size: 1.45vw; + text-align: center; +} + +section.api div.heading p.title { + color: #FFF; + text-align: center; + font-size: 6.65vw; + font-weight: 700; +} + +div.form { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 10vh; +} + +div.form p.desc { + text-align: center; + color: rgba(255, 255, 255, 0.70); + font-size: 1.159vw; +} + +div.input { + width: 50vw; + display: flex; + flex-direction: row; + justify-content: center; + position: relative; + align-items: center; +} + +div.input input { + outline: none; + border: none; + border-radius: 6vw; + background: rgba(255, 255, 255, 0.1); + width: 100%; + padding: 2.25vh 3.15vw 2.25vh 1.65vw; + color: rgb(234, 234, 234); + position: relative; + font-size: 1.125vw; + letter-spacing: .075vw; +} + +div.input button { + position: absolute; + right: .3vw; + height: calc(100% - .45vw); + width: 6vw; + border: none; + outline: none; + color: rgb(244, 244, 244); + border-radius: 3.38vw; + background: #1F7268; + letter-spacing: .075vw; + text-align: center; + cursor: pointer; + transition: 60ms ease-in; + font-size: .98vw; +} + +div.input button:hover { + width: 6.75vw; +} + +@media (max-width: 767px) { + + section.api { + gap: 90px; + } + + div.heading { + gap: 17px; + } + + section.api div.heading p.note { + font-size: 14px; + } + + section.api div.heading p.title { + font-size: 70px; + } + + div.form { + gap: 70px; + } + + div.form p.desc { + font-size: 14.5px; + width: 85%; + } + + div.input { + width: 85%; + } + + div.input input { + border-radius: 80px; + padding: 15px 42px 15px 22px; + font-size: 15px; + letter-spacing: 1px; + } + + div.input button { + font-size: 13.333px; + right: 3px; + height: calc(100% - 6px); + width: 80px; + border-radius: 45px; + letter-spacing: 1px; + } + + div.input button:hover { + width: 85px; + } +} \ No newline at end of file diff --git a/app/(beta)/layout.js b/app/(beta)/layout.js new file mode 100644 index 0000000000000000000000000000000000000000..fc7043659fce5b973bdf72369b8aac398a6684ef --- /dev/null +++ b/app/(beta)/layout.js @@ -0,0 +1,25 @@ +import Provider from '@/Provider/Provider.jsx'; + + +import "../globals.css"; + +export const metadata = { + title: 'RayAI API', + description: 'RayAI: Your Personal AI , Now use as API.', + +}; + +export default function RootLayout ( { children } ) { + + return ( + + + + + { children } + + + + + ); +} diff --git a/app/(working)/ChildLayout.js b/app/(working)/ChildLayout.js new file mode 100644 index 0000000000000000000000000000000000000000..9198a62ccbc3f6ff4ea4662012ed0ccf58886f60 --- /dev/null +++ b/app/(working)/ChildLayout.js @@ -0,0 +1,192 @@ +"use client"; + +import styles from "./layout.module.css"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGears, faMagnifyingGlass, faRightFromBracket, faServer } from '@fortawesome/free-solid-svg-icons'; +import { faEnvelope, faMessage } from '@fortawesome/free-regular-svg-icons'; +import { signIn, signOut, useSession } from 'next-auth/react'; +import Image from 'next/image'; +import Link from 'next/link'; +import { faGoogle } from '@fortawesome/free-brands-svg-icons'; +import { useTheme } from '../Contexts/ThemeContext/ThemeContext'; +import Loading from "./loading"; +import { isMobileDevice, toggleNavDevice } from "../Contexts/IsMobileContext/IsMobileContext"; +import { useEffect, useState } from "react"; +import { usePathname } from "next/navigation"; + + +const ChildLayout = ( { children } ) => { + + const { data: session, status } = useSession(); + const { darkMode } = useTheme(); + const { isMobile, setIsMobile } = isMobileDevice(); + const { toggleNav, setToggleNav } = toggleNavDevice(); + const [ isLoading, setLoading ] = useState( true ); + const [ sessionLoading, setSessionLoading ] = useState( true ); + const specialRoutes = [ "api-access" ]; + const pathName = usePathname(); + + useEffect( () => { + if ( status != "loading" ) { + setSessionLoading( false ); + } + console.log( sessionLoading ); + }, [ session, status ] ); + + useEffect( () => { + + const handleResize = () => setIsMobile( window.innerWidth <= 767 ); + + handleResize(); + + window.addEventListener( "resize", handleResize ); + + setLoading( false ); + + return () => { + window.removeEventListener( "resize", handleResize ); + }; + + }, [] ); + + let content; + + // if ( specialRoutes.includes( pathName ) ) { + // content = + //
+ // { !isLoading && ( + // <> + //
+ // { isMobile && ( + // + // ) } + //
+ // logo + + //
+ //
+ //    Chats + //    Search + //    Settings + //    Use as API + //
+ //
+ // { session?.user && !sessionLoading ? ( + //
+ //
+ // profile + //
+ //
+ //

{ session.user.name }

+ //

{ session.user.email.length > 22 ? session.user.email.substring( 0, 22 ) + "..." : session.user.email }

+ //
+ // signOut() } className={ styles[ "logout-icon" ] } icon={ faRightFromBracket } /> + //
+ // ) : status != "loading" ? ( + // + // ) : ( + // + // ) } + //
+ //
+ //
+ // { isMobile && ( + // + // ) } + // { children } + //
+ // + // ) } + //
; + // } else { + // content = children; + // } + + return ( +
+ { !isLoading && ( + <> +
+ { isMobile && ( + + ) } +
+ logo + +
+
+    Chats +    Search +    Settings +    Use as API +
+
+ { session?.user && !sessionLoading ? ( +
+
+ profile +
+
+

{ session.user.name }

+

{ session.user.email.length > 22 ? session.user.email.substring( 0, 22 ) + "..." : session.user.email }

+
+ signOut() } className={ styles[ "logout-icon" ] } icon={ faRightFromBracket } /> +
+ ) : status != "loading" && !isLoading ? ( + + ) : ( + + ) } +
+
+
+ { isMobile && ( + + ) } + { children } +
+ + ) } +
+ ); +}; + +export default ChildLayout; diff --git a/app/(working)/layout.js b/app/(working)/layout.js new file mode 100644 index 0000000000000000000000000000000000000000..838cf30244fa41a8dfd74766c6c61d5a7ebc6493 --- /dev/null +++ b/app/(working)/layout.js @@ -0,0 +1,44 @@ +import Provider from '@/Provider/Provider.jsx'; +import ThemeProvider from '../Contexts/ThemeContext/ThemeContext'; +import MessagesProvider from '../Contexts/MessagesContext/MessagesContext'; +import ChildLayout from './ChildLayout'; +import IsMobileProvider, { ToggleNavProvider } from '../Contexts/IsMobileContext/IsMobileContext'; + + +import "../globals.css"; + +export const metadata = { + title: 'RayAI', + description: 'RayAI: Your Personal AI', + +}; + +export default function RootLayout ( { children } ) { + + return ( + + + + +
+
+
+
+
+
+ + + + + { children } + + + + +
+
+
+ + + ); +} diff --git a/app/(working)/layout.module.css b/app/(working)/layout.module.css new file mode 100644 index 0000000000000000000000000000000000000000..5b61b1c056b061cbb39027a6bae55af65628b0ff --- /dev/null +++ b/app/(working)/layout.module.css @@ -0,0 +1,317 @@ +div.chat-container { + width: 100%; + height: 100vh; + display: flex; + flex-direction: row; +} + +div.previous-chats { + /* background: #fff; */ + height: 100%; + width: 20.5vw; + display: flex; + flex-direction: column; + padding: .9vw 1.45vw; +} + +div.layout { + width: calc(100% - 20.5vw); + display: flex; + margin: .75vw; + background: #b3b3b308; + overflow: hidden; + border-radius: 3.75vw; + border: .075vw solid #365057; + flex-direction: column; + backdrop-filter: blur(71px); + align-items: center; +} + +div.layout.light { + border: none; + background: #ffffffe6; +} + +div.previous-chats div.links { + display: flex; + flex-direction: column; + position: relative; + top: 7vh; + /* Updated from 5.86vw to 12.12vh */ + /* gap: 2px; */ +} + +.link-icons { + opacity: 0.4; +} + +div.previous-chats div.links a { + text-decoration: none; + color: #eee; + padding: .9vw; + font-family: abeezee; + font-size: .97vw; +} + +div.previous-chats div.logo { + display: flex; + position: relative; + top: 2.62vh; + /* Updated from 1.125vw to 2.62vh */ +} + +div.previous-chats div.logo img { + width: 6.3vw; + height: auto; +} + +div.account { + position: absolute; + bottom: 8vh; + left: 2vw; + width: 17vw; +} + +div.build-info { + padding: .8vw; + position: relative; + top: 22vh; + border-radius: .7vw; + display: flex; + width: 90%; + justify-content: center; + /* align-items: center; */ + flex-direction: column; + gap: 2.5vh; + font-family: Quicksand; + /* border: .05vw solid #2f2f2f; */ + /* box-shadow: inset 0 0 2px; */ + color: white; + transform: scale(1); + animation: card infinite 3s ease-in-out; + /* background: linear-gradient(108deg, #1a0044 -7.56%, #660868 29.51%, #db5e83 69.57%, #ffd098 107.24%); */ + /* background: linear-gradient(rgba(255, 255, 255, .1), rgba(255, 255, 255, .1)), url("/card-bg.svg"); */ + /* background: url("/card-bg-3.svg") no-repeat; */ + background: linear-gradient(108deg, #052437 -7.56%, #14507d 29.51%, #47a2a5 69.57%, #bcf7ff 107.24%); + backdrop-filter: blur(50px); +} + +div.version { + display: flex; + flex-direction: row; + justify-content: space-between; + font-size: 1.3vw; + font-family: abeezee; + font-weight: bold; +} + +div.build-info p.desc { + position: relative; + top: -1.2vh; + font-size: .97vw; +} + +div.build-info button.card-btn { + width: fit-content; + position: relative; + left: 50%; + transform: translateX(-50%); + padding: 1.2vh 1.5vw; + font-size: .9vw; + border-radius: .3vw; + border: none; + background: #00000049; + color: white; + cursor: pointer; + transition: 90ms linear; +} + +div.build-info button.card-btn.light { + background: white; + color: rgb(34, 42, 46); +} + +div.build-info button.card-btn:hover { + background: white; + color: rgb(34, 42, 46); +} + +@keyframes card { + 0% { + transform: scale(1); + } + + 50% { + transform: scale(1.03); + } + + 100% { + transform: scale(1); + } +} + +div.profile { + display: flex; + flex-direction: row; + gap: .7vw; + align-items: center; + font-family: abeezee; + width: 100%; +} + +div.img img { + border-radius: 50%; + width: 2.5vw; + height: 2.5vw; +} + +div.name-email { + display: flex; + flex-direction: column; + font-size: .9vw; + color: white; + gap: .6vh; +} + +p.email { + font-size: .85vw; +} + +div.account button { + background-color: #4285F4; + color: #fff; + padding: .75vw .75vw; + border: none; + border-radius: .375vw; + cursor: pointer; + display: flex; + flex-direction: row; + font-size: 1vw; + gap: .65vw; +} + +.logout-icon { + color: white; + position: absolute; + right: 0; + font-size: .9vw; + cursor: pointer; + padding: .7vw; +} + +@media (max-width: 767px) { + + div.previous-chats { + /* background: #fff; */ + height: 100%; + /* width: 20.5vw; */ + width: 150px; + display: flex; + flex-direction: column; + /* padding: .9vw 1.45vw; */ + padding: 5px; + position: absolute; + transition: 150ms ease-in-out; + background: rgb(13 36 40); + } + + div.layout { + width: 100%; + height: 100%; + } + + div.previous-chats div.links { + display: flex; + flex-direction: column; + position: relative; + top: 50px; + /* Updated from 5.86vw to 12.12vh */ + gap: 2px; + } + + .link-icons { + opacity: 0.4; + } + + div.previous-chats div.links a { + text-decoration: none; + color: #eee; + padding: 6px; + font-family: abeezee; + font-size: 10px; + } + + div.previous-chats div.logo { + display: flex; + position: relative; + top: 20px; + /* Updated from 1.125vw to 2.62vh */ + } + + div.previous-chats div.logo img { + width: 60px; + height: auto; + } + + div.account { + position: absolute; + bottom: 30px; + left: 20px; + width: 120px; + } + + button.close-nav { + position: absolute; + right: 0; + border: none; + width: 25px; + height: 25px; + background: #ffffff; + font-size: 12px; + border-radius: 50%; + } + + button.open-nav { + position: relative; + left: calc(-50% + 17px); + border: none; + width: 25px; + height: 25px; + background: #ffffff; + font-size: 12px; + border-radius: 50%; + } + + div.profile { + gap: 7px; + width: 100%; + } + + div.img img { + border-radius: 50%; + width: 20px; + height: 20px; + } + + div.name-email { + font-size: 7px; + gap: 6px; + } + + p.email { + font-size: 6px; + } + + div.account button { + padding: 10px; + border-radius: 3px; + font-size: 12px; + gap: 8px; + } + + .logout-icon { + font-size: 9px; + padding: 3px; + } + +} \ No newline at end of file diff --git a/app/(working)/loading.js b/app/(working)/loading.js new file mode 100644 index 0000000000000000000000000000000000000000..831500e55edc4c1fce37a3e9ad4f81eca471f11d --- /dev/null +++ b/app/(working)/loading.js @@ -0,0 +1,10 @@ +import styles from "./loading.module.css"; + + +const Loading = () => { + return ( +
+ ); +}; + +export default Loading; \ No newline at end of file diff --git a/app/(working)/loading.module.css b/app/(working)/loading.module.css new file mode 100644 index 0000000000000000000000000000000000000000..560ea3d50fe34fe6c72caa256544cb2ed658a886 --- /dev/null +++ b/app/(working)/loading.module.css @@ -0,0 +1,20 @@ +div.loading { + border-radius: 50%; + background: transparent; + border: .5vw solid #6464d1; + width: 2.5vw; + height: 2.5vw; + animation: loader infinite ease-in-out 1s; + transform: rotate(0); + border-top-color: #2d2d85; +} + +@keyframes loader { + 0% { + transform: rotate(0); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/app/(working)/page.jsx b/app/(working)/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..9d92403d225e0d823e5a0e09180cc8dbf1c2fe55 --- /dev/null +++ b/app/(working)/page.jsx @@ -0,0 +1,42 @@ +"use client"; + +import { useEffect, useState } from 'react'; +import Chat from '../Components/Chat/chat'; +import { useMessages } from '../Contexts/MessagesContext/MessagesContext'; +import { signIn, useSession } from 'next-auth/react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGoogle } from '@fortawesome/free-brands-svg-icons'; + +import styles from "./page.module.css"; +import Loading from './loading'; + + + +const page = () => { + const { data: session, status } = useSession(); + const [ signedIn, setSignedIn ] = useState( false ); + + useEffect( () => { + if ( session?.user ) { + setSignedIn( true ); + } else { + setSignedIn( false ); + } + }, [ session ] ); + + const { messages, setMessages, Msgsloading } = useMessages(); + + return ( + <> + { signedIn && status != "loading" ? ( + + ) : status == "loading" ? ( + + ) : ( + + ) } + + ); +}; + +export default page; \ No newline at end of file diff --git a/app/(working)/page.module.css b/app/(working)/page.module.css new file mode 100644 index 0000000000000000000000000000000000000000..69c2e5baf37fdf97adb378a29b5e8883979de894 --- /dev/null +++ b/app/(working)/page.module.css @@ -0,0 +1,24 @@ +button.google-btn { + background-color: #4285F4; + color: #fff; + padding: .75vw .75vw; + border: none; + border-radius: .375vw; + cursor: pointer; + display: flex; + flex-direction: row; + font-size: 1vw; + gap: .65vw; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.logout-icon { + color: white; + position: absolute; + right: 0; + font-size: .9vw; + cursor: pointer; + padding: .7vw; +} \ No newline at end of file diff --git a/app/(working)/search/page.jsx b/app/(working)/search/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..88c60ef3acc326fd6fa1be472a60ff4227cc42f5 --- /dev/null +++ b/app/(working)/search/page.jsx @@ -0,0 +1,227 @@ +"use client"; + +import { useEffect, useRef, useState } from 'react'; +import styles from "./page.module.css"; +import { useMessages } from '../../Contexts/MessagesContext/MessagesContext'; +import { useTheme } from '../../Contexts/ThemeContext/ThemeContext'; +import { useSession } from 'next-auth/react'; +import { useRouter } from 'next/navigation'; +import dynamic from 'next/dynamic'; + + +const Loading = dynamic( () => import( '../loading.js' ) ); + +const Message = dynamic( () => import( '../../Components/Message/Message' ), { + loading: Loading +} ); + +const Search = () => { + const { messages } = useMessages(); + const { darkMode } = useTheme(); + const { data: session } = useSession(); + const router = useRouter(); + const [ prompts, setPrompts ] = useState( [] ); + const [ cancel, setCancel ] = useState( false ); + const msgsRef = useRef(); + + // Debounce the input with a 500ms delay + const debounce = ( func, delay ) => { + let timeoutId; + return function ( ...args ) { + clearTimeout( timeoutId ); + timeoutId = setTimeout( () => { + func.apply( this, args ); + }, delay ); + }; + }; + + const filtering = ( searchText ) => { + try { + if ( cancel ) { + return; + } + + if ( searchText.trim().length === 0 ) { + setPrompts( [] ); + } else { + let filteredArray = messages.filter( ( message ) => + message.content.toLowerCase().includes( searchText.toLowerCase() ) + ); + console.log( "filtered: ", filteredArray ); + setPrompts( filteredArray ); + } + } catch ( err ) { + console.log( err ); + } + }; + + const debouncedFiltering = useRef( debounce( filtering, 500 ) ); + + const handleInputChange = ( e ) => { + setCancel( false ); + debouncedFiltering.current( e.target.value ); + }; + + useEffect( () => { + return () => { + setCancel( true ); + }; + }, [] ); + + return ( +
+
+ +
+ { !prompts.length && ( +

No Messages :(

+ ) } +
+ { prompts.map( ( msg, key ) => ( + { + e.stopPropagation(); + router.replace( "/#" + msg.key, { scroll: false } ); + } } + key={ key } + msg={ msg } + session={ session } + styles={ styles } + /> + ) ) } +
+
+ ); +}; + +export default Search; + + + + + + + + + +// "use client"; + +// import { useEffect, useRef, useState } from 'react'; +// import styles from "./page.module.css"; +// import { useMessages } from '../Contexts/MessagesContext/MessagesContext'; +// import Message from '../Components/Message/Message'; +// import { useTheme } from '../Contexts/ThemeContext/ThemeContext'; +// import { useSession } from 'next-auth/react'; +// import { useRouter } from 'next/navigation'; +// import { useChat } from 'ai/react'; + + +// const Search = () => { + +// const { messages } = useMessages(); +// const { darkMode, _ } = useTheme(); +// const { data: session } = useSession(); +// const [ prompts, setPrompts ] = useState( [] ); +// const router = useRouter(); +// const [ Input, setInput ] = useState( "" ); +// const [ cancel, setCancel ] = useState( false ); +// const msgsRef = useRef(); + +// const debounce = ( func, delay ) => { +// let timeoutId; +// return function ( ...args ) { +// clearTimeout( timeoutId ); +// timeoutId = setTimeout( () => { +// func.apply( this, args ); +// }, delay ); +// }; +// }; + +// // const handleInputChange = debounce( ( e ) => { + +// // console.log( messages ); + +// // if ( e.target.value.trim().length == 0 ) { +// // setPrompts( [] ); +// // } else { +// // let filteredMessages = messages.filter( ( message ) => message.content.toLowerCase().includes( e.target.value.toLowerCase() ) ); +// // setPrompts( [ ...filteredMessages ] ); +// // } + +// // }, 300 ); + +// const handleInputChange = ( e ) => { +// setCancel( false ); +// setInput( e.target.value ); +// }; + +// useEffect( () => { + +// const Filtering = async () => { +// console.log( messages ); + +// try { + +// if ( cancel ) { +// return; +// } + +// if ( Input.trim().length == 0 ) { + +// setPrompts( [] ); + +// } else { + +// let filteredArray = await filtering(); +// console.log( "filtered: ", filteredArray ); +// setPrompts( filteredArray ); + +// } + +// } catch ( err ) { +// console.log( err ); +// } + +// }; + +// Filtering(); + +// return () => { +// setCancel( true ); +// }; + +// }, [ Input ] ); + +// const filtering = async () => { + +// let filteredMessages = messages.filter( ( message ) => message.content.toLowerCase().includes( Input.toLowerCase() ) ); +// return filteredMessages; + +// }; + + +// return ( +//
+//
+// +//
+// { !prompts.length && ( +//

No Messages :(

+// ) } +//
+// { prompts.map( ( msg, key ) => ( +// { +// e.stopPropagation(); +// router.replace( "/#" + msg.key, { scroll: false } ); +// } } key={ key } msg={ msg } session={ session } styles={ styles } /> +// ) ) } +//
+//
+// ); +// }; + +// export default Search; \ No newline at end of file diff --git a/app/(working)/search/page.module.css b/app/(working)/search/page.module.css new file mode 100644 index 0000000000000000000000000000000000000000..044e213488c91d85548282d71080ae819cfb435b --- /dev/null +++ b/app/(working)/search/page.module.css @@ -0,0 +1,152 @@ +div.search-container { + width: calc(100% - 4.6vw); + height: calc(100% - 4.6vw); + position: relative; + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: column; + align-items: center; + gap: 6vh; +} + +p.placeholder { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 4vw; + font-family: abeezee; + color: #17c4ab26; +} + +div.search-container div.input { + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; +} + +div.search-container div.input input { + width: 100%; + border: none; + padding: 1.1vw 1.3vw; + outline: none; + border-radius: .4vw; + font-size: 1.3vw; + color: #cbcbcb; + background: #22454D; +} + +div.msgs { + width: 100%; + overflow: auto; + display: flex; + flex-direction: column; + position: relative; + align-items: center; + gap: 3.1vh; + scroll-behavior: smooth; + transition: 150ms ease-in-out; +} + +div.msgs.light div.user, +div.msgs.light div.ai { + border-color: #c9e0df; + background: #def7f352; + color: #254a4d; +} + +div.msgs div.markdown-content > pre { + position: relative; +} + +div.msgs.light div.markdown-content > pre > pre { + border: 1px solid #e8ebec; + transition: 150ms ease-in-out; +} + +div.markdown-content, +div.markdown-content * { + white-space: pre-wrap; + line-height: 1.7; +} + +div.user, +div.ai { + font-family: abeezee; + font-size: 1vw; + background: #5656563c; + border-radius: 1.4vw; + padding: 2vw 2vw 2vw 3vw; + border: #365057 1px solid; + display: flex; + color: #bebebe; + flex-direction: row; + width: calc(100% - 1.8vw); + position: relative; + left: .5vw !important; + cursor: pointer; + transition: 200ms ease-in-out; +} + +@keyframes msg { + 0% { + height: 0; + } + + 100% { + height: auto; + } +} + +.text-pic { + width: 2.7vw; + height: 2.7vw; + position: absolute; + left: -1vw; + top: 2.8vh; + border-radius: .5vw; +} + +@media (max-width: 767px) { + div.search-container { + width: calc(100% - 13px); + height: calc(100% - 43px); + gap: 30px; + position: absolute; + top: calc(50% + 20px); + transform: translateY(-50%); + } + + p.placeholder { + font-size: 10px; + } + + div.search-container div.input input { + padding: 5px 10px; + border-radius: 4px; + font-size: 10px; + } + + div.msgs { + gap: 20px; + } + + div.user, + div.ai { + font-size: 11px; + border-radius: 10px; + padding: 10px 10px 10px 20px; + width: calc(100% - 20px); + left: 2px; + } + + .text-pic { + width: 20px; + height: 20px; + left: -10px; + top: 10px; + border-radius: 5px; + } +} \ No newline at end of file diff --git a/app/(working)/settings/page.jsx b/app/(working)/settings/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..8cb24fb61d8f09361a7041390cbb5b24a1edc874 --- /dev/null +++ b/app/(working)/settings/page.jsx @@ -0,0 +1,59 @@ +"use client"; + +import ToggleButton from '@/app/Components/ToggleButton/ToggleButton'; +import { useTheme } from '@/app/Contexts/ThemeContext/ThemeContext'; + +import styles from "./page.module.css"; +import { signIn, signOut } from 'next-auth/react'; +import { getUser } from '@/Provider/Provider'; +import { memo, useCallback, useEffect, useMemo, useState } from "react"; + + +const ThemeButton = memo( () => { + + const { darkMode, toggleDarkMode } = useTheme(); + const themeToggle = useCallback( () => toggleDarkMode(), [] ); + + return ; + +} ); + +const page = () => { + const { darkMode } = useTheme(); + const [ user, setUser ] = useState( null ); + + useEffect( () => { + async function fetchUser () { + const user = await getUser(); + setUser( user ); + } + + fetchUser(); + } ); + + const signedIn = useMemo( () => { + return user !== null; + }, [ user ] ); + + let button; + + if ( signedIn ) { + button = ; + } else { + button = ; + } + + return ( +
+
+

Toggle Dark Mode

+ +
+
+ { button } +
+
+ ); +}; + +export default page; \ No newline at end of file diff --git a/app/(working)/settings/page.module.css b/app/(working)/settings/page.module.css new file mode 100644 index 0000000000000000000000000000000000000000..73fc51b181860c24b066e6478859e47f317865de --- /dev/null +++ b/app/(working)/settings/page.module.css @@ -0,0 +1,67 @@ +div.options { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; +} + +div.theme-changer { + display: flex; + justify-content: space-between; + align-items: center; + width: 80%; + font-family: abeezee; + font-size: 1.3vw; + color: #a5c6c8; + position: relative; + top: 5vh; + left: 7.5vw; +} + +div.options.light div.theme-changer { + color: #3b5557; +} + +div.logout { + position: relative; + top: 13vh; + background: #555; + left: 7.5vw; +} + +div.logout button { + background: #a30f3e; + padding: 1vw 2vw; + color: white; + border: none; + font-size: 1.1vw; +} + +div.options.light div.logout button { + background: #d40c4c; +} + +@media (max-width: 768px) { + div.theme-changer { + font-size: 13px; + color: #a5c6c8; + top: 45px; + left: 37px; + } + + div.logout { + position: relative; + top: 90px; + background: #555; + left: 37px; + } + + div.logout button { + background: #a30f3e; + padding: 8px 12px; + color: white; + border: none; + font-size: 12px; + } +} \ No newline at end of file diff --git a/app/Components/Chat/chat.jsx b/app/Components/Chat/chat.jsx new file mode 100644 index 0000000000000000000000000000000000000000..304521df54ba670302aed0ebf10805cc58b2ab3a --- /dev/null +++ b/app/Components/Chat/chat.jsx @@ -0,0 +1,368 @@ +"use client"; + +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faBarsStaggered, faChevronDown, faPaperPlane, faStop, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons'; +import { useSession } from 'next-auth/react'; +import { useChat } from "ai/react"; +import { useTheme } from "../../Contexts/ThemeContext/ThemeContext"; +import { memo, useCallback, useEffect, useRef, useState } from "react"; +import { insertData } from "@/app/Supabase/Supabase"; +import { v4 as uuid } from "uuid"; +import Image from 'next/image'; +import styles from "./chat.module.css"; +import Message from "../Message/Message"; +import { isMobileDevice } from '@/app/Contexts/IsMobileContext/IsMobileContext'; + +const debounce = ( func, delay ) => { + let timeoutId; + return function ( ...args ) { + clearTimeout( timeoutId ); + timeoutId = setTimeout( () => { + func.apply( this, args ); + }, delay ); + }; +}; + +const Chat = ( { messages, setMessages, Msgsloading } ) => { + + const { data: session } = useSession(); + const { darkMode } = useTheme(); + const [ newPrompt, setNewPrompt ] = useState( [] ); + const [ pageRendered, setPageRendered ] = useState( false ); + const [ hash, setHash ] = useState( "" ); + const [ buttonToBottom, setbuttonToBottom ] = useState( false ); + const { isMobile, setIsMobile } = isMobileDevice(); + const [ input, setInput ] = useState( "" ); + const [ isLoading, setLoading ] = useState( false ); + + const inputChange = ( e ) => { + setInput( e.target.value ); + }; + + const handleSubmit = async ( e ) => { + e.preventDefault(); + setInput( "" ); + + try { + setLoading( true ); + + const response = await fetch( "/api/chat", { + method: "POST", + body: JSON.stringify( { + input, + // chatbot_model: 0, + // web_search: true, + new_convo: !messages.length + } ) + } ); + + // const response = await fetch( "https://AIONS.pythonanywhere.com/api/huggingface", { + // method: "POST", + // body: JSON.stringify( { + // prompt: input, + // chatbot_model: 0, + // web_search: true, + // new_conversation: false + // } ), + // headers: { + // 'Content-Type': 'application/json' + // }, + // mode: "cors" + // } ); + + if ( response.ok ) { + let body = await response.json(); + console.log( body ); + + let key = uuid(); + + setMessages( prev => [ + ...prev, + { content: body.body.response, role: "assistant", key } + ] ); + + setNewPrompt( prev => [ ...prev, { value: body.body.response, key } ] ); + // setNewPrompt( [] ); + } + + } catch ( e ) { + console.log( e ); + setNewPrompt( [] ); + } finally { + setLoading( false ); + } + }; + + const stop = () => { }; + + + + // const { messages: msgs, input, handleInputChange: inputChange, handleSubmit, stop, isLoading } = useChat( { + // id: "_RAY_AI_CHAT_", + // initialMessages: messages, + // onFinish: ( msg ) => { + // setNewPrompt( prev => [ ...prev, { value: msg.content, key: msg.id } ] ); + // } + // } ); + + useEffect( () => { + + if ( typeof window !== "undefined" ) { + setHash( window.location.hash.slice( 1 ) ); + } + + const handleResize = () => setIsMobile( window.innerWidth <= 767 ); + + handleResize(); + + window.addEventListener( "resize", handleResize ); + + const scrollEvent = e => { + + let element = e.target; + + if ( element.scrollHeight - element.clientHeight - element.scrollTop >= 2000 ) setbuttonToBottom( true ); + else setbuttonToBottom( false ); + + }; + + let msgsDiv = document.getElementsByClassName( styles[ "msgs" ] )[ 0 ]; + msgsDiv.addEventListener( "scroll", scrollEvent ); + + return () => { + window.removeEventListener( "resize", handleResize ); + msgsDiv.removeEventListener( "scroll", scrollEvent ); + }; + + }, [] ); + + useEffect( () => { + console.log( "isLoading: ", isLoading ); + }, [ isLoading ] ); + + const msgsRef = useRef(); + + + const scrollToMessage = () => { + const messageElement = document.getElementById( hash ); + + if ( messageElement ) { + messageElement.scrollIntoView( { behavior: 'smooth' } ); + } + }; + + useEffect( () => { + + if ( hash.trim().length ) scrollToMessage(); + + }, [ hash, pageRendered ] ); + + const send = async ( e ) => { + + if ( input.trim().length && !isLoading ) { + + let key = uuid(); + + setMessages( prev => [ + ...prev, + { content: input, role: "user", key } + ] ); + + handleSubmit( e ); + + setNewPrompt( prev => [ ...prev, { value: input, key } ] ); + + } + + }; + + const debouncedScrollToBottom = debounce( () => { + let isNearBottom = msgsRef.current.scrollHeight - msgsRef.current.clientHeight - msgsRef.current.scrollTop <= 250; + + if ( isNearBottom ) { + + msgsRef.current.scrollTo( { + top: msgsRef.current.scrollHeight, + // behavior: "smooth" + } ); + + // msgsRef.current.scrollIntoView( { behavior: 'smooth', block: 'end' } ); + + } + + }, 500 ); + + useEffect( () => { + if ( messages.length ) { + + debouncedScrollToBottom(); + + if ( !pageRendered ) { + msgsRef.current.scroll( 0, msgsRef.current.scrollHeight ); + } + + setPageRendered( true ); + } + }, [ messages ] ); + + useEffect( () => { + + console.log( "useffectt newPromp: ", newPrompt ); + + if ( newPrompt.length == 2 ) { + + // setMessages( prev => [ ...prev, + // { content: newPrompt[ 0 ].value, role: "user", key: newPrompt[ 0 ].key }, + // { content: newPrompt[ 1 ].value, role: "assistant", key: newPrompt[ 1 ].key } + // ] ); + + const sendMsg = async () => { + try { + + let currentDate = new Date(); + + await insertData( { + table: "prompts", + object: { + author: session?.user.id, + prompt: newPrompt, + created_at: `${ currentDate.getDate() }-${ currentDate.toLocaleString( 'default', { month: 'long' } ).substring( 0, 3 ) } ${ currentDate.getFullYear() }` + } + } ); + + } catch ( e ) { + console.log( e ); + } finally { + setNewPrompt( [] ); + } + }; + + sendMsg(); + + } + + + }, [ newPrompt ] ); + + const handleTermination = () => { + // setProcessing( false ); + stop(); + setNewPrompt( [] ); + }; + + const handleInputSubmit = e => { + if ( e.key == "Enter" && !e.shiftKey && !isLoading && !isMobile ) { + // e.preventDefault(); + send( e ); + } else if ( isMobile && e.key == "Enter" ) { + return; + } + }; + + const handleInputChange = useCallback( ( e ) => { + + inputChange( e ); + + e.target.style.height = 'auto'; + e.target.style.height = e.target.scrollHeight + 'px'; + + }, [] ); + + function handleExampleCopy ( e ) { + let text = e.target.innerText; + text = [ ...text ]; + + text.pop(); + text.shift(); + text = text.join( "" ); + + navigator.clipboard.writeText( text ); + } + + function handleBottomButtonClick () { + msgsRef.current.scrollTo( { + top: msgsRef.current.scrollHeight, + behavior: "smooth" + } ); + } + + return ( + <> + { ( !messages.length && !Msgsloading ) && ( + <> + logo +

RayAI:{ " " }Your Personal AI.

+
+
+
+ + Example +
+
+

{ `"Tell me about the history of Eiffel Tower."` }

+

{ `"Give me information related to EarthQuakes."` }

+

{ `"Calculate the derivative of the function : 4x + 9"` }

+
+
+
+
+ + Limitations +
+
+

{ `May Somatimes produce in-accurate Results.` }

+

{ `Might Create Harmful or Biased Content.` }

+

{ `Limited Knowledge.` }

+
+
+
+ + ) } + +
+ { messages.map( ( m, i, a ) => ( + <> + + + { ( () => { + + if ( i == a.length - 1 ) { + if ( m.role == "user" && isLoading ) { + return ( + + ); + } + } + + } )() } + + ) ) } +
+ {/* { !isMobile && ( + + )} */} + { buttonToBottom && ( + + ) } +
+