-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic search agent functionality
- Loading branch information
Showing
5 changed files
with
213 additions
and
1 deletion.
There are no files selected for viewing
Submodule api
updated
from c0729d to 937023
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
'use client'; | ||
|
||
import React, { useState, useCallback, createRef } from 'react'; | ||
|
||
import Card from '@mui/material/Card'; | ||
import CardContent from '@mui/material/CardContent'; | ||
import Alert from '@mui/material/Alert'; | ||
import TextField from '@mui/material/TextField'; | ||
import IconButton from '@mui/material/IconButton'; | ||
import CircularProgress from '@mui/material/CircularProgress'; | ||
import SendIcon from '@mui/icons-material/Send'; | ||
|
||
import ReCAPTCHA from 'react-google-recaptcha'; | ||
import { RECAPTCHA_SITE_KEY } from '@/constants/constants'; | ||
|
||
import invokeAgent from './invokeAgent'; | ||
import Skeleton from '@mui/material/Skeleton'; | ||
import { List, ListItem, ListItemText } from '@mui/material'; | ||
|
||
const enum FormState { | ||
NotSubmitted, | ||
Submitted, | ||
Error, | ||
Answered, | ||
} | ||
|
||
export default function FindProjectForm({ host }: { host: string }) { | ||
const [formState, setFormState] = useState(FormState.NotSubmitted); | ||
const [errorMessage, setErrorMessage] = useState(''); | ||
const [prompt, setPrompt] = useState(''); | ||
const [previousPrompt, setPreviousPrompt] = useState(''); | ||
const [answer, setAnswer] = useState(''); | ||
const [projectList, setProjectList] = useState<Array<string>>([]); | ||
const recaptchaRef = createRef<ReCAPTCHA>(); | ||
|
||
const submitCallback = useCallback((): void => { | ||
if (!recaptchaRef.current) { | ||
return; | ||
} | ||
|
||
recaptchaRef.current.reset(); | ||
setPreviousPrompt(prompt); | ||
setPrompt(''); | ||
setAnswer(''); | ||
setErrorMessage(''); | ||
setFormState(FormState.Submitted); | ||
recaptchaRef.current.execute(); | ||
}, [prompt, recaptchaRef]); | ||
|
||
const recaptchaHandler = useCallback( | ||
(token: string | null): void => { | ||
if (!token) { | ||
setErrorMessage('Captcha error'); | ||
setFormState(FormState.Error); | ||
return; | ||
} | ||
|
||
invokeAgent(host, previousPrompt, token) | ||
.then((answer: string) => { | ||
const sentences = answer.split('- ').map((sentence) => sentence.trim()); | ||
setAnswer(sentences[0]); | ||
setProjectList(sentences.slice(1)); | ||
setFormState(FormState.Answered); | ||
}) | ||
.catch((err) => { | ||
setErrorMessage(`${err}`); | ||
setFormState(FormState.Error); | ||
}); | ||
}, | ||
[host, previousPrompt] | ||
); | ||
|
||
const handleChange = useCallback((event: any) => { | ||
const { value } = event.target; | ||
setPrompt(value); | ||
}, []); | ||
|
||
const loading = formState === FormState.Submitted; | ||
const buttonDisabled = loading || prompt.length === 0; | ||
|
||
return ( | ||
<> | ||
<ReCAPTCHA | ||
ref={recaptchaRef} | ||
size="invisible" | ||
sitekey={RECAPTCHA_SITE_KEY} | ||
onChange={recaptchaHandler} | ||
/> | ||
<TextField | ||
label="Request" | ||
name="request" | ||
onChange={handleChange} | ||
onKeyDown={(event) => { | ||
if (event.key === 'Enter' && !buttonDisabled) { | ||
event.preventDefault(); | ||
submitCallback(); | ||
} | ||
}} | ||
value={prompt} | ||
sx={{ m: 1, width: '100ch' }} | ||
inputProps={{ maxLength: 100 }} | ||
/> | ||
<IconButton | ||
aria-label="send request" | ||
disabled={buttonDisabled} | ||
onClick={submitCallback} | ||
style={{ height: 50, width: 50 }} | ||
> | ||
{loading ? <CircularProgress size={25} /> : <SendIcon />} | ||
</IconButton> | ||
<br /> | ||
<br /> | ||
{formState !== FormState.NotSubmitted && ( | ||
<Card style={{ marginRight: '20%' }}> | ||
<CardContent>{previousPrompt}</CardContent> | ||
</Card> | ||
)} | ||
<br /> | ||
<Card style={{ marginLeft: '20%' }}> | ||
{formState === FormState.Submitted && ( | ||
<CardContent> | ||
<Skeleton /> | ||
<Skeleton width="75%" /> | ||
<Skeleton width="60%" /> | ||
</CardContent> | ||
)} | ||
{formState === FormState.Answered && ( | ||
<CardContent> | ||
{answer.replace('\n', '')} | ||
<List> | ||
{projectList.map((project, index) => ( | ||
<ListItem key={index}> | ||
<ListItemText primary={project} /> | ||
</ListItem> | ||
))} | ||
</List> | ||
</CardContent> | ||
)} | ||
{formState === FormState.Error && formState === FormState.Error && ( | ||
<Alert severity="error">{errorMessage}</Alert> | ||
)} | ||
</Card> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
'use client'; | ||
|
||
export default async function sendPrompt( | ||
host: string, | ||
prompt: string, | ||
recaptcha: string | ||
) { | ||
try { | ||
const endpoint = `${host}/api/invoke-agent`; | ||
const data = { prompt, recaptcha }; | ||
const res = await fetch(endpoint, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify(data), | ||
}); | ||
|
||
if (!res.ok) { | ||
const errData = await res.json(); | ||
const { reason } = errData; | ||
throw new Error(`Failed to invoke agent: ${reason}`); | ||
} | ||
|
||
const { answer } = await res.json(); | ||
return answer; | ||
} catch (err: any) { | ||
// eslint-disable-next-line no-console | ||
console.log(`Error invoking agent: ${err}`); | ||
throw new Error(`Failed to invoke agent`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// 'use server'; | ||
|
||
import React, { Suspense } from 'react'; | ||
import { Metadata } from 'next'; | ||
import Typography from '@mui/material/Typography'; | ||
|
||
import getHost from '@/utils/getHost'; | ||
|
||
import FindProjectForm from './FindProjectForm'; | ||
|
||
export const metadata: Metadata = { | ||
title: 'Ask and find your project!', | ||
}; | ||
|
||
export default async function FindProject() { | ||
return ( | ||
<> | ||
<Typography variant="h1">Find my project!</Typography> | ||
<p>Ask away, and let the AI agent recommend projects for you to contribute to.</p> | ||
<Typography variant="h2">I am looking for ...</Typography> | ||
<br /> | ||
<Suspense> | ||
<FindProjectForm host={getHost()} /> | ||
</Suspense> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters