Skip to content

Commit

Permalink
add upload file function, not tested
Browse files Browse the repository at this point in the history
Signed-off-by: cbh778899 <[email protected]>
  • Loading branch information
cbh778899 committed Sep 15, 2024
1 parent e4cfb79 commit fe11e82
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 38 deletions.
71 changes: 59 additions & 12 deletions src/components/chat/Conversation.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from "react";
import ConversationBubble from "./ConversationBubble";
import { Send, StopCircleFill } from 'react-bootstrap-icons';
import { FileImageFill, FileTextFill, Paperclip, Send, StopCircleFill } from 'react-bootstrap-icons';
import useIDB from "../../utils/idb";
import { isModelLoaded, loadModel } from '../../utils/workers/worker'
import { getCompletionFunctions } from "../../utils/workers";
Expand All @@ -11,6 +11,7 @@ export default function Conversation({ uid }) {
const [message, setMessage] = useState('');
const [pending_message, setPendingMessage] = useState('');
const [hide_pending, setHidePending] = useState(true);
const [upload_file, setUploadFile] = useState(null);
const chat_functions = useRef(getCompletionFunctions());
const idb = useIDB();

Expand Down Expand Up @@ -45,7 +46,6 @@ export default function Conversation({ uid }) {
const user_msg = {role: 'user', content: message}
setConversation([...conversation, user_msg])
setMessage('');
setHidePending(false);

function cb(text, isFinished) {
if(!isFinished) {
Expand All @@ -69,12 +69,41 @@ export default function Conversation({ uid }) {
}
}

if(chat_functions.current.type === "Wllama") {
let messages = [];
setHidePending(false);

if(chat_functions.current.platform === "Wllama") {
if(!isModelLoaded()) {
await loadModel();
await loadModel('completion', (progress)=>{
setPendingMessage(
typeof progress === 'number' ?
`**Downloading model, ${progress}% completed**` :
'**Loading model...**'
)
});
setPendingMessage('')
}
messages = [user_msg];
} else {
let user_message = user_msg;
if(upload_file) {
const is_img = upload_file.type.startsWith('image')
const file_obj = {
content: new Uint8Array(await upload_file.arrayBuffer())
}
if(!is_img) file_obj.name = upload_file.name;
user_message[
is_img ? 'image' : 'document'
] = file_obj;
setUploadFile(null);
}
messages = [
...conversation,
user_message
]
}
const result = await chat_functions.current.completions([user_msg], cb);

const result = await chat_functions.current.completions(messages, cb);
if(!result) {
setPendingMessage('');
setHidePending(true);
Expand All @@ -85,6 +114,7 @@ export default function Conversation({ uid }) {

useEffect(()=>{
uid && getConversationByUid();
setUploadFile(null);
// eslint-disable-next-line
}, [uid]);

Expand Down Expand Up @@ -115,14 +145,31 @@ export default function Conversation({ uid }) {
/>
</div>
<form className="send-message-form" onSubmit={sendMessage}>
<input type="text" value={message} onChange={messageOnChange}/>
<div className="send-message-button-container">
{
hide_pending ?
<Send className="button-icon" /> :
<StopCircleFill className="button-icon stop clickable" onClick={chat_functions.current.abort} />
<div className="input-container">
{
chat_functions.current && chat_functions.current.platform !== 'Wllama' &&
<div className="button-container file-upload">
{
upload_file ?
upload_file.type.startsWith("image") ?
<FileImageFill className="button-icon highlight" /> : <FileTextFill className="button-icon highlight" />:
<Paperclip className="button-icon" />
}
<input
type="file" className="clickable"
title={upload_file ? `Append file ${upload_file.name}` : "Select file to append"}
onChange={evt=>setUploadFile(evt.target.files.length ? evt.target.files[0] : null)} />
</div>
}
<input type='submit' className={`clickable${!hide_pending?" disabled":''}`}/>
<input type="text" value={message} onChange={messageOnChange}/>
<div className="button-container">
{
hide_pending ?
<Send className="button-icon animated" /> :
<StopCircleFill className="button-icon clickable" onClick={chat_functions.current.abort} />
}
<input type='submit' className={`clickable${!hide_pending?" disabled":''}`}/>
</div>
</div>
</form>
</> :
Expand Down
67 changes: 47 additions & 20 deletions src/styles/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@
position: absolute;
bottom: 0;
left: 0;
display: block;
display: flex;
align-items: center;
overflow: hidden;
background-color: var(--normal-bg-color);
}
Expand Down Expand Up @@ -186,41 +187,62 @@
animation-delay: .8s;
}

.chat > .conversation-main > .send-message-form >
input[type="text"] {
.chat > .conversation-main > .send-message-form > .input-container {
width: calc(100% - 20px);
margin-left: 10px;
margin-top: 10px;
position: relative;
height: var(--elem-size);
border: 1px solid lightgray;
position: relative;
margin: auto;
border: 2px solid lightgray;
overflow: hidden;
border-radius: 30px;
}

.chat > .conversation-main > .send-message-form > .input-container >
input[type="text"] {
width: 100%;
height: 100%;
position: relative;
border: none;
padding: 0px var(--elem-size) 0px 10px;
}

.chat > .conversation-main > .send-message-form >
.chat > .conversation-main > .send-message-form > .input-container >
input[type="text"]:focus {
outline: none;
}


.chat > .conversation-main > .send-message-form >
.send-message-button-container {
.chat > .conversation-main > .send-message-form > .input-container >
.button-container {
position: absolute;
width: var(--elem-size);
height: var(--elem-size);
right: 10px;
top: 10px;
right: 0;
top: 0;
display: flex;
z-index: 1;
background-color: rgba(230, 230, 230, 0.6);
}
.chat > .conversation-main > .send-message-form > .input-container >
.button-container.file-upload {
right: unset;
left: 0;
}

.chat > .conversation-main > .send-message-form >
.send-message-button-container:hover > .button-icon:not(.stop) {
.chat > .conversation-main >
.send-message-form > .input-container:has(>.button-container.file-upload) >
input[type="text"] {
padding-left: calc(5px + var(--elem-size));
}


.chat > .conversation-main > .send-message-form > .input-container >
.button-container:hover > .button-icon.animated {
transform: rotate(45deg);
}

.chat > .conversation-main > .send-message-form >
.send-message-button-container > input[type="submit"]{
.chat > .conversation-main > .send-message-form > .input-container >
.button-container > input{
width: 100%;
height: 100%;
position: absolute;
Expand All @@ -229,17 +251,22 @@ input[type="text"]:focus {
z-index: 2;
opacity: 0;
}
.chat > .conversation-main > .send-message-form >
.send-message-button-container > input[type="submit"].disabled {
.chat > .conversation-main > .send-message-form > .input-container >
.button-container > input.disabled {
pointer-events: none;
}

.chat > .conversation-main > .send-message-form >
.send-message-button-container > .button-icon {
.chat > .conversation-main > .send-message-form > .input-container >
.button-container > .button-icon {
--size: 40%;
width: var(--size);
height: var(--size);
margin: auto;
color: rgb(90, 90, 90);
transition-duration: .3s;
}

.chat > .conversation-main > .send-message-form > .input-container >
.button-container > .button-icon.highlight {
color: dodgerblue;
}
8 changes: 6 additions & 2 deletions src/utils/workers/aws-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ let abort_signal = false;
/**
* @typedef ImageMessage
* @property {"png" | "jpeg" | "gif" | "webp"} format Format of image
* @property {Buffer} content Content in bytes
* @property {Uint8Array} content Content in bytes
*/

/**
Expand Down Expand Up @@ -95,7 +95,11 @@ let abort_signal = false;
*/
export async function chatCompletions(messages, cb = null) {
const { aws_model_id } = getPlatformSettings();
if(!aws_model_id || (!bedrock_client && !await initBedrockClient())) return null;
if(!aws_model_id || (!bedrock_client && !await initBedrockClient())) {
console.log('no bedrock')
cb && cb("**Cannot Initialize AWS Bedrock Client**", true)
return null;
}

const system = [];
const normal_messages = [];
Expand Down
6 changes: 3 additions & 3 deletions src/utils/workers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { chatCompletions as AwsCompletions, abortCompletion as AwsAbort } from "
* @typedef CompletionFunctions
* @property {Function} completions
* @property {Function} abort
* @property {"Wllama" | "AWS"} type
* @property {"Wllama" | "AWS"} platform
*/

/**
Expand All @@ -18,9 +18,9 @@ export function getCompletionFunctions() {

switch(platform_settings.enabled_platform ) {
case 'AWS':
return { completions: AwsCompletions, abort: AwsAbort, type: "AWS" }
return { completions: AwsCompletions, abort: AwsAbort, platform: "AWS" }
default:
return { completions: WllamaCompletions, abort: WllamaAbort, type: "Wllama" }
return { completions: WllamaCompletions, abort: WllamaAbort, platform: "Wllama" }
}

}
7 changes: 6 additions & 1 deletion src/utils/workers/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,16 @@ export async function deleteModel(type = 'completion') {
await instance.cacheManager.delete(cacheKey);
}

export async function loadModel(type = 'completion') {
export async function loadModel(type = 'completion', cb = null) {
// check if model already in cache
const { instance, model_src } = engines[type];

try {
// if not downloaded, download first
if(!await isModelDownloaded(type)) {
await downloadModel(type, cb);
}
cb && cb('loading')
await instance.loadModelFromUrl(model_src, {
n_threads: 6,
n_ctx: 4096,
Expand Down

0 comments on commit fe11e82

Please sign in to comment.