Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Extras/ImageTextExtraction.cshtml

223 lines
9.1 KiB
Plaintext

@{
Layout = "_ConfigurePlugin";
}
@await Component.InvokeAsync("StoreScopeConfiguration")
<form asp-action="ExtractTextFromImage" asp-controller="FileManager" method="post">
@Html.AntiForgeryToken()
</form>
<div class="card card-default">
<div class="card-body">
<h4>Image & PDF Text Extraction (OCR)</h4>
<p>Upload an image or PDF to extract text using OpenAI Vision API.</p>
<div class="form-group row">
<div class="col-md-9">
<div class="custom-file">
<input type="file" class="custom-file-input" id="imageFile" accept="image/*,.pdf,application/pdf">
<label class="custom-file-label" for="imageFile">Choose image or PDF file...</label>
</div>
<small class="form-text text-muted">Supported formats: JPG, PNG, GIF, WebP, PDF</small>
</div>
</div>
<div class="form-group row">
<div class="col-md-9">
<label for="customPrompt">Custom Prompt (Optional)</label>
<input type="text" class="form-control" id="customPrompt" placeholder="Leave empty for default: 'Olvasd ki a szöveget és add vissza szépen strukturálva.'">
<small class="form-text text-muted">Customize how the AI should extract and format the text</small>
</div>
</div>
<div class="form-group row">
<div class="col-md-9">
<button type="button" id="uploadButton" class="btn btn-primary" disabled>
<i class="fas fa-upload"></i> Extract Text
</button>
</div>
</div>
<div class="form-group row">
<div class="col-md-9">
<div id="responseMessage" class="alert" style="display:none;"></div>
</div>
</div>
<div class="form-group row" id="filePreviewSection" style="display:none;">
<div class="col-md-9">
<h5>File Preview:</h5>
<div id="imagePreviewContainer" style="display:none;">
<img id="imagePreview" src="" alt="Preview" style="max-width: 100%; max-height: 400px; border: 1px solid #ddd; padding: 5px;">
</div>
<div id="pdfPreviewContainer" style="display:none;">
<div class="alert alert-info">
<i class="fas fa-file-pdf"></i> PDF file selected. The first page will be converted to image for text extraction.
</div>
<embed id="pdfPreview" type="application/pdf" style="width: 100%; height: 500px; border: 1px solid #ddd;">
</div>
</div>
</div>
<div class="form-group row" id="extractedTextSection" style="display:none;">
<div class="col-md-9">
<h5>Extracted Text:</h5>
<div class="card">
<div class="card-body">
<pre id="extractedText" style="white-space: pre-wrap; word-wrap: break-word; max-height: 500px; overflow-y: auto;"></pre>
</div>
</div>
<button type="button" id="copyButton" class="btn btn-secondary mt-2">
<i class="fas fa-copy"></i> Copy to Clipboard
</button>
</div>
</div>
</div>
</div>
<script>
const imageFileInput = document.getElementById('imageFile');
const customPromptInput = document.getElementById('customPrompt');
const uploadButton = document.getElementById('uploadButton');
const responseMessage = document.getElementById('responseMessage');
const filePreviewSection = document.getElementById('filePreviewSection');
const imagePreviewContainer = document.getElementById('imagePreviewContainer');
const pdfPreviewContainer = document.getElementById('pdfPreviewContainer');
const imagePreview = document.getElementById('imagePreview');
const pdfPreview = document.getElementById('pdfPreview');
const extractedTextSection = document.getElementById('extractedTextSection');
const extractedText = document.getElementById('extractedText');
const copyButton = document.getElementById('copyButton');
const fileLabel = document.querySelector('.custom-file-label');
let selectedFile = null;
// Update file label and enable upload button when file is selected
imageFileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
selectedFile = file;
fileLabel.textContent = file.name;
uploadButton.disabled = false;
// Check file type and show appropriate preview
const isPdf = file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
if (isPdf) {
// Show PDF preview
imagePreviewContainer.style.display = 'none';
pdfPreviewContainer.style.display = 'block';
const fileUrl = URL.createObjectURL(file);
pdfPreview.src = fileUrl;
filePreviewSection.style.display = 'block';
} else {
// Show image preview
pdfPreviewContainer.style.display = 'none';
imagePreviewContainer.style.display = 'block';
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
filePreviewSection.style.display = 'block';
};
reader.readAsDataURL(file);
}
} else {
selectedFile = null;
fileLabel.textContent = 'Choose image or PDF file...';
uploadButton.disabled = true;
filePreviewSection.style.display = 'none';
}
extractedTextSection.style.display = 'none';
});
uploadButton.addEventListener('click', async () => {
if (!selectedFile) {
showMessage('Please select a file first!', 'warning');
return;
}
const formData = new FormData();
formData.append('imageFile', selectedFile);
const customPrompt = customPromptInput.value.trim();
if (customPrompt) {
formData.append('customPrompt', customPrompt);
}
try {
uploadButton.disabled = true;
const isPdf = selectedFile.type === 'application/pdf' || selectedFile.name.toLowerCase().endsWith('.pdf');
uploadButton.innerHTML = isPdf
? '<i class="fas fa-spinner fa-spin"></i> Converting PDF & Extracting...'
: '<i class="fas fa-spinner fa-spin"></i> Extracting...';
// Get the antiforgery token
const token = document.querySelector('input[name="__RequestVerificationToken"]').value;
const response = await fetch('@Url.Action("ExtractTextFromImage", "FileManager")', {
method: 'POST',
headers: {
'RequestVerificationToken': token
},
body: formData
});
const result = await response.json();
if (response.ok && result.success) {
const message = result.wasConverted
? 'PDF converted and text extracted successfully!'
: 'Text extracted successfully!';
showMessage(message, 'success');
// Display extracted text
if (result.extractedText) {
extractedText.textContent = result.extractedText;
extractedTextSection.style.display = 'block';
}
} else {
showMessage('Error: ' + (result.message || 'Failed to extract text'), 'danger');
}
} catch (error) {
console.error('Error extracting text:', error);
showMessage('Error: Failed to communicate with server', 'danger');
} finally {
uploadButton.disabled = false;
uploadButton.innerHTML = '<i class="fas fa-upload"></i> Extract Text';
}
});
copyButton.addEventListener('click', () => {
const textToCopy = extractedText.textContent;
navigator.clipboard.writeText(textToCopy).then(() => {
const originalText = copyButton.innerHTML;
copyButton.innerHTML = '<i class="fas fa-check"></i> Copied!';
copyButton.classList.remove('btn-secondary');
copyButton.classList.add('btn-success');
setTimeout(() => {
copyButton.innerHTML = originalText;
copyButton.classList.remove('btn-success');
copyButton.classList.add('btn-secondary');
}, 2000);
}).catch(err => {
console.error('Failed to copy text:', err);
showMessage('Failed to copy to clipboard', 'warning');
});
});
function showMessage(message, type) {
responseMessage.textContent = message;
responseMessage.className = 'alert alert-' + type;
responseMessage.style.display = 'block';
setTimeout(() => {
responseMessage.style.display = 'none';
}, 5000);
}
</script>