GPT Vision: Storing filenames only in chat message

This commit is contained in:
vinodkiran
2023-12-07 14:26:17 +05:30
parent dc265eb472
commit b492153f8a
3 changed files with 57 additions and 36 deletions
@@ -3,6 +3,9 @@ import { BaseChain, ChainInputs } from 'langchain/chains'
import { ChainValues } from 'langchain/schema' import { ChainValues } from 'langchain/schema'
import { BasePromptTemplate, ChatPromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts' import { BasePromptTemplate, ChatPromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts'
import { ChatOpenAI } from 'langchain/chat_models/openai' import { ChatOpenAI } from 'langchain/chat_models/openai'
import path from 'path'
import { getUserHome } from '../../../src/utils'
import fs from 'fs'
/** /**
* Interface for the input parameters of the OpenAIVisionChain class. * Interface for the input parameters of the OpenAIVisionChain class.
@@ -89,10 +92,18 @@ export class VLLMChain extends BaseChain implements OpenAIVisionChainInput {
}) })
if (this.imageUrls && this.imageUrls.length > 0) { if (this.imageUrls && this.imageUrls.length > 0) {
this.imageUrls.forEach((imageUrl: any) => { this.imageUrls.forEach((imageUrl: any) => {
let bf = imageUrl?.data
if (imageUrl.type == 'stored-file') {
const filePath = path.join(getUserHome(), '.flowise', 'gptvision', imageUrl.data)
// as the image is stored in the server, read the file and convert it to base64
const contents = fs.readFileSync(filePath)
bf = 'data:' + imageUrl.mime + ';base64,' + contents.toString('base64')
}
userRole.content.push({ userRole.content.push({
type: 'image_url', type: 'image_url',
image_url: { image_url: {
url: imageUrl?.data, url: bf,
detail: this.imageResolution detail: this.imageResolution
} }
}) })
+9 -6
View File
@@ -1349,17 +1349,20 @@ export class App {
if (incomingInput.uploads) { if (incomingInput.uploads) {
// @ts-ignore // @ts-ignore
;(incomingInput.uploads as any[]).forEach((url: any) => { ;(incomingInput.uploads as any[]).forEach((upload: any) => {
if (url.type === 'file') { if (upload.type === 'file') {
const filename = url.name const filename = upload.name
const bf = url.data
const filePath = path.join(getUserHome(), '.flowise', 'gptvision', filename) const filePath = path.join(getUserHome(), '.flowise', 'gptvision', filename)
if (!fs.existsSync(path.join(getUserHome(), '.flowise', 'gptvision'))) { if (!fs.existsSync(path.join(getUserHome(), '.flowise', 'gptvision'))) {
fs.mkdirSync(path.dirname(filePath), { recursive: true }) fs.mkdirSync(path.dirname(filePath), { recursive: true })
} }
const splitDataURI = upload.data.split(',')
//const fname = splitDataURI.pop()?.split(':')[1] ?? ''
const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
if (!fs.existsSync(filePath)) fs.writeFileSync(filePath, bf) if (!fs.existsSync(filePath)) fs.writeFileSync(filePath, bf)
fs.unlinkSync(filePath) // don't need to store the file contents in chatmessage, just the filename
url.data = bf.toString('base64') upload.data = filename //bf.toString('base64')
upload.type = 'stored-file'
} }
}) })
} }
@@ -128,7 +128,8 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
data: result, data: result,
preview: URL.createObjectURL(file), preview: URL.createObjectURL(file),
type: 'file', type: 'file',
name: name name: name,
mime: file.type
}) })
} }
reader.readAsDataURL(file) reader.readAsDataURL(file)
@@ -138,9 +139,11 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
const newFiles = await Promise.all(files) const newFiles = await Promise.all(files)
setPreviews((prevPreviews) => [...prevPreviews, ...newFiles]) setPreviews((prevPreviews) => [...prevPreviews, ...newFiles])
// if (newFiles.length > 0) {
// document.getElementById('messagelist').style.height = '80%'
// }
} }
if (e.dataTransfer.items) { if (e.dataTransfer.items) {
const newUploads = []
for (const item of e.dataTransfer.items) { for (const item of e.dataTransfer.items) {
if (item.kind === 'string' && item.type.match('^text/uri-list')) { if (item.kind === 'string' && item.type.match('^text/uri-list')) {
item.getAsString((s) => { item.getAsString((s) => {
@@ -194,7 +197,8 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
data: result, data: result,
preview: URL.createObjectURL(file), preview: URL.createObjectURL(file),
type: 'file', type: 'file',
name: name name: name,
mime: file.type
}) })
} }
reader.readAsDataURL(file) reader.readAsDataURL(file)
@@ -312,7 +316,8 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
urls.push({ urls.push({
data: item.data, data: item.data,
type: item.type, type: item.type,
name: item.name name: item.name,
mime: item.mime
}) })
}) })
clearPreviews() clearPreviews()
@@ -510,7 +515,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
</Box> </Box>
)} )}
<div className={`${isDialog ? 'cloud-dialog' : 'cloud'}`}> <div className={`${isDialog ? 'cloud-dialog' : 'cloud'}`}>
<div ref={ps} className={'messagelist'}> <div ref={ps} id='messagelist' className={'messagelist'}>
{messages && {messages &&
messages.map((message, index) => { messages.map((message, index) => {
return ( return (
@@ -710,31 +715,33 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
</form> </form>
</div> </div>
</div> </div>
{previews && previews.length > 0 && ( <div className='preview-container'>
<Grid className='preview-container' container spacing={2} sx={{ p: 1, mt: '5px', ml: '1px' }}> {previews && previews.length > 0 && (
{previews.map((item, index) => ( <Grid container spacing={2} sx={{ p: 1, mt: '5px', ml: '1px' }}>
<Grid item xs={12} sm={6} md={3} key={index}> {previews.map((item, index) => (
<Card variant='outlined' sx={{ maxWidth: 64 }}> <Grid item xs={12} sm={6} md={3} key={index}>
<CardMedia <Card variant='outlined' sx={{ maxWidth: 64 }}>
component='img' <CardMedia
image={item.preview} component='img'
sx={{ height: 64 }} image={item.preview}
alt={`preview ${index}`} sx={{ height: 64 }}
style={previewStyle} alt={`preview ${index}`}
/> style={previewStyle}
<CardActions className='center' sx={{ padding: 0, margin: 0 }}>
<Button
startIcon={<DeleteIcon />}
onClick={() => handleDeletePreview(item)}
size='small'
variant='text'
/> />
</CardActions> <CardActions className='center' sx={{ padding: 0, margin: 0 }}>
</Card> <Button
</Grid> startIcon={<DeleteIcon />}
))} onClick={() => handleDeletePreview(item)}
</Grid> size='small'
)} variant='text'
/>
</CardActions>
</Card>
</Grid>
))}
</Grid>
)}
</div>
<SourceDocDialog show={sourceDialogOpen} dialogProps={sourceDialogProps} onCancel={() => setSourceDialogOpen(false)} /> <SourceDocDialog show={sourceDialogOpen} dialogProps={sourceDialogProps} onCancel={() => setSourceDialogOpen(false)} />
</div> </div>
) )