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());