2025-11-17 12:17:44 +07:00

153 lines
4.7 KiB
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)
}