feat: add screenshot OCR extraction
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/mmmy/snapgo/internal/infrastructure/display"
|
||||
"github.com/mmmy/snapgo/internal/infrastructure/hotkey"
|
||||
llmpkg "github.com/mmmy/snapgo/internal/infrastructure/llm"
|
||||
ocrpkg "github.com/mmmy/snapgo/internal/infrastructure/ocr"
|
||||
"github.com/mmmy/snapgo/internal/infrastructure/oss"
|
||||
"github.com/mmmy/snapgo/internal/infrastructure/screencapture"
|
||||
sshpkg "github.com/mmmy/snapgo/internal/infrastructure/ssh"
|
||||
@@ -501,6 +502,48 @@ func (a *App) finishSummary(svc *application.CaptureSummaryService, summary stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) runOCRPipeline(pngBytes []byte) error {
|
||||
a.mu.RLock()
|
||||
cfg := a.cfg
|
||||
a.mu.RUnlock()
|
||||
|
||||
if !cfg.IsOCRConfigured() {
|
||||
err := fmt.Errorf("请先在文字提取配置页填写 OCR Provider 的 AccessKey ID 和 AccessKey Secret")
|
||||
a.emitOperationStatus("ocr", "需要配置 OCR", err.Error(), "error")
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
providerID, ocrCfg, _ := cfg.ActiveOCRProvider()
|
||||
recognizer, err := ocrpkg.NewClient(providerID, ocrCfg)
|
||||
if err != nil {
|
||||
a.emitOperationStatus("ocr", "OCR 配置错误", err.Error(), "error")
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
svc := &application.CaptureOCRService{
|
||||
Recognizer: recognizer,
|
||||
Clipboard: a.clip,
|
||||
}
|
||||
|
||||
a.emitOperationStatus("ocr", "识别中", "正在提取截图文字", "running")
|
||||
text, err := svc.Recognize(a.ctx, pngBytes)
|
||||
if err != nil {
|
||||
a.emitOperationStatus("ocr", "识别失败", err.Error(), "error")
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
if err := svc.CopyText(a.ctx, text); err != nil {
|
||||
a.emitOperationStatus("ocr", "复制失败", err.Error(), "error")
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
a.emitOperationStatus("ocr", "提取完成", "文字已复制到剪贴板", "success")
|
||||
wruntime.EventsEmit(a.ctx, "upload:success", "ocr text copied to clipboard")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) consumePendingCapture() (*pendingCapture, error) {
|
||||
a.pendingMu.Lock()
|
||||
pc := a.pending
|
||||
@@ -906,6 +949,35 @@ func (a *App) SummarizeRegion(result CaptureResult) error {
|
||||
return a.runSummaryPipeline(cropped)
|
||||
}
|
||||
|
||||
// ExtractTextRegion sends the selected screenshot to the configured OCR
|
||||
// provider and copies the extracted text to the clipboard.
|
||||
func (a *App) ExtractTextRegion(result CaptureResult) error {
|
||||
pc, err := a.consumePendingCapture()
|
||||
if err != nil {
|
||||
slog.Warn("ExtractTextRegion: no pending capture", "err", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
a.capturing.Store(false)
|
||||
a.dismissOverlay()
|
||||
}()
|
||||
|
||||
a.dismissOverlay()
|
||||
flushFrame()
|
||||
|
||||
slog.Info("ExtractTextRegion: capturing region",
|
||||
"x", result.Rect.X, "y", result.Rect.Y,
|
||||
"w", result.Rect.W, "h", result.Rect.H,
|
||||
"annotations", len(result.Annotations))
|
||||
cropped, err := a.captureSelectedPNG(result, pc)
|
||||
if err != nil {
|
||||
slog.Error("ExtractTextRegion: capture failed", "err", err)
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
return a.runOCRPipeline(cropped)
|
||||
}
|
||||
|
||||
// SaveNativeRegionToRemote is the macOS-native overlay equivalent of
|
||||
// SaveRegionToRemote. The AppKit panel is already closed by the time this
|
||||
// runs (see saveRemoteSelection in native_overlay_darwin.go), so we only
|
||||
@@ -963,6 +1035,33 @@ func (a *App) SummarizeNativeRegion(result CaptureResult) error {
|
||||
return a.runSummaryPipeline(cropped)
|
||||
}
|
||||
|
||||
// ExtractTextNativeRegion is the macOS-native overlay equivalent of
|
||||
// ExtractTextRegion. The AppKit panel is already closed before this runs.
|
||||
func (a *App) ExtractTextNativeRegion(result CaptureResult) error {
|
||||
pc, err := a.consumePendingCapture()
|
||||
if err != nil {
|
||||
slog.Warn("ExtractTextNativeRegion: no pending capture", "err", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
a.capturing.Store(false)
|
||||
hideDockIcon()
|
||||
}()
|
||||
|
||||
flushFrame()
|
||||
slog.Info("ExtractTextNativeRegion: capturing region",
|
||||
"x", result.Rect.X, "y", result.Rect.Y,
|
||||
"w", result.Rect.W, "h", result.Rect.H,
|
||||
"annotations", len(result.Annotations))
|
||||
cropped, err := a.captureSelectedPNG(result, pc)
|
||||
if err != nil {
|
||||
slog.Error("ExtractTextNativeRegion: capture failed", "err", err)
|
||||
wruntime.EventsEmit(a.ctx, "upload:failure", err.Error())
|
||||
return err
|
||||
}
|
||||
return a.runOCRPipeline(cropped)
|
||||
}
|
||||
|
||||
func parseNativeAnnotations(raw string) []application.Annotation {
|
||||
if raw == "" {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user