Add AI procedure reference formatting and parsing functions with unit tests
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
- Introduced `FormatAIProcedureRef` and `ParseAIProcedureRef` functions in the `tender` domain for handling AI service tender references. - Added unit tests for these functions in `ai_reference_test.go` to ensure correct parsing and formatting behavior. - Updated the `TenderResponse` struct to include a new `ProcedureRef` field for improved data representation. - Enhanced the `GetByProcedureReference` method in the repository to retrieve tenders based on the new procedure reference format. - Modified the `Recommend` method in the service layer to utilize the new procedure reference handling, improving the recommendation process. This update enhances the handling of AI procedure references, ensuring better data integrity and usability in the tender management system.
This commit is contained in:
+60
-23
@@ -941,36 +941,17 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
|
||||
return s.emptySearchResponse(pagination), nil
|
||||
}
|
||||
|
||||
tenderIDs := make([]string, 0, len(recommendations))
|
||||
for _, rec := range recommendations {
|
||||
if id := strings.TrimSpace(rec.TenderID); id != "" {
|
||||
tenderIDs = append(tenderIDs, id)
|
||||
}
|
||||
}
|
||||
if len(tenderIDs) == 0 {
|
||||
return s.emptySearchResponse(pagination), nil
|
||||
}
|
||||
|
||||
tenders, err := s.repository.GetByIDs(ctx, tenderIDs)
|
||||
tenderByRef, err := s.resolveRecommendedTenders(ctx, recommendations)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to load recommended tenders", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, fmt.Errorf("failed to load recommended tenders: %w", err)
|
||||
}
|
||||
|
||||
tenderByID := make(map[string]Tender, len(tenders))
|
||||
for i := range tenders {
|
||||
tenderByID[tenders[i].GetID()] = tenders[i]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lang := s.pickResponseLanguage(form.Language)
|
||||
now := time.Now().Unix()
|
||||
ordered := make([]TenderResponse, 0, len(recommendations))
|
||||
for _, rec := range recommendations {
|
||||
tenderID := strings.TrimSpace(rec.TenderID)
|
||||
tender, ok := tenderByID[tenderID]
|
||||
tenderRef := strings.TrimSpace(rec.TenderID)
|
||||
tender, ok := tenderByRef[tenderRef]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -984,6 +965,7 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
|
||||
resp := tender.ToResponseWithLanguage(lang)
|
||||
resp.Rank = rec.Rank
|
||||
resp.Analysis = rec.Analysis
|
||||
resp.ProcedureRef = tenderRef
|
||||
ordered = append(ordered, *resp)
|
||||
}
|
||||
|
||||
@@ -1688,6 +1670,61 @@ func (s *tenderService) enrichDocumentsScrapedFilter(ctx context.Context, form *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *tenderService) resolveRecommendedTenders(ctx context.Context, recommendations []company.RecommendedTenderResponse) (map[string]Tender, error) {
|
||||
out := make(map[string]Tender)
|
||||
mongoIDs := make([]string, 0)
|
||||
|
||||
for _, rec := range recommendations {
|
||||
ref := strings.TrimSpace(rec.TenderID)
|
||||
if ref == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if folder, notice, ok := ParseAIProcedureRef(ref); ok {
|
||||
tender, err := s.repository.GetByProcedureReference(ctx, folder, notice)
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||
s.logger.Warn("Recommended tender not found by procedure reference", map[string]interface{}{
|
||||
"tender_ref": ref,
|
||||
"contract_folder_id": folder,
|
||||
"notice_publication_id": notice,
|
||||
})
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("failed to load recommended tender %s: %w", ref, err)
|
||||
}
|
||||
out[ref] = *tender
|
||||
continue
|
||||
}
|
||||
|
||||
if IsMongoObjectIDRef(ref) {
|
||||
mongoIDs = append(mongoIDs, ref)
|
||||
continue
|
||||
}
|
||||
|
||||
s.logger.Warn("Skipping unrecognized recommended tender reference", map[string]interface{}{
|
||||
"tender_ref": ref,
|
||||
})
|
||||
}
|
||||
|
||||
if len(mongoIDs) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
tenders, err := s.repository.GetByIDs(ctx, mongoIDs)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to load recommended tenders by Mongo ID", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, fmt.Errorf("failed to load recommended tenders: %w", err)
|
||||
}
|
||||
for i := range tenders {
|
||||
out[tenders[i].GetID()] = tenders[i]
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *tenderService) emptySearchResponse(pagination *response.Pagination) *SearchResponse {
|
||||
return &SearchResponse{
|
||||
Tenders: []TenderResponse{},
|
||||
|
||||
Reference in New Issue
Block a user