ollama source for Momentry Core verification
This commit is contained in:
128
app/store/image.go
Normal file
128
app/store/image.go
Normal file
@@ -0,0 +1,128 @@
|
||||
//go:build windows || darwin
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
Filename string `json:"filename"`
|
||||
Path string `json:"path"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
}
|
||||
|
||||
// Bytes loads image data from disk for a given ImageData reference
|
||||
func (i *Image) Bytes() ([]byte, error) {
|
||||
return ImgBytes(i.Path)
|
||||
}
|
||||
|
||||
// ImgBytes reads image data from the specified file path
|
||||
func ImgBytes(path string) ([]byte, error) {
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("empty image path")
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read image file %s: %w", path, err)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ImgDir returns the directory path for storing images for a specific chat
|
||||
func (s *Store) ImgDir() string {
|
||||
dbPath := s.DBPath
|
||||
if dbPath == "" {
|
||||
dbPath = defaultDBPath
|
||||
}
|
||||
storeDir := filepath.Dir(dbPath)
|
||||
return filepath.Join(storeDir, "cache", "images")
|
||||
}
|
||||
|
||||
// ImgToFile saves image data to disk and returns ImageData reference
|
||||
func (s *Store) ImgToFile(chatID string, imageBytes []byte, filename, mimeType string) (Image, error) {
|
||||
baseImageDir := s.ImgDir()
|
||||
if err := os.MkdirAll(baseImageDir, 0o755); err != nil {
|
||||
return Image{}, fmt.Errorf("create base image directory: %w", err)
|
||||
}
|
||||
|
||||
// Root prevents path traversal issues
|
||||
root, err := os.OpenRoot(baseImageDir)
|
||||
if err != nil {
|
||||
return Image{}, fmt.Errorf("open image root directory: %w", err)
|
||||
}
|
||||
defer root.Close()
|
||||
|
||||
// Create chat-specific subdirectory within the root
|
||||
chatDir := sanitize(chatID)
|
||||
if err := root.Mkdir(chatDir, 0o755); err != nil && !os.IsExist(err) {
|
||||
return Image{}, fmt.Errorf("create chat directory: %w", err)
|
||||
}
|
||||
|
||||
// Generate a unique filename to avoid conflicts
|
||||
// Use hash of content + original filename for uniqueness
|
||||
hash := sha256.Sum256(imageBytes)
|
||||
hashStr := hex.EncodeToString(hash[:])[:16] // Use first 16 chars of hash
|
||||
|
||||
// Extract file extension from original filename or mime type
|
||||
ext := filepath.Ext(filename)
|
||||
if ext == "" {
|
||||
switch mimeType {
|
||||
case "image/jpeg":
|
||||
ext = ".jpg"
|
||||
case "image/png":
|
||||
ext = ".png"
|
||||
case "image/webp":
|
||||
ext = ".webp"
|
||||
default:
|
||||
ext = ".img"
|
||||
}
|
||||
}
|
||||
|
||||
// Create unique filename: hash + original name + extension
|
||||
baseFilename := sanitize(strings.TrimSuffix(filename, ext))
|
||||
uniqueFilename := fmt.Sprintf("%s_%s%s", hashStr, baseFilename, ext)
|
||||
relativePath := filepath.Join(chatDir, uniqueFilename)
|
||||
file, err := root.Create(relativePath)
|
||||
if err != nil {
|
||||
return Image{}, fmt.Errorf("create image file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err := file.Write(imageBytes); err != nil {
|
||||
return Image{}, fmt.Errorf("write image data: %w", err)
|
||||
}
|
||||
|
||||
return Image{
|
||||
Filename: uniqueFilename,
|
||||
Path: filepath.Join(baseImageDir, relativePath),
|
||||
Size: int64(len(imageBytes)),
|
||||
MimeType: mimeType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// sanitize removes unsafe characters from filenames
|
||||
func sanitize(filename string) string {
|
||||
// Convert to safe characters only
|
||||
safe := strings.Map(func(r rune) rune {
|
||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' {
|
||||
return r
|
||||
}
|
||||
return '_'
|
||||
}, filename)
|
||||
|
||||
// Clean up and validate
|
||||
safe = strings.Trim(safe, "_")
|
||||
if safe == "" {
|
||||
return "image"
|
||||
}
|
||||
return safe
|
||||
}
|
||||
Reference in New Issue
Block a user