# Generated by Django 5.2.7 on 2025-10-04 07:17 import django.db.models.deletion import uuid from decimal import Decimal from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='AvailableTool', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('tool_name', models.CharField(help_text='Internal tool name (matches code implementation)', max_length=100, unique=True)), ('display_name', models.CharField(help_text='Human-readable name', max_length=255)), ('description', models.TextField(help_text='Detailed description of tool functionality')), ('icon', models.CharField(blank=True, help_text='Icon class or emoji for UI', max_length=50, null=True)), ('category', models.CharField(choices=[('search', 'Search & Retrieval'), ('code', 'Code Execution'), ('data', 'Data Processing'), ('integration', 'External Integration'), ('utility', 'Utility'), ('custom', 'Custom')], default='general', help_text='Tool category', max_length=50)), ('is_active', models.BooleanField(default=True, help_text='Whether this tool is available for use')), ('is_public', models.BooleanField(default=True, help_text='Whether all users can access this tool')), ('requires_admin_approval', models.BooleanField(default=False, help_text='Whether enabling this tool requires admin approval')), ('config_schema', models.JSONField(blank=True, default=dict, help_text='JSON schema for tool configuration')), ('default_config', models.JSONField(blank=True, default=dict, help_text='Default configuration values')), ('total_users', models.IntegerField(default=0, help_text='Number of users who have enabled this tool')), ], options={ 'verbose_name': 'Available Tool', 'verbose_name_plural': 'Available Tools', 'ordering': ['category', 'display_name'], }, ), migrations.CreateModel( name='ChatSession', fields=[ ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='UUID that also serves as LangGraph thread_id', primary_key=True, serialize=False)), ('title', models.CharField(default='New Conversation', help_text='User-defined or auto-generated conversation title', max_length=255)), ('description', models.TextField(blank=True, help_text='Optional description or summary of the conversation', null=True)), ('model_name', models.CharField(default='gpt-5-mini', help_text='AI model used for this session', max_length=100)), ('temperature', models.FloatField(default=0.7, help_text='Model temperature (0.0 to 2.0)')), ('enable_summarization', models.BooleanField(default=True, help_text='Enable automatic conversation summarization')), ('summarization_threshold', models.IntegerField(default=384, help_text='Token count to trigger summarization')), ('is_active', models.BooleanField(default=True, help_text='Whether this session is active')), ('is_archived', models.BooleanField(default=False, help_text='Whether this session is archived')), ('is_pinned', models.BooleanField(default=False, help_text='Whether this session is pinned to top')), ('tags', models.JSONField(blank=True, default=list, help_text='User-defined tags for organization')), ('metadata', models.JSONField(blank=True, default=dict, help_text='Additional session metadata')), ('message_count', models.IntegerField(default=0, help_text='Total messages in this session (updated via signals)')), ('total_tokens_used', models.IntegerField(default=0, help_text='Total tokens used in this session')), ('last_message_at', models.DateTimeField(blank=True, help_text='Timestamp of last message in this session', null=True)), ('user', models.ForeignKey(help_text='User who owns this chat session', on_delete=django.db.models.deletion.CASCADE, related_name='chat_sessions', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Chat Session', 'verbose_name_plural': 'Chat Sessions', 'ordering': ['-is_pinned', '-last_message_at', '-updated_at'], }, ), migrations.CreateModel( name='MessageFeedback', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('checkpoint_id', models.CharField(help_text='LangGraph checkpoint ID containing the message', max_length=255)), ('message_index', models.IntegerField(help_text='Index of the message in the checkpoint')), ('rating', models.CharField(choices=[('thumbs_up', 'Thumbs Up 👍'), ('thumbs_down', 'Thumbs Down 👎'), ('excellent', 'Excellent'), ('good', 'Good'), ('neutral', 'Neutral'), ('poor', 'Poor'), ('very_poor', 'Very Poor')], help_text='User rating for the message', max_length=20)), ('feedback_categories', models.JSONField(blank=True, default=list, help_text='Categories of feedback (e.g., ["incorrect", "helpful", "creative"])')), ('feedback_text', models.TextField(blank=True, help_text='Optional detailed feedback from user', null=True)), ('reported_issue', models.CharField(blank=True, choices=[('incorrect', 'Incorrect Information'), ('harmful', 'Harmful Content'), ('biased', 'Biased Response'), ('off_topic', 'Off Topic'), ('incomplete', 'Incomplete Answer'), ('technical_error', 'Technical Error'), ('other', 'Other')], help_text='Type of issue if reporting a problem', max_length=50, null=True)), ('message_preview', models.TextField(blank=True, help_text='Preview of the message (for admin review)', null=True)), ('model_used', models.CharField(blank=True, help_text='AI model that generated the message', max_length=100, null=True)), ('reviewed', models.BooleanField(default=False, help_text='Whether admin has reviewed this feedback')), ('reviewed_at', models.DateTimeField(blank=True, help_text='When this feedback was reviewed', null=True)), ('admin_notes', models.TextField(blank=True, help_text='Internal notes from admin review', null=True)), ('action_taken', models.CharField(blank=True, choices=[('none', 'No Action'), ('noted', 'Noted for Training'), ('fixed', 'Issue Fixed'), ('escalated', 'Escalated'), ('user_notified', 'User Notified')], help_text='Action taken based on this feedback', max_length=50, null=True)), ('chat_session', models.ForeignKey(help_text='Chat session this feedback belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='message_feedback', to='chatbot.chatsession')), ('reviewed_by', models.ForeignKey(blank=True, help_text='Admin who reviewed this feedback', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='reviewed_feedback', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(help_text='User who provided feedback', on_delete=django.db.models.deletion.CASCADE, related_name='message_feedback', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Message Feedback', 'verbose_name_plural': 'Message Feedback', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='SystemPromptTemplate', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('name', models.CharField(help_text='Unique name for this prompt template', max_length=255, unique=True)), ('slug', models.SlugField(help_text='URL-friendly slug', max_length=255, unique=True)), ('content', models.TextField(help_text='The system prompt content')), ('description', models.TextField(blank=True, help_text='Description of what this prompt does', null=True)), ('category', models.CharField(choices=[('general', 'General Purpose'), ('coding', 'Coding Assistant'), ('writing', 'Writing Helper'), ('research', 'Research Assistant'), ('education', 'Educational'), ('business', 'Business/Professional'), ('creative', 'Creative Writing'), ('analysis', 'Data Analysis'), ('custom', 'Custom')], default='general', help_text='Category of this prompt template', max_length=50)), ('tags', models.JSONField(blank=True, default=list, help_text='Tags for organization and search')), ('is_default', models.BooleanField(default=False, help_text='Whether this is the default system prompt')), ('is_active', models.BooleanField(default=True, help_text='Whether this template is active and available')), ('is_public', models.BooleanField(default=False, help_text='Whether this template is publicly available to all users')), ('variables', models.JSONField(blank=True, default=list, help_text='List of variables that can be replaced in the prompt (e.g., {user_name}, {topic})')), ('example_variables', models.JSONField(blank=True, default=dict, help_text='Example values for variables')), ('recommended_model', models.CharField(blank=True, help_text='Recommended AI model for this prompt', max_length=100, null=True)), ('recommended_temperature', models.FloatField(blank=True, help_text='Recommended temperature setting', null=True)), ('usage_count', models.IntegerField(default=0, help_text='Number of times this template has been used')), ('rating_sum', models.IntegerField(default=0, help_text='Sum of all ratings')), ('rating_count', models.IntegerField(default=0, help_text='Number of ratings')), ], options={ 'verbose_name': 'System Prompt Template', 'verbose_name_plural': 'System Prompt Templates', 'ordering': ['-is_default', '-usage_count', 'name'], 'indexes': [models.Index(fields=['category', 'is_active'], name='sysprompt_cat_active_idx'), models.Index(fields=['is_default'], name='sysprompt_default_idx'), models.Index(fields=['-usage_count'], name='sysprompt_usage_idx')], }, ), migrations.CreateModel( name='TokenUsage', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('model_name', models.CharField(help_text='AI model used (e.g., gpt-4o, gpt-4o-mini)', max_length=100)), ('prompt_tokens', models.IntegerField(default=0, help_text='Tokens in the prompt/input')), ('completion_tokens', models.IntegerField(default=0, help_text='Tokens in the completion/output')), ('total_tokens', models.IntegerField(default=0, help_text='Total tokens (prompt + completion)')), ('reasoning_tokens', models.IntegerField(blank=True, default=0, help_text='Reasoning tokens (for models that support it)', null=True)), ('prompt_cost', models.DecimalField(decimal_places=6, default=Decimal('0.000000'), help_text='Cost for prompt tokens in USD', max_digits=10)), ('completion_cost', models.DecimalField(decimal_places=6, default=Decimal('0.000000'), help_text='Cost for completion tokens in USD', max_digits=10)), ('total_cost', models.DecimalField(decimal_places=6, default=Decimal('0.000000'), help_text='Total cost in USD', max_digits=10)), ('request_type', models.CharField(choices=[('chat', 'Chat Completion'), ('summarization', 'Conversation Summarization'), ('embedding', 'Text Embedding'), ('tool_call', 'Tool/Function Call'), ('vision', 'Vision Analysis')], default='chat', help_text='Type of API request', max_length=50)), ('endpoint', models.CharField(blank=True, help_text='API endpoint used', max_length=255, null=True)), ('response_time_ms', models.IntegerField(blank=True, help_text='Response time in milliseconds', null=True)), ('was_cached', models.BooleanField(default=False, help_text='Whether response was served from cache')), ('had_error', models.BooleanField(default=False, help_text='Whether this request had an error')), ('error_message', models.TextField(blank=True, help_text='Error message if request failed', null=True)), ('metadata', models.JSONField(blank=True, default=dict, help_text='Additional usage metadata')), ('chat_session', models.ForeignKey(blank=True, help_text='Chat session this usage belongs to', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='token_usage', to='chatbot.chatsession')), ('user', models.ForeignKey(help_text='User who incurred this usage', on_delete=django.db.models.deletion.CASCADE, related_name='token_usage', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Token Usage', 'verbose_name_plural': 'Token Usage', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='UserAPIKey', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('provider', models.CharField(choices=[('openai', 'OpenAI'), ('anthropic', 'Anthropic (Claude)'), ('google', 'Google AI'), ('cohere', 'Cohere'), ('huggingface', 'HuggingFace'), ('azure', 'Azure OpenAI'), ('custom', 'Custom Provider')], help_text='AI provider for this key', max_length=50)), ('provider_display_name', models.CharField(blank=True, help_text='Custom display name for provider', max_length=100, null=True)), ('encrypted_key', models.BinaryField(help_text='Encrypted API key (stored securely)')), ('key_name', models.CharField(help_text='User-friendly name for this key', max_length=255)), ('key_prefix', models.CharField(blank=True, help_text='First few characters of key (for identification)', max_length=20, null=True)), ('is_active', models.BooleanField(default=True, help_text='Whether this key is active and usable')), ('is_default', models.BooleanField(default=False, help_text='Whether this is the default key for this provider')), ('is_validated', models.BooleanField(default=False, help_text='Whether key has been validated with provider')), ('last_validated_at', models.DateTimeField(blank=True, help_text='When key was last validated', null=True)), ('validation_error', models.TextField(blank=True, help_text='Error message from last validation attempt', null=True)), ('usage_count', models.IntegerField(default=0, help_text='Number of times this key has been used')), ('last_used_at', models.DateTimeField(blank=True, help_text='When this key was last used', null=True)), ('total_tokens_used', models.BigIntegerField(default=0, help_text='Total tokens used with this key')), ('daily_limit', models.IntegerField(blank=True, help_text='Daily usage limit (in tokens, null = unlimited)', null=True)), ('monthly_limit', models.IntegerField(blank=True, help_text='Monthly usage limit (in tokens, null = unlimited)', null=True)), ('custom_config', models.JSONField(blank=True, default=dict, help_text='Provider-specific configuration')), ('user', models.ForeignKey(help_text='User who owns this API key', on_delete=django.db.models.deletion.CASCADE, related_name='api_keys', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User API Key', 'verbose_name_plural': 'User API Keys', 'ordering': ['-is_default', '-last_used_at'], }, ), migrations.CreateModel( name='UserDocument', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('file', models.FileField(help_text='Uploaded document file', upload_to='user_documents/%Y/%m/%d/')), ('file_name', models.CharField(help_text='Original filename', max_length=255)), ('file_size', models.BigIntegerField(help_text='File size in bytes')), ('file_type', models.CharField(help_text='MIME type of the file', max_length=100)), ('file_extension', models.CharField(help_text='File extension (e.g., .pdf, .docx)', max_length=10)), ('processing_status', models.CharField(choices=[('pending', 'Pending Processing'), ('processing', 'Processing'), ('completed', 'Completed'), ('failed', 'Failed')], default='pending', help_text='Document processing status', max_length=20)), ('processed_at', models.DateTimeField(blank=True, help_text='When processing completed', null=True)), ('vector_collection_name', models.CharField(blank=True, db_index=True, help_text='PGVector collection name where embeddings are stored (REQUIRED for vector operations)', max_length=255, null=True)), ('vector_collection_metadata', models.JSONField(blank=True, default=dict, help_text='Optional metadata for the PGVector collection itself')), ('vector_store_ids', models.JSONField(blank=True, default=list, help_text="List of pgvector document IDs for this file's chunks")), ('chunk_count', models.IntegerField(default=0, help_text='Number of chunks/embeddings created')), ('title', models.CharField(blank=True, help_text='User-defined or extracted document title', max_length=255, null=True)), ('description', models.TextField(blank=True, help_text='User description or summary of document', null=True)), ('tags', models.JSONField(blank=True, default=list, help_text='User-defined tags for organization')), ('extracted_metadata', models.JSONField(blank=True, default=dict, help_text='Metadata extracted from document (author, date, pages, etc.)')), ('vector_metadata', models.JSONField(blank=True, default=dict, help_text="Searchable metadata for pgvector filtering (e.g., {'user_id': '123', 'category': 'research', 'date': '2025-01'})")), ('page_count', models.IntegerField(blank=True, help_text='Number of pages (for PDFs, documents)', null=True)), ('word_count', models.IntegerField(blank=True, help_text='Approximate word count', null=True)), ('is_active', models.BooleanField(default=True, help_text='Whether this document is active and searchable')), ('is_shared', models.BooleanField(default=False, help_text='Whether document is shared with other users')), ('share_settings', models.JSONField(blank=True, default=dict, help_text='Document sharing configuration')), ('processing_error', models.TextField(blank=True, help_text='Error message if processing failed', null=True)), ('retry_count', models.IntegerField(default=0, help_text='Number of processing retries')), ('chat_session', models.ForeignKey(blank=True, help_text='Chat session this document is associated with', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='documents', to='chatbot.chatsession')), ('user', models.ForeignKey(help_text='User who uploaded this document', on_delete=django.db.models.deletion.CASCADE, related_name='documents', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User Document', 'verbose_name_plural': 'User Documents', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='UserPreference', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('default_model', models.CharField(choices=[('gpt-5-mini', 'GPT-5 Mini (Recommended)'), ('gpt-5-nano', 'GPT-5 Nano (Smaller/Faster)'), ('gpt-4.1-mini', 'GPT-4.1 Mini (Faster/Cheaper)'), ('gpt-4o-mini', 'GPT-4o Mini (Faster/Cheaper)'), ('o4-mini', 'GPT-o4 Mini (Reasoning)')], default='gpt-5-mini', help_text='Default AI model for new conversations', max_length=100)), ('default_temperature', models.FloatField(default=0.7, help_text='Default temperature (0.0-2.0). Higher = more creative')), ('default_max_tokens', models.IntegerField(default=2000, help_text='Default max tokens for responses')), ('enable_auto_summarization', models.BooleanField(default=True, help_text='Enable automatic conversation summarization')), ('summarization_trigger_tokens', models.IntegerField(default=384, help_text='Token count to trigger summarization')), ('max_summary_tokens', models.IntegerField(default=128, help_text='Maximum tokens in summary')), ('summarization_style', models.CharField(choices=[('concise', 'Concise (Brief summaries)'), ('detailed', 'Detailed (More context)'), ('bullet', 'Bullet Points')], default='concise', help_text='Style of automatic summaries', max_length=20)), ('custom_system_prompt', models.TextField(blank=True, help_text='Custom system prompt for all conversations', null=True)), ('use_custom_system_prompt', models.BooleanField(default=False, help_text='Use custom system prompt instead of default')), ('response_language', models.CharField(default='en', help_text='Preferred response language code (e.g., en, es, fr)', max_length=10)), ('enable_streaming', models.BooleanField(default=True, help_text='Enable streaming responses (word-by-word)')), ('enable_code_execution', models.BooleanField(default=False, help_text='Allow AI to execute code (advanced users only)')), ('daily_message_limit', models.IntegerField(default=100, help_text='Maximum messages per day (0 = unlimited)')), ('daily_token_limit', models.IntegerField(default=50000, help_text='Maximum tokens per day (0 = unlimited)')), ('theme', models.CharField(choices=[('light', 'Light Theme'), ('dark', 'Dark Theme'), ('auto', 'Auto (System)')], default='auto', help_text='Chat interface theme', max_length=20)), ('show_token_count', models.BooleanField(default=False, help_text='Show token count in chat interface')), ('enable_notifications', models.BooleanField(default=True, help_text='Enable browser notifications for AI responses')), ('save_conversation_history', models.BooleanField(default=True, help_text='Save conversation history for future reference')), ('allow_data_training', models.BooleanField(default=False, help_text='Allow conversations to be used for model improvement')), ('additional_settings', models.JSONField(blank=True, default=dict, help_text='Additional user-specific settings')), ('user', models.OneToOneField(help_text='User these preferences belong to', on_delete=django.db.models.deletion.CASCADE, related_name='ai_preferences', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User Preference', 'verbose_name_plural': 'User Preferences', }, ), migrations.CreateModel( name='UserTool', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('tool_name', models.CharField(help_text='Internal name of the tool (e.g., "web_search", "code_executor")', max_length=100)), ('tool_display_name', models.CharField(help_text='Human-readable tool name', max_length=255)), ('is_enabled', models.BooleanField(default=True, help_text='Whether this tool is enabled for the user')), ('configuration', models.JSONField(blank=True, default=dict, help_text='Tool-specific configuration settings')), ('description', models.TextField(blank=True, help_text='Description of what this tool does', null=True)), ('category', models.CharField(choices=[('search', 'Search & Retrieval'), ('code', 'Code Execution'), ('data', 'Data Processing'), ('integration', 'External Integration'), ('utility', 'Utility'), ('custom', 'Custom')], default='general', help_text='Tool category', max_length=50)), ('usage_count', models.IntegerField(default=0, help_text='Number of times this tool has been used')), ('last_used_at', models.DateTimeField(blank=True, help_text='When this tool was last used', null=True)), ('rate_limit', models.IntegerField(blank=True, help_text='Maximum uses per hour (null = unlimited)', null=True)), ('rate_limit_period', models.CharField(choices=[('minute', 'Per Minute'), ('hour', 'Per Hour'), ('day', 'Per Day')], default='hour', help_text='Rate limit period', max_length=20)), ('requires_approval', models.BooleanField(default=False, help_text='Whether tool usage requires admin approval')), ('is_approved', models.BooleanField(default=True, help_text='Whether usage is approved by admin')), ('approved_at', models.DateTimeField(blank=True, help_text='When this tool was approved', null=True)), ('approved_by', models.ForeignKey(blank=True, help_text='Admin who approved this tool', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='approved_tools', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(help_text='User who configured this tool', on_delete=django.db.models.deletion.CASCADE, related_name='enabled_tools', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User Tool', 'verbose_name_plural': 'User Tools', 'ordering': ['tool_display_name'], }, ), migrations.AddIndex( model_name='chatsession', index=models.Index(fields=['user', '-last_message_at'], name='chatsession_user_lastmsg_idx'), ), migrations.AddIndex( model_name='chatsession', index=models.Index(fields=['user', 'is_active'], name='chatsession_user_active_idx'), ), migrations.AddIndex( model_name='chatsession', index=models.Index(fields=['user', 'is_archived'], name='chatsession_user_archived_idx'), ), migrations.AddIndex( model_name='chatsession', index=models.Index(fields=['is_pinned', '-last_message_at'], name='chatsession_pinned_idx'), ), migrations.AddIndex( model_name='messagefeedback', index=models.Index(fields=['user', '-created_at'], name='msgfeedback_user_date_idx'), ), migrations.AddIndex( model_name='messagefeedback', index=models.Index(fields=['chat_session', '-created_at'], name='msgfeedback_session_date_idx'), ), migrations.AddIndex( model_name='messagefeedback', index=models.Index(fields=['rating'], name='msgfeedback_rating_idx'), ), migrations.AddIndex( model_name='messagefeedback', index=models.Index(fields=['reported_issue'], name='msgfeedback_issue_idx'), ), migrations.AddIndex( model_name='messagefeedback', index=models.Index(fields=['reviewed'], name='msgfeedback_reviewed_idx'), ), migrations.AlterUniqueTogether( name='messagefeedback', unique_together={('checkpoint_id', 'message_index', 'user')}, ), migrations.AddIndex( model_name='tokenusage', index=models.Index(fields=['user', '-created_at'], name='tokenusage_user_date_idx'), ), migrations.AddIndex( model_name='tokenusage', index=models.Index(fields=['chat_session', '-created_at'], name='tokenusage_session_date_idx'), ), migrations.AddIndex( model_name='tokenusage', index=models.Index(fields=['model_name'], name='tokenusage_model_idx'), ), migrations.AddIndex( model_name='tokenusage', index=models.Index(fields=['request_type'], name='tokenusage_type_idx'), ), migrations.AddIndex( model_name='tokenusage', index=models.Index(fields=['user', 'model_name'], name='tokenusage_user_model_idx'), ), migrations.AddIndex( model_name='userapikey', index=models.Index(fields=['user', 'provider'], name='apikey_user_provider_idx'), ), migrations.AddIndex( model_name='userapikey', index=models.Index(fields=['user', 'is_active'], name='apikey_user_active_idx'), ), migrations.AddIndex( model_name='userapikey', index=models.Index(fields=['is_default'], name='apikey_default_idx'), ), migrations.AlterUniqueTogether( name='userapikey', unique_together={('user', 'provider', 'key_name')}, ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['user', '-created_at'], name='userdoc_user_date_idx'), ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['user', 'is_active'], name='userdoc_user_active_idx'), ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['processing_status'], name='userdoc_status_idx'), ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['file_type'], name='userdoc_type_idx'), ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['vector_collection_name'], name='userdoc_collection_idx'), ), migrations.AddIndex( model_name='userdocument', index=models.Index(fields=['user', 'vector_collection_name'], name='userdoc_user_collection_idx'), ), migrations.AddIndex( model_name='usertool', index=models.Index(fields=['user', 'is_enabled'], name='usertool_user_enabled_idx'), ), migrations.AddIndex( model_name='usertool', index=models.Index(fields=['tool_name'], name='usertool_name_idx'), ), migrations.AddIndex( model_name='usertool', index=models.Index(fields=['category'], name='usertool_category_idx'), ), migrations.AlterUniqueTogether( name='usertool', unique_together={('user', 'tool_name')}, ), ]