get rid of credential for langchain hub

This commit is contained in:
Henry
2023-12-09 13:49:53 +00:00
parent 4c406ee63a
commit 9a5d5720f9
3 changed files with 140 additions and 190 deletions
+3 -24
View File
@@ -1044,18 +1044,9 @@ export class App {
// ---------------------------------------- // ----------------------------------------
this.app.post('/api/v1/load-prompt', async (req: Request, res: Response) => { this.app.post('/api/v1/load-prompt', async (req: Request, res: Response) => {
try { try {
const credential = await this.AppDataSource.getRepository(Credential).findOneBy({ let hub = new Client()
id: req.body.credential
})
if (!credential) return res.status(404).json({ error: `Credential ${req.body.credential} not found` })
// Decrypt credentialData
const decryptedCredentialData = await decryptCredentialData(credential.encryptedData, credential.credentialName, undefined)
let hub = new Client({ apiKey: decryptedCredentialData.langsmithApiKey, apiUrl: decryptedCredentialData.langsmithEndpoint })
const prompt = await hub.pull(req.body.promptName) const prompt = await hub.pull(req.body.promptName)
const templates = parsePrompt(prompt) const templates = parsePrompt(prompt)
return res.json({ status: 'OK', prompt: req.body.promptName, templates: templates }) return res.json({ status: 'OK', prompt: req.body.promptName, templates: templates })
} catch (e: any) { } catch (e: any) {
return res.json({ status: 'ERROR', prompt: req.body.promptName, error: e?.message }) return res.json({ status: 'ERROR', prompt: req.body.promptName, error: e?.message })
@@ -1064,22 +1055,10 @@ export class App {
this.app.post('/api/v1/prompts-list', async (req: Request, res: Response) => { this.app.post('/api/v1/prompts-list', async (req: Request, res: Response) => {
try { try {
const credential = await this.AppDataSource.getRepository(Credential).findOneBy({
id: req.body.credential
})
if (!credential) return res.status(404).json({ error: `Credential ${req.body.credential} not found` })
// Decrypt credentialData
const decryptedCredentialData = await decryptCredentialData(credential.encryptedData, credential.credentialName, undefined)
const headers = {}
// @ts-ignore
headers['x-api-key'] = decryptedCredentialData.langsmithApiKey
const tags = req.body.tags ? `tags=${req.body.tags}` : '' const tags = req.body.tags ? `tags=${req.body.tags}` : ''
// Default to 100, TODO: add pagination and use offset & limit // Default to 100, TODO: add pagination and use offset & limit
const url = `https://web.hub.langchain.com/repos/?limit=100&${tags}has_commits=true&sort_field=num_likes&sort_direction=desc&is_archived=false` const url = `https://api.hub.langchain.com/repos/?limit=100&${tags}has_commits=true&sort_field=num_likes&sort_direction=desc&is_archived=false`
axios.get(url, headers).then((response) => { axios.get(url).then((response) => {
if (response.data.repos) { if (response.data.repos) {
return res.json({ status: 'OK', repos: response.data.repos }) return res.json({ status: 'OK', repos: response.data.repos })
} }
@@ -42,12 +42,12 @@ import ClearIcon from '@mui/icons-material/Clear'
import { styled } from '@mui/material/styles' import { styled } from '@mui/material/styles'
//Project Import //Project Import
import CredentialInputHandler from 'views/canvas/CredentialInputHandler'
import { StyledButton } from 'ui-component/button/StyledButton' import { StyledButton } from 'ui-component/button/StyledButton'
import { MemoizedReactMarkdown } from 'ui-component/markdown/MemoizedReactMarkdown' import { MemoizedReactMarkdown } from 'ui-component/markdown/MemoizedReactMarkdown'
import { CodeBlock } from 'ui-component/markdown/CodeBlock' import { CodeBlock } from 'ui-component/markdown/CodeBlock'
import promptEmptySVG from 'assets/images/prompt_empty.svg' import promptEmptySVG from 'assets/images/prompt_empty.svg'
import useApi from 'hooks/useApi'
import promptApi from 'api/prompt' import promptApi from 'api/prompt'
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
@@ -89,6 +89,7 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
const portalElement = document.getElementById('portal') const portalElement = document.getElementById('portal')
const dispatch = useDispatch() const dispatch = useDispatch()
const customization = useSelector((state) => state.customization) const customization = useSelector((state) => state.customization)
const getAvailablePromptsApi = useApi(promptApi.getAvailablePrompts)
useEffect(() => { useEffect(() => {
if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
@@ -98,6 +99,22 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [show, dispatch]) }, [show, dispatch])
useEffect(() => {
if (promptType) {
getAvailablePromptsApi.request({ tags: promptType === 'template' ? 'StringPromptTemplate&' : 'ChatPromptTemplate&' })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [promptType])
useEffect(() => {
if (getAvailablePromptsApi.data && getAvailablePromptsApi.data.repos) {
setAvailablePrompNameList(getAvailablePromptsApi.data.repos)
if (getAvailablePromptsApi.data.repos?.length) handleListItemClick(0, getAvailablePromptsApi.data.repos)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [getAvailablePromptsApi.data])
const ITEM_HEIGHT = 48 const ITEM_HEIGHT = 48
const ITEM_PADDING_TOP = 8 const ITEM_PADDING_TOP = 8
const MenuProps = { const MenuProps = {
@@ -156,7 +173,6 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
const [availablePrompNameList, setAvailablePrompNameList] = useState([]) const [availablePrompNameList, setAvailablePrompNameList] = useState([])
const [selectedPrompt, setSelectedPrompt] = useState({}) const [selectedPrompt, setSelectedPrompt] = useState({})
const [credentialId, setCredentialId] = useState('')
const [accordionExpanded, setAccordionExpanded] = useState(['prompt']) const [accordionExpanded, setAccordionExpanded] = useState(['prompt'])
const handleAccordionChange = (accordionName) => (event, isExpanded) => { const handleAccordionChange = (accordionName) => (event, isExpanded) => {
@@ -173,7 +189,6 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
if (!prompt.detailed) { if (!prompt.detailed) {
const createResp = await promptApi.getPrompt({ const createResp = await promptApi.getPrompt({
credential: credentialId,
promptName: prompt.full_name promptName: prompt.full_name
}) })
if (createResp.data) { if (createResp.data) {
@@ -194,14 +209,7 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
language.forEach((item) => { language.forEach((item) => {
tags += `tags=${item.name}&` tags += `tags=${item.name}&`
}) })
const createResp = await promptApi.getAvailablePrompts({ getAvailablePromptsApi.request({ tags: tags })
credential: credentialId,
tags: tags
})
if (createResp.data) {
setAvailablePrompNameList(createResp.data.repos)
if (createResp.data.repos?.length) await handleListItemClick(0, createResp.data.repos)
}
} }
const removeDuplicates = (value) => { const removeDuplicates = (value) => {
@@ -238,176 +246,139 @@ const PromptLangsmithHubDialog = ({ promptType, show, onCancel, onSubmit }) => {
setLanguage(removeDuplicates(value)) setLanguage(removeDuplicates(value))
} }
const clear = () => {
setModelName([])
setUsecase([])
setLanguage([])
setSelectedPrompt({})
setAvailablePrompNameList([])
setAccordionExpanded(['prompt'])
}
const component = show ? ( const component = show ? (
<Dialog <Dialog
onClose={onCancel} onClose={onCancel}
open={show} open={show}
fullWidth fullWidth
maxWidth={credentialId ? 'lg' : 'sm'} maxWidth={'lg'}
aria-labelledby='prompt-dialog-title' aria-labelledby='prompt-dialog-title'
aria-describedby='prompt-dialog-description' aria-describedby='prompt-dialog-description'
> >
<DialogTitle sx={{ fontSize: '1rem' }} id='prompt-dialog-title'> <DialogTitle sx={{ fontSize: '1rem' }} id='prompt-dialog-title'>
Load Prompts from Langsmith Hub ({promptType === 'template' ? 'PromptTemplate' : 'ChatPromptTemplate'}) Langchain Hub ({promptType === 'template' ? 'PromptTemplate' : 'ChatPromptTemplate'})
</DialogTitle> </DialogTitle>
<DialogContent dividers sx={{ p: 1 }}> <DialogContent dividers sx={{ p: 1 }}>
<Box sx={{ width: credentialId ? '40%' : '100%', display: 'flex', flexDirection: 'row', p: 2, alignItems: 'center' }}> <Box sx={{ display: 'flex', flexDirection: 'row', p: 2, pt: 1, alignItems: 'center' }}>
<Typography sx={{ mr: 2 }}> <FormControl sx={{ mr: 1, width: '30%' }}>
Langsmith Credential &nbsp; <InputLabel size='small' id='model-checkbox-label'>
<span style={{ color: 'red' }}>*</span> Model
</Typography> </InputLabel>
<FormControl sx={{ flex: 1 }}> <Select
<CredentialInputHandler id='model-checkbox'
labelId='model-checkbox-label'
multiple
size='small' size='small'
sx={{ flexGrow: 1 }} value={modelName}
key={credentialId} onChange={handleModelChange}
data={credentialId ? { credential: credentialId } : {}} input={<OutlinedInput label='Model' />}
inputParam={{ renderValue={(selected) => selected.map((x) => x.name).join(', ')}
label: 'Connect Credential', endAdornment={
name: 'credential', modelName.length ? (
type: 'credential', <IconButton sx={{ mr: 2 }} onClick={() => setModelName([])}>
credentialNames: ['langsmithApi'] <ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}} }}
onSelect={(newValue) => { MenuProps={MenuProps}
setCredentialId(newValue) >
if (!newValue) clear() {models.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={modelName.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mr: 1, width: '30%' }}>
<InputLabel size='small' id='usecase-checkbox-label'>
Usecase
</InputLabel>
<Select
autoWidth={false}
labelId='usecase-checkbox-label'
id='usecase-checkbox'
multiple
size='small'
value={usecase}
onChange={handleUsecaseChange}
input={<OutlinedInput label='Usecase' />}
renderValue={(selected) => selected.map((x) => x.name).join(', ')}
endAdornment={
usecase.length ? (
<IconButton sx={{ mr: 2 }} onClick={() => setUsecase([])}>
<ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}} }}
/> MenuProps={MenuProps}
>
{usecases.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={usecase.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mr: 1, width: '30%' }}>
<InputLabel size='small' id='language-checkbox-label'>
Language
</InputLabel>
<Select
labelId='language-checkbox-label'
id='language-checkbox'
multiple
size='small'
value={language}
onChange={handleLanguageChange}
input={<OutlinedInput label='language' />}
renderValue={(selected) => selected.map((x) => x.name).join(', ')}
endAdornment={
language.length ? (
<IconButton sx={{ mr: 2 }} onClick={() => setLanguage([])}>
<ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}}
MenuProps={MenuProps}
>
{languages.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={language.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ width: '10%' }}>
<Button disableElevation variant='outlined' onClick={fetchPrompts}>
Search
</Button>
</FormControl> </FormControl>
</Box> </Box>
{credentialId && (
<Box sx={{ display: 'flex', flexDirection: 'row', p: 2, pt: 1, alignItems: 'center' }}>
<FormControl sx={{ mr: 1, width: '30%' }}>
<InputLabel size='small' id='model-checkbox-label'>
Model
</InputLabel>
<Select
disabled={!credentialId}
id='model-checkbox'
labelId='model-checkbox-label'
multiple
size='small'
value={modelName}
onChange={handleModelChange}
input={<OutlinedInput label='Model' />}
renderValue={(selected) => selected.map((x) => x.name).join(', ')}
endAdornment={
modelName.length ? (
<IconButton sx={{ mr: 2 }} onClick={() => setModelName([])}>
<ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}}
MenuProps={MenuProps}
>
{models.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={modelName.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mr: 1, width: '30%' }}>
<InputLabel size='small' id='usecase-checkbox-label'>
Usecase
</InputLabel>
<Select
autoWidth={false}
disabled={!credentialId}
labelId='usecase-checkbox-label'
id='usecase-checkbox'
multiple
size='small'
value={usecase}
onChange={handleUsecaseChange}
input={<OutlinedInput label='Usecase' />}
renderValue={(selected) => selected.map((x) => x.name).join(', ')}
endAdornment={
usecase.length ? (
<IconButton sx={{ mr: 2 }} onClick={() => setUsecase([])}>
<ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}}
MenuProps={MenuProps}
>
{usecases.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={usecase.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mr: 1, width: '30%' }}>
<InputLabel size='small' id='language-checkbox-label'>
Language
</InputLabel>
<Select
labelId='language-checkbox-label'
id='language-checkbox'
disabled={!credentialId}
multiple
size='small'
value={language}
onChange={handleLanguageChange}
input={<OutlinedInput label='language' />}
renderValue={(selected) => selected.map((x) => x.name).join(', ')}
endAdornment={
language.length ? (
<IconButton sx={{ mr: 2 }} onClick={() => setLanguage([])}>
<ClearIcon style={{ width: 20, height: 20 }} />
</IconButton>
) : (
false
)
}
sx={{
'.MuiSvgIcon-root ': {
fill: customization.isDarkMode ? 'white !important' : ''
}
}}
MenuProps={MenuProps}
>
{languages.map((variant) => (
<MenuItem key={variant.id} value={variant}>
<Checkbox id={variant.id} checked={language.findIndex((item) => item.id === variant.id) >= 0} />
<ListItemText primary={variant.name} />
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ width: '10%' }}>
<Button disableElevation variant='outlined' onClick={fetchPrompts}>
Search
</Button>
</FormControl>
</Box>
)}
{availablePrompNameList && availablePrompNameList.length == 0 && ( {availablePrompNameList && availablePrompNameList.length == 0 && (
<Stack sx={{ alignItems: 'center', justifyContent: 'center', width: '100%', pb: 3 }} flexDirection='column'> <Stack sx={{ alignItems: 'center', justifyContent: 'center', width: '100%', pb: 3 }} flexDirection='column'>
<Box sx={{ p: 5, height: 'auto' }}> <Box sx={{ p: 5, height: 'auto' }}>
@@ -238,7 +238,7 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
onClick={() => onShowPromptHubButtonClicked()} onClick={() => onShowPromptHubButtonClicked()}
endIcon={<IconAutoFixHigh />} endIcon={<IconAutoFixHigh />}
> >
Langsmith Prompt Hub Langchain Hub
</Button> </Button>
<PromptLangsmithHubDialog <PromptLangsmithHubDialog
promptType={inputParam.name} promptType={inputParam.name}