Skip to content

Commit

Permalink
Azure deploy prod (#209)
Browse files Browse the repository at this point in the history
* 20240429 @Mookse
- assets

* 20240429 @Mookse
wip stable

* 20240429 @Mookse
- assets

Signed-off-by: Erik Jespersen <mookse@gmail.com>

* 20240429 @Mookse
wip stable

Signed-off-by: Erik Jespersen <mookse@gmail.com>

* Update azure-deploy-prod_maht.yml

Updated version numbers

* Update azure-deploy-prod_maht.yml

updated azure/webapps-deploy to v3

* 20240507 @Mookse
- `Globals` improvement
- select help type
- submit help
- receive reponse
- cosmetic update of @module in ESDocs

* 20240511 @Mookse
- display chat/request response bubbles
- begin breakout of animations.css
- llm conectivity
- await css

* 20240512 @Mookse
- help chat refresh

* 20240512 @Mookse
- availableExperiences()
- launch tutorial button
- launchExperience event

* 20240513 @Mookse
- popup-container css

* 20240513 @Mookse
- env defaults to gpt-4o

* 20240513 @Mookse
- gpt updates
- improved message parsing
- cosmetic

* 20240513 @Mookse
wip unstable

* Version 0.0.6 Release (#198)

* 20240429 @Mookse
- assets

* 20240429 @Mookse
wip stable

* 20240429 @Mookse
- assets

Signed-off-by: Erik Jespersen <mookse@gmail.com>

* 20240429 @Mookse
wip stable

Signed-off-by: Erik Jespersen <mookse@gmail.com>

* 20240507 @Mookse
- `Globals` improvement
- select help type
- submit help
- receive reponse
- cosmetic update of @module in ESDocs

* 20240511 @Mookse
- display chat/request response bubbles
- begin breakout of animations.css
- llm conectivity
- await css

* 20240512 @Mookse
- help chat refresh

* 20240512 @Mookse
- availableExperiences()
- launch tutorial button
- launchExperience event

* 20240513 @Mookse
- popup-container css

* 20240513 @Mookse
- env defaults to gpt-4o

* 20240513 @Mookse
- gpt updates
- improved message parsing
- cosmetic

---------

Signed-off-by: Erik Jespersen <mookse@gmail.com>

* 20240513 @Mookse
- clean-up after wip

* 20240514 @Mookse
- vector store initial paint

* 20240514 @Mookse
- bug fix: system experiences frontend function

* 20240514 @Mookse
- multi-file upload button frontend

* 20240515 @Mookse
- pipeline to vector-store to attach files

* 20240515 @Mookse
- vector store attached to PA

* 20240515 @Mookse
- avatar upload() returns
```
{
 uploads: files,
 files: vectorstoreFileList,
 success: true,
}
```
- api adds:
```
{
 type: type,
 message: `File(s) [type=${ type }] uploaded successfully.`
}
```

* 20240515 @Mookse
- file-collection returned correctly on refresh

* 20240515 @Mookse
- file-collection displays

* 20240516 @Mookse
- HTML parsed in bubbles

* 20240516 @Mookse
- bot thread memory restored

* 197 version 007 updates (#208)

* 20240516 @Mookse
- alert background -> aliceblue

* 20240517 @Mookse
- `createBot` endpoint
- cosmetic

* 20240518 @Mookse
- `updateTools` becomes `updateAssistant`
- fix: merge error

* 20240518 @Mookse
- createBot, type=journaler succeeds

* 20240518 @Mookse
- icon asset

* 202401518 @Mookse
- journal-thumb.png
- cosmetic console clear

* 20240519 @Mookse
- entrySummary()

* 20240519 @Mookse
- cosmetic

* 20240519 @Mookse
- Teams placeholder
- addTeamMember()
- getAvailableTeamMembers(team)

* 20240520 @Mookse
- public/private avatar placeholder toggle
- cosmetic

---------

Signed-off-by: Erik Jespersen <mookse@gmail.com>
Signed-off-by: Erik Jespersen <42016062+Mookse@users.noreply.github.com>
  • Loading branch information
Mookse committed May 21, 2024
1 parent 9740264 commit 27f5ff3
Show file tree
Hide file tree
Showing 20 changed files with 1,494 additions and 345 deletions.
160 changes: 111 additions & 49 deletions inc/js/agents/system/asset-assistant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,95 @@ const { MYLIFE_EMBEDDING_SERVER_BEARER_TOKEN, MYLIFE_EMBEDDING_SERVER_FILESIZE_L
const bearerToken = MYLIFE_EMBEDDING_SERVER_BEARER_TOKEN
const fileSizeLimit = parseInt(MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT) || 1048576
const fileSizeLimitAdmin = parseInt(MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT_ADMIN) || 10485760
// module variables
let AgentFactory
let Globals
// module class definition
class oAIAssetAssistant {
// pseudo-constructor
#ctx // @todo: only useful if assistant only exists for duration of request
#file
#mbr_id
constructor(_ctx){
// primary direct assignment
this.#ctx = _ctx
this.#mbr_id = this.#ctx.state.member.mbr_id
// module direct assignment
if(!AgentFactory) AgentFactory = this.#ctx.AgentFactory
if(!Globals) Globals = this.#ctx.Globals
// secondary direct assignment
this.#file = this.#extractFile(this.#ctx)
// validate asset construction
this.#validateFile()
#factory
#uploadedFileList=[] // uploaded versions
#globals
#includeMyLife=false
#llm
#response
#vectorstoreId
#vectorstoreFileList // openai vectorstore versions
constructor(factory, globals, llm){
this.#factory = factory
this.#globals = globals
this.#llm = llm
this.#vectorstoreId = this.#factory.vectorstoreId
}
async init(){
await this.#embedFile() // critical step
await this.#enactFile() // critical step
/**
* Initializes the asset assistant by uploading the files to the vectorstore and optionally embedding and enacting the files.
* @param {string} vectorstoreId - The vectorstore id to upload the files into, if already exists (avatar would know).
* @param {boolean} includeMyLife - Whether to embed and enact the files.
* @returns {Promise<oAIAssetAssistant>} - The initialized asset assistant instance.
*/
async init(includeMyLife=false){
await this.updateVectorstoreFileList() // sets `this.#vectorstoreFileList`
this.#includeMyLife = includeMyLife
return this
}
// getters
get ctx(){
return this.#ctx
async updateVectorstoreFileList(){
if(this.#vectorstoreId?.length){
const updateList = (await this.#llm.files(this.#vectorstoreId)).data
.filter(file=>!(this.#vectorstoreFileList ?? []).find(vsFile=>vsFile.id===file.id))
if(updateList?.length){
this.#vectorstoreFileList = await Promise.all(
updateList.map(async file =>await this.#llm.file(file.id))
)
}
}
}
get file(){
return this.#file
async upload(files){
if(!files || !files.length)
throw new Error('No files found in request.')
const newFiles = []
files.forEach(file => {
const hasFile = this.#uploadedFileList.some(_file=>_file.originalName===file.originalName)
if(!hasFile)
newFiles.push(this.#extractFile(file))
})
if(newFiles.length){ // only upload new files
const vectorstoreId = this.#vectorstoreId
this.#uploadedFileList.push(...newFiles)
const fileStreams = newFiles.map(file=>fs.createReadStream(file.filepath))
const dataRecord = await this.#llm.upload(vectorstoreId, fileStreams, this.mbr_id)
const { response, vectorstoreId: newVectorstoreId, success } = dataRecord
this.#response = response
this.#vectorstoreId = newVectorstoreId
if(!vectorstoreId && newVectorstoreId)
this.#factory.vectorstoreId = newVectorstoreId // saves to datacore
if(success && this.#vectorstoreId?.length)
await this.updateVectorstoreFileList()
}
files.forEach(file=>fs.unlinkSync(file.filepath)) /* delete .tmp files */
}
// getters
get files(){
return this.vectorstoreFileList
}
get mbr_id(){
return this.#mbr_id
return this.#factory.mbr_id
}
get session(){
return this.#ctx.session?.MemberSession??null
get response(){
return this.#response
}
get vectorstoreFileList(){
return this.#vectorstoreFileList
}
get vectorstoreId(){
return this.#vectorstoreId
}
// setters
// private functions
async #embedFile(){
console.log(this.file)
console.log('#embedFile() begin')
const _metadata = {
source: 'corporate', // logickify this
source_id: this.file.originalFilename,
source: 'corporate', // logickify
source_id: file.originalFilename,
url: 'testing-0001', // may or may not use url
author: 'MAHT', // convert to session member (or agent)
}
const _token = bearerToken
const _data = new FormData()
_data.append('file', fs.createReadStream(this.file.filepath), { contentType: this.file.mimetype })
_data.append('file', fs.createReadStream(file.filepath), { contentType: file.mimetype })
_data.append('metadata', JSON.stringify(_metadata))
const _request = {
method: 'post',
Expand All @@ -77,30 +113,56 @@ class oAIAssetAssistant {
console.log(`#embedFile() finished: ${response.data.ids}`)
return response.data
})
.then(response=>{
if(this.#includeMyLife)
return this.#enactFile(response.data)
return response.data
})
.catch((error) => {
console.error(error.message)
return {'#embedFile() finished error': error.message }
})
}
async #enactFile(){ // vitalizes by saving to MyLife database
async #enactFile(file){ // vitalizes by saving to MyLife database
console.log('#enactFile() begin')
const _fileContent = {
...this.file,
...file,
...{ mbr_id: this.mbr_id }
}
const oFile = new (AgentFactory.file)(_fileContent)
console.log('testing factory',oFile.inspect(true))
return oFile
}
#extractFile(){
if(!this.#ctx.request?.files?.file??false) throw new Error('No file found in request.')
const { lastModifiedDate, filepath, newFilename, originalFilename, mimetype, size } = this.#ctx.request.files.file
/**
* Takes an uploaded file object and extracts relevant file properties.
* @param {File} file - File object
* @returns {object} - Extracted file object.
*/
#extractFile(file){
if(!file)
throw new Error('No file found in request.')
const { lastModifiedDate, filepath, newFilename, originalFilename, mimetype, size } = file
this.#validateFile(file)
return {
...{ lastModifiedDate, filepath, newFilename, originalFilename, mimetype, size, localFilename: `${Globals.newGuid}.${mime.extension(mimetype)}` },
...this.#ctx.request.body
...{ lastModifiedDate, filepath, newFilename, originalFilename, mimetype, size, localFilename: `${this.#globals.newGuid}.${mime.extension(mimetype)}` },
}
}
#validateFile(){
/**
* Takes an array of uploaded file objects and extracts relevant file properties.
* @param {File[]} files - Array of file objects.
* @returns {File[]} - Array of extracted file objects.
*/
#extractFiles(files){
if(!Array.isArray(files) || !files.length)
throw new Error('No files found in request.')
return files.map(file=>this.#extractFile(file))
}
/**
* Validates a file object, _throws error_ if file is invalid.
* @param {File} file - File object
* @returns {void}
*/
#validateFile(file){
const allowedMimeTypes = [
'application/json',
'application/msword',
Expand All @@ -114,14 +176,14 @@ class oAIAssetAssistant {
'text/markdown',
'text/plain',
]
// reject size
let _mbr_id = this.#ctx.state.member.mbr_id
let _maxFileSize = _mbr_id === mylifeMbrId
const { size, mimetype } = file
const maxFileSize = this.mbr_id === mylifeMbrId
? fileSizeLimitAdmin
: fileSizeLimit
if (this.#file.size > _maxFileSize) throw new Error(`File size too large: ${this.#file.size}. Maximum file size is 1MB.`)
// reject mime-type
if (!allowedMimeTypes.includes(this.#file.mimetype)) throw new Error(`Unsupported media type: ${this.#file.mimetype}. File type not allowed.`)
if((size ?? 0) > maxFileSize)
throw new Error(`File size too large: ${ size }. Maximum file size is 1MB.`)
if(!allowedMimeTypes.includes(mimetype))
throw new Error(`Unsupported media type: ${ mimetype }. File type not allowed.`)
}
}
// exports
Expand Down
16 changes: 16 additions & 0 deletions inc/js/api-functions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,21 @@ async function tokenValidation(ctx, next) {
return
}
}
async function upload(ctx){
const { body, files: filesWrapper, } = ctx.request
const { type } = body
let files = filesWrapper['files[]'] // protocol for multiple files in `ctx.request`
if(!files)
ctx.throw(400, 'No files uploaded.')
if(!Array.isArray(files))
files = [files]
await mAPIKeyValidation(ctx)
const { avatar, } = ctx.state
const upload = await avatar.upload(files)
upload.type = type
upload.message = `File(s) [type=${ type }] attempted upload, see "success".`,
ctx.body = upload
}
/* "private" module functions */
/**
* Validates key and sets `ctx.state` and `ctx.session` properties. `ctx.state`: [ assistantType, isValidated, mbr_id, ]. `ctx.session`: [ isAPIValidated, APIMemberKey, ].
Expand Down Expand Up @@ -353,4 +368,5 @@ export {
story,
storyLibrary,
tokenValidation,
upload,
}
Loading

0 comments on commit 27f5ff3

Please sign in to comment.