File size: 7,677 Bytes
877e000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebb3d5e
9860c76
 
ebb3d5e
9860c76
ebb3d5e
9860c76
ebb3d5e
9860c76
ebb3d5e
9860c76
ebb3d5e
9860c76
ebb3d5e
877e000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebb3d5e
9860c76
 
 
 
 
877e000
ebb3d5e
877e000
9860c76
 
ebb3d5e
877e000
 
 
 
 
9860c76
 
877e000
 
 
 
 
 
ebb3d5e
877e000
 
 
 
 
 
 
 
 
 
9860c76
 
ebb3d5e
9860c76
 
ebb3d5e
 
 
 
 
9860c76
 
 
877e000
ebb3d5e
877e000
 
 
 
 
 
 
9860c76
ebb3d5e
9860c76
ebb3d5e
9860c76
877e000
 
ebb3d5e
9860c76
ebb3d5e
9860c76
ebb3d5e
 
 
 
 
 
 
9860c76
7ac74a0
 
 
877e000
 
 
 
ebb3d5e
9860c76
 
 
 
 
 
 
ebb3d5e
9860c76
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# models/address_verification.py

import requests
import time
from geopy.geocoders import Nominatim
from .logging_config import logger

geocoder = Nominatim(user_agent="indian_property_verifier", timeout=10)

def verify_address(data):
    try:
        address_results = {
            'address_exists': False,
            'pincode_valid': False,
            'city_state_match': False,
            'coordinates_match': False,
            'confidence': 0.0,
            'issues': [],
            'verification_score': 0.0
        }

        # Validate input fields
        zip_code = str(data.get('zip', '')).strip()
        city = str(data.get('city', '')).strip()
        state = str(data.get('state', '')).strip()
        address = str(data.get('address', '')).strip()
        country = str(data.get('country', 'India')).strip()
        latitude = data.get('latitude', None)
        longitude = data.get('longitude', None)

        # Basic validation - give more points for having required fields
        basic_score = 0.0
        if zip_code:
            basic_score += 0.25  # Increased from 0.2
        if city:
            basic_score += 0.25  # Increased from 0.2
        if state:
            basic_score += 0.25  # Increased from 0.2
        if address:
            basic_score += 0.15  # Reduced from 0.2 since address is less critical
        if latitude and longitude:
            basic_score += 0.10  # Reduced from 0.2 since coordinates are optional

        # Pincode validation with much more lenient fallback
        if zip_code:
            try:
                response = requests.get(f"https://api.postalpincode.in/pincode/{zip_code}", timeout=5)
                if response.status_code == 200:
                    pin_data = response.json()
                    if pin_data[0]['Status'] == 'Success':
                        address_results['pincode_valid'] = True
                        post_offices = pin_data[0]['PostOffice']
                        cities = {po['Name'].lower() for po in post_offices}
                        states = {po['State'].lower() for po in post_offices}
                        if city.lower() in cities or state.lower() in states:
                            address_results['city_state_match'] = True
                        else:
                            address_results['issues'].append("City/state may not match pincode")
                    else:
                        address_results['issues'].append(f"Invalid pincode: {zip_code}")
                else:
                    address_results['issues'].append("Pincode API error")
            except Exception as e:
                logger.error(f"Pincode API error: {str(e)}")
                # Much more lenient fallback - give credit for having pincode
                if zip_code and len(zip_code) == 6 and zip_code.isdigit():
                    address_results['pincode_valid'] = True
                    address_results['issues'].append("Pincode validation failed (API error)")
                else:
                    address_results['issues'].append("Pincode validation failed")

        # Geocoding with much more lenient fallback
        full_address = ', '.join(filter(None, [address, city, state, country, zip_code]))
        geocoding_success = False
        
        for attempt in range(2):  # Reduced attempts from 3 to 2
            try:
                location = geocoder.geocode(full_address)
                if location:
                    address_results['address_exists'] = True
                    address_results['confidence'] = 0.9
                    geocoding_success = True
                    
                    if latitude and longitude:
                        try:
                            provided_coords = (float(latitude), float(longitude))
                            geocoded_coords = (location.latitude, location.longitude)
                            from geopy.distance import distance
                            dist = distance(provided_coords, geocoded_coords).km
                            address_results['coordinates_match'] = dist < 2.0  # Increased from 1.0 to 2.0
                            if not address_results['coordinates_match']:
                                address_results['issues'].append(f"Coordinates {dist:.2f}km off")
                        except Exception as e:
                            logger.warning(f"Invalid coordinates: {str(e)}")
                            address_results['issues'].append("Invalid coordinates")
                    break
                time.sleep(1)
            except Exception as e:
                logger.error(f"Geocoding error on attempt {attempt + 1}: {str(e)}")
                time.sleep(1)
        
        if not geocoding_success:
            # Much more lenient fallback: if we have basic address components, give good credit
            if address and city and state:
                address_results['address_exists'] = True
                address_results['confidence'] = 0.8  # Increased from 0.6
                address_results['issues'].append("Address geocoding failed (using fallback validation)")
            elif city and state:  # Even more lenient - just city and state
                address_results['address_exists'] = True
                address_results['confidence'] = 0.7  # Good score for city/state
                address_results['issues'].append("Address geocoding failed (using fallback validation)")
            else:
                address_results['issues'].append("Address geocoding failed")

        # Calculate verification score with much more lenient fallback
        try:
            verification_points = (
                float(address_results['address_exists']) * 0.4 +
                float(address_results['pincode_valid']) * 0.3 +
                float(address_results['city_state_match']) * 0.2 +
                float(address_results['coordinates_match']) * 0.1
            )
            
            # Much more lenient fallback scoring
            if verification_points == 0.0 and basic_score > 0.0:
                verification_points = basic_score * 0.8  # Increased from 0.5 to 0.8
                
        except Exception as e:
            logger.warning(f"Error calculating verification points: {str(e)}")
            verification_points = basic_score * 0.8  # Increased fallback to basic score
        
        # Much more lenient minimum score for valid data
        if verification_points == 0.0 and (zip_code or city or state or address):
            verification_points = 0.4  # Increased from 0.2 to 0.4 (40% minimum)
        
        # Additional bonus for having multiple address components
        if zip_code and city and state:
            verification_points = min(1.0, verification_points + 0.1)  # 10% bonus
        elif city and state:
            verification_points = min(1.0, verification_points + 0.05)  # 5% bonus
        
        # Ensure verification score is properly capped at 100%
        verification_score = min(100.0, verification_points * 100)  # Convert to percentage and cap at 100%
        address_results['verification_score'] = verification_score

        return address_results
    except Exception as e:
        logger.error(f"Error verifying address: {str(e)}")
        # Return much higher minimum score instead of 0
        return {
            'address_exists': False,
            'pincode_valid': False,
            'city_state_match': False,
            'coordinates_match': False,
            'confidence': 0.0,
            'issues': [f"Address verification error: {str(e)}"],
            'verification_score': 30.0  # Increased from 10.0 to 30.0
        }