-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is there a way to send attachments from web widget? #23
Comments
If you wish to upload files you may need to redesign your interface and implement the upload function your self using javascript. var form = new FormData();
form.append("driver", "web");
form.append("attachment", "file");
form.append("file", "");
var settings = {
"url": "http://localhost:500",
"method": "POST",
"timeout": 0,
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"data": form
};
$.ajax(settings).done(function (response) {
console.log(response);
}); Explanation:
|
@claretnnamocha where do I have to add this code? Into which file? |
It could be in a file or script that handles the upload event on your interface @menno-dev |
@claretnnamocha mhm.. unfortunately I have no clue. Where could it be within Botman Studio? Thank you very much! |
This upload code is written on the front-end not in the back-end |
@claretnnamocha could you help me with an example of implementation? do I have to copy paste your code in my front end and that all? which parameter do I have to change? do you have any working example that will help me please? @avorozheev have you finaly found a solution? @menno-dev have you found a solution? |
Hi, any news on this issue? I am currently trying to implement this solution but don´t know where should I put this code or if something is missing. Thanks! |
Just wondering if there is any more help with this issue as I am having the same dilemma uploading images via the web widget. |
There is a way. It's entirely a front-end issue, on the back-end you can listen for images, video, and attachments in general however you want to.
Two script files do the most of my magic for me, the chat_changes.js (This file helps me adjust the appearance of changes I make to the interface) and bot_attachment.js (Here I upload the selected file to the server) files Here's what my bot_attachment.js file looks like
here's what my chat_changes.js file looks like
now so far, this allows you send files to the server as long as you have the
or
similar functions exists for files and images and whatever if you notice in the bot_attachment I use the postMessage method to post a a message from the iframe back to my main page here's what the code looks like, in a script file I named botmanTest.js (you can use whatever name of course)
i use a tacky method to make sure I'm not using the botmanChatWidet object before it is defined. |
Here's the stylesheet code for the styles_attachment.css files .view-attachment-left { |
it is possible to use above code inside conversations? i try to catch an image inside conversation and it seems that image is sended directly to routes/botman.php in my fallback function. |
The problem is with the userId in the form, make sure the right id is being passed there, I had issues with that too |
form.append("userId", make very sure the right userId is appearing here, else the default response gets activated like there is no on going conversation) Just make sure the right userId is being passed in there, it should work fine afterwards. I Encountered the same problem too, took me a while to figure it out |
shdi |
the code u have refere is not working |
Hi! It took me some time, but I found what I believe is a nice way to do this without having to modify the library. Basically, the idea is to inject the <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
</head>
<body>
<!-- YOUR HTML HERE -->
</body>
<script>
const userId = (Math.random() + 1).toString(36).substring(7);
const botmanInterval = setInterval(checkBotman, 1000);
function checkBotman() {
const elChatBotManFrame = document.getElementById('chatBotManFrame');
if (elChatBotManFrame) {
const elChatWidget = elChatBotManFrame.contentWindow.document.getElementById('botmanChatRoot');
const elMessageArea = elChatBotManFrame.contentWindow.document.getElementById('messageArea');
const elTextInput = elChatBotManFrame.contentWindow.document.getElementById('userText');
if (!elChatWidget || !elMessageArea || !elTextInput) {
return;
}
clearInterval(botmanInterval);
// Append the file upload component to the DOM
const elFileInputContainer = document.createElement('div');
elFileInputContainer.innerHTML = `
<style>
.gg-software-upload {
box-sizing: border-box;
position: relative;
display: block;
transform: scale(var(--ggs,1));
width: 16px;
height: 6px;
border: 2px solid;
border-top: 0;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
margin-top: 8px
}
.gg-software-upload::after {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
width: 8px;
height: 8px;
border-left: 2px solid;
border-top: 2px solid;
transform: rotate(45deg);
left: 2px;
bottom: 4px
}
.gg-software-upload::before {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
border-radius: 3px;
width: 2px;
height: 10px;
background: currentColor;
left: 5px;
bottom: 3px
}
.hidden {
display: none !important;
}
.file-input {
width: 92%;
position: fixed;
display: flex;
bottom: 0;
padding: 15px;
background: #ffffff;
box-shadow: 0 -6px 12px 0 rgba(235,235,235,.95);
}
.file-input input {
width: 90%;
overflow: hidden;
}
.disabled {
display: none;
}
.file-upload-btn {
align-self: center;
margin-left: auto;
cursor: pointer;
}
</style>
<div class="file-input hidden">
<input type="file" name="file" id="file" />
<i class="gg-software-upload file-upload-btn disabled"></i>
</div>
`;
elChatWidget.append(elFileInputContainer);
const elFileUploadBtn = elChatBotManFrame.contentWindow.document.getElementsByClassName('file-upload-btn')[0];
const elFileInput = elChatBotManFrame.contentWindow.document.getElementsByClassName('file-input')[0];
const elFile = elChatBotManFrame.contentWindow.document.getElementById('file');
const selection = [];
elFile.addEventListener('change', event => {
const files = event.target.files;
if (files.length > 0) {
selection.push(files); // push the whole FileList
elFileUploadBtn.classList.toggle('disabled'); // show upload button
}
});
elFileUploadBtn.addEventListener('click', event => {
for (let i=0; i<selection.length; i++) {
for (let j=0; j<selection[i].length; j++) {
const file = selection[i][j];
const filename = file['name'];
const form = new FormData();
form.append("driver", "web");
form.append("attachment", "file"); // audio | video | location | file
form.append("interactive", "0");
form.append("file", file);
form.append("userId", userId);
const options = {
method: 'POST',
body: form,
};
fetch(window.location.origin + "/botman", options).then(response => {
if (response.status === 200) {
window.botmanChatWidget.sayAsBot('Your file ' + filename + ' has been sent :-)');
} else {
window.botmanChatWidget.sayAsBot('Your file ' + filename + ' could not be sent :-(');
}
});
}
}
selection.length = 0; // remove selected files
elFile.value = ""; // reset file-input
elFileInput.classList.toggle('hidden'); // hide file-input
elFileUploadBtn.classList.toggle('disabled'); // hide upload button
elTextInput.classList.toggle('hidden'); // display text area
elTextInput.focus(); // set focus on text area
});
// Observe incoming messages and react accordingly
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(addedNode => {
// If the bot asks for a file upload, display the file input instead of the text area
if (addedNode.classList.contains('chatbot')) {
const elMessage = addedNode.getElementsByTagName('p')[0].innerText;
if (/.*(upload|téléverser?).*/i.test(elMessage)) {
elTextInput.classList.toggle('hidden');
elFileInput.classList.toggle('hidden');
}
}
});
});
});
const elChatArea = elMessageArea.getElementsByClassName('chat')[0];
observer.observe(elChatArea, { subtree: false, childList: true });
}
}
</script>
<link rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/npm/botman-web-widget@0/build/assets/css/chat.min.css">
<script>
window.botmanWidget = {
title: 'BotMan',
aboutText: 'Powered by ComputableFacts',
aboutLink: 'https://computablefacts.com',
userId: userId,
};
</script>
<script src='https://cdn.jsdelivr.net/npm/botman-web-widget@0/build/js/widget.js'></script>
</html> On the server side, I have the following code in <?php
namespace App\Providers;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
VerifyCsrfToken::except(['botman']);
}
} I have the following code in <?php
use App\Http\Controllers\BotManController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::match(['get', 'post'], '/botman', [BotManController::class, 'handle']); I have the following code in <?php
namespace App\Http\Controllers;
use BotMan\BotMan\BotMan;
use BotMan\BotMan\Messages\Incoming\Answer;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class BotManController extends Controller
{
public function handle(): void
{
$botman = app('botman');
$botman->receivesFiles(function (BotMan $botman, $files) {
});
$botman->hears('.*(hi|hello|bonjour).*', function (BotMan $botman, string $message) {
if (Str::lower($message) === 'hi' || Str::lower($message) === 'hello') {
$this->askNameEn($botman);
} else if (Str::lower($message) === 'bonjour') {
$this->askNameFr($botman);
}
});
$botman->fallback(function (BotMan $botman) {
$botman->reply('Sorry, I did not understand these commands.');
});
$botman->listen();
}
private function askNameEn(BotMan $botman): void
{
$botman->ask('Hello! What is your name?', function (Answer $answer) use ($botman) {
$name = $answer->getText();
$this->say("Nice to meet you {$name}!");
$this->askForFiles('I am ready now. Upload your file!', function ($files) {
foreach ($files as $file) {
$url = $file->getUrl();
$payload = $file->getPayload();
Log::debug($url);
}
});
});
}
private function askNameFr(BotMan $botman): void
{
$botman->ask('Bonjour! Quel est ton nom?', function (Answer $answer) use ($botman) {
$name = $answer->getText();
$this->say("Enchanté, {$name}!");
$this->askForFiles('Je suis prêt maintenant. Téléverse ton fichier!', function ($files) {
foreach ($files as $file) {
$url = $file->getUrl();
$payload = $file->getPayload();
Log::debug($url);
}
});
});
}
} |
@csavelief, thanks a lot! The code works really well. However, can the code be modified to send multiple files? |
I'm using Botman WebWidget implementation from tutorial here: https://botman.io/2.0/driver-web
But it doesn't seem to have an attachment functionality: neither button, nor drag-n-drop into the chat window. Also surfed in documentation and related issues - no even mention of attachment functionality in web widget.
Am I doing something wrong, or it is really not implemented?
The text was updated successfully, but these errors were encountered: