Implement a custom token-window sliding algorithm that respects sentence boundaries while chunking large scientific papers.
Implement chunk_paper(text, max_tokens, overlap_tokens). Normalize whitespace, split sentences only after ., !, or ?, and return chunks containing complete sentences. Each chunk should greedily include as many sentences as possible without exceeding max_tokens. When another chunk is needed, begin it with the smallest number of complete sentences from the previous chunk whose total token count is at least overlap_tokens. If a sentence alone exceeds max_tokens, return it as its own chunk. Return an empty list for blank input.
text is a string, and the token count is the number of whitespace-separated words. max_tokens is positive and overlap_tokens is nonnegative. Return a list of strings.
def chunk_paper(text, max_tokens, overlap_tokens):