From 7ad06c6227be7959afcf75d787ec816f341b1dbb Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Wed, 17 Dec 2025 07:37:36 +0000 Subject: [PATCH] Refactor keyword handling: Replace 'intent' with 'country' across backend and frontend - Updated AutomationService to include estimated_word_count. - Increased stage_1_batch_size from 20 to 50 in AutomationViewSet. - Changed Keywords model to replace 'intent' property with 'country'. - Adjusted ClusteringService to allow a maximum of 50 keywords for clustering. - Modified admin and management commands to remove 'intent' and use 'country' instead. - Updated serializers to reflect the change from 'intent' to 'country'. - Adjusted views and filters to use 'country' instead of 'intent'. - Updated frontend forms, filters, and pages to replace 'intent' with 'country'. - Added migration to remove 'intent' field and add 'country' field to SeedKeyword model. --- .../igny8_core/ai/functions/auto_cluster.py | 3 +- .../api/tests/test_integration_base.py | 2 +- backend/igny8_core/auth/admin.py | 8 +- ...8_add_country_remove_intent_seedkeyword.py | 30 ++++++++ backend/igny8_core/auth/models.py | 17 ++-- backend/igny8_core/auth/serializers.py | 4 +- backend/igny8_core/auth/views.py | 14 ++-- .../igny8_core/business/automation/models.py | 2 +- .../automation/services/automation_service.py | 1 + .../igny8_core/business/automation/views.py | 2 +- .../igny8_core/business/planning/models.py | 6 +- .../planning/services/clustering_service.py | 4 +- backend/igny8_core/modules/planner/admin.py | 6 +- .../commands/add_keywords_to_sectors.py | 1 - .../commands/create_home_garden_industry.py | 1 - .../commands/migrate_keywords_to_seed.py | 2 +- .../igny8_core/modules/planner/serializers.py | 20 ++--- backend/igny8_core/modules/planner/views.py | 12 +-- backend/igny8_core/utils/ai_processor.py | 6 +- .../src/config/forms/keyword-form.config.ts | 17 ++-- frontend/src/config/import-export.config.tsx | 2 +- frontend/src/config/pages/keywords.config.tsx | 77 ++++++++++--------- .../src/config/snippets/columns.snippets.ts | 6 +- .../src/config/snippets/filters.snippets.ts | 19 +++-- frontend/src/pages/Planner/Dashboard.tsx | 10 +-- .../pages/Planner/KeywordOpportunities.tsx | 58 +++++++------- frontend/src/pages/Planner/Keywords.tsx | 32 ++++---- frontend/src/pages/Reference/SeedKeywords.tsx | 4 +- .../pages/Setup/IndustriesSectorsKeywords.tsx | 59 +++++++------- frontend/src/services/api.ts | 20 ++--- 30 files changed, 240 insertions(+), 205 deletions(-) create mode 100644 backend/igny8_core/auth/migrations/0018_add_country_remove_intent_seedkeyword.py diff --git a/backend/igny8_core/ai/functions/auto_cluster.py b/backend/igny8_core/ai/functions/auto_cluster.py index 2f94b39a..e1b61f4c 100644 --- a/backend/igny8_core/ai/functions/auto_cluster.py +++ b/backend/igny8_core/ai/functions/auto_cluster.py @@ -97,7 +97,6 @@ class AutoClusterFunction(BaseAIFunction): 'keyword': kw.keyword, 'volume': kw.volume, 'difficulty': kw.difficulty, - 'intent': kw.intent, } for kw in keywords ], @@ -111,7 +110,7 @@ class AutoClusterFunction(BaseAIFunction): # Format keywords keywords_text = '\n'.join([ - f"- {kw['keyword']} (Volume: {kw['volume']}, Difficulty: {kw['difficulty']}, Intent: {kw['intent']})" + f"- {kw['keyword']} (Volume: {kw['volume']}, Difficulty: {kw['difficulty']})" for kw in keyword_data ]) diff --git a/backend/igny8_core/api/tests/test_integration_base.py b/backend/igny8_core/api/tests/test_integration_base.py index 58c7fd52..a86df97c 100644 --- a/backend/igny8_core/api/tests/test_integration_base.py +++ b/backend/igny8_core/api/tests/test_integration_base.py @@ -79,7 +79,7 @@ class IntegrationTestBase(TestCase): sector=self.industry_sector, volume=1000, difficulty=50, - intent="informational" + country="US" ) # Authenticate client diff --git a/backend/igny8_core/auth/admin.py b/backend/igny8_core/auth/admin.py index 8b054ac0..633e7f21 100644 --- a/backend/igny8_core/auth/admin.py +++ b/backend/igny8_core/auth/admin.py @@ -548,18 +548,18 @@ class IndustrySectorAdmin(Igny8ModelAdmin): @admin.register(SeedKeyword) class SeedKeywordAdmin(Igny8ModelAdmin): """SeedKeyword admin - Global reference data, no account filtering""" - list_display = ['keyword', 'industry', 'sector', 'volume', 'difficulty', 'intent', 'is_active', 'created_at'] - list_filter = ['is_active', 'industry', 'sector', 'intent'] + list_display = ['keyword', 'industry', 'sector', 'volume', 'difficulty', 'country', 'is_active', 'created_at'] + list_filter = ['is_active', 'industry', 'sector', 'country'] search_fields = ['keyword'] readonly_fields = ['created_at', 'updated_at'] actions = ['delete_selected'] # Enable bulk delete fieldsets = ( ('Keyword Info', { - 'fields': ('keyword', 'industry', 'sector', 'is_active') + 'fields': ('keyword', 'industry', 'sector', 'country', 'is_active') }), ('SEO Metrics', { - 'fields': ('volume', 'difficulty', 'intent') + 'fields': ('volume', 'difficulty') }), ('Timestamps', { 'fields': ('created_at', 'updated_at') diff --git a/backend/igny8_core/auth/migrations/0018_add_country_remove_intent_seedkeyword.py b/backend/igny8_core/auth/migrations/0018_add_country_remove_intent_seedkeyword.py new file mode 100644 index 00000000..ced24ba6 --- /dev/null +++ b/backend/igny8_core/auth/migrations/0018_add_country_remove_intent_seedkeyword.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.9 on 2025-12-17 06:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('igny8_core_auth', '0017_add_history_tracking'), + ] + + operations = [ + migrations.RemoveIndex( + model_name='seedkeyword', + name='igny8_seed__intent_15020d_idx', + ), + migrations.RemoveField( + model_name='seedkeyword', + name='intent', + ), + migrations.AddField( + model_name='seedkeyword', + name='country', + field=models.CharField(choices=[('US', 'United States'), ('CA', 'Canada'), ('GB', 'United Kingdom'), ('AE', 'United Arab Emirates'), ('AU', 'Australia'), ('IN', 'India'), ('PK', 'Pakistan')], default='US', help_text='Target country for this keyword', max_length=2), + ), + migrations.AddIndex( + model_name='seedkeyword', + index=models.Index(fields=['country'], name='igny8_seed__country_4127a5_idx'), + ), + ] diff --git a/backend/igny8_core/auth/models.py b/backend/igny8_core/auth/models.py index f722c374..00ec7b30 100644 --- a/backend/igny8_core/auth/models.py +++ b/backend/igny8_core/auth/models.py @@ -517,11 +517,14 @@ class SeedKeyword(models.Model): These are canonical keywords that can be imported into account-specific Keywords. Non-deletable global reference data. """ - INTENT_CHOICES = [ - ('informational', 'Informational'), - ('navigational', 'Navigational'), - ('commercial', 'Commercial'), - ('transactional', 'Transactional'), + COUNTRY_CHOICES = [ + ('US', 'United States'), + ('CA', 'Canada'), + ('GB', 'United Kingdom'), + ('AE', 'United Arab Emirates'), + ('AU', 'Australia'), + ('IN', 'India'), + ('PK', 'Pakistan'), ] keyword = models.CharField(max_length=255, db_index=True) @@ -533,7 +536,7 @@ class SeedKeyword(models.Model): validators=[MinValueValidator(0), MaxValueValidator(100)], help_text='Keyword difficulty (0-100)' ) - intent = models.CharField(max_length=50, choices=INTENT_CHOICES, default='informational') + country = models.CharField(max_length=2, choices=COUNTRY_CHOICES, default='US', help_text='Target country for this keyword') is_active = models.BooleanField(default=True, db_index=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -547,7 +550,7 @@ class SeedKeyword(models.Model): models.Index(fields=['keyword']), models.Index(fields=['industry', 'sector']), models.Index(fields=['industry', 'sector', 'is_active']), - models.Index(fields=['intent']), + models.Index(fields=['country']), ] ordering = ['keyword'] diff --git a/backend/igny8_core/auth/serializers.py b/backend/igny8_core/auth/serializers.py index 01965177..1978ff83 100644 --- a/backend/igny8_core/auth/serializers.py +++ b/backend/igny8_core/auth/serializers.py @@ -524,14 +524,14 @@ class SeedKeywordSerializer(serializers.ModelSerializer): industry_slug = serializers.CharField(source='industry.slug', read_only=True) sector_name = serializers.CharField(source='sector.name', read_only=True) sector_slug = serializers.CharField(source='sector.slug', read_only=True) - intent_display = serializers.CharField(source='get_intent_display', read_only=True) + country_display = serializers.CharField(source='get_country_display', read_only=True) class Meta: model = SeedKeyword fields = [ 'id', 'keyword', 'industry', 'industry_name', 'industry_slug', 'sector', 'sector_name', 'sector_slug', - 'volume', 'difficulty', 'intent', 'intent_display', + 'volume', 'difficulty', 'country', 'country_display', 'is_active', 'created_at', 'updated_at' ] read_only_fields = ['created_at', 'updated_at'] diff --git a/backend/igny8_core/auth/views.py b/backend/igny8_core/auth/views.py index ae66e0ea..9b42990f 100644 --- a/backend/igny8_core/auth/views.py +++ b/backend/igny8_core/auth/views.py @@ -839,7 +839,7 @@ class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet): search_fields = ['keyword'] ordering_fields = ['keyword', 'volume', 'difficulty', 'created_at'] ordering = ['keyword'] - filterset_fields = ['industry', 'sector', 'intent', 'is_active'] + filterset_fields = ['industry', 'sector', 'country', 'is_active'] def retrieve(self, request, *args, **kwargs): """Override retrieve to return unified format""" @@ -877,7 +877,7 @@ class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet): def import_seed_keywords(self, request): """ Import seed keywords from CSV (Admin/Superuser only). - Expected columns: keyword, industry_name, sector_name, volume, difficulty, intent + Expected columns: keyword, industry_name, sector_name, volume, difficulty, country """ import csv from django.db import transaction @@ -960,7 +960,7 @@ class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet): sector=sector, volume=int(row.get('volume', 0) or 0), difficulty=int(row.get('difficulty', 0) or 0), - intent=row.get('intent', 'informational') or 'informational', + country=row.get('country', 'US') or 'US', is_active=True ) imported_count += 1 @@ -1487,9 +1487,9 @@ def seedkeyword_csv_template(request): response['Content-Disposition'] = 'attachment; filename="seedkeyword_template.csv"' writer = csv.writer(response) - writer.writerow(['keyword', 'industry', 'sector', 'volume', 'difficulty', 'intent', 'is_active']) - writer.writerow(['python programming', 'Technology', 'Software Development', '10000', '45', 'Informational', 'true']) - writer.writerow(['medical software', 'Healthcare', 'Healthcare IT', '5000', '60', 'Commercial', 'true']) + writer.writerow(['keyword', 'industry', 'sector', 'volume', 'difficulty', 'country', 'is_active']) + writer.writerow(['python programming', 'Technology', 'Software Development', '10000', '45', 'US', 'true']) + writer.writerow(['medical software', 'Healthcare', 'Healthcare IT', '5000', '60', 'CA', 'true']) return response @@ -1534,7 +1534,7 @@ def seedkeyword_csv_import(request): defaults={ 'volume': int(row.get('volume', 0)), 'difficulty': int(row.get('difficulty', 0)), - 'intent': row.get('intent', 'Informational'), + 'country': row.get('country', 'US'), 'is_active': is_active } ) diff --git a/backend/igny8_core/business/automation/models.py b/backend/igny8_core/business/automation/models.py index 597686ba..8f4836c5 100644 --- a/backend/igny8_core/business/automation/models.py +++ b/backend/igny8_core/business/automation/models.py @@ -24,7 +24,7 @@ class AutomationConfig(models.Model): scheduled_time = models.TimeField(default='02:00', help_text="Time to run (e.g., 02:00)") # Batch sizes per stage - stage_1_batch_size = models.IntegerField(default=20, help_text="Keywords per batch") + stage_1_batch_size = models.IntegerField(default=50, help_text="Keywords per batch") stage_2_batch_size = models.IntegerField(default=1, help_text="Clusters at a time") stage_3_batch_size = models.IntegerField(default=20, help_text="Ideas per batch") stage_4_batch_size = models.IntegerField(default=1, help_text="Tasks - sequential") diff --git a/backend/igny8_core/business/automation/services/automation_service.py b/backend/igny8_core/business/automation/services/automation_service.py index e40d65bc..0b73177e 100644 --- a/backend/igny8_core/business/automation/services/automation_service.py +++ b/backend/igny8_core/business/automation/services/automation_service.py @@ -637,6 +637,7 @@ class AutomationService: content_type=idea.content_type or 'post', content_structure=idea.content_structure or 'article', keywords=keywords_str, + word_count=idea.estimated_word_count, status='queued', account=idea.account, site=idea.site, diff --git a/backend/igny8_core/business/automation/views.py b/backend/igny8_core/business/automation/views.py index 18197113..6eb67c75 100644 --- a/backend/igny8_core/business/automation/views.py +++ b/backend/igny8_core/business/automation/views.py @@ -82,7 +82,7 @@ class AutomationViewSet(viewsets.ViewSet): "is_enabled": true, "frequency": "daily", "scheduled_time": "02:00", - "stage_1_batch_size": 20, + "stage_1_batch_size": 50, ... } """ diff --git a/backend/igny8_core/business/planning/models.py b/backend/igny8_core/business/planning/models.py index 65651e11..42adf528 100644 --- a/backend/igny8_core/business/planning/models.py +++ b/backend/igny8_core/business/planning/models.py @@ -131,9 +131,9 @@ class Keywords(SoftDeletableModel, SiteSectorBaseModel): return self.difficulty_override if self.difficulty_override is not None else (self.seed_keyword.difficulty if self.seed_keyword else 0) @property - def intent(self): - """Get intent from seed_keyword""" - return self.seed_keyword.intent if self.seed_keyword else 'informational' + def country(self): + """Get country from seed_keyword""" + return self.seed_keyword.country if self.seed_keyword else 'US' def save(self, *args, **kwargs): """Validate that seed_keyword's industry/sector matches site's industry/sector""" diff --git a/backend/igny8_core/business/planning/services/clustering_service.py b/backend/igny8_core/business/planning/services/clustering_service.py index 49838c3e..bf6f77c3 100644 --- a/backend/igny8_core/business/planning/services/clustering_service.py +++ b/backend/igny8_core/business/planning/services/clustering_service.py @@ -38,10 +38,10 @@ class ClusteringService: 'error': 'No keyword IDs provided' } - if len(keyword_ids) > 20: + if len(keyword_ids) > 50: return { 'success': False, - 'error': 'Maximum 20 keywords allowed for clustering' + 'error': 'Maximum 50 keywords allowed for clustering' } # Check credits (fixed cost per clustering operation) diff --git a/backend/igny8_core/modules/planner/admin.py b/backend/igny8_core/modules/planner/admin.py index 2ae78276..b887126e 100644 --- a/backend/igny8_core/modules/planner/admin.py +++ b/backend/igny8_core/modules/planner/admin.py @@ -18,7 +18,7 @@ class KeywordsResource(resources.ModelResource): class Meta: model = Keywords fields = ('id', 'keyword', 'seed_keyword__keyword', 'site__name', 'sector__name', - 'cluster__name', 'volume', 'difficulty', 'intent', 'status', 'created_at') + 'cluster__name', 'volume', 'difficulty', 'country', 'status', 'created_at') export_order = fields @@ -55,11 +55,11 @@ class ClustersAdmin(SiteSectorAdminMixin, Igny8ModelAdmin): @admin.register(Keywords) class KeywordsAdmin(ExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin): resource_class = KeywordsResource - list_display = ['keyword', 'seed_keyword', 'site', 'sector', 'cluster', 'volume', 'difficulty', 'intent', 'status', 'created_at'] + list_display = ['keyword', 'seed_keyword', 'site', 'sector', 'cluster', 'volume', 'difficulty', 'country', 'status', 'created_at'] list_editable = ['status'] # Enable inline editing for status list_filter = [ ('status', ChoicesDropdownFilter), - ('intent', ChoicesDropdownFilter), + ('country', ChoicesDropdownFilter), ('site', RelatedDropdownFilter), ('sector', RelatedDropdownFilter), ('cluster', RelatedDropdownFilter), diff --git a/backend/igny8_core/modules/planner/management/commands/add_keywords_to_sectors.py b/backend/igny8_core/modules/planner/management/commands/add_keywords_to_sectors.py index 5b6ffad2..7ec416c8 100644 --- a/backend/igny8_core/modules/planner/management/commands/add_keywords_to_sectors.py +++ b/backend/igny8_core/modules/planner/management/commands/add_keywords_to_sectors.py @@ -109,7 +109,6 @@ class Command(BaseCommand): 'account': site.account, 'volume': 1000 + (created_count * 100), # Varying volumes 'difficulty': 30 + (created_count * 10), # Varying difficulty (0-100 scale) - 'intent': 'informational' if created_count % 2 == 0 else 'commercial', 'status': 'active', } ) diff --git a/backend/igny8_core/modules/planner/management/commands/create_home_garden_industry.py b/backend/igny8_core/modules/planner/management/commands/create_home_garden_industry.py index 8ed01c30..c19c1516 100644 --- a/backend/igny8_core/modules/planner/management/commands/create_home_garden_industry.py +++ b/backend/igny8_core/modules/planner/management/commands/create_home_garden_industry.py @@ -243,7 +243,6 @@ class Command(BaseCommand): 'account': site.account, 'volume': 500 + (created_count * 50), # Varying volumes 'difficulty': 20 + (created_count * 8), # Varying difficulty (0-100 scale) - 'intent': 'informational' if created_count % 2 == 0 else 'commercial', 'status': 'active', } ) diff --git a/backend/igny8_core/modules/planner/management/commands/migrate_keywords_to_seed.py b/backend/igny8_core/modules/planner/management/commands/migrate_keywords_to_seed.py index 3e3ce9ea..648d2284 100755 --- a/backend/igny8_core/modules/planner/management/commands/migrate_keywords_to_seed.py +++ b/backend/igny8_core/modules/planner/management/commands/migrate_keywords_to_seed.py @@ -93,7 +93,7 @@ class Command(BaseCommand): sector=industry_sector, volume=keyword.volume or 0, difficulty=keyword.difficulty or 0, - intent=keyword.intent or 'informational', + country='US', # Default country for migration is_active=True ) created_count += 1 diff --git a/backend/igny8_core/modules/planner/serializers.py b/backend/igny8_core/modules/planner/serializers.py index 73635a98..e62b42b3 100644 --- a/backend/igny8_core/modules/planner/serializers.py +++ b/backend/igny8_core/modules/planner/serializers.py @@ -13,7 +13,7 @@ class KeywordSerializer(serializers.ModelSerializer): keyword = serializers.CharField(read_only=True) # From seed_keyword.keyword volume = serializers.IntegerField(read_only=True) # From seed_keyword.volume or volume_override difficulty = serializers.IntegerField(read_only=True) # From seed_keyword.difficulty or difficulty_override - intent = serializers.CharField(read_only=True) # From seed_keyword.intent + country = serializers.CharField(read_only=True) # From seed_keyword.country # SeedKeyword relationship # Optional for create - can either provide seed_keyword_id OR custom keyword fields @@ -24,11 +24,11 @@ class KeywordSerializer(serializers.ModelSerializer): custom_keyword = serializers.CharField(write_only=True, required=False, allow_blank=False) custom_volume = serializers.IntegerField(write_only=True, required=False, allow_null=True) custom_difficulty = serializers.IntegerField(write_only=True, required=False, allow_null=True) - custom_intent = serializers.ChoiceField( + custom_country = serializers.ChoiceField( write_only=True, required=False, - choices=['informational', 'navigational', 'transactional', 'commercial'], - default='informational' + choices=['US', 'CA', 'GB', 'AE', 'AU', 'IN', 'PK'], + default='US' ) # Overrides @@ -50,11 +50,11 @@ class KeywordSerializer(serializers.ModelSerializer): 'keyword', 'volume', 'difficulty', - 'intent', + 'country', 'custom_keyword', # Write-only field for creating custom keywords 'custom_volume', # Write-only 'custom_difficulty', # Write-only - 'custom_intent', # Write-only + 'custom_country', # Write-only 'volume_override', 'difficulty_override', 'cluster_id', @@ -67,7 +67,7 @@ class KeywordSerializer(serializers.ModelSerializer): 'sector_id', 'account_id', ] - read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keyword', 'volume', 'difficulty', 'intent'] + read_only_fields = ['id', 'created_at', 'updated_at', 'account_id', 'keyword', 'volume', 'difficulty', 'country'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -106,7 +106,7 @@ class KeywordSerializer(serializers.ModelSerializer): custom_keyword = validated_data.pop('custom_keyword', None) custom_volume = validated_data.pop('custom_volume', None) custom_difficulty = validated_data.pop('custom_difficulty', None) - custom_intent = validated_data.pop('custom_intent', None) or 'informational' + custom_country = validated_data.pop('custom_country', None) or 'US' # Get site and sector - they're passed as objects via save() in the view site = validated_data.get('site') @@ -132,7 +132,7 @@ class KeywordSerializer(serializers.ModelSerializer): defaults={ 'volume': custom_volume or 0, 'difficulty': custom_difficulty or 0, - 'intent': custom_intent or 'informational', + 'country': custom_country or 'US', 'is_active': True, } ) @@ -162,7 +162,7 @@ class KeywordSerializer(serializers.ModelSerializer): validated_data.pop('custom_keyword', None) validated_data.pop('custom_volume', None) validated_data.pop('custom_difficulty', None) - validated_data.pop('custom_intent', None) + validated_data.pop('custom_country', None) # seed_keyword_id is optional for updates - only update if provided if 'seed_keyword_id' in validated_data: diff --git a/backend/igny8_core/modules/planner/views.py b/backend/igny8_core/modules/planner/views.py index 9b84b763..f7bcb907 100644 --- a/backend/igny8_core/modules/planner/views.py +++ b/backend/igny8_core/modules/planner/views.py @@ -55,7 +55,7 @@ class KeywordViewSet(SiteSectorModelViewSet): ordering = ['-created_at'] # Default ordering (newest first) # Filter configuration - filter by status, cluster_id, and seed_keyword fields - filterset_fields = ['status', 'cluster_id', 'seed_keyword__intent', 'seed_keyword_id'] + filterset_fields = ['status', 'cluster_id', 'seed_keyword__country', 'seed_keyword_id'] def get_queryset(self): """ @@ -475,7 +475,7 @@ class KeywordViewSet(SiteSectorModelViewSet): writer = csv.writer(response) # Header row - writer.writerow(['ID', 'Keyword', 'Volume', 'Difficulty', 'Intent', 'Status', 'Cluster ID', 'Created At']) + writer.writerow(['ID', 'Keyword', 'Volume', 'Difficulty', 'Country', 'Status', 'Cluster ID', 'Created At']) # Data rows for keyword in keywords: @@ -484,7 +484,7 @@ class KeywordViewSet(SiteSectorModelViewSet): keyword.keyword, keyword.volume, keyword.difficulty, - keyword.intent, + keyword.country, keyword.status, keyword.cluster_id or '', keyword.created_at.isoformat() if keyword.created_at else '', @@ -631,12 +631,13 @@ class KeywordViewSet(SiteSectorModelViewSet): skipped_count += 1 continue - # Create keyword + # Note: This direct creation bypasses seed_keyword linkage + # Keywords should ideally be created through seed_keyword FK + # Country comes from seed_keyword.country property Keywords.objects.create( keyword=keyword_text, volume=int(row.get('volume', 0) or 0), difficulty=int(row.get('difficulty', 0) or 0), - intent=row.get('intent', 'informational') or 'informational', status=row.get('status', 'new') or 'new', site=site, sector=sector, @@ -1193,6 +1194,7 @@ class ContentIdeasViewSet(SiteSectorModelViewSet): content_structure=idea.content_structure or 'article', taxonomy_term=None, # Can be set later if taxonomy is available keywords=keywords_str, # Comma-separated keywords string + word_count=idea.estimated_word_count, # Copy word count from idea status='queued', account=idea.account, site=idea.site, diff --git a/backend/igny8_core/utils/ai_processor.py b/backend/igny8_core/utils/ai_processor.py index ca34b73e..799e6334 100644 --- a/backend/igny8_core/utils/ai_processor.py +++ b/backend/igny8_core/utils/ai_processor.py @@ -1050,7 +1050,7 @@ Make sure each prompt is detailed enough for image generation, describing the vi def cluster_keywords( self, - keywords: List[Dict[str, Any]], # List of keyword dicts with 'keyword', 'volume', 'difficulty', 'intent' + keywords: List[Dict[str, Any]], # List of keyword dicts with 'keyword', 'volume', 'difficulty' sector_name: Optional[str] = None, account=None, response_steps=None, @@ -1069,7 +1069,7 @@ Make sure each prompt is detailed enough for image generation, describing the vi Based on reference plugin's clustering prompt. Args: - keywords: List of keyword dicts with keyword, volume, difficulty, intent + keywords: List of keyword dicts with keyword, volume, difficulty sector_name: Optional sector name for context account: Optional account for getting custom prompts @@ -1085,7 +1085,7 @@ Make sure each prompt is detailed enough for image generation, describing the vi # Format keywords for prompt keywords_text = '\n'.join([ - f"- {kw.get('keyword', '')} (Volume: {kw.get('volume', 0)}, Difficulty: {kw.get('difficulty', 0)}, Intent: {kw.get('intent', 'unknown')})" + f"- {kw.get('keyword', '')} (Volume: {kw.get('volume', 0)}, Difficulty: {kw.get('difficulty', 0)})" for kw in keywords ]) diff --git a/frontend/src/config/forms/keyword-form.config.ts b/frontend/src/config/forms/keyword-form.config.ts index aa35b3c8..2f29ff23 100644 --- a/frontend/src/config/forms/keyword-form.config.ts +++ b/frontend/src/config/forms/keyword-form.config.ts @@ -55,16 +55,19 @@ export const getKeywordFormConfig = (options?: { required: false, }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', type: 'select', - value: 'informational', + value: 'US', onChange: () => {}, options: [ - { value: 'informational', label: 'Informational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'commercial', label: 'Commercial' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], required: false, }, diff --git a/frontend/src/config/import-export.config.tsx b/frontend/src/config/import-export.config.tsx index 398a9ad9..cdd4ec69 100644 --- a/frontend/src/config/import-export.config.tsx +++ b/frontend/src/config/import-export.config.tsx @@ -161,7 +161,7 @@ export function useImportExport(

{filename === 'keywords' && (

- Expected columns: keyword, volume, difficulty, intent, status + Expected columns: keyword, volume, difficulty, country, status

)} diff --git a/frontend/src/config/pages/keywords.config.tsx b/frontend/src/config/pages/keywords.config.tsx index 17df873b..da9ecbc1 100644 --- a/frontend/src/config/pages/keywords.config.tsx +++ b/frontend/src/config/pages/keywords.config.tsx @@ -11,7 +11,7 @@ import { keywordColumn, volumeColumn, difficultyColumn, - intentColumn, + countryColumn, clusterColumn, sectorColumn, statusColumn, @@ -106,7 +106,7 @@ export const createKeywordsPageConfig = ( keyword?: string; volume?: number | null; difficulty?: number | null; - intent?: string; + country?: string; cluster_id?: number | null; status: string; }; @@ -116,8 +116,8 @@ export const createKeywordsPageConfig = ( setSearchTerm: (value: string) => void; statusFilter: string; setStatusFilter: (value: string) => void; - intentFilter: string; - setIntentFilter: (value: string) => void; + countryFilter: string; + setCountryFilter: (value: string) => void; difficultyFilter: string; setDifficultyFilter: (value: string) => void; clusterFilter: string; @@ -197,28 +197,23 @@ export const createKeywordsPageConfig = ( }, }, { - ...intentColumn, - sortable: false, // Backend doesn't support sorting by intent - sortField: 'seed_keyword__intent', + ...countryColumn, + sortable: false, // Backend doesn't support sorting by country + sortField: 'seed_keyword__country', render: (value: string) => { - // Map intent values to badge colors - // Transactional and Commercial → success (green, like active) - // Navigational → warning (amber/yellow, like pending) - // Informational → info (blue) - const getIntentColor = (intent: string) => { - const lowerIntent = intent?.toLowerCase() || ''; - if (lowerIntent === 'transactional' || lowerIntent === 'commercial') { - return 'success'; // Green, like active status - } else if (lowerIntent === 'navigational') { - return 'warning'; // Amber/yellow, like pending status - } - return 'info'; // Blue for informational or default + const countryNames: Record = { + 'US': 'United States', + 'CA': 'Canada', + 'GB': 'United Kingdom', + 'AE': 'United Arab Emirates', + 'AU': 'Australia', + 'IN': 'India', + 'PK': 'Pakistan', }; - - const properCase = value ? value.charAt(0).toUpperCase() + value.slice(1) : '-'; + const displayName = countryNames[value] || value || '-'; return ( - - {properCase} + + {value || '-'} ); }, @@ -317,15 +312,18 @@ export const createKeywordsPageConfig = ( ], }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', type: 'select', options: [ - { value: '', label: 'All Intent' }, - { value: 'informational', label: 'Informational' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'commercial', label: 'Commercial' }, + { value: '', label: 'All Countries' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], }, { @@ -541,18 +539,21 @@ export const createKeywordsPageConfig = ( max: 100, }, { - key: 'intent', - label: 'Search Intent', + key: 'country', + label: 'Country', type: 'select', - value: handlers.formData.intent || 'informational', + value: handlers.formData.country || 'US', onChange: (value: any) => - handlers.setFormData({ ...handlers.formData, intent: value }), + handlers.setFormData({ ...handlers.formData, country: value }), required: true, options: [ - { value: 'informational', label: 'Informational' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'commercial', label: 'Commercial' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], }, { diff --git a/frontend/src/config/snippets/columns.snippets.ts b/frontend/src/config/snippets/columns.snippets.ts index 16eb8a7e..9ecf9c0e 100644 --- a/frontend/src/config/snippets/columns.snippets.ts +++ b/frontend/src/config/snippets/columns.snippets.ts @@ -41,9 +41,9 @@ export const difficultyColumn = { width: '120px', }; -export const intentColumn = { - key: 'intent', - label: 'Intent', +export const countryColumn = { + key: 'country', + label: 'Country', sortable: true, badge: true, width: '120px', diff --git a/frontend/src/config/snippets/filters.snippets.ts b/frontend/src/config/snippets/filters.snippets.ts index 3d4d7972..71e04af9 100644 --- a/frontend/src/config/snippets/filters.snippets.ts +++ b/frontend/src/config/snippets/filters.snippets.ts @@ -15,16 +15,19 @@ export const statusFilter = { ], }; -export const intentFilter = { - key: 'intent', - label: 'Intent', +export const countryFilter = { + key: 'country', + label: 'Country', type: 'select', options: [ - { value: '', label: 'All Intent' }, - { value: 'informational', label: 'Informational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'commercial', label: 'Commercial' }, + { value: '', label: 'All Countries' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], }; diff --git a/frontend/src/pages/Planner/Dashboard.tsx b/frontend/src/pages/Planner/Dashboard.tsx index e2191a5f..3e9288e6 100644 --- a/frontend/src/pages/Planner/Dashboard.tsx +++ b/frontend/src/pages/Planner/Dashboard.tsx @@ -39,7 +39,7 @@ interface DashboardStats { mapped: number; unmapped: number; byStatus: Record; - byIntent: Record; + byCountry: Record; }; clusters: { total: number; @@ -90,11 +90,11 @@ export default function PlannerDashboard() { const unmappedKeywords = keywords.filter(k => !k.cluster || k.cluster.length === 0); const keywordsByStatus: Record = {}; - const keywordsByIntent: Record = {}; + const keywordsByCountry: Record = {}; keywords.forEach(k => { keywordsByStatus[k.status || 'unknown'] = (keywordsByStatus[k.status || 'unknown'] || 0) + 1; - if (k.intent) { - keywordsByIntent[k.intent] = (keywordsByIntent[k.intent] || 0) + 1; + if (k.country) { + keywordsByCountry[k.country] = (keywordsByCountry[k.country] || 0) + 1; } }); @@ -135,7 +135,7 @@ export default function PlannerDashboard() { mapped: mappedKeywords.length, unmapped: unmappedKeywords.length, byStatus: keywordsByStatus, - byIntent: keywordsByIntent + byCountry: keywordsByCountry }, clusters: { total: clusters.length, diff --git a/frontend/src/pages/Planner/KeywordOpportunities.tsx b/frontend/src/pages/Planner/KeywordOpportunities.tsx index e9593d94..32bb1d0d 100644 --- a/frontend/src/pages/Planner/KeywordOpportunities.tsx +++ b/frontend/src/pages/Planner/KeywordOpportunities.tsx @@ -47,7 +47,7 @@ export default function KeywordOpportunities() { // Filter state const [searchTerm, setSearchTerm] = useState(''); - const [intentFilter, setIntentFilter] = useState(''); + const [countryFilter, setCountryFilter] = useState(''); const [difficultyFilter, setDifficultyFilter] = useState(''); const [volumeMin, setVolumeMin] = useState(''); const [volumeMax, setVolumeMax] = useState(''); @@ -119,7 +119,7 @@ export default function KeywordOpportunities() { } if (searchTerm) baseFilters.search = searchTerm; - if (intentFilter) baseFilters.intent = intentFilter; + if (countryFilter) baseFilters.country = countryFilter; // Fetch ALL pages to get complete dataset let allResults: SeedKeyword[] = []; @@ -227,7 +227,7 @@ export default function KeywordOpportunities() { } finally { setLoading(false); } - }, [activeSite, activeSector, currentPage, pageSize, searchTerm, intentFilter, difficultyFilter, volumeMin, volumeMax, sortBy, sortDirection]); + }, [activeSite, activeSector, currentPage, pageSize, searchTerm, countryFilter, difficultyFilter, volumeMin, volumeMax, sortBy, sortDirection]); // Load data on mount and when filters change (excluding search - handled separately) useEffect(() => { @@ -504,28 +504,27 @@ export default function KeywordOpportunities() { }, }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', sortable: true, - sortField: 'intent', + sortField: 'country', render: (value: string) => { - const getIntentColor = (intent: string) => { - const lowerIntent = intent?.toLowerCase() || ''; - if (lowerIntent === 'transactional' || lowerIntent === 'commercial') { - return 'success'; - } else if (lowerIntent === 'navigational') { - return 'warning'; - } - return 'info'; + const countryNames: Record = { + 'US': 'United States', + 'CA': 'Canada', + 'GB': 'United Kingdom', + 'AE': 'United Arab Emirates', + 'AU': 'Australia', + 'IN': 'India', + 'PK': 'Pakistan', }; - return ( - {value} + {value || '-'} ); }, @@ -539,15 +538,18 @@ export default function KeywordOpportunities() { placeholder: 'Search keywords...', }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', type: 'select', options: [ - { value: '', label: 'All Intent' }, - { value: 'informational', label: 'Informational' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'commercial', label: 'Commercial' }, + { value: '', label: 'All Countries' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], }, { @@ -612,7 +614,7 @@ export default function KeywordOpportunities() { filters={pageConfig.filters} filterValues={{ search: searchTerm, - intent: intentFilter, + country: countryFilter, difficulty: difficultyFilter, }} onFilterChange={(key, value) => { @@ -620,8 +622,8 @@ export default function KeywordOpportunities() { if (key === 'search') { setSearchTerm(stringValue); - } else if (key === 'intent') { - setIntentFilter(stringValue); + } else if (key === 'country') { + setCountryFilter(stringValue); setCurrentPage(1); } else if (key === 'difficulty') { setDifficultyFilter(stringValue); diff --git a/frontend/src/pages/Planner/Keywords.tsx b/frontend/src/pages/Planner/Keywords.tsx index 2e54f471..19a78e82 100644 --- a/frontend/src/pages/Planner/Keywords.tsx +++ b/frontend/src/pages/Planner/Keywords.tsx @@ -52,7 +52,7 @@ export default function Keywords() { const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [clusterFilter, setClusterFilter] = useState(''); - const [intentFilter, setIntentFilter] = useState(''); + const [countryFilter, setCountryFilter] = useState(''); const [difficultyFilter, setDifficultyFilter] = useState(''); const [volumeMin, setVolumeMin] = useState(''); const [volumeMax, setVolumeMax] = useState(''); @@ -81,7 +81,7 @@ export default function Keywords() { keyword: '', volume: null, difficulty: null, - intent: 'informational', + country: 'US', cluster_id: null, status: 'new', }); @@ -156,7 +156,7 @@ export default function Keywords() { ...(searchTerm && { search: searchTerm }), ...(statusFilter && { status: statusFilter }), ...(clusterFilter && { cluster_id: clusterFilter }), - ...(intentFilter && { intent: intentFilter }), + ...(countryFilter && { country: countryFilter }), ...(activeSector?.id && { sector_id: activeSector.id }), page: currentPage, page_size: pageSize || 10, // Ensure we always send a page_size @@ -200,7 +200,7 @@ export default function Keywords() { setShowContent(true); setLoading(false); } - }, [currentPage, statusFilter, clusterFilter, intentFilter, difficultyFilter, volumeMin, volumeMax, sortBy, sortDirection, searchTerm, activeSite, activeSector, pageSize]); + }, [currentPage, statusFilter, clusterFilter, countryFilter, difficultyFilter, volumeMin, volumeMax, sortBy, sortDirection, searchTerm, activeSite, activeSector, pageSize]); // Listen for site and sector changes and refresh data useEffect(() => { @@ -324,8 +324,8 @@ export default function Keywords() { toast.error('Please select at least one keyword to cluster'); return; } - if (ids.length > 20) { - toast.error('Maximum 20 keywords allowed for clustering'); + if (ids.length > 50) { + toast.error('Maximum 50 keywords allowed for clustering'); return; } @@ -536,7 +536,7 @@ export default function Keywords() { keyword: '', volume: null, difficulty: null, - intent: 'informational', + country: 'US', cluster_id: null, status: 'new', }); @@ -605,8 +605,8 @@ export default function Keywords() { setSearchTerm, statusFilter, setStatusFilter, - intentFilter, - setIntentFilter, + countryFilter, + setCountryFilter, difficultyFilter, setDifficultyFilter, clusterFilter, @@ -632,7 +632,7 @@ export default function Keywords() { formData, searchTerm, statusFilter, - intentFilter, + countryFilter, difficultyFilter, clusterFilter, volumeMin, @@ -776,7 +776,7 @@ export default function Keywords() { keyword: keyword.keyword, volume: keyword.volume, difficulty: keyword.difficulty, - intent: keyword.intent, + country: keyword.country, cluster_id: keyword.cluster_id, status: keyword.status, }); @@ -807,7 +807,7 @@ export default function Keywords() { filterValues={{ search: searchTerm, status: statusFilter, - intent: intentFilter, + country: countryFilter, difficulty: difficultyFilter, cluster_id: clusterFilter, volumeMin: volumeMin, @@ -823,8 +823,8 @@ export default function Keywords() { } else if (key === 'status') { setStatusFilter(stringValue); setCurrentPage(1); - } else if (key === 'intent') { - setIntentFilter(stringValue); + } else if (key === 'country') { + setCountryFilter(stringValue); setCurrentPage(1); } else if (key === 'difficulty') { setDifficultyFilter(stringValue); @@ -868,7 +868,7 @@ export default function Keywords() { search: searchTerm, status: statusFilter, cluster_id: clusterFilter, - intent: intentFilter, + country: countryFilter, difficulty: difficultyFilter, }; await handleExport('csv', filterValues); @@ -903,7 +903,7 @@ export default function Keywords() { setSearchTerm(''); setStatusFilter(''); setClusterFilter(''); - setIntentFilter(''); + setCountryFilter(''); setDifficultyFilter(''); setVolumeMin(''); setVolumeMax(''); diff --git a/frontend/src/pages/Reference/SeedKeywords.tsx b/frontend/src/pages/Reference/SeedKeywords.tsx index d210616f..d1e9c5da 100644 --- a/frontend/src/pages/Reference/SeedKeywords.tsx +++ b/frontend/src/pages/Reference/SeedKeywords.tsx @@ -87,7 +87,7 @@ export default function SeedKeywords() { Sector Volume Difficulty - Intent + Country @@ -109,7 +109,7 @@ export default function SeedKeywords() { {keyword.difficulty} - {keyword.intent_display} + {keyword.country_display} ))} diff --git a/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx b/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx index 72f1f928..9f37d9c9 100644 --- a/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx +++ b/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx @@ -58,7 +58,7 @@ export default function IndustriesSectorsKeywords() { // Filter state const [searchTerm, setSearchTerm] = useState(''); - const [intentFilter, setIntentFilter] = useState(''); + const [countryFilter, setCountryFilter] = useState(''); const [difficultyFilter, setDifficultyFilter] = useState(''); // Check if user is admin/superuser (role is 'admin' or 'developer') @@ -153,7 +153,7 @@ export default function IndustriesSectorsKeywords() { } if (searchTerm) baseFilters.search = searchTerm; - if (intentFilter) baseFilters.intent = intentFilter; + if (countryFilter) baseFilters.country = countryFilter; // Fetch ALL pages to get complete dataset let allResults: SeedKeyword[] = []; @@ -215,9 +215,9 @@ export default function IndustriesSectorsKeywords() { } else if (sortBy === 'difficulty') { aVal = a.difficulty; bVal = b.difficulty; - } else if (sortBy === 'intent') { - aVal = a.intent.toLowerCase(); - bVal = b.intent.toLowerCase(); + } else if (sortBy === 'country') { + aVal = a.country.toLowerCase(); + bVal = b.country.toLowerCase(); } else { return 0; } @@ -249,7 +249,7 @@ export default function IndustriesSectorsKeywords() { setTotalCount(0); setTotalPages(1); } - }, [activeSite, activeSector, currentPage, pageSize, searchTerm, intentFilter, difficultyFilter, sortBy, sortDirection, toast]); + }, [activeSite, activeSector, currentPage, pageSize, searchTerm, countryFilter, difficultyFilter, sortBy, sortDirection, toast]); // Load data on mount and when filters change useEffect(() => { @@ -521,28 +521,18 @@ export default function IndustriesSectorsKeywords() { }, }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', sortable: true, - sortField: 'intent', + sortField: 'country', render: (value: string) => { - const getIntentColor = (intent: string) => { - const lowerIntent = intent?.toLowerCase() || ''; - if (lowerIntent === 'transactional' || lowerIntent === 'commercial') { - return 'success'; - } else if (lowerIntent === 'navigational') { - return 'warning'; - } - return 'info'; - }; - return ( - {value} + {value || '-'} ); }, @@ -584,15 +574,18 @@ export default function IndustriesSectorsKeywords() { placeholder: 'Search keywords...', }, { - key: 'intent', - label: 'Intent', + key: 'country', + label: 'Country', type: 'select' as const, options: [ - { value: '', label: 'All Intent' }, - { value: 'informational', label: 'Informational' }, - { value: 'navigational', label: 'Navigational' }, - { value: 'transactional', label: 'Transactional' }, - { value: 'commercial', label: 'Commercial' }, + { value: '', label: 'All Countries' }, + { value: 'US', label: 'United States' }, + { value: 'CA', label: 'Canada' }, + { value: 'GB', label: 'United Kingdom' }, + { value: 'AE', label: 'United Arab Emirates' }, + { value: 'AU', label: 'Australia' }, + { value: 'IN', label: 'India' }, + { value: 'PK', label: 'Pakistan' }, ], }, { @@ -691,7 +684,7 @@ export default function IndustriesSectorsKeywords() { filters={pageConfig.filters} filterValues={{ search: searchTerm, - intent: intentFilter, + country: countryFilter, difficulty: difficultyFilter, }} onFilterChange={(key, value) => { @@ -699,8 +692,8 @@ export default function IndustriesSectorsKeywords() { if (key === 'search') { setSearchTerm(stringValue); - } else if (key === 'intent') { - setIntentFilter(stringValue); + } else if (key === 'country') { + setCountryFilter(stringValue); setCurrentPage(1); } else if (key === 'difficulty') { setDifficultyFilter(stringValue); @@ -762,7 +755,7 @@ export default function IndustriesSectorsKeywords() {

- Expected columns: keyword, volume, difficulty, intent, industry_name, sector_name + Expected columns: keyword, volume, difficulty, country, industry_name, sector_name

{ requestData.custom_keyword = data.keyword; requestData.custom_volume = data.volume; requestData.custom_difficulty = data.difficulty; - requestData.custom_intent = data.intent || 'informational'; + requestData.custom_country = data.country || 'US'; // Remove the frontend-only fields delete requestData.keyword; delete requestData.volume; delete requestData.difficulty; - delete requestData.intent; + delete requestData.country; } return fetchAPI('/v1/planner/keywords/', { @@ -2073,8 +2073,8 @@ export interface SeedKeyword { sector_slug: string; volume: number; difficulty: number; - intent: string; - intent_display: string; + country: string; + country_display: string; is_active: boolean; created_at: string; updated_at: string; @@ -2090,7 +2090,7 @@ export interface SeedKeywordResponse { export async function fetchSeedKeywords(filters?: { industry?: number; sector?: number; - intent?: string; + country?: string; search?: string; page?: number; page_size?: number; @@ -2105,7 +2105,7 @@ export async function fetchSeedKeywords(filters?: { params.append('sector', filters.sector.toString()); params.append('sector_id', filters.sector.toString()); // Also send sector_id for get_queryset } - if (filters?.intent) params.append('intent', filters.intent); + if (filters?.country) params.append('country', filters.country); if (filters?.search) params.append('search', filters.search); if (filters?.page) params.append('page', filters.page.toString()); if (filters?.page_size) params.append('page_size', filters.page_size.toString());