Files
AI-Writie-Assistant/internal/parser/queue.go
T
2026-04-07 17:35:09 +08:00

135 lines
3.1 KiB
Go

package parser
import (
"fmt"
"log/slog"
"sync"
"github.com/wailsapp/wails/v3/pkg/application"
)
// Job represents a file parsing task.
type Job struct {
FilePath string
FileID string
ProjectID string
}
// Result is the outcome of a parsing job.
type Result struct {
Job Job
Content string
Err error
}
// ProcessingQueue manages concurrent file parsing with a worker pool.
type ProcessingQueue struct {
registry *Registry
jobs chan Job
results chan Result
concurrency int
wg sync.WaitGroup
onComplete func(Result)
}
// NewProcessingQueue creates a queue with the given concurrency limit.
func NewProcessingQueue(registry *Registry, concurrency int, onComplete func(Result)) *ProcessingQueue {
q := &ProcessingQueue{
registry: registry,
jobs: make(chan Job, 100),
results: make(chan Result, 100),
concurrency: concurrency,
onComplete: onComplete,
}
q.start()
return q
}
func (q *ProcessingQueue) start() {
// Start workers
for i := 0; i < q.concurrency; i++ {
go q.worker(i)
}
// Start result collector
go func() {
for result := range q.results {
if q.onComplete != nil {
q.onComplete(result)
}
}
}()
}
func (q *ProcessingQueue) worker(id int) {
for job := range q.jobs {
slog.Info("parser worker processing", "worker", id, "file", job.FilePath)
content, err := q.registry.Parse(job.FilePath)
if err != nil {
slog.Error("parse failed", "file", job.FilePath, "err", err)
}
q.results <- Result{Job: job, Content: content, Err: err}
q.wg.Done()
}
}
// Submit adds a job to the processing queue.
func (q *ProcessingQueue) Submit(job Job) {
q.wg.Add(1)
q.jobs <- job
}
// Wait blocks until all queued jobs are complete.
func (q *ProcessingQueue) Wait() {
q.wg.Wait()
}
// Close shuts down the queue.
func (q *ProcessingQueue) Close() {
close(q.jobs)
q.wg.Wait()
close(q.results)
}
// ParseService wraps the parsing pipeline for Wails binding.
type ParseService struct {
registry *Registry
queue *ProcessingQueue
}
// NewParseService creates a new parse service.
func NewParseService() *ParseService {
return &ParseService{
registry: NewRegistry(),
}
}
// ParseFile synchronously parses a single file. For Wails binding.
func (s *ParseService) ParseFile(path string) (string, error) {
content, err := s.registry.Parse(path)
if err != nil {
return "", fmt.Errorf("parse %s: %w", path, err)
}
return content, nil
}
// GetSupportedTypes returns supported file extensions.
func (s *ParseService) GetSupportedTypes() []string {
return []string{".xlsx", ".xls", ".pdf", ".dwg", ".dxf", ".docx"}
}
// ParseDeliveryStandard opens a file dialog to select a document, parses it, and returns the markdown.
func (s *ParseService) ParseDeliveryStandard() (string, error) {
dialog := application.Get().Dialog.OpenFile()
dialog.SetTitle("选择交付标准文件 (Delivery Standard)")
dialog.AddFilter("Documents", "*.pdf;*.xlsx;*.xls;*.docx")
path, err := dialog.PromptForSingleSelection()
if err != nil {
return "", fmt.Errorf("open file dialog: %w", err)
}
if path == "" {
return "", nil // user cancelled
}
return s.ParseFile(path)
}