generated from eea/volto-addon-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from eea/develop
Develop
- Loading branch information
Showing
24 changed files
with
1,816 additions
and
7 deletions.
There are no files selected for viewing
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
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
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,40 @@ | ||
const path = require('path'); | ||
const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder'); | ||
|
||
const modify = (config, { target, dev }, webpack) => { | ||
const markedPath = path.dirname(require.resolve('marked')); | ||
const nodeFetch = path.dirname(require.resolve('node-fetch')); | ||
|
||
const babelLoaderFinder = makeLoaderFinder('babel-loader'); | ||
const babelLoader = config.module.rules.find(babelLoaderFinder); | ||
|
||
// config.module.rules.push({ | ||
// test: /node_modules\/vfile\//, // \/lib\/index\.js | ||
// use: [ | ||
// { | ||
// loader: 'imports-loader', | ||
// options: { | ||
// type: 'commonjs', | ||
// // imports: ['single process/browser process'], | ||
// }, | ||
// }, | ||
// ], | ||
// }); | ||
|
||
const { include } = babelLoader; | ||
|
||
include.push(markedPath); | ||
// include.push(nodeFetch); | ||
|
||
babelLoader.use[0].options.plugins = [ | ||
...(babelLoader.use[0].options.plugins || []), | ||
'@babel/plugin-proposal-private-methods', | ||
]; | ||
|
||
return config; | ||
}; | ||
|
||
module.exports = { | ||
plugins: (plugs) => plugs, | ||
modify, | ||
}; |
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,15 @@ | ||
import TextareaAutosize from 'react-textarea-autosize'; | ||
|
||
import React from 'react'; | ||
|
||
export default React.forwardRef(function AutoResizeTextarea( | ||
{ trigger, ...rest }, | ||
ref, | ||
) { | ||
return ( | ||
<> | ||
<TextareaAutosize {...rest} ref={ref} /> | ||
{trigger} | ||
</> | ||
); | ||
}); |
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,42 @@ | ||
import React from 'react'; | ||
import superagent from 'superagent'; | ||
import { BlockDataForm, SidebarPortal } from '@plone/volto/components'; | ||
|
||
import ChatBlockView from './ChatBlockView'; | ||
import { ChatBlockSchema } from './schema'; | ||
import withDanswerData from './withDanswerData'; | ||
|
||
const SearchBlockEdit = (props) => { | ||
const { onChangeBlock, block, assistants } = props; | ||
|
||
const schema = React.useMemo( | ||
() => ChatBlockSchema({ assistants }), | ||
[assistants], | ||
); | ||
|
||
return ( | ||
<div> | ||
<ChatBlockView {...props} mode="edit" /> | ||
<SidebarPortal selected={props.selected}> | ||
<BlockDataForm | ||
schema={schema} | ||
title={schema.title} | ||
block={block} | ||
onChangeBlock={onChangeBlock} | ||
onChangeField={(id, value) => { | ||
onChangeBlock(props.block, { | ||
...props.data, | ||
[id]: value, | ||
}); | ||
}} | ||
formData={props.data} | ||
/> | ||
</SidebarPortal> | ||
</div> | ||
); | ||
}; | ||
|
||
export default withDanswerData(() => [ | ||
'assistants', | ||
superagent.get('/_da/persona?include_deleted=false').type('json'), | ||
])(SearchBlockEdit); |
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,26 @@ | ||
import React from 'react'; | ||
import withDanswerData from './withDanswerData'; | ||
import ChatWindow from './ChatWindow'; | ||
import superagent from 'superagent'; | ||
|
||
function ChatBlockView(props) { | ||
const { assistantData } = props; | ||
|
||
return assistantData ? ( | ||
<div> | ||
<div> | ||
<ChatWindow persona={assistantData} /> | ||
</div> | ||
</div> | ||
) : ( | ||
<div>Chatbot</div> | ||
); | ||
} | ||
|
||
export default withDanswerData((props) => [ | ||
'assistantData', | ||
typeof props.data?.assistant !== 'undefined' | ||
? superagent.get(`/_da/persona/${props.data.assistant}`).type('json') | ||
: null, | ||
props.data?.assistant, | ||
])(ChatBlockView); |
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,120 @@ | ||
import React from 'react'; | ||
import loadable from '@loadable/component'; | ||
import { Citation } from './Citation'; | ||
import { SourceDetails } from './Source'; | ||
import { transformEmailsToLinks, SVGIcon } from './utils'; | ||
import BotIcon from './../icons/bot.svg'; | ||
import UserIcon from './../icons/user.svg'; | ||
|
||
const Markdown = loadable(() => import('react-markdown')); | ||
|
||
const components = (message) => { | ||
return { | ||
a: (props) => { | ||
const { node, ...rest } = props; | ||
const value = rest.children; | ||
|
||
if (value?.toString().startsWith('*')) { | ||
return ( | ||
<div className="flex-none bg-background-800 inline-block rounded-full h-3 w-3 ml-2" /> | ||
); | ||
} else { | ||
return ( | ||
<Citation link={rest?.href} value={value} message={message}> | ||
{rest.children} | ||
</Citation> | ||
); | ||
} | ||
}, | ||
p: ({ node, ...props }) => { | ||
const children = props.children; | ||
const text = React.Children.map(children, (child) => { | ||
if (typeof child === 'string') { | ||
return transformEmailsToLinks(child); | ||
} | ||
return child; | ||
}); | ||
|
||
return ( | ||
<p {...props} className="text-default"> | ||
{text} | ||
</p> | ||
); | ||
}, | ||
}; | ||
}; | ||
|
||
const CITATION_MATCH = /\[\d+\](?![[(\])])/gm; | ||
|
||
function addCitations(text) { | ||
return text.replaceAll(CITATION_MATCH, (match) => { | ||
const number = match.match(/\d+/)[0]; | ||
return `${match}(${number})`; | ||
}); | ||
} | ||
|
||
export function ChatMessageBubble(props) { | ||
const { message, isLoading, isMostRecent, libs } = props; | ||
const { remarkGfm } = libs; // , rehypePrism | ||
const { citations = {}, documents, type } = message; | ||
const isUser = type === 'user'; | ||
|
||
const showLoader = isMostRecent && isLoading; | ||
|
||
// TODO: these classes are not actually used, remove them | ||
const colorClassName = isUser ? 'bg-lime-300' : 'bg-slate-50'; | ||
const alignmentClassName = isUser ? 'ml-auto' : 'mr-auto'; | ||
|
||
const icon = isUser ? ( | ||
<div className="circle user"> | ||
<SVGIcon name={UserIcon} size="20" color="white" /> | ||
</div> | ||
) : ( | ||
<div className="circle assistant"> | ||
<SVGIcon name={BotIcon} size="20" color="white" /> | ||
</div> | ||
); | ||
|
||
// For some reason the list is shifted by one. It's all weird | ||
const sources = Object.keys(citations).map( | ||
(index) => documents[(parseInt(index) - 1).toString()], | ||
); | ||
const inverseMap = Object.entries(citations).reduce((acc, [k, v]) => { | ||
return { ...acc, [v]: k }; | ||
}, {}); | ||
|
||
return ( | ||
<div className={`${alignmentClassName} ${colorClassName} `}> | ||
<div className="comment"> | ||
{icon} | ||
|
||
<div> | ||
<Markdown | ||
components={components(message)} | ||
remarkPlugins={[remarkGfm]} | ||
> | ||
{addCitations(message.message)} | ||
</Markdown> | ||
|
||
{!showLoader && sources.length ? ( | ||
<> | ||
<h5>Sources:</h5> | ||
|
||
<div className="sources"> | ||
{sources.map((source, i) => ( | ||
<SourceDetails | ||
source={source} | ||
key={i} | ||
index={inverseMap[source.db_doc_id]} | ||
/> | ||
))} | ||
</div> | ||
</> | ||
) : ( | ||
'' | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.