// internal/services/verification_service.go package services import ( "encoding/json" "errors" "lost-and-found/internal/models" "lost-and-found/internal/repositories" "lost-and-found/internal/utils" "gorm.io/gorm" ) type VerificationService struct { verificationRepo *repositories.ClaimVerificationRepository claimRepo *repositories.ClaimRepository itemRepo *repositories.ItemRepository } func NewVerificationService(db *gorm.DB) *VerificationService { return &VerificationService{ verificationRepo: repositories.NewClaimVerificationRepository(db), claimRepo: repositories.NewClaimRepository(db), itemRepo: repositories.NewItemRepository(db), } } // VerificationResult represents the verification result type VerificationResult struct { SimilarityScore float64 `json:"similarity_score"` MatchLevel string `json:"match_level"` MatchedKeywords []string `json:"matched_keywords"` Details map[string]string `json:"details"` Recommendation string `json:"recommendation"` } // VerifyClaimDescription verifies claim description against item description func (s *VerificationService) VerifyClaimDescription(claimID uint) (*VerificationResult, error) { claim, err := s.claimRepo.FindByID(claimID) if err != nil { return nil, err } item, err := s.itemRepo.FindByID(claim.ItemID) if err != nil { return nil, err } // Calculate similarity between claim description and item description similarity := utils.CalculateStringSimilarity(claim.Description, item.Description) similarityPercent := similarity * 100 // Extract matched keywords claimKeywords := utils.ExtractKeywords(claim.Description) itemKeywords := utils.ExtractKeywords(item.Description) matchedKeywords := utils.FindMatchedKeywords(claimKeywords, itemKeywords) // Determine match level matchLevel := "low" recommendation := "REJECT - Deskripsi tidak cocok" if similarityPercent >= 70.0 { matchLevel = "high" recommendation = "APPROVE - Deskripsi sangat cocok" } else if similarityPercent >= 50.0 { matchLevel = "medium" recommendation = "REVIEW - Perlu verifikasi lebih lanjut" } // Create or update verification record verification, _ := s.verificationRepo.FindByClaimID(claimID) if verification == nil { verification = &models.ClaimVerification{ ClaimID: claimID, SimilarityScore: similarityPercent, MatchedKeywords: stringSliceToJSON(matchedKeywords), IsAutoMatched: false, } s.verificationRepo.Create(verification) } else { verification.SimilarityScore = similarityPercent verification.MatchedKeywords = stringSliceToJSON(matchedKeywords) s.verificationRepo.Update(verification) } return &VerificationResult{ SimilarityScore: similarityPercent, MatchLevel: matchLevel, MatchedKeywords: matchedKeywords, Details: map[string]string{ "claim_description": claim.Description, "item_description": item.Description, "matched_count": string(len(matchedKeywords)), }, Recommendation: recommendation, }, nil } // GetVerificationByClaimID gets verification data for a claim func (s *VerificationService) GetVerificationByClaimID(claimID uint) (*models.ClaimVerification, error) { verification, err := s.verificationRepo.FindByClaimID(claimID) if err != nil { return nil, err } if verification == nil { return nil, errors.New("verification not found") } return verification, nil } // GetHighMatchVerifications gets all high match verifications func (s *VerificationService) GetHighMatchVerifications() ([]models.ClaimVerificationResponse, error) { verifications, err := s.verificationRepo.FindHighMatches() if err != nil { return nil, err } var responses []models.ClaimVerificationResponse for _, v := range verifications { responses = append(responses, v.ToResponse()) } return responses, nil } // CompareDescriptions provides detailed comparison between two descriptions func (s *VerificationService) CompareDescriptions(desc1, desc2 string) map[string]interface{} { similarity := utils.CalculateStringSimilarity(desc1, desc2) keywords1 := utils.ExtractKeywords(desc1) keywords2 := utils.ExtractKeywords(desc2) matchedKeywords := utils.FindMatchedKeywords(keywords1, keywords2) return map[string]interface{}{ "similarity_score": similarity * 100, "description_1": desc1, "description_2": desc2, "keywords_1": keywords1, "keywords_2": keywords2, "matched_keywords": matchedKeywords, "total_keywords_1": len(keywords1), "total_keywords_2": len(keywords2), "matched_count": len(matchedKeywords), } } // Helper function to convert string slice to JSON func stringSliceToJSON(slice []string) string { if len(slice) == 0 { return "[]" } data, _ := json.Marshal(slice) return string(data) }