feat: you can summary screen shot directly

This commit is contained in:
2026-07-07 00:59:26 +08:00
parent 39f0aaae02
commit 712a2cbb6a
17 changed files with 1432 additions and 51 deletions
+72
View File
@@ -0,0 +1,72 @@
package application
import (
"context"
"fmt"
"time"
"github.com/mmmy/snapgo/internal/domain"
"github.com/mmmy/snapgo/internal/infrastructure/clipboard"
)
// VisionSummarizer describes a multimodal model capable of reading a public
// image URL and returning a textual summary.
type VisionSummarizer interface {
SummarizeImage(ctx context.Context, prompt string, imageURL string) (string, error)
}
// CaptureSummaryService wires screenshot bytes -> S3 public URL -> LLM
// summary -> clipboard. It intentionally does not notify UI state itself:
// the caller emits fine-grained "uploading / recognizing / done" progress.
type CaptureSummaryService struct {
Provider domain.OSSProvider
Summarizer VisionSummarizer
Clipboard clipboard.Writer
Prompt string
PathPrefix string
}
// UploadImage uploads the screenshot and returns the public URL visible to
// the multimodal provider.
func (s *CaptureSummaryService) UploadImage(ctx context.Context, pngBytes []byte) (*domain.UploadResult, error) {
if s.Provider == nil {
return nil, fmt.Errorf("s3 is not configured")
}
if len(pngBytes) == 0 {
return nil, fmt.Errorf("empty screenshot")
}
key := buildObjectKey(s.PathPrefix)
start := time.Now()
url, err := s.Provider.Upload(ctx, key, pngBytes, "image/png")
if err != nil {
return nil, fmt.Errorf("s3 put object: %w", err)
}
return &domain.UploadResult{
URL: url,
Key: key,
Provider: s.Provider.Name(),
Elapsed: time.Since(start),
}, nil
}
// Summarize asks the configured model to summarize the uploaded image URL.
func (s *CaptureSummaryService) Summarize(ctx context.Context, imageURL string) (string, error) {
if s.Summarizer == nil {
return "", fmt.Errorf("llm is not configured")
}
return s.Summarizer.SummarizeImage(ctx, s.Prompt, imageURL)
}
// CopySummary writes the final summary text to the clipboard.
func (s *CaptureSummaryService) CopySummary(_ context.Context, summary string) error {
if summary == "" {
return fmt.Errorf("empty summary")
}
if s.Clipboard == nil {
return fmt.Errorf("clipboard is not configured")
}
if err := s.Clipboard.WriteText(summary); err != nil {
return fmt.Errorf("clipboard write failed: %w", err)
}
return nil
}