109 lines
3.7 KiB
Java
109 lines
3.7 KiB
Java
package com.aiteacher.book;
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.List;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.UUID;
|
|
|
|
@Service
|
|
public class BookService {
|
|
|
|
private final BookRepository bookRepository;
|
|
private final BookEmbeddingService bookEmbeddingService;
|
|
private final Path bookStoragePath;
|
|
|
|
public BookService(
|
|
BookRepository bookRepository,
|
|
BookEmbeddingService bookEmbeddingService,
|
|
@Value("${app.figure-storage.base-path:./uploads}") String basePath) {
|
|
this.bookRepository = bookRepository;
|
|
this.bookEmbeddingService = bookEmbeddingService;
|
|
this.bookStoragePath = Paths.get(basePath).toAbsolutePath().normalize().resolve("books");
|
|
}
|
|
|
|
public Book upload(MultipartFile file) throws IOException {
|
|
String originalFilename = file.getOriginalFilename();
|
|
if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".pdf")) {
|
|
throw new IllegalArgumentException("Only PDF files are accepted.");
|
|
}
|
|
|
|
String title = deriveTitle(originalFilename);
|
|
Book book = new Book(title, originalFilename, file.getSize());
|
|
book = bookRepository.save(book);
|
|
|
|
// Persist PDF in a stable location for potential re-embedding
|
|
Files.createDirectories(bookStoragePath);
|
|
Path pdfPath = bookStoragePath.resolve(book.getId() + ".pdf");
|
|
file.transferTo(pdfPath.toFile());
|
|
|
|
UUID bookId = book.getId();
|
|
bookEmbeddingService.embedBook(bookId, title, pdfPath);
|
|
return book;
|
|
}
|
|
|
|
public Book reembed(UUID id) {
|
|
Book book = bookRepository.findById(id)
|
|
.orElseThrow(() -> new NoSuchElementException("Book not found."));
|
|
|
|
if (book.getStatus() == BookStatus.PROCESSING) {
|
|
throw new IllegalStateException("Book is already being processed.");
|
|
}
|
|
|
|
Path pdfPath = bookStoragePath.resolve(id + ".pdf");
|
|
if (!Files.exists(pdfPath)) {
|
|
throw new IllegalStateException(
|
|
"Original PDF not found. Please re-upload the book before re-embedding.");
|
|
}
|
|
|
|
bookEmbeddingService.deleteBookChunks(id);
|
|
bookEmbeddingService.embedBook(id, book.getTitle(), pdfPath);
|
|
return book;
|
|
}
|
|
|
|
public List<Book> listAll() {
|
|
return bookRepository.findAll();
|
|
}
|
|
|
|
public Book getById(UUID id) {
|
|
return bookRepository.findById(id)
|
|
.orElseThrow(() -> new NoSuchElementException("Book not found."));
|
|
}
|
|
|
|
public void delete(UUID id) {
|
|
Book book = bookRepository.findById(id)
|
|
.orElseThrow(() -> new NoSuchElementException("Book not found."));
|
|
|
|
if (book.getStatus() == BookStatus.PROCESSING) {
|
|
throw new IllegalStateException("Cannot delete a book that is currently being processed.");
|
|
}
|
|
|
|
bookEmbeddingService.deleteBookChunks(id);
|
|
|
|
// Delete the stored PDF
|
|
Path pdfPath = bookStoragePath.resolve(id + ".pdf");
|
|
try {
|
|
Files.deleteIfExists(pdfPath);
|
|
} catch (IOException ex) {
|
|
// Non-fatal — log only
|
|
}
|
|
|
|
bookRepository.deleteById(id);
|
|
}
|
|
|
|
private String deriveTitle(String filename) {
|
|
String name = filename.replaceAll("(?i)\\.pdf$", "");
|
|
name = name.replaceAll("[-_]", " ");
|
|
if (!name.isEmpty()) {
|
|
name = Character.toUpperCase(name.charAt(0)) + name.substring(1);
|
|
}
|
|
return name;
|
|
}
|
|
}
|