223 lines
9.1 KiB
Plaintext
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> |