File size: 6,823 Bytes
40e5eae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
"""
Document Conversion Module
Converts various document formats (PDF, DOCX, TXT) to markdown format
"""
import fitz  # PyMuPDF
from pathlib import Path
from typing import Optional
import logging
from docx import Document

from config import (
    DOCUMENTS_DIR,
    PROCESSED_DOCS_DIR,
    SUPPORTED_FORMATS,
)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def convert_pdf_to_markdown(pdf_path: Path) -> str:
    """
    Convert PDF file to markdown format using PyMuPDF
    
    Args:
        pdf_path: Path to the PDF file
        
    Returns:
        Markdown formatted text
    """
    try:
        doc = fitz.open(pdf_path)
        markdown_content = []
        
        for page_num, page in enumerate(doc, 1):
            # Extract text from page
            text = page.get_text()
            
            # Add page header
            markdown_content.append(f"\n## Page {page_num}\n")
            markdown_content.append(text)
        
        doc.close()
        return "\n".join(markdown_content)
    
    except Exception as e:
        logger.error(f"Error converting PDF {pdf_path}: {e}")
        raise


def convert_docx_to_markdown(docx_path: Path) -> str:
    """
    Convert DOCX file to markdown format
    
    Args:
        docx_path: Path to the DOCX file
        
    Returns:
        Markdown formatted text
    """
    try:
        doc = Document(docx_path)
        markdown_content = []
        
        for para in doc.paragraphs:
            text = para.text.strip()
            if not text:
                continue
            
            # Determine heading level based on style
            if para.style.name.startswith('Heading'):
                level = para.style.name.replace('Heading ', '')
                if level.isdigit():
                    markdown_content.append(f"\n{'#' * int(level)} {text}\n")
                else:
                    markdown_content.append(f"\n## {text}\n")
            else:
                markdown_content.append(text)
        
        return "\n".join(markdown_content)
    
    except Exception as e:
        logger.error(f"Error converting DOCX {docx_path}: {e}")
        raise


def convert_txt_to_markdown(txt_path: Path) -> str:
    """
    Read plain text file (already in markdown or plain text format)
    
    Args:
        txt_path: Path to the text file
        
    Returns:
        File content as string
    """
    try:
        with open(txt_path, 'r', encoding='utf-8') as f:
            return f.read()
    except UnicodeDecodeError:
        # Try with different encoding
        with open(txt_path, 'r', encoding='latin-1') as f:
            return f.read()
    except Exception as e:
        logger.error(f"Error reading text file {txt_path}: {e}")
        raise


def convert_document_to_markdown(file_path: Path) -> Optional[str]:
    """
    Convert a document to markdown format based on its extension
    
    Args:
        file_path: Path to the document
        
    Returns:
        Markdown formatted text or None if conversion fails
    """
    suffix = file_path.suffix.lower()
    
    if suffix not in SUPPORTED_FORMATS:
        logger.warning(f"Unsupported format: {suffix}")
        return None
    
    try:
        if suffix == '.pdf':
            return convert_pdf_to_markdown(file_path)
        elif suffix == '.docx':
            return convert_docx_to_markdown(file_path)
        elif suffix in ['.txt', '.md']:
            return convert_txt_to_markdown(file_path)
        else:
            logger.warning(f"No converter available for {suffix}")
            return None
    
    except Exception as e:
        logger.error(f"Failed to convert {file_path}: {e}")
        return None


def convert_all_documents() -> dict[str, Path]:
    """
    Convert all documents in the documents directory to markdown
    
    Returns:
        Dictionary mapping original filenames to converted file paths
    """
    converted_files = {}
    
    if not DOCUMENTS_DIR.exists():
        logger.error(f"Documents directory not found: {DOCUMENTS_DIR}")
        return converted_files
    
    # Find all supported documents
    for file_path in DOCUMENTS_DIR.iterdir():
        if file_path.suffix.lower() not in SUPPORTED_FORMATS:
            continue
        
        if file_path.name.startswith('.'):
            continue
        
        logger.info(f"Converting {file_path.name}...")
        
        # Convert to markdown
        markdown_content = convert_document_to_markdown(file_path)
        
        if markdown_content is None:
            logger.warning(f"Skipping {file_path.name}")
            continue
        
        # Save converted content
        output_filename = file_path.stem + ".md"
        output_path = PROCESSED_DOCS_DIR / output_filename
        
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(markdown_content)
            
            converted_files[file_path.name] = output_path
            logger.info(f"Successfully converted {file_path.name} -> {output_filename}")
        
        except Exception as e:
            logger.error(f"Failed to save {output_filename}: {e}")
    
    logger.info(f"Converted {len(converted_files)} documents")
    return converted_files


def download_test_document() -> Optional[Path]:
    """
    Download the test document (Think Python PDF) if not already present
    
    Returns:
        Path to the downloaded file or None if download fails
    """
    import requests
    from config import TEST_DOCUMENT_URL, TEST_DOCUMENT_NAME
    
    output_path = DOCUMENTS_DIR / TEST_DOCUMENT_NAME
    
    if output_path.exists():
        logger.info(f"Test document already exists: {TEST_DOCUMENT_NAME}")
        return output_path
    
    try:
        logger.info(f"Downloading test document from {TEST_DOCUMENT_URL}...")
        response = requests.get(TEST_DOCUMENT_URL, stream=True, timeout=30)
        response.raise_for_status()
        
        with open(output_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                f.write(chunk)
        
        logger.info(f"Successfully downloaded {TEST_DOCUMENT_NAME}")
        return output_path
    
    except Exception as e:
        logger.error(f"Failed to download test document: {e}")
        return None


if __name__ == "__main__":
    # Test the conversion functions
    logger.info("Testing document conversion...")
    
    # Download test document
    test_doc = download_test_document()
    
    if test_doc:
        # Convert all documents
        converted = convert_all_documents()
        logger.info(f"Conversion complete. Converted files: {list(converted.keys())}")
    else:
        logger.error("Failed to download test document")