package channels
import (
"fmt"
"html"
"os"
"path/filepath"
"strings"
)
const (
// DocMaxChars is the max characters to extract from text documents (matching TS: 200K).
DocMaxChars = 200_000
)
// TextExtensions maps file extensions to MIME types for text files we can extract.
var TextExtensions = map[string]string{
".txt": "text/plain",
".md": "text/markdown",
".csv": "text/csv",
".tsv": "text/tab-separated-values",
".json": "application/json",
".yaml": "text/yaml",
".yml": "text/yaml",
".xml": "text/xml",
".log": "text/plain",
".ini": "text/plain",
".cfg": "text/plain",
".env": "text/plain",
".sh": "text/x-shellscript",
".py": "text/x-python",
".go": "text/x-go",
".js": "text/javascript",
".ts": "text/typescript",
".html": "text/html",
".css": "text/css",
".sql": "text/x-sql",
".rs": "text/x-rust",
".java": "text/x-java",
".c": "text/x-c",
".cpp": "text/x-c++",
".h": "text/x-c",
".rb": "text/x-ruby",
".php": "text/x-php",
".toml": "text/x-toml",
}
// ExtractDocumentContent reads a document file and returns its content wrapped in XML tags.
// For text files: extracts content, truncates at DocMaxChars, wraps in block.
// For binary files: returns a placeholder message.
func ExtractDocumentContent(filePath, fileName string) (string, error) {
if filePath == "" {
return fmt.Sprintf("[File: %s — download failed]", fileName), nil
}
ext := strings.ToLower(filepath.Ext(fileName))
mime, isText := TextExtensions[ext]
if !isText {
return fmt.Sprintf("[File: %s — binary format not supported, only text files can be processed]", fileName), nil
}
data, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("read file %s: %w", fileName, err)
}
content := string(data)
if len(content) > DocMaxChars {
content = content[:DocMaxChars] + "\n... [truncated]"
}
escaped := html.EscapeString(content)
return fmt.Sprintf("\n%s\n", fileName, mime, escaped), nil
}