diff --git a/client/package.json b/client/package.json
new file mode 100644
index 0000000..9188d28
--- /dev/null
+++ b/client/package.json
@@ -0,0 +1,48 @@
+{
+ "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
new file mode 100644
index 0000000..91a68aa
Binary files /dev/null and b/client/public/favicon.ico differ
diff --git a/client/public/index.html b/client/public/index.html
new file mode 100644
index 0000000..821c14f
--- /dev/null
+++ b/client/public/index.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AutoGPT
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
diff --git a/client/public/logo192.png b/client/public/logo192.png
new file mode 100644
index 0000000..1d48f8b
Binary files /dev/null and b/client/public/logo192.png differ
diff --git a/client/public/logo512.png b/client/public/logo512.png
new file mode 100644
index 0000000..8b8f295
Binary files /dev/null and b/client/public/logo512.png differ
diff --git a/client/public/manifest.json b/client/public/manifest.json
new file mode 100644
index 0000000..080d6c7
--- /dev/null
+++ b/client/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "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
new file mode 100644
index 0000000..e9e57dc
--- /dev/null
+++ b/client/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/client/src/App.js b/client/src/App.js
new file mode 100644
index 0000000..d261476
--- /dev/null
+++ b/client/src/App.js
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 0000000..1f03afe
--- /dev/null
+++ b/client/src/App.test.js
@@ -0,0 +1,8 @@
+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
new file mode 100644
index 0000000..a9b0c5c
Binary files /dev/null and b/client/src/assets/camelagi.png differ
diff --git a/client/src/assets/discord.svg b/client/src/assets/discord.svg
new file mode 100644
index 0000000..22ee27b
--- /dev/null
+++ b/client/src/assets/discord.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/google.svg b/client/src/assets/google.svg
new file mode 100644
index 0000000..47889ad
--- /dev/null
+++ b/client/src/assets/google.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
ionicons-v5_logos
+
+
+
\ No newline at end of file
diff --git a/client/src/assets/key.svg b/client/src/assets/key.svg
new file mode 100644
index 0000000..950c1c8
--- /dev/null
+++ b/client/src/assets/key.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/client/src/assets/logout-white.svg b/client/src/assets/logout-white.svg
new file mode 100644
index 0000000..d52ec8f
--- /dev/null
+++ b/client/src/assets/logout-white.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/question-mark.svg b/client/src/assets/question-mark.svg
new file mode 100644
index 0000000..30cf4d6
--- /dev/null
+++ b/client/src/assets/question-mark.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/src/assets/reload.svg b/client/src/assets/reload.svg
new file mode 100644
index 0000000..bcd86b9
--- /dev/null
+++ b/client/src/assets/reload.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/src/assets/send.svg b/client/src/assets/send.svg
new file mode 100644
index 0000000..fabeea7
--- /dev/null
+++ b/client/src/assets/send.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/share-white.svg b/client/src/assets/share-white.svg
new file mode 100644
index 0000000..2e99fc6
--- /dev/null
+++ b/client/src/assets/share-white.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/client/src/assets/user-1.svg b/client/src/assets/user-1.svg
new file mode 100644
index 0000000..3485a31
--- /dev/null
+++ b/client/src/assets/user-1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/user-2.svg b/client/src/assets/user-2.svg
new file mode 100644
index 0000000..231c05e
--- /dev/null
+++ b/client/src/assets/user-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/user-3.svg b/client/src/assets/user-3.svg
new file mode 100644
index 0000000..5d40e62
--- /dev/null
+++ b/client/src/assets/user-3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/user-4.svg b/client/src/assets/user-4.svg
new file mode 100644
index 0000000..03e5246
--- /dev/null
+++ b/client/src/assets/user-4.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/user.png b/client/src/assets/user.png
new file mode 100644
index 0000000..3046f3a
Binary files /dev/null and b/client/src/assets/user.png differ
diff --git a/client/src/index.css b/client/src/index.css
new file mode 100644
index 0000000..ec2585e
--- /dev/null
+++ b/client/src/index.css
@@ -0,0 +1,13 @@
+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
new file mode 100644
index 0000000..a74730c
--- /dev/null
+++ b/client/src/index.js
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 0000000..9dfc1c0
--- /dev/null
+++ b/client/src/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/pages/AgentConvo.js b/client/src/pages/AgentConvo.js
new file mode 100644
index 0000000..3ab5795
--- /dev/null
+++ b/client/src/pages/AgentConvo.js
@@ -0,0 +1,262 @@
+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&&Share }
+
+
+ {finished?
+ Task Completed!
+ :
+ <>
+ {turnRef.current<3?
+ Loading
+ :startDiscussion(true)}>Continue }
+ >}
+ >
+ :
+ <>
+ 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)}/>
+
+ startDiscussion(true)}>Start Discussion
+ >
+
+ }
+ >:
+
+ 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
+ VIDEO
+
+ }
+ :
+
+
+ {/* Login to agi */}
+ Accomplish your task with AI agents
+ Login with Google
+ Star CamelAGI on Github
+ {/* navigate('/agi/faq')}> Know More */}
+
+ }
+
+
+
setShowBanner(false)}>
+
+ setShowBanner(false)} className="position-absolute top-0 end-0 me-4 mt-2">X
+
+
+ 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
new file mode 100644
index 0000000..8b48db9
--- /dev/null
+++ b/client/src/pages/AgentConvoShare.js
@@ -0,0 +1,125 @@
+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
+ navigate('/conversation')}>Create your own
+
+
+
+
+
+
+ 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
+
+
+
+
+
+
+ >
+ )
+
+}
+
+export default AgentConvoShare;
\ No newline at end of file
diff --git a/client/src/reportWebVitals.js b/client/src/reportWebVitals.js
new file mode 100644
index 0000000..5253d3a
--- /dev/null
+++ b/client/src/reportWebVitals.js
@@ -0,0 +1,13 @@
+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
new file mode 100644
index 0000000..8f2609b
--- /dev/null
+++ b/client/src/setupTests.js
@@ -0,0 +1,5 @@
+// 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
new file mode 100644
index 0000000..fa3f701
--- /dev/null
+++ b/client/src/styles/agent-convo.css
@@ -0,0 +1,149 @@
+.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
new file mode 100644
index 0000000..d5bf605
--- /dev/null
+++ b/client/src/styles/home.css
@@ -0,0 +1,291 @@
+@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/agent_convo.py b/server/agent_convo.py
new file mode 100644
index 0000000..dfb21af
--- /dev/null
+++ b/server/agent_convo.py
@@ -0,0 +1,286 @@
+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['google_client_id']
+google_client_secret = os.environ['google_client_secret']
+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
new file mode 100644
index 0000000..04599b2
--- /dev/null
+++ b/server/database.py
@@ -0,0 +1,43 @@
+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
new file mode 100644
index 0000000..e69de29
diff --git a/server/webserver.py b/server/webserver.py
new file mode 100644
index 0000000..26370ff
--- /dev/null
+++ b/server/webserver.py
@@ -0,0 +1,66 @@
+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)