diff --git a/client/package.json b/client/package.json deleted file mode 100644 index 9188d28..0000000 --- a/client/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "autogpt", - "version": "0.1.0", - "private": true, - "proxy": "http://localhost:5000", - "dependencies": { - "@reduxjs/toolkit": "^1.9.0", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "axios": "^1.2.0", - "bootstrap": "^5.2.3", - "react": "^18.2.0", - "react-bootstrap": "^2.6.0", - "react-dom": "^18.2.0", - "react-markdown": "^8.0.5", - "react-redux": "^8.0.5", - "react-router-dom": "^6.4.3", - "react-scripts": "5.0.1", - "react-toastify": "^9.1.1", - "remark-gfm": "^3.0.1", - "web-vitals": "^2.1.4" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/client/public/favicon.ico b/client/public/favicon.ico deleted file mode 100644 index 91a68aa..0000000 Binary files a/client/public/favicon.ico and /dev/null differ diff --git a/client/public/index.html b/client/public/index.html deleted file mode 100644 index 821c14f..0000000 --- a/client/public/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - AutoGPT - - - -
- - - diff --git a/client/public/logo192.png b/client/public/logo192.png deleted file mode 100644 index 1d48f8b..0000000 Binary files a/client/public/logo192.png and /dev/null differ diff --git a/client/public/logo512.png b/client/public/logo512.png deleted file mode 100644 index 8b8f295..0000000 Binary files a/client/public/logo512.png and /dev/null differ diff --git a/client/public/manifest.json b/client/public/manifest.json deleted file mode 100644 index 080d6c7..0000000 --- a/client/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/client/public/robots.txt b/client/public/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/client/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/client/src/App.js b/client/src/App.js deleted file mode 100644 index d261476..0000000 --- a/client/src/App.js +++ /dev/null @@ -1,20 +0,0 @@ -import './styles/home.css'; -import { BrowserRouter, Route, Routes,Navigate } from 'react-router-dom'; -import AgentConvo from './pages/AgentConvo'; -import AgentConvoShare from './pages/AgentConvoShare'; - - -function App() { - return ( -
- - - }/> - }/> - - -
- ); -} - -export default App; diff --git a/client/src/App.test.js b/client/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/client/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/client/src/assets/camelagi.png b/client/src/assets/camelagi.png deleted file mode 100644 index a9b0c5c..0000000 Binary files a/client/src/assets/camelagi.png and /dev/null differ diff --git a/client/src/assets/discord.svg b/client/src/assets/discord.svg deleted file mode 100644 index 22ee27b..0000000 --- a/client/src/assets/discord.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/google.svg b/client/src/assets/google.svg deleted file mode 100644 index 47889ad..0000000 --- a/client/src/assets/google.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - ionicons-v5_logos - - - \ No newline at end of file diff --git a/client/src/assets/key.svg b/client/src/assets/key.svg deleted file mode 100644 index 950c1c8..0000000 --- a/client/src/assets/key.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/client/src/assets/logout-white.svg b/client/src/assets/logout-white.svg deleted file mode 100644 index d52ec8f..0000000 --- a/client/src/assets/logout-white.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/question-mark.svg b/client/src/assets/question-mark.svg deleted file mode 100644 index 30cf4d6..0000000 --- a/client/src/assets/question-mark.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/client/src/assets/reload.svg b/client/src/assets/reload.svg deleted file mode 100644 index bcd86b9..0000000 --- a/client/src/assets/reload.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/client/src/assets/send.svg b/client/src/assets/send.svg deleted file mode 100644 index fabeea7..0000000 --- a/client/src/assets/send.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/share-white.svg b/client/src/assets/share-white.svg deleted file mode 100644 index 2e99fc6..0000000 --- a/client/src/assets/share-white.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/client/src/assets/user-1.svg b/client/src/assets/user-1.svg deleted file mode 100644 index 3485a31..0000000 --- a/client/src/assets/user-1.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/user-2.svg b/client/src/assets/user-2.svg deleted file mode 100644 index 231c05e..0000000 --- a/client/src/assets/user-2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/user-3.svg b/client/src/assets/user-3.svg deleted file mode 100644 index 5d40e62..0000000 --- a/client/src/assets/user-3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/user-4.svg b/client/src/assets/user-4.svg deleted file mode 100644 index 03e5246..0000000 --- a/client/src/assets/user-4.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/user.png b/client/src/assets/user.png deleted file mode 100644 index 3046f3a..0000000 Binary files a/client/src/assets/user.png and /dev/null differ diff --git a/client/src/index.css b/client/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/client/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/client/src/index.js b/client/src/index.js deleted file mode 100644 index a74730c..0000000 --- a/client/src/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; -import "bootstrap/dist/css/bootstrap.min.css"; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/client/src/logo.svg b/client/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/client/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/pages/AgentConvo.js b/client/src/pages/AgentConvo.js deleted file mode 100644 index 3ab5795..0000000 --- a/client/src/pages/AgentConvo.js +++ /dev/null @@ -1,262 +0,0 @@ -import {useState,useEffect,useRef} from 'react'; -import '../styles/agent-convo.css' -import { Button, Stack, Image, Form, Row, Col, Spinner, InputGroup,FormControl, Modal } from "react-bootstrap"; -import { ReactComponent as ReloadIcon } from "../assets/reload.svg"; -import { ReactComponent as KeyIcon } from "../assets/key.svg"; -import { ReactComponent as LogoutIcon } from "../assets/logout-white.svg"; -import { ReactComponent as Bot1Icon } from "../assets/user-1.svg"; -import { ReactComponent as Bot2Icon } from "../assets/user-2.svg"; -import { ReactComponent as Bot3Icon } from "../assets/user-3.svg"; -import { ReactComponent as Bot4Icon } from "../assets/user-4.svg"; -import logoImage from '../assets/camelagi.png' -import {ReactComponent as SendIcon} from '../assets/send.svg' -import { ToastContainer, toast } from 'react-toastify'; -import {ReactComponent as GoogleIcon} from '../assets/google.svg' -import { ReactComponent as DiscordIcon } from "../assets/discord.svg"; -import axios from "axios" -import ReactMarkdown from 'react-markdown' -import remarkGfm from 'remark-gfm' -import { ReactComponent as ShareIcon } from "../assets/share-white.svg"; - - -function AgentConvo() { - const [isLoggedIn,setIsLoggedIn] = useState(false); - const [authUrl,setAuthUrl] = useState("") - const [ranUser1, setRanUser1] = useState(null); - const [ranUser2, setRanUser2] = useState(null); - const [started, setStarted] = useState(false); - const [key, setKey] = useState(""); - const [task, setTask] = useState(""); - const [finished, setFinished] = useState(false); - const [keyAdded, setKeyAdded] = useState(false); - const [user, setUser] = useState(false); - const [role1, setRole1] = useState(""); - const [role2, setRole2] = useState(""); - const [chat,setChat] = useState([]) - const [sessId,setSessId] = useState(0) - const [showBanner, setShowBanner] = useState(false); - const [turn,setTurn] = useState(0) - const sessionRef = useRef(null) - sessionRef.current = sessId - const chatRef = useRef(null) - chatRef.current = chat - const turnRef = useRef(null) - turnRef.current = turn - - let fetchMessages = () => { - setChat([...chatRef.current,{role:0,msg:null}]) - - axios.post("/rp/start",{role1:role1,role2:role2,task:task,sessId:sessionRef.current}).then((res)=>{ - setSessId(res.data.sessId) - if(res.data.convoEnd==true){ - setFinished((prev)=>true) - }else{ - chatRef.current.at(-1).msg = res.data.userMsg - setChat([...chatRef.current,{role:1,msg:null}]) - setTimeout(() => { - chatRef.current.at(-1).msg = res.data.assistantMsg; - setTurn((prev)=>prev+1) - startDiscussion(false) - }, 3000); - // setUpdate((prev)=>!prev) - - } - - }) - .catch((err)=>{ - toast("Failed to respond " + err.response.data); - }) - } - - let startDiscussion = (newTurn) => { - let getTurn = turnRef.current - if(newTurn==true){ - getTurn = 0 - setTurn((prev)=>0) - setStarted((prev)=>true) - } - - if(getTurn<2){ - fetchMessages() - } - } - - const addKey = () => { - axios.post("/store_key",{key:key}).then((res)=>{ - setKeyAdded(true) - }).catch((err)=>{ - toast("Key cannot be verified, try again"); - }) - } - - const logout = () => { - axios.get("/heybot/logout").then((res)=>{ - window.location.reload(); - }).catch((err)=>{ - console.log(err) - }) - } - - const shareChat = () => { - navigator.clipboard.writeText(window.location.host+'/conversation/share?session='+sessionRef.current) - window.open('/conversation/share?session='+sessionRef.current, "_blank"); - } - - useEffect(() => { - setRanUser1(Math.random()) - setRanUser2(Math.random()) - axios.get("/rp/isLoggedIn").then((res)=>{ - setIsLoggedIn(res.data.isLoggedIn) - if(res.data.isLoggedIn == false){ - setAuthUrl(res.data.auth_url) - }else{ - setUser({id:res.data.userId,image:res.data.image}) - if(res.data.key_added==null){ - setKeyAdded((prev)=>false) - }else{ - setKeyAdded((prev)=>true) - setKey(res.data.key_added) - } - - } - }).catch((err)=>{ - console.log(err) - }) - - window.setTimeout(()=>setShowBanner(true),30000) - },[]) - useEffect(() => { - if(document.querySelector('.end-chat')!=null){document.querySelector('.end-chat').scrollIntoView({ behavior: 'smooth', block: 'end' });} - }, [chat]) - - return ( - <> -
-
-
-

CamelAGI

- {isLoggedIn&&
- window.location.reload()} className="icon"/> - {setKeyAdded(false)} className="icon"/>} - -
} -
- {isLoggedIn? - - {keyAdded? - <> - {started? - <> - - {chatRef.current.length>0&&chatRef.current.map((message)=> - message.role==0? -
- {ranUser1!=null&&ranUser1>0.5?:} -
-
- {message.msg==null? - - - - - : -

} -
- {role1} -
-
: -
-
-
- {message.msg==null? - - - - - : -

} -
- {role2} -
- {ranUser2!=null&&ranUser2>0.5?:} -
- )} - {sessionRef.current!=0&&} -
-
- {finished? -
Task Completed!
- : - <> - {turnRef.current<3? - - :} - } - - : - <> -
Get started with a task to discuss
- - Enter Role of the Instructor - setRole1(e.target.value)}/> - - - Enter Role of the Assistant - setRole2(e.target.value)}/> - - - Enter topic of discussion - setTask(e.target.value)}/> - - - - - } - : - -
Add your OpenAI Key
-

Get your OpenAI Key by signing up/ logging in from the OpenAI Dashboard. Go to Dashboard

- - setKey(e.target.value)} - onKeyDown={(e)=>{e.code=="Enter"&&addKey()}} - /> - - - Watch this video to get started - -
- } -
: - - - {/*
Login to agi
*/} -
Accomplish your task with AI agents
- - - {/* navigate('/agi/faq')}> Know More */} -
- } -
- - setShowBanner(false)}> - - setShowBanner(false)} className="position-absolute top-0 end-0 me-4 mt-2">X - - Camel AGI - Communicative Agents on GPT | Product Hunt - Join Our Discord - Star CamelAGI on Github - - - -
- - ) - -} - -export default AgentConvo; \ No newline at end of file diff --git a/client/src/pages/AgentConvoShare.js b/client/src/pages/AgentConvoShare.js deleted file mode 100644 index 8b48db9..0000000 --- a/client/src/pages/AgentConvoShare.js +++ /dev/null @@ -1,125 +0,0 @@ -import {useState,useEffect,useRef} from 'react'; -import '../styles/agent-convo.css' -import { Button, Stack, Image, Form,Modal, Spinner, } from "react-bootstrap"; -import { ReactComponent as Bot1Icon } from "../assets/user-1.svg"; -import { ReactComponent as Bot2Icon } from "../assets/user-2.svg"; -import { ReactComponent as Bot3Icon } from "../assets/user-3.svg"; -import { ReactComponent as Bot4Icon } from "../assets/user-4.svg"; -import logoImage from '../assets/camelagi.png' -import { useNavigate } from "react-router-dom"; -import { ToastContainer, toast } from 'react-toastify'; -import axios from "axios" -import ReactMarkdown from 'react-markdown' -import remarkGfm from 'remark-gfm' -import { ReactComponent as ShareIcon } from "../assets/share-white.svg"; -import { useSearchParams, useParams } from "react-router-dom"; - - -function AgentConvoShare() { - - const [ranUser1, setRanUser1] = useState(null); - const [ranUser2, setRanUser2] = useState(null); - const navigate = useNavigate() - const [showBanner, setShowBanner] = useState(false); - const [user, setUser] = useState(false); - const [role1, setRole1] = useState(""); - const [role2, setRole2] = useState(""); - const [task, setTask] = useState(""); - const [chat,setChat] = useState([]) - const [sessId,setSessId] = useState(0) - const sessionRef = useRef(null) - sessionRef.current = sessId - const chatRef = useRef(null) - chatRef.current = chat - let [searchParams, setSearchParams] = useSearchParams(); - - - useEffect(() => { - setRanUser1(Math.random()) - setRanUser2(Math.random()) - axios.get("/rp/get_chat?sessId="+searchParams.get("session")).then((res)=>{ - setChat(res.data.messages) - setRole1(res.data.role1) - setRole2(res.data.role2) - setTask(res.data.task) - - - }).catch((err)=>{ - console.log(err) - }) - window.setTimeout(()=>setShowBanner(true),30000) - },[]) - // useEffect(() => { - // if(document.querySelector('.end-chat')!=null){document.querySelector('.end-chat').scrollIntoView({ behavior: 'smooth', block: 'end' });} - // }, [chat]) - - return ( - <> -
-
-
-

CamelAGI

- - -
- - - - - Check out this conversation between {role1} and {role2} to discuss:
{task}
- {chatRef.current.length>0&&chatRef.current.map((message)=> - message.role==0? -
- {ranUser1!=null&&ranUser1>0.5?:} -
-
- {message.msg==null? - - - - - : -

} -
- {role1} -
-
: -
-
-
- {message.msg==null? - - - - - : -

} -
- {role2} -
- {ranUser2!=null&&ranUser2>0.5?:} -
- )} -
-
- -
- - -
- - setShowBanner(false)}> - - setShowBanner(false)} className="position-absolute top-0 end-0 me-4 mt-2">X - - Camel AGI - Communicative Agents on GPT | Product Hunt - - - -
- - ) - -} - -export default AgentConvoShare; \ No newline at end of file diff --git a/client/src/reportWebVitals.js b/client/src/reportWebVitals.js deleted file mode 100644 index 5253d3a..0000000 --- a/client/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/client/src/setupTests.js b/client/src/setupTests.js deleted file mode 100644 index 8f2609b..0000000 --- a/client/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; diff --git a/client/src/styles/agent-convo.css b/client/src/styles/agent-convo.css deleted file mode 100644 index fa3f701..0000000 --- a/client/src/styles/agent-convo.css +++ /dev/null @@ -1,149 +0,0 @@ -.agent-convo-container{ - background: #eee; -} -.agent-convo-box{ - border-radius: 12px; - background: #2b2d2f; - box-shadow: 10px 10px 40px #2b2d2f; - height: 80%; - width: 60%; -} -.agent-msg-data{ - color: #fff !important; - background-color: transparent !important; - font-family: var(--fontFamily) !important; - white-space: break-spaces; - font-size: 1rem !important; - margin: 0 !important; - overflow: hidden; - padding: 0 !important; -} - -.bubble { - --r: 12px; - --t: 10px; - - padding: calc(2*var(--r)/3); - -webkit-mask: - radial-gradient(var(--t) at var(--_d) 0,#0000 98%,#000 102%) - var(--_d) 100%/calc(100% - var(--r)) var(--t) no-repeat, - conic-gradient(at var(--r) var(--r),#000 75%,#0000 0) - calc(var(--r)/-2) calc(var(--r)/-2) padding-box, - radial-gradient(50% 50%,#000 98%,#0000 101%) - 0 0/var(--r) var(--r) space padding-box; - - color: #fff; -} -.agent-1-chat { - --_d: 0%; - border-left: var(--t) solid #0000; - margin-right: var(--t); - box-shadow: 10px 10px 40px #2b2d2f; - background: var(--themeColor) border-box; -} -.agent-2-chat { - --_d: 100%; - border-right: var(--t) solid #0000; - margin-left: var(--t); - box-shadow: 10px 10px 40px #2b2d2f; - background: #3f65f9 border-box; -} -.agent-chat-icon{ - min-width: 2.5rem; - min-height: 2.5rem; - max-width: 2.5rem; - max-height: 2.5rem; - -} -.continue-button{ - background-color: #eee !important; - color: #000 !important; - border: none !important; - border-radius: 12px !important; - /* font-size: 12px !important; */ - font-weight: 800 !important; -} -.agent-input{ - background-color: transparent !important; - color: #fff !important; - border-top: none !important; - border-left: none !important; - border-right: none !important; -} -.agent-scroll{ - overflow-y: scroll; - scrollbar-width: thin; -} -.agent-scroll::-webkit-scrollbar { - width: 0; -} -.scroll-container{ - height: 90% !important; -} -.agent-msg-container>pre{ - max-width: 30rem; -} -.key-video-agent{ - width: 60%; - min-height: 14rem; - border-radius: 12px; -} -.role-name{ - opacity: 60%; - font-size: 12px; -} -.role1-container{ - animation: role1msg 0.3s ease-out 0s forwards; - -} -.role2-container{ - animation: role2msg 0.3s ease-out 0s forwards; - -} -@keyframes role1msg { - 0% { - margin-left: -2rem; - opacity: 0; - } - 80% { - transform: scale(1.1); - } - 100% { - transform: scale(1); - opacity: 1; - } - } -.agent-share-btn{ - opacity: 0.8; - background: transparent !important; - border: 1px solid white !important; - padding: 0.2rem 0.4rem !important; - font-size: 12px !important; -} -@keyframes role1msg { - 0% { - margin-right: -2rem; - opacity: 0; - } - 80% { - transform: scale(1.1); - } - 100% { - transform: scale(1); - opacity: 1; - } - } -@media screen and (max-width:1000px){ - .agent-convo-box{ - height: 100%; - width: 100%; - border-radius: 0; - } - .agent-msg-container>pre{ - max-width: 20rem; - } -} - -.logo{ - width: 4rem; -} \ No newline at end of file diff --git a/client/src/styles/home.css b/client/src/styles/home.css deleted file mode 100644 index d5bf605..0000000 --- a/client/src/styles/home.css +++ /dev/null @@ -1,291 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800&display=swap"); -:root { - - --hoverColor: rgb(71, 24, 182) !important ; - --fontFamily: "Nunito", sans-serif; - --border: 1px solid #dfdfdf; - --themeColor: #763FF9; - -} - -.powered-by{ - background-color: #F6F3FF; - border-radius: 22px 22px 0 0; - opacity: 0.8; - z-index: 99; - position: fixed; - bottom: 0; - right: 1rem; -} -.banner-modal>.modal-dialog>.modal-content{ - border-radius: 22px !important; -} -.producthunt-banner{ - z-index: 99; - position: fixed; - top: 1.5rem; - right: 1rem; -} - -.powered-by a{ - color: black; - font-size: 0.8rem; -} -.discord-invite{ - background-color: #5865f2; - color: white; - border-radius: 12px; - text-decoration: none; -} - -.powered-by a:hover{ - color: black; - text-decoration: underline !important; -} - -.btn-filled{ - background: #763FF9 !important; -box-shadow: 0px 2px 25px #F0EDF9 !important; -border-radius: 12px !important; -border: 1px solid #763FF9 !important; - color: white !important; -} - -.btn-filled:hover{ - background: var(--hoverColor) !important; - -} -.side-nav{ - width: 13.5rem ; - min-height: 100vh; - background: #FFFFFF; - border-right: 1px solid #DFDFDF; - box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.04); - font-size: 0.75rem; - font-weight: 700; -} -/* .mobile-nav{ - font-size: 0.75rem !important; -} */ -body,html{ - background-color: #ffffff !important; - font-family: var(--fontFamily) !important; - color:#000000 !important; -} -.nav-body, -.nav-header > .accordion-button { - padding:0.5rem 0rem !important; - border:0 !important; - background-color: transparent !important; - color: #000 !important; - font-size: 0.75rem; - font-weight: 700; -} -.os-logo{ - width: 3.75rem; - height: 3.75rem; - margin: 2.5rem 0; -} -.os-logo-mobile{ - width: 2.5rem; - height: 2.5rem; -} -.offcanvas-backdrop{ - width: 100% !important; - height: 100% !important; -} -.nav-icon{ - height: 1rem; - width: 1rem; - margin-right: 1.5rem; -} -.side-accordion{ - --bs-accordion-bg: transparent !important; -} -.nav-width{ - width: 10.5rem; -} -.nav-width>.nav-item{ - width: 100%; -} - -.nav-header > .accordion-button::after { - margin-left: auto; - -} -.accordion-button.collapsed::after{ - background-size: 1rem; - color: #000 !important; - margin-left: auto; -} -.accordion-button:not(.collapsed) { - box-shadow: none !important; - color: #000 !important; -} -.nav-header > .accordion-button:not(.collapsed)::after { - transform: rotate(-180deg) !important; - background-size: 1rem; - color: #000 !important; -} -.nav-header > .accordion-button:focus { - border: none !important; - box-shadow: none !important; -} - -.side-nav-links >.nav-link.active{ - color: #763FF9 !important; - border-radius: 1.875rem; -} - -.side-nav-links >.nav-link{ - color: #5F5B66 !important; - padding: 0.375rem 2.5rem; -} - -.side-nav-links > .active{ - background-color: #F6F3FF !important; - color: #763FF9 !important; -} - - -.rounded-cards{ - box-sizing: border-box; - background: #FFFFFF !important; - border: 1px solid #DFDFDF; - box-shadow: 0px 2px 25px #F0EDF9; - border-radius: 22px; -} - -.top-filters-cards{ - height: 2.81rem; - background: #FFFFFF !important; - border: 1px solid #DFDFDF !important; - box-shadow: 0px 2px 25px #F0EDF9 !important; - border-radius: 0.75rem; - color: #000 !important; - font-size: 0.75rem !important; - padding: 0.5rem 0.75rem !important; -} - -.dropdown>.dropdown-toggle::after{ - margin-left:20px !important; -} - -.small-text{ - font-size: 0.75rem !important ; -} -.content-container{ - max-width: 50rem; -} -.number-text{ - font-size: 1.5rem !important; - font-weight: 600 !important; -} - -.navbar-toggler:focus{ - box-shadow: none; -} -.graph-title{ - font-weight: 400; -} -.stats-table{ - background: #FFFFFF !important; - border: 1px solid #DFDFDF !important; -} -.stats-table>thead{ - background-color: #F2F2F2; - font-size: 0.75rem; -} -.stats-table>thead>tr>th,.stats-table>tbody>tr>td{ - padding: 1.5rem; - -} -/* .stats-table tr:first-child th:first-child { - border-top-left-radius: 22px; -} - -.stats-table tr:first-child th:last-child { - border-top-right-radius: 22px; -} -.stats-table tr:last-child td:first-child { - border-bottom-left-radius: 22px; -} - -.stats-table tr:last-child td:last-child { - border-bottom-right-radius: 22px; -} */ -@media screen and (max-width:992px){ - .main-col{ - margin-top: 7rem !important; - } - .nav-header > .accordion-button { - font-size: 1rem; - } - .graph-title{ - font-size: 0.9rem; - } - .stats-table>thead>tr>th,.stats-table>tbody>tr>td{ - padding: 1rem; - - } - .powered-by{ - background-color: #21cd9c; - border-radius: 0 0 12px 12px ; - top: 0; - right: 0; - bottom: auto; - } -} - -@media screen and (min-width:1600px){ - .content-container{ - max-width: 75rem; - } -} -@media screen and (max-width:500px){ - .stats-table>thead>tr>th,.stats-table>tbody>tr>td{ - padding: 0.5rem; - - } -} - -.options-bg{ -box-sizing: border-box; -background: #FFFFFF !important; -border: 1px solid #DFDFDF !important; -box-shadow: 0px 2px 25px #F0EDF9 !important; -border-radius: 50px !important; -color: #000000 !important; -font-size: 12px !important; -} - -.filter-drop > button{ - background-color: white !important; - color: #000 !important; - border: 0px !important; - font-size: 12px !important; - padding-left: 3px !important; - padding-right: 3px !important; - padding-top: 6px !important; - padding-bottom: 6px !important; -} -.filter-drop >.dropdown-toggle::after{ - content:none !important; -} - -.filter-drop > .dropdown-menu{ - font-size: 12px !important; - min-width: 5rem !important; - border: 1px solid #ececec!important; - box-shadow: 0px 2px 25px #F0EDF9 !important; -} - -.vr{ - background-color: #acacac !important; -} - -.icon{ - width: 1.3rem ; - height: 1.3rem ; - cursor: pointer ; -} diff --git a/server/.env.example b/server/.env.example deleted file mode 100644 index 22fda5e..0000000 --- a/server/.env.example +++ /dev/null @@ -1,12 +0,0 @@ -# Flask Configuration -FLASK_ENV=dev -FLASK_APP=webserver.py -SECRET_KEY=your-secret-key-here - -# Google OAuth Credentials (for user authentication) -# Get these from https://console.cloud.google.com/apis/credentials -google_client_id=your-google-client-id -google_client_secret=your-google-client-secret - -# OpenAI API Key (users can also add this in the UI) -# OPENAI_API_KEY=sk-your-openai-api-key diff --git a/server/agent_convo.py b/server/agent_convo.py deleted file mode 100644 index b7e7c33..0000000 --- a/server/agent_convo.py +++ /dev/null @@ -1,297 +0,0 @@ -from database import * -import urllib.parse -from flask import jsonify,request,session,render_template,redirect,url_for,Blueprint -from requests_oauthlib import OAuth2Session -from flask_login import login_required, login_user, current_user, logout_user -import secrets -from datetime import datetime, date, timedelta, timezone -import os, pickle, codecs -from typing import List -from langchain.chat_models import ChatOpenAI -from langchain.prompts.chat import ( - SystemMessagePromptTemplate, - HumanMessagePromptTemplate, -) -from langchain.schema import ( - AIMessage, - HumanMessage, - SystemMessage, - BaseMessage, -) - -authorization_base_url = "https://accounts.google.com/o/oauth2/v2/auth" -scope = [ - "https://www.googleapis.com/auth/userinfo.email", - "https://www.googleapis.com/auth/userinfo.profile", - "openid" -] -google_client_id = os.environ.get('google_client_id') -google_client_secret = os.environ.get('google_client_secret') - -if not google_client_id or not google_client_secret: - print("=" * 60) - print("WARNING: Google OAuth credentials not found!") - print("Please set the following environment variables:") - print(" - google_client_id") - print(" - google_client_secret") - print("") - print("Get these from: https://console.cloud.google.com/apis/credentials") - print("See server/.env.example for reference.") - print("=" * 60) -word_limit = 50 # word limit for task brainstorming - -rp = Blueprint('rp', __name__) - - -@rp.route("/rp/isLoggedIn", methods=['GET']) -def rp_isLoggedIn(): - url_host = urllib.parse.urlsplit(request.url).hostname - if "5000" in request.url: - redirect_uri = "http://"+url_host+":5000/rp/google_callback" - else: - redirect_uri = "https://"+url_host+"/rp/google_callback" - google = OAuth2Session( - google_client_id, scope=scope, redirect_uri=redirect_uri) - login_url, state = google.authorization_url(authorization_base_url) - session['oauth_state'] = google_client_id - if current_user.is_authenticated: - if current_user.openai_key == "" or current_user.openai_key == None: - keyAdded = None - else: - keyAdded = current_user.openai_key - return jsonify(isLoggedIn=current_user.is_authenticated,userId=current_user.id,key_added=keyAdded,image=current_user.profile_image) - else: - return jsonify(isLoggedIn=False,auth_url=login_url) - -@rp.route("/rp/google_callback", methods=['GET']) -def rp_google_callback(): - url_host = urllib.parse.urlsplit(request.url).hostname - if "5000" in request.url: - redirect_uri = "http://"+url_host+":5000/rp/google_callback" - else: - redirect_uri = "https://"+url_host+"/rp/google_callback" - google = OAuth2Session( - google_client_id, scope=scope, redirect_uri=redirect_uri) - token_url = "https://www.googleapis.com/oauth2/v4/token" - welcome = False - try: - google.fetch_token(token_url, client_secret=google_client_secret, - authorization_response=request.url) - except: - pass - response = google.get( - 'https://www.googleapis.com/oauth2/v1/userinfo').json() - email = response["email"].lower() - googleId = str(response["id"]) - name = response["name"] - image = response["picture"] - getAdmin = Admin.query.filter_by(email=email).first() - if getAdmin == None: - getAdmin = Admin(id=secrets.token_urlsafe(24), email=email,google_id=googleId, name=name,profile_image=image, created_date=datetime.now()) - db.session.add(getAdmin) - db.session.commit() - else: - getAdmin.google_id = googleId - getAdmin.profile_image = image - db.session.commit() - login_user(getAdmin, remember=True) - return redirect("http://localhost:3000/") - -class CAMELAgent: - - def __init__( - self, - system_message, - model: ChatOpenAI, - store - ) -> None: - self.model = model - if store == None: - self.system_message = system_message - self.init_messages() - # print("NEW") - else: - self.stored_messages = store - self.system_message = store[0] - # print("MESSAGES \n",self.stored_messages,"\n SYSTEM MESSAGE \n",self.system_message) - - def reset(self) -> None: - self.init_messages() - return self.stored_messages - - def init_messages(self) -> None: - self.stored_messages = [self.system_message] - # for msg in self.stored_messages: - # print("INTIALIZED",msg.content,"\n") - - def update_messages(self, message: BaseMessage) -> List[BaseMessage]: - self.stored_messages.append(message) - # for msg in self.stored_messages: - # print("UPDATED",msg.content,"\n") - return self.stored_messages - - def step( - self, - input_message: HumanMessage, - ) -> AIMessage: - messages = self.update_messages(input_message) - output_message = self.model(messages) - self.update_messages(output_message) - - return output_message - - def store_messages(self) -> None: - return self.stored_messages - - - - -def starting_convo(assistant_role_name,user_role_name,task): - task_specifier_sys_msg = SystemMessage(content="You can make a task more specific.") - task_specifier_prompt = ( - """Here is a task that {assistant_role_name} will help {user_role_name} to complete: {task}. - Please make it more specific. Be creative and imaginative. - Please reply with the specified task in {word_limit} words or less. Do not add anything else.""" - ) - task_specifier_template = HumanMessagePromptTemplate.from_template(template=task_specifier_prompt) - task_specify_agent = CAMELAgent(task_specifier_sys_msg, ChatOpenAI(temperature=1.0),None) - task_specifier_msg = task_specifier_template.format_messages(assistant_role_name=assistant_role_name, - user_role_name=user_role_name, - task=task, word_limit=word_limit)[0] - specified_task_msg = task_specify_agent.step(task_specifier_msg) - # print(f"Specified task: {specified_task_msg.content}") - specified_task = specified_task_msg.content - - assistant_inception_prompt = ( - """Never forget you are a {assistant_role_name} and I am a {user_role_name}. Never flip roles! Never instruct me! - We share a common interest in collaborating to successfully complete a task. - You must help me to complete the task. - Here is the task: {task}. Never forget our task! - I must instruct you based on your expertise and my needs to complete the task. - - I must give you one instruction at a time. - You must write a specific solution that appropriately completes the requested instruction. - You must decline my instruction honestly if you cannot perform the instruction due to physical, moral, legal reasons or your capability and explain the reasons. - Do not add anything else other than your solution to my instruction. - You are never supposed to ask me any questions you only answer questions. - You are never supposed to reply with a flake solution. Explain your solutions. - Your solution must be declarative sentences and simple present tense. - Unless I say the task is completed, you should always start with: - - Solution: - - should be specific and provide preferable implementations and examples for task-solving. - Always end with: Next request.""" - ) - - user_inception_prompt = ( - """Never forget you are a {user_role_name} and I am a {assistant_role_name}. Never flip roles! You will always instruct me. - We share a common interest in collaborating to successfully complete a task. - I must help you to complete the task. - Here is the task: {task}. Never forget our task! - You must instruct me based on my expertise and your needs to complete the task ONLY in the following two ways: - - 1. Instruct with a necessary input: - Instruction: - Input: - - 2. Instruct without any input: - Instruction: - Input: None - - The "Instruction" describes a task or question. The paired "Input" provides further context or information for the requested "Instruction". - - You must give me one instruction at a time. - I must write a response that appropriately completes the requested instruction. - I must decline your instruction honestly if I cannot perform the instruction due to physical, moral, legal reasons or my capability and explain the reasons. - You should instruct me not ask me questions. - Now you must start to instruct me using the two ways described above. - Do not add anything else other than your instruction and the optional corresponding input! - Keep giving me instructions and necessary inputs until you think the task is completed. - When the task is completed, you must only reply with a single word . - Never say unless my responses have solved your task.""" - ) - return specified_task,assistant_inception_prompt,user_inception_prompt - -def get_sys_msgs(assistant_role_name: str, user_role_name: str, task: str,assistant_inception_prompt,user_inception_prompt): - - assistant_sys_template = SystemMessagePromptTemplate.from_template(template=assistant_inception_prompt) - assistant_sys_msg = assistant_sys_template.format_messages(assistant_role_name=assistant_role_name, user_role_name=user_role_name, task=task)[0] - - user_sys_template = SystemMessagePromptTemplate.from_template(template=user_inception_prompt) - user_sys_msg = user_sys_template.format_messages(assistant_role_name=assistant_role_name, user_role_name=user_role_name, task=task)[0] - - return assistant_sys_msg, user_sys_msg - -@rp.route("/rp/start", methods=['POST']) -def start_rp(): - if not current_user.is_authenticated: - return redirect("/agent_convo") - os.environ["OPENAI_API_KEY"] = current_user.openai_key - assistant_role_name = request.json["role1"] - user_role_name = request.json["role2"] - task = request.json["task"] - sessId = request.json["sessId"] - if sessId == 0: - getSession = Agent_Session(role_1=assistant_role_name,role_2=user_role_name,task=task,admin_id=current_user.id) - db.session.add(getSession) - db.session.commit() - specified_task,assistant_inception_prompt,user_inception_prompt = starting_convo(assistant_role_name, user_role_name, task) - assistant_sys_msg, user_sys_msg = get_sys_msgs(assistant_role_name, user_role_name, specified_task,assistant_inception_prompt,user_inception_prompt) - assistant_agent = CAMELAgent(assistant_sys_msg, ChatOpenAI(temperature=0.2),None) - user_agent = CAMELAgent(user_sys_msg, ChatOpenAI(temperature=0.2),None) - # Reset agents - assistant_agent.reset() - user_agent.reset() - - # Initialize chats - assistant_msg = HumanMessage( - content=(f"{user_sys_msg.content}. " - "Now start to give me introductions one by one. " - "Only reply with Instruction and Input.")) - - user_msg = HumanMessage(content=f"{assistant_sys_msg.content}") - user_msg = assistant_agent.step(user_msg) - else: - getSession = Agent_Session.query.filter_by(id=sessId).first() - user_store = pickle.loads(codecs.decode((getSession.user_store).encode(), "base64")) - assistant_store = pickle.loads(codecs.decode((getSession.assistant_store).encode(), "base64")) - user_agent = CAMELAgent(None, ChatOpenAI(temperature=0.2),user_store) - assistant_agent = CAMELAgent(None, ChatOpenAI(temperature=0.2),assistant_store) - assistant_msg = HumanMessage( - content=(f"{assistant_store[-1].content}")) - - # chat_turn_limit, n = 10, 0 - # while n < chat_turn_limit: - # n += 1 - user_ai_msg = user_agent.step(assistant_msg) - user_msg = HumanMessage(content=user_ai_msg.content) - userMsg = user_msg.content.replace("Instruction: ","").replace("Input: None","").replace("Input: None.","") - # print(f"AI User ({user_role_name}):\n\n{user_msg.content}\n\n") - assistant_ai_msg = assistant_agent.step(user_msg) - assistant_msg = HumanMessage(content=assistant_ai_msg.content) - assistantMsg = assistant_msg.content.replace("Solution: ","").replace("Next request.","") - # print(f"AI Assistant ({assistant_role_name}):\n\n{assistant_msg.content}\n\n") - convoEnd = False - if "" in user_msg.content: - convoEnd = True - getUserStore = user_agent.store_messages() - getSession.user_store = codecs.encode(pickle.dumps(getUserStore), "base64").decode() - getAssistantStore = assistant_agent.store_messages() - getSession.assistant_store = codecs.encode(pickle.dumps(getAssistantStore), "base64").decode() - db.session.commit() - return jsonify(sessId=getSession.id,userMsg=userMsg,assistantMsg=assistantMsg,convoEnd=convoEnd) - - -@rp.route("/rp/get_chat", methods=['get']) -def rp_get_chat(): - sessId = request.args.get('sessId') - getSession = Agent_Session.query.filter_by(id=sessId).first() - assistant_store = pickle.loads(codecs.decode((getSession.assistant_store).encode(), "base64")) - messages = [] - for store in assistant_store[2:]: - if str(type(store)) == "": - messages.append({"role":0,"msg":store.content.replace("Instruction: ","").replace("Input: None","").replace("Input: None.","")}) - elif str(type(store)) == "": - messages.append({"role":1,"msg":store.content.replace("Solution: ","").replace("Next request.","")}) - return jsonify(role1=getSession.role_1,role2=getSession.role_2,task=getSession.task,messages=messages) diff --git a/server/database.py b/server/database.py deleted file mode 100644 index 04599b2..0000000 --- a/server/database.py +++ /dev/null @@ -1,43 +0,0 @@ -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import DateTime, ForeignKey, MetaData -from flask_login import UserMixin - -from flask import Flask - -convention = { - "ix": 'ix_%(column_0_label)s', - "uq": "uq_%(table_name)s_%(column_0_name)s", - "ck": "ck_%(table_name)s_%(constraint_name)s", - "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", - "pk": "pk_%(table_name)s" -} - -metadata = MetaData(naming_convention=convention) -db = SQLAlchemy(metadata=metadata) -app = Flask(__name__) - -class Agent_Session(db.Model): - __tablename__ = "agent_session" - id = db.Column(db.Integer, primary_key=True, autoincrement=True) - role_1 = db.Column(db.String(200), default="", server_default = "") - role_2 = db.Column(db.String(200), default="", server_default = "") - task = db.Column(db.String(3000), default="", server_default = "") - user_store = db.Column(db.String, default="", server_default = "") - assistant_store = db.Column(db.String, default="", server_default = "") - admin_id = db.Column(db.String(100), ForeignKey("admin.id"), index=True) - -class Admin(UserMixin,db.Model): - __tablename__ = "admin" - id = db.Column(db.String(100), primary_key=True) - name = db.Column(db.String(100)) - email = db.Column(db.String(100), unique=True, index=True) - google_id = db.Column(db.String(100)) - openai_key = db.Column(db.String(100)) - profile_image = db.Column(db.String(100000)) - password = db.Column(db.String(100)) - created_date = db.Column(DateTime) - gpt_model = db.Column(db.String, default="gpt-3.5-turbo", server_default="gpt-3.5-turbo") - agent_sessions = db.relationship('Agent_Session', backref='admin', - cascade="all,delete", lazy='dynamic') - def get_id(self): - return (self.id) \ No newline at end of file diff --git a/server/requirements.txt b/server/requirements.txt deleted file mode 100644 index 62591c5..0000000 --- a/server/requirements.txt +++ /dev/null @@ -1,48 +0,0 @@ -aiohttp==3.8.4 -aiosignal==1.3.1 -alembic==1.10.4 -async-timeout==4.0.2 -attrs==23.1.0 -blinker==1.6.2 -certifi==2022.12.7 -charset-normalizer==3.1.0 -click==8.1.3 -colorama==0.4.6 -dataclasses-json==0.5.7 -Flask==2.3.1 -Flask-Login==0.6.2 -Flask-Migrate==4.0.4 -Flask-SQLAlchemy==3.0.3 -frozenlist==1.3.3 -greenlet==2.0.2 -idna==3.4 -importlib-metadata==6.6.0 -importlib-resources==5.12.0 -itsdangerous==2.1.2 -Jinja2==3.1.2 -langchain==0.0.152 -Mako==1.2.4 -MarkupSafe==2.1.2 -marshmallow==3.19.0 -marshmallow-enum==1.5.1 -multidict==6.0.4 -mypy-extensions==1.0.0 -numexpr==2.8.4 -numpy==1.24.3 -oauthlib==3.2.2 -openai==0.27.5 -openapi-schema-pydantic==1.2.4 -packaging==23.1 -pydantic==1.10.7 -PyYAML==6.0 -requests==2.29.0 -requests-oauthlib==1.3.1 -SQLAlchemy==2.0.11 -tenacity==8.2.2 -tqdm==4.65.0 -typing-extensions==4.5.0 -typing-inspect==0.8.0 -urllib3==1.26.15 -Werkzeug==2.3.1 -yarl==1.9.2 -zipp==3.15.0 diff --git a/server/webserver.py b/server/webserver.py deleted file mode 100644 index 26370ff..0000000 --- a/server/webserver.py +++ /dev/null @@ -1,66 +0,0 @@ -from flask import Flask -from flask_migrate import Migrate -from database import * -import os -import urllib.parse -from flask import jsonify,request,session,render_template,redirect,url_for,Blueprint -from requests_oauthlib import OAuth2Session -from flask_login import UserMixin, LoginManager, login_required, login_user, current_user, logout_user -import secrets -from datetime import datetime, date, timedelta, timezone -import os -import json -import random -import requests -from agent_convo import rp - -try: - import config -except ModuleNotFoundError: - pass - - -app = Flask(__name__) -app.register_blueprint(rp) -app.secret_key = 'autogptsamurai@123' - -app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./test.db' -db.init_app(app) -db.app = app -migrate = Migrate(app, db, compare_type=True, - render_as_batch=True) - -login_manager = LoginManager(app) - - -@login_manager.user_loader -def load_user(user_id): - return Admin.query.filter_by(id=user_id).first() - -os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' - -@app.route("/change_model", methods=['POST']) -def change_model(): - model = request.values["model"] - current_user.gpt_model = model - db.session.commit() - return "Success" - -@app.route("/logout", methods=['GET']) -def logout(): - logout_user() - return "Success", 200 - -@app.route("/store_key", methods=['POST']) -def store_key(): - key = request.json['key'] - getAdmin = Admin.query.filter_by(id=current_user.id).first() - if len(key) == 51: - getAdmin.openai_key = key - db.session.commit() - return jsonify(True) - else: - return jsonify(False), 400 - -if __name__ == '__main__': - app.run(host="0.0.0.0", debug=True) diff --git a/steps_to_run.md b/steps_to_run.md deleted file mode 100644 index 2790d26..0000000 --- a/steps_to_run.md +++ /dev/null @@ -1,37 +0,0 @@ -# Server - -1. To run server, install virtualenv first https://virtualenv.pypa.io/en/latest/ and create a new virtual environment to load all necessary python packages - -2. Go to server folder and install all necessary packages using command `pip install -r requirements.txt` - -3. Set up environment variables: - - Copy `.env.example` to `.env`: `cp .env.example .env` - - Edit `.env` and add your credentials: - - `FLASK_ENV=dev` - - `FLASK_APP=webserver.py` - - `google_client_id` - Get from [Google Cloud Console](https://console.cloud.google.com/apis/credentials) - - `google_client_secret` - Get from Google Cloud Console - - **To create Google OAuth credentials:** - 1. Go to Google Cloud Console > APIs & Services > Credentials - 2. Click "Create Credentials" > "OAuth client ID" - 3. Select "Web application" - 4. Add authorized redirect URIs: - - `http://localhost:5000/rp/google_callback` (for development) - 5. Copy the Client ID and Client Secret to your `.env` file - -4. Create a db for storing all the info using commands: - ```bash - flask db init - flask db migrate - flask db upgrade - ``` - -5. Run the server using `python webserver.py` - - -# Client - -1. To run client, go to client folder and do `npm install` - -2. Now run `npm start` and this should start the client