Text Extraction Logic
BIN
docengine/.DS_Store
vendored
Normal file
59
docengine/.env
Normal file
@@ -0,0 +1,59 @@
|
||||
# Application
|
||||
APP_NAME=DocEngine
|
||||
APP_VERSION=1.0.0
|
||||
APP_ENV=development
|
||||
APP_DEBUG=true
|
||||
APP_HOST=0.0.0.0
|
||||
APP_PORT=7989
|
||||
APP_WORKERS=4
|
||||
|
||||
# Database
|
||||
DB_HOST=103.125.129.116
|
||||
DB_PORT=5432
|
||||
DB_NAME=ocr
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=M@triXPostgr3s@6202
|
||||
DB_SCHEMA=admin
|
||||
DB_POOL_SIZE=20
|
||||
DB_MAX_OVERFLOW=10
|
||||
DB_ECHO=false
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=103.125.129.116
|
||||
REDIS_PORT=7901
|
||||
REDIS_DB=0
|
||||
REDIS_PASSWORD=M@triXR3d1s@6202
|
||||
|
||||
# Celery
|
||||
CELERY_BROKER_URL=redis://:M%40triXR3d1s%406202@103.125.129.116:7901/0
|
||||
CELERY_RESULT_BACKEND=redis://:M%40triXR3d1s%406202@103.125.129.116:7901/1
|
||||
|
||||
# JWT
|
||||
JWT_SECRET_KEY=a7f3c9e1d4b8f2a6c0e5d7b3a9f1c4e8d2b6a0f5c3e7d1b9a4f8c2e6d0b5a3
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
|
||||
# Storage
|
||||
STORAGE_PROVIDER=local
|
||||
STORAGE_LOCAL_PATH=./storage
|
||||
STORAGE_MAX_FILE_SIZE_MB=100
|
||||
|
||||
# OCR
|
||||
OCR_LANGUAGE=en
|
||||
OCR_USE_GPU=false
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FORMAT=json
|
||||
|
||||
# CORS
|
||||
CORS_ORIGINS=["http://localhost:3000","http://localhost:8080","http://localhost:4200"]
|
||||
CORS_ALLOW_CREDENTIALS=true
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_REQUESTS=100
|
||||
RATE_LIMIT_WINDOW_SECONDS=60
|
||||
|
||||
# Prometheus
|
||||
PROMETHEUS_ENABLED=true
|
||||
BIN
docengine/alembic/__pycache__/env.cpython-313.pyc
Normal file
BIN
docengine/app/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/__pycache__/main.cpython-313.pyc
Normal file
BIN
docengine/app/api/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/api/__pycache__/router.cpython-313.pyc
Normal file
BIN
docengine/app/api/v1/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/api/v1/__pycache__/auth.cpython-313.pyc
Normal file
BIN
docengine/app/api/v1/__pycache__/documents.cpython-313.pyc
Normal file
BIN
docengine/app/api/v1/__pycache__/health.cpython-313.pyc
Normal file
BIN
docengine/app/api/v1/__pycache__/templates.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/aes.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/config.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/database.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/dependencies.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/exceptions.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/logging_config.cpython-313.pyc
Normal file
BIN
docengine/app/core/__pycache__/security.cpython-313.pyc
Normal file
BIN
docengine/app/events/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/events/__pycache__/handlers.cpython-313.pyc
Normal file
BIN
docengine/app/middleware/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/middleware/__pycache__/audit.cpython-313.pyc
Normal file
BIN
docengine/app/middleware/__pycache__/cors.cpython-313.pyc
Normal file
BIN
docengine/app/middleware/__pycache__/metrics.cpython-313.pyc
Normal file
BIN
docengine/app/middleware/__pycache__/rate_limit.cpython-313.pyc
Normal file
BIN
docengine/app/models/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/models/__pycache__/base.cpython-313.pyc
Normal file
BIN
docengine/app/models/__pycache__/document.cpython-313.pyc
Normal file
BIN
docengine/app/models/__pycache__/template.cpython-313.pyc
Normal file
BIN
docengine/app/models/__pycache__/user.cpython-313.pyc
Normal file
BIN
docengine/app/repositories/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/repositories/__pycache__/base.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/auth.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/common.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/document.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/template.cpython-313.pyc
Normal file
BIN
docengine/app/schemas/__pycache__/user.cpython-313.pyc
Normal file
BIN
docengine/app/services/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/services/__pycache__/ocr_service.cpython-313.pyc
Normal file
BIN
docengine/app/services/__pycache__/pdf_service.cpython-313.pyc
Normal file
0
docengine/app/storage/__init__.py
Normal file
BIN
docengine/app/storage/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/storage/__pycache__/provider.cpython-313.pyc
Normal file
163
docengine/app/storage/provider.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.exceptions import StorageError
|
||||
from app.core.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class StorageProvider(ABC):
|
||||
"""Abstract base class for storage providers."""
|
||||
|
||||
@abstractmethod
|
||||
def save_file(self, file_data: bytes, directory: str, filename: str | None = None) -> str:
|
||||
"""Save file data and return the storage path."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def read_file(self, storage_path: str) -> bytes:
|
||||
"""Read file data from storage."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def delete_file(self, storage_path: str) -> bool:
|
||||
"""Delete a file from storage. Returns True if successful."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def file_exists(self, storage_path: str) -> bool:
|
||||
"""Check if a file exists in storage."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def get_file_size(self, storage_path: str) -> int:
|
||||
"""Get the file size in bytes."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def get_absolute_path(self, storage_path: str) -> str:
|
||||
"""Get the absolute filesystem path for a storage path."""
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def compute_checksum(data: bytes, algorithm: str = "sha256") -> str:
|
||||
"""Compute checksum of file data."""
|
||||
hasher = hashlib.new(algorithm)
|
||||
hasher.update(data)
|
||||
return hasher.hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def generate_filename(original_filename: str) -> str:
|
||||
"""Generate a unique filename preserving the original extension."""
|
||||
ext = Path(original_filename).suffix.lower()
|
||||
return f"{uuid.uuid4().hex}{ext}"
|
||||
|
||||
|
||||
class LocalStorageProvider(StorageProvider):
|
||||
"""Local filesystem storage provider."""
|
||||
|
||||
def __init__(self, base_path: str | None = None) -> None:
|
||||
self.base_path = Path(base_path or settings.storage_local_path).resolve()
|
||||
self._ensure_directories()
|
||||
|
||||
def _ensure_directories(self) -> None:
|
||||
"""Create required storage directories."""
|
||||
for subdir in ("documents", "templates", "images", "temp", "rendered"):
|
||||
(self.base_path / subdir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _resolve_path(self, storage_path: str) -> Path:
|
||||
"""Resolve a storage path to an absolute path."""
|
||||
resolved = (self.base_path / storage_path).resolve()
|
||||
if not str(resolved).startswith(str(self.base_path)):
|
||||
raise StorageError(f"Path traversal detected: {storage_path}")
|
||||
return resolved
|
||||
|
||||
def save_file(self, file_data: bytes, directory: str, filename: str | None = None) -> str:
|
||||
"""Save file data to local storage."""
|
||||
if filename is None:
|
||||
filename = f"{uuid.uuid4().hex}.bin"
|
||||
|
||||
dir_path = self.base_path / directory
|
||||
dir_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
file_path = dir_path / filename
|
||||
try:
|
||||
file_path.write_bytes(file_data)
|
||||
storage_path = str(file_path.relative_to(self.base_path))
|
||||
logger.info("file_saved", storage_path=storage_path, size=len(file_data))
|
||||
return storage_path
|
||||
except OSError as e:
|
||||
raise StorageError(f"Failed to save file: {e}") from e
|
||||
|
||||
def read_file(self, storage_path: str) -> bytes:
|
||||
"""Read file data from local storage."""
|
||||
file_path = self._resolve_path(storage_path)
|
||||
if not file_path.exists():
|
||||
raise StorageError(f"File not found: {storage_path}")
|
||||
try:
|
||||
return file_path.read_bytes()
|
||||
except OSError as e:
|
||||
raise StorageError(f"Failed to read file: {e}") from e
|
||||
|
||||
def delete_file(self, storage_path: str) -> bool:
|
||||
"""Delete a file from local storage."""
|
||||
file_path = self._resolve_path(storage_path)
|
||||
if not file_path.exists():
|
||||
return False
|
||||
try:
|
||||
file_path.unlink()
|
||||
logger.info("file_deleted", storage_path=storage_path)
|
||||
return True
|
||||
except OSError as e:
|
||||
logger.error("file_delete_failed", storage_path=storage_path, error=str(e))
|
||||
raise StorageError(f"Failed to delete file: {e}") from e
|
||||
|
||||
def file_exists(self, storage_path: str) -> bool:
|
||||
"""Check if a file exists in local storage."""
|
||||
file_path = self._resolve_path(storage_path)
|
||||
return file_path.exists()
|
||||
|
||||
def get_file_size(self, storage_path: str) -> int:
|
||||
"""Get the file size in bytes."""
|
||||
file_path = self._resolve_path(storage_path)
|
||||
if not file_path.exists():
|
||||
raise StorageError(f"File not found: {storage_path}")
|
||||
return file_path.stat().st_size
|
||||
|
||||
def get_absolute_path(self, storage_path: str) -> str:
|
||||
"""Get the absolute filesystem path."""
|
||||
return str(self._resolve_path(storage_path))
|
||||
|
||||
def save_temp_file(self, file_data: bytes, filename: str) -> str:
|
||||
"""Save a temporary file."""
|
||||
return self.save_file(file_data, "temp", filename)
|
||||
|
||||
def cleanup_temp(self) -> int:
|
||||
"""Remove all files in the temp directory."""
|
||||
temp_dir = self.base_path / "temp"
|
||||
count = 0
|
||||
if temp_dir.exists():
|
||||
for item in temp_dir.iterdir():
|
||||
if item.is_file():
|
||||
item.unlink()
|
||||
count += 1
|
||||
elif item.is_dir():
|
||||
shutil.rmtree(item)
|
||||
count += 1
|
||||
logger.info("temp_cleanup", files_removed=count)
|
||||
return count
|
||||
|
||||
|
||||
def get_storage_provider() -> StorageProvider:
|
||||
"""Factory function to get the configured storage provider."""
|
||||
if settings.storage_provider == "local":
|
||||
return LocalStorageProvider()
|
||||
raise StorageError(f"Unknown storage provider: {settings.storage_provider}")
|
||||
BIN
docengine/app/tasks/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/tasks/__pycache__/document_tasks.cpython-313.pyc
Normal file
BIN
docengine/app/workers/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
docengine/app/workers/__pycache__/celery_app.cpython-313.pyc
Normal file
BIN
docengine/storage/documents/132cc8646df7415cb619809de75dbf3f.pdf
Normal file
BIN
docengine/storage/documents/1a2895b54df943c1bc2d715394ad58d0.pdf
Normal file
BIN
docengine/storage/documents/240fc5973ed14397997da20d547e141f.pdf
Normal file
BIN
docengine/storage/documents/588cc01bb78b46b785ff9cfef9ad5f04.pdf
Normal file
BIN
docengine/storage/documents/6b01bfc43bf44909a24e7d9950e193e7.pdf
Normal file
BIN
docengine/storage/documents/7eaabc95fa8d407490e07a5e49feb5dc.pdf
Normal file
BIN
docengine/storage/documents/9364f5c4c1a34cc69a729b9ab573801e.pdf
Normal file
BIN
docengine/storage/documents/968b0d7dc1d84b5994b4afe5a98f4d60.pdf
Normal file
BIN
docengine/storage/documents/a82e16443a7640d4b8830cee83f41fba.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
docengine/storage/documents/b97ac6eff5634b159a778ab0a75fcedb.pdf
Normal file
BIN
docengine/storage/documents/de0a62d8bd524f53a894178b4863346f.pdf
Normal file
|
After Width: | Height: | Size: 241 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 307 KiB |