2980a3beb4
continuous-integration/drone/push Build is passing
- Renamed the test function to `TestBuildRecommendedTenderListResponsesPreservesOrderWithoutStorage` for clarity and updated its logic to reflect changes in the recommendation response building process. - Removed unnecessary sleep in the test to enhance performance. - Refactored the `buildRecommendedTenderResponsesParallel` method to `buildRecommendedTenderListResponses`, simplifying the response building without relying on MinIO translation lookups. - Updated the repository's `mapProcedureReferencesToTenders` function to improve efficiency by grouping candidates by their contract folder IDs, enhancing the mapping process. This update streamlines the recommendation response handling and enhances the test suite for better maintainability and performance.
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package tender
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"tm/pkg/ai_summarizer"
|
|
)
|
|
|
|
type rankedRecommendedTender struct {
|
|
tender Tender
|
|
rank int
|
|
analysis string
|
|
tenderRef string
|
|
}
|
|
|
|
type recommendationTranslationCache struct {
|
|
mu sync.Mutex
|
|
items map[string]ai_summarizer.StoredTranslation
|
|
}
|
|
|
|
func newRecommendationTranslationCache() *recommendationTranslationCache {
|
|
return &recommendationTranslationCache{
|
|
items: make(map[string]ai_summarizer.StoredTranslation),
|
|
}
|
|
}
|
|
|
|
func recommendationTranslationCacheKey(tenderID, language string) string {
|
|
return strings.TrimSpace(tenderID) + "|" + strings.TrimSpace(language)
|
|
}
|
|
|
|
func (c *recommendationTranslationCache) get(tenderID, language string) (ai_summarizer.StoredTranslation, bool) {
|
|
if c == nil {
|
|
return ai_summarizer.StoredTranslation{}, false
|
|
}
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
stored, ok := c.items[recommendationTranslationCacheKey(tenderID, language)]
|
|
return stored, ok
|
|
}
|
|
|
|
func (c *recommendationTranslationCache) set(tenderID, language string, stored ai_summarizer.StoredTranslation) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
c.items[recommendationTranslationCacheKey(tenderID, language)] = stored
|
|
}
|
|
|
|
// buildRecommendedTenderListResponses builds list responses without MinIO translation lookups.
|
|
// Recommendation pages use MongoDB text; tender detail endpoints still enrich from storage.
|
|
func (s *tenderService) buildRecommendedTenderListResponses(items []rankedRecommendedTender, language string) []TenderResponse {
|
|
if len(items) == 0 {
|
|
return nil
|
|
}
|
|
|
|
out := make([]TenderResponse, len(items))
|
|
for i, item := range items {
|
|
resp := item.tender.ToResponseWithLanguage(language)
|
|
resp.Rank = item.rank
|
|
resp.Analysis = item.analysis
|
|
resp.ProcedureRef = item.tenderRef
|
|
out[i] = *resp
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (s *tenderService) loadRecommendationExclusions(
|
|
ctx context.Context,
|
|
form *SearchForm,
|
|
companyID string,
|
|
companyIDs []string,
|
|
) (map[string]struct{}, map[string]map[string]struct{}, error) {
|
|
if !form.ExcludeRejectedTenders {
|
|
return nil, nil, nil
|
|
}
|
|
|
|
if len(companyIDs) > 0 {
|
|
excludedByCompany, err := s.buildRejectedTenderIDSetsForCompanies(ctx, companyIDs)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to build recommendation exclusions: %w", err)
|
|
}
|
|
return nil, excludedByCompany, nil
|
|
}
|
|
|
|
excluded, err := s.buildRejectedTenderIDSet(ctx, companyID)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to build recommendation exclusions: %w", err)
|
|
}
|
|
return excluded, nil, nil
|
|
}
|