Spaces:
Sleeping
Sleeping
| """ | |
| Trademark Valuation Computation Logic | |
| Heuristic-based approach for estimating trademark value based on multiple factors | |
| """ | |
| import re | |
| from typing import Dict, Any | |
| from datetime import datetime | |
| import math | |
| import random | |
| # ========================================= | |
| # Constants | |
| # ========================================= | |
| REGISTERED = {700, 701, 702, 703, 704, 705, 706, 707, 708, 739, 717, 800} | |
| ITU = {688, 718, 719, 720, 721, 722, 724, 725, 730, 731, 732, 733, 734} | |
| POU = { | |
| 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, | |
| 821, 822, 823, 824, 825, 632, 638, 640, 641, 642, 643, 644, 645, 646, 647, | |
| 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660 | |
| } | |
| STATUS_BOOST = {801, 802, 803, 804, 773, 774, 775, 777, 778, 779, 780, 781, 782, 790} | |
| CLASS_CFG = { | |
| 5: (50e6, 500e6, 0.08, 0.15, 1), 9: (50e6, 500e6, 0.10, 0.18, 1), 42: (40e6, 400e6, 0.10, 0.18, 1), | |
| 36: (40e6, 400e6, 0.05, 0.12, 1), 45: (35e6, 350e6, 0.08, 0.15, 1), 3: (20e6, 200e6, 0.15, 0.25, 2), | |
| 10: (25e6, 250e6, 0.08, 0.15, 2), 44: (25e6, 250e6, 0.08, 0.15, 2), 35: (20e6, 200e6, 0.10, 0.18, 2), | |
| 38: (25e6, 250e6, 0.08, 0.15, 2), 41: (20e6, 200e6, 0.12, 0.20, 2), 25: (15e6, 150e6, 0.15, 0.25, 3), | |
| 29: (10e6, 100e6, 0.12, 0.22, 3), 30: (10e6, 100e6, 0.12, 0.22, 3), 32: (15e6, 150e6, 0.15, 0.25, 3), | |
| 33: (20e6, 200e6, 0.18, 0.28, 3), 34: (25e6, 250e6, 0.15, 0.25, 3), 43: (10e6, 100e6, 0.15, 0.25, 3), | |
| 28: (10e6, 100e6, 0.12, 0.20, 3), 14: (15e6, 150e6, 0.12, 0.20, 3), 18: (15e6, 150e6, 0.18, 0.28, 3), | |
| 7: (8e6, 80e6, 0.05, 0.12, 4), 11: (8e6, 80e6, 0.08, 0.15, 4), 12: (10e6, 100e6, 0.08, 0.15, 4), | |
| 37: (5e6, 50e6, 0.05, 0.10, 4), 39: (8e6, 80e6, 0.08, 0.15, 4), 20: (5e6, 50e6, 0.10, 0.18, 4), | |
| 21: (5e6, 50e6, 0.10, 0.18, 4), 1: (3e6, 40e6, 0.03, 0.08, 5), 2: (3e6, 40e6, 0.05, 0.10, 5), | |
| 4: (3e6, 40e6, 0.03, 0.08, 5), 6: (2e6, 30e6, 0.02, 0.06, 5), 8: (3e6, 40e6, 0.05, 0.12, 5), | |
| 13: (5e6, 50e6, 0.08, 0.15, 5), 15: (3e6, 30e6, 0.10, 0.18, 5), 16: (2e6, 25e6, 0.05, 0.10, 5), | |
| 17: (2e6, 25e6, 0.03, 0.08, 5), 19: (3e6, 35e6, 0.03, 0.08, 5), 22: (1.5e6, 20e6, 0.03, 0.08, 5), | |
| 23: (1.5e6, 20e6, 0.03, 0.08, 5), 24: (2e6, 25e6, 0.05, 0.10, 5), 26: (1e6, 15e6, 0.05, 0.10, 5), | |
| 27: (2e6, 25e6, 0.05, 0.10, 5), 31: (3e6, 35e6, 0.03, 0.08, 5), 40: (2e6, 25e6, 0.03, 0.08, 5), | |
| } | |
| DEFAULT_CFG = (1e6, 10e6, 0.02, 0.05, 6) | |
| GENERICS = { | |
| 'THE', 'BEST', 'QUALITY', 'SUPER', 'PREMIUM', 'SERVICES', 'SOLUTIONS', 'GROUP', 'GLOBAL', | |
| 'INTERNATIONAL', 'ENTERPRISE', 'CONSULTING', 'DIGITAL', 'TECH', 'CLOUD', 'SMART', 'PRO', | |
| 'PLUS', 'MAX', 'ULTRA', 'ELITE', 'PRIME', 'EXPRESS', 'DIRECT', 'ONLINE', 'NETWORK', 'SYSTEMS' | |
| } | |
| INDUSTRY_KW = { | |
| 5: ['pharm', 'med', 'health', 'cure', 'heal', 'vita', 'bio', 'thera', 'care'], | |
| 9: ['tech', 'soft', 'data', 'cyber', 'digit', 'smart', 'logic', 'byte', 'net', 'web', 'app', 'cloud', 'code'], | |
| 35: ['biz', 'corp', 'market', 'brand', 'consult', 'strat', 'manage'], | |
| 36: ['fin', 'bank', 'fund', 'invest', 'capital', 'wealth', 'pay', 'credit'], | |
| 42: ['tech', 'soft', 'dev', 'code', 'cyber', 'cloud', 'data', 'lab'], | |
| 45: ['law', 'legal', 'just', 'counsel', 'attorney', 'protect', 'secure'], | |
| } | |
| PARENT_COS = { | |
| 'johnson & johnson': ['kenvue', 'janssen', 'neutrogena', 'tylenol', 'band-aid', 'listerine'], | |
| 'procter & gamble': ['tide', 'pampers', 'gillette', 'oral-b', 'crest', 'pantene', 'olay', 'old spice'], | |
| 'unilever': ['dove', 'axe', 'lipton', 'knorr', 'hellmanns', 'ben & jerrys', 'vaseline'], | |
| 'nestle': ['nescafe', 'nespresso', 'kitkat', 'gerber', 'purina', 'perrier', 'haagen-dazs'], | |
| 'pepsico': ['frito-lay', 'doritos', 'lays', 'cheetos', 'quaker', 'gatorade', 'tropicana'], | |
| 'coca-cola': ['sprite', 'fanta', 'minute maid', 'powerade', 'dasani', 'smartwater'], | |
| 'meta': ['facebook', 'instagram', 'whatsapp', 'oculus', 'threads'], | |
| 'alphabet': ['google', 'youtube', 'android', 'chrome', 'gmail', 'waymo', 'nest'], | |
| 'amazon': ['alexa', 'kindle', 'prime', 'aws', 'whole foods', 'twitch', 'audible', 'ring'], | |
| 'apple': ['iphone', 'ipad', 'macbook', 'airpods', 'apple watch', 'apple music', 'siri'], | |
| 'disney': ['marvel', 'pixar', 'lucasfilm', 'star wars', 'espn', 'abc', 'hulu'], | |
| } | |
| PREMIUM_DESIGN = {'02.01', '02.03', '03.01', '03.03', '03.05', '04.01', '01.01', '01.03', '24.01', '26.03', '26.05'} | |
| STANDARD_DESIGN = {'05.01', '05.03', '06.01', '07.01', '08.01', '19.01'} | |
| ENTITY_HINTS = [ | |
| 'INC', 'LLC', 'CORP', 'CORPORATION', 'LTD', 'LIMITED', 'GMBH', 'PLC', 'COMPANY', 'CO', 'CO ', | |
| 'HOLDINGS', 'GROUP', 'LP', 'LLP', 'PC', 'SA', 'S A', 'SAS', 'BV', 'AB', 'AG', 'NV', 'PTY' | |
| ] | |
| def evaluate_trademark( | |
| mark: str, | |
| party_name: str, | |
| primary_code: int, | |
| status_code: int, | |
| goods_and_service: str = "", | |
| registration_date_epoch: int = None, | |
| market_cap: float = 0, | |
| portfolio_size: int = 1, | |
| design_codes: str = "", | |
| mark_drawing_code: int = 4, | |
| multi_class_count: int = 1, | |
| intl_reg_count: int = 0, | |
| competitor_count: int = 0, | |
| office_action_count: int = 0, | |
| actual_renewal_count: int = 0, | |
| late_renewal_count: int = 0, | |
| survived_trial: bool = False, | |
| section15_filed: bool = False, | |
| filing_66a: bool = False, | |
| is_supplemental: bool = False, | |
| clamp_total_mult: bool = True, | |
| total_mult_min: float = 0.20, | |
| total_mult_max: float = 6.00, | |
| ) -> Dict[str, Any]: | |
| """ | |
| Evaluate a single trademark and return full breakdown. | |
| """ | |
| result: Dict[str, Any] = {} | |
| now = int(datetime.now().timestamp() * 1000) | |
| # Class config | |
| cfg = CLASS_CFG.get(primary_code, DEFAULT_CFG) | |
| base_min, base_max, pct_min, pct_max, tier = cfg | |
| brand_pct = (pct_min + pct_max) / 2 | |
| result['class_tier'] = tier | |
| result['class_mult'] = {1: 1.25, 2: 1.15, 3: 1.10}.get(tier, 1.0) | |
| # Status flags | |
| is_registered = status_code in REGISTERED | |
| is_itu = status_code in ITU | |
| is_pou = status_code in POU | |
| has_boost = status_code in STATUS_BOOST | |
| # Base value calculation - PRIMARY DRIVER OF VALUATION | |
| portfolio = max(1, min(portfolio_size, 1000)) | |
| # Portfolio-based factor: Larger portfolios indicate established businesses | |
| # Log scale prevents extreme multipliers while rewarding size | |
| if portfolio >= 500: | |
| portfolio_factor = 3.5 + math.log10(portfolio / 100) * 0.5 | |
| elif portfolio >= 100: | |
| portfolio_factor = 2.5 + (portfolio - 100) / 200 | |
| elif portfolio >= 50: | |
| portfolio_factor = 2.0 + (portfolio - 50) / 100 | |
| elif portfolio >= 20: | |
| portfolio_factor = 1.5 + (portfolio - 20) / 60 | |
| elif portfolio >= 10: | |
| portfolio_factor = 1.2 + (portfolio - 10) / 30 | |
| elif portfolio >= 5: | |
| portfolio_factor = 1.0 + (portfolio - 5) / 20 | |
| else: | |
| portfolio_factor = 0.7 + (portfolio * 0.06) | |
| # Class-based positioning adjustment | |
| # Higher tier classes get more aggressive base values | |
| if tier == 1: # Premium tech/pharma/finance | |
| class_base_factor = 1.8 | |
| elif tier == 2: # High-value services | |
| class_base_factor = 1.4 | |
| elif tier == 3: # Consumer goods | |
| class_base_factor = 1.2 | |
| elif tier == 4: # Industrial/Manufacturing | |
| class_base_factor = 1.0 | |
| else: # Misc/Low-value | |
| class_base_factor = 0.7 | |
| if is_itu: | |
| # Intent-to-use: speculative value only | |
| base = 2000 if market_cap > 0 else 800 | |
| result['base_value'] = base | |
| elif is_pou: | |
| # Proof of use: some value but limited | |
| base = 5000 * class_base_factor | |
| result['base_value'] = base | |
| elif market_cap > 0: | |
| # Known company: use market cap proportional valuation | |
| base = (market_cap * brand_pct) / portfolio | |
| result['base_value'] = max(base, base_min * 0.1) | |
| elif is_registered: | |
| # Registered mark: main valuation path | |
| # Combine class value with portfolio strength | |
| base = ((base_min * 0.3) + (base_max * 0.15)) * class_base_factor * portfolio_factor | |
| # Add randomness to prevent clustering (±15%) | |
| variance = random.uniform(0.85, 1.15) | |
| base = base * variance | |
| result['base_value'] = max(base, base_min * 0.05) | |
| else: | |
| # Abandoned/dead marks | |
| base = base_min * 0.02 | |
| result['base_value'] = max(base, 1000) | |
| # Temporal multiplier - AGE PREMIUM | |
| # Older marks = more established brand recognition and goodwill | |
| if registration_date_epoch and registration_date_epoch > 0: | |
| years = (now - registration_date_epoch) / 31557600000 | |
| years = max(0.0, years) | |
| else: | |
| years = 0.0 | |
| if years <= 0: | |
| # No registration date: penalty | |
| result['temporal_mult'] = 0.6 | |
| elif years < 1: | |
| # Very new: still establishing | |
| result['temporal_mult'] = 0.7 + 0.4 * years | |
| elif years < 3: | |
| # Young but registered | |
| result['temporal_mult'] = 1.1 + 0.2 * (years - 1.0) | |
| elif years < 7: | |
| # Established presence | |
| result['temporal_mult'] = 1.5 + 0.15 * (years - 3.0) | |
| elif years < 15: | |
| # Strong history | |
| result['temporal_mult'] = 2.1 + 0.12 * (years - 7.0) | |
| elif years < 30: | |
| # Legacy brand | |
| result['temporal_mult'] = 3.06 + 0.08 * (years - 15.0) | |
| else: | |
| # Historic mark (rare premium) | |
| result['temporal_mult'] = 4.26 + 0.04 * min(50.0, years - 30.0) | |
| # Renewal multiplier | |
| result['renewal_mult'] = 1.0 + actual_renewal_count * 0.03 - late_renewal_count * 0.07 | |
| result['renewal_mult'] = max(0.70, min(1.30, result['renewal_mult'])) | |
| # Description multiplier | |
| desc_words = len(goods_and_service.split()) if goods_and_service else 0 | |
| result['desc_mult'] = min(1.10, 1.0 + 0.02 * math.sqrt(desc_words / 50.0)) if desc_words > 0 else 1.0 | |
| # Multi-class registration - SCOPE OF PROTECTION | |
| # More classes = broader market coverage = higher value | |
| mc = min(10, max(1, multi_class_count)) | |
| if mc >= 8: | |
| result['multi_class_mult'] = 1.85 | |
| elif mc >= 6: | |
| result['multi_class_mult'] = 1.65 | |
| elif mc >= 4: | |
| result['multi_class_mult'] = 1.42 | |
| elif mc >= 3: | |
| result['multi_class_mult'] = 1.28 | |
| elif mc >= 2: | |
| result['multi_class_mult'] = 1.15 | |
| else: | |
| result['multi_class_mult'] = 1.0 | |
| # Geographic reach - INTERNATIONAL PRESENCE | |
| # International registrations show serious commercial intent | |
| geo = min(15, max(1, intl_reg_count + 1)) | |
| if geo >= 10: | |
| result['geo_mult'] = 2.5 | |
| elif geo >= 6: | |
| result['geo_mult'] = 2.0 | |
| elif geo >= 4: | |
| result['geo_mult'] = 1.6 | |
| elif geo >= 3: | |
| result['geo_mult'] = 1.35 | |
| elif geo >= 2: | |
| result['geo_mult'] = 1.18 | |
| else: | |
| result['geo_mult'] = 1.0 | |
| # Competitor proximity - MARKET POSITION | |
| # Fewer similar marks = stronger distinctiveness and market power | |
| if competitor_count <= 0: | |
| result['proximity_mult'] = 1.60 # Unique in class | |
| result['market_dominance'] = 'DOMINANT' | |
| elif competitor_count < 3: | |
| result['proximity_mult'] = 1.45 # Near monopoly | |
| result['market_dominance'] = 'STRONG' | |
| elif competitor_count < 10: | |
| result['proximity_mult'] = 1.25 # Leading position | |
| result['market_dominance'] = 'STRONG' | |
| elif competitor_count < 30: | |
| result['proximity_mult'] = 1.05 # Competitive space | |
| result['market_dominance'] = 'MODERATE' | |
| elif competitor_count < 75: | |
| result['proximity_mult'] = 0.80 # Crowded field | |
| result['market_dominance'] = 'WEAK' | |
| elif competitor_count < 150: | |
| result['proximity_mult'] = 0.60 # Saturated | |
| result['market_dominance'] = 'CROWDED' | |
| else: | |
| result['proximity_mult'] = 0.40 # Commodity space | |
| result['market_dominance'] = 'SATURATED' | |
| # Section 15 | |
| result['section15_mult'] = 1.30 if section15_filed else 1.0 | |
| # Individual vs company | |
| party_upper = (party_name or '').upper() | |
| party_clean = party_upper.replace('.', ' ').replace(',', ' ') | |
| is_individual = not any(h in party_clean for h in ENTITY_HINTS) | |
| if is_individual and market_cap == 0 and portfolio_size <= 3: | |
| result['individual_mult'] = 0.75 | |
| elif is_individual: | |
| result['individual_mult'] = 0.90 | |
| else: | |
| result['individual_mult'] = 1.0 | |
| # Uniqueness heuristic | |
| mark_upper = (mark or '').upper() | |
| mark_len = len(mark_upper) | |
| has_digit = bool(re.search(r'\d', mark_upper)) | |
| vowels = sum(1 for c in mark_upper if c in 'AEIOU') | |
| vowel_ratio = vowels / max(1, mark_len) | |
| if mark_len <= 3: | |
| result['uniqueness_mult'] = 1.05 | |
| elif has_digit: | |
| result['uniqueness_mult'] = 1.08 | |
| elif vowel_ratio < 0.2 or vowel_ratio > 0.6: | |
| result['uniqueness_mult'] = 1.10 | |
| else: | |
| result['uniqueness_mult'] = 1.0 | |
| # Industry relevance | |
| mark_lower = mark_upper.lower() | |
| kws = INDUSTRY_KW.get(primary_code, []) | |
| matches = sum(1 for kw in kws if kw in mark_lower) | |
| if matches >= 2: | |
| result['industry_relevance_mult'] = 1.15 | |
| elif matches == 1: | |
| result['industry_relevance_mult'] = 1.08 | |
| else: | |
| result['industry_relevance_mult'] = 1.0 | |
| # Generic / descriptive checks | |
| is_generic = mark_upper in GENERICS | |
| mark_in_gs = False | |
| if mark and goods_and_service and len(mark) >= 4: | |
| pattern = r'\b' + re.escape(mark_lower) + r'\b' | |
| mark_in_gs = bool(re.search(pattern, goods_and_service.lower())) | |
| if is_generic and mark_in_gs: | |
| result['generic_mult'] = 0.10 | |
| elif is_generic: | |
| result['generic_mult'] = 0.30 | |
| elif mark_in_gs: | |
| result['generic_mult'] = 0.60 | |
| else: | |
| result['generic_mult'] = 1.0 | |
| # Parent vs subsidiary | |
| party_lower = (party_name or '').lower() | |
| is_parent_mark = False | |
| for parent, subs in PARENT_COS.items(): | |
| parent_words = parent.replace('&', '').split() | |
| if all(w in party_lower for w in parent_words): | |
| if all(w in mark_lower for w in parent_words): | |
| is_parent_mark = True | |
| break | |
| result['parent_mult'] = 1.15 if is_parent_mark else 1.0 | |
| # Office actions | |
| oa = min(6, max(0, office_action_count)) | |
| result['oa_mult'] = max(0.70, 1.0 - 0.05 * oa) | |
| # Portfolio multiplier - CORPORATE STRENGTH INDICATOR | |
| # Large portfolios = institutional backing and resources for enforcement | |
| if portfolio_size >= 500: | |
| result['portfolio_mult'] = 1.65 # Major corporation | |
| elif portfolio_size >= 250: | |
| result['portfolio_mult'] = 1.50 # Large enterprise | |
| elif portfolio_size >= 100: | |
| result['portfolio_mult'] = 1.35 # Established company | |
| elif portfolio_size >= 50: | |
| result['portfolio_mult'] = 1.22 # Mid-size business | |
| elif portfolio_size >= 25: | |
| result['portfolio_mult'] = 1.14 # Growing portfolio | |
| elif portfolio_size >= 10: | |
| result['portfolio_mult'] = 1.08 # Active filer | |
| elif portfolio_size >= 5: | |
| result['portfolio_mult'] = 1.02 # Small business | |
| else: | |
| result['portfolio_mult'] = 0.90 # Individual/startup | |
| # Logo value | |
| has_design = mark_drawing_code in [2, 3, 5, 6] | |
| codes = set(design_codes.split(';')) if design_codes else set() | |
| if not has_design: | |
| result['logo_value'] = 0 | |
| elif codes & PREMIUM_DESIGN: | |
| result['logo_value'] = 75000 + min(25000, len(codes) * 5000) | |
| elif codes & STANDARD_DESIGN: | |
| result['logo_value'] = 35000 + min(25000, len(codes) * 5000) | |
| else: | |
| result['logo_value'] = 10000 + min(25000, len(codes) * 5000) | |
| # Flat bonuses / penalties | |
| if filing_66a: | |
| result['filing_66a_bonus'] = {1: 20000, 2: 20000, 3: 12500, 4: 12500}.get(tier, 5000) | |
| else: | |
| result['filing_66a_bonus'] = 0 | |
| result['trial_bonus'] = 50000 if survived_trial else 0 | |
| result['status_bonus'] = 10000 if has_boost else 0 | |
| result['supplemental_penalty'] = -25000 if is_supplemental else 0 | |
| # Final calculation | |
| mult_keys = [ | |
| 'temporal_mult', 'renewal_mult', 'class_mult', 'desc_mult', | |
| 'multi_class_mult', 'geo_mult', 'proximity_mult', 'section15_mult', | |
| 'individual_mult', 'uniqueness_mult', 'industry_relevance_mult', | |
| 'generic_mult', 'parent_mult', 'oa_mult', 'portfolio_mult' | |
| ] | |
| mult_product = 1.0 | |
| for k in mult_keys: | |
| mult_product *= float(result[k]) | |
| if clamp_total_mult: | |
| mult_product = max(total_mult_min, min(total_mult_max, mult_product)) | |
| computed = ( | |
| result['base_value'] * mult_product | |
| + result['logo_value'] | |
| + result['filing_66a_bonus'] | |
| + result['trial_bonus'] | |
| + result['status_bonus'] | |
| + result['supplemental_penalty'] | |
| ) | |
| result['computed_value'] = max(500, min(50e9, computed)) | |
| # CONFIDENCE SCORE - ESTIMATION RELIABILITY | |
| # Measures how confident we are in the valuation (data quality + factors) | |
| conf = 30 # Baseline: minimal data scenario | |
| # === STRONG POSITIVE INDICATORS === | |
| # Public company data (highest confidence) | |
| if market_cap > 0: | |
| conf += 28 | |
| # Core registration strength | |
| if is_registered: | |
| conf += 18 | |
| if section15_filed: # Incontestable status | |
| conf += 10 | |
| if registration_date_epoch: | |
| conf += 8 | |
| # Portfolio sophistication (signals professional management) | |
| if portfolio_size >= 200: conf += 15 | |
| elif portfolio_size >= 100: conf += 12 | |
| elif portfolio_size >= 50: conf += 9 | |
| elif portfolio_size >= 20: conf += 6 | |
| elif portfolio_size >= 10: conf += 4 | |
| # Market coverage breadth | |
| if multi_class_count >= 6: conf += 12 | |
| elif multi_class_count >= 4: conf += 8 | |
| elif multi_class_count >= 2: conf += 4 | |
| # International validation | |
| if intl_reg_count >= 5: conf += 14 | |
| elif intl_reg_count >= 3: conf += 10 | |
| elif intl_reg_count >= 1: conf += 5 | |
| # Goods/services specificity | |
| if desc_words > 60: conf += 9 | |
| elif desc_words > 30: conf += 6 | |
| elif desc_words > 15: conf += 3 | |
| # Proven longevity | |
| if actual_renewal_count >= 4: conf += 12 | |
| elif actual_renewal_count >= 2: conf += 8 | |
| elif actual_renewal_count >= 1: conf += 4 | |
| # Temporal confidence | |
| if years >= 25: conf += 12 | |
| elif years >= 15: conf += 9 | |
| elif years >= 10: conf += 6 | |
| elif years >= 5: conf += 3 | |
| # Recognized brand indicators | |
| if is_parent_mark: conf += 18 | |
| if result['industry_relevance_mult'] >= 1.12: conf += 7 | |
| elif result['industry_relevance_mult'] > 1: conf += 3 | |
| # Legal strength | |
| if survived_trial: conf += 10 | |
| # Market position clarity | |
| if competitor_count == 0: conf += 10 | |
| elif competitor_count <= 5: conf += 6 | |
| elif competitor_count <= 20: conf += 2 | |
| # === NEGATIVE INDICATORS (REDUCE CONFIDENCE) === | |
| # Individual ownership (less data, more variability) | |
| if is_individual and market_cap == 0: | |
| if portfolio_size <= 2: conf -= 20 | |
| elif portfolio_size <= 5: conf -= 12 | |
| elif portfolio_size <= 10: conf -= 6 | |
| # Weakness indicators | |
| if is_generic: conf -= 30 # Highly uncertain value | |
| if mark_in_gs: conf -= 18 # Descriptive = lower distinctiveness | |
| if is_itu: conf -= 30 # Not yet in commerce | |
| if not party_name: conf -= 25 # Missing critical data | |
| if is_supplemental: conf -= 22 # Weaker protection | |
| if late_renewal_count >= 3: conf -= 15 | |
| elif late_renewal_count > 0: conf -= 8 * late_renewal_count | |
| # Prosecution issues | |
| if office_action_count >= 5: conf -= 15 | |
| elif office_action_count >= 3: conf -= 10 | |
| elif office_action_count > 0: conf -= 5 | |
| # Market saturation uncertainty | |
| if competitor_count >= 200: conf -= 20 | |
| elif competitor_count >= 100: conf -= 12 | |
| elif competitor_count >= 50: conf -= 6 | |
| # Immaturity penalty | |
| if years < 0.5: conf -= 15 | |
| elif years < 2: conf -= 8 | |
| # Finalize confidence | |
| conf = max(5, min(100, conf)) | |
| result['confidence_score'] = conf | |
| # Classification thresholds | |
| if conf >= 78: | |
| result['confidence_level'] = 'HIGH' | |
| elif conf >= 58: | |
| result['confidence_level'] = 'MEDIUM' | |
| elif conf >= 35: | |
| result['confidence_level'] = 'LOW' | |
| else: | |
| result['confidence_level'] = 'VERY_LOW' | |
| return result | |