405 lines
33 KiB
Python
405 lines
33 KiB
Python
# 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')},
|
|
),
|
|
]
|