class TextSectionService
Service class for managing TextSection entities, providing CRUD operations, versioning, chat functionality, and search capabilities.
/tf/active/vicechatdev/vice_ai/services.py
16 - 335
complex
Purpose
TextSectionService is a comprehensive service layer for managing text sections in a document management system. It handles creation, retrieval, updating, and deletion of text sections, maintains version history, manages chat configurations and messages, supports duplication and search operations, and integrates with a DatabaseManager for persistence. The service ensures proper state management, automatic versioning on content updates, and provides methods for reverting to previous versions.
Source Code
class TextSectionService:
"""Service for managing TextSections"""
def __init__(self, db_manager: DatabaseManager):
self.db = db_manager
def create_text_section(
self,
owner: str,
title: str,
section_type: SectionType = SectionType.TEXT,
level: int = 1,
initial_content: str = ""
) -> TextSection:
"""Create a new text section"""
section_id = str(uuid.uuid4())
version_id = str(uuid.uuid4())
text_section = TextSection(
id=section_id,
owner=owner,
title=title,
section_type=section_type,
level=level,
current_content=initial_content,
current_version_id=version_id
)
# Save the text section
self.db.save_text_section(text_section)
# Create initial version
if initial_content:
self.create_version(
section_id,
initial_content,
owner,
"Initial version"
)
return text_section
def get_text_section(self, section_id: str) -> Optional[TextSection]:
"""Get a text section by ID"""
return self.db.get_text_section(section_id)
def get_user_text_sections(self, owner: str) -> List[TextSection]:
"""Get all text sections for a user"""
return self.db.get_user_text_sections(owner)
def update_text_section_content(
self,
section_id: str,
new_content: str,
author: str,
change_summary: str = "",
generated_by_ai: bool = False
) -> bool:
"""Update text section content with versioning"""
text_section = self.get_text_section(section_id)
if not text_section:
return False
# Create new version
version_id = self.create_version(
section_id,
new_content,
author,
change_summary,
generated_by_ai
)
if version_id:
# Update current content and version
text_section.current_content = new_content
text_section.current_version_id = version_id
text_section.updated_at = datetime.now()
return self.db.save_text_section(text_section)
return False
def update_text_section_title(self, section_id: str, new_title: str) -> bool:
"""Update text section title"""
text_section = self.get_text_section(section_id)
if not text_section:
return False
text_section.title = new_title
text_section.updated_at = datetime.now()
return self.db.save_text_section(text_section)
def create_version(
self,
text_section_id: str,
content: str,
author: str,
change_summary: str = "",
generated_by_ai: bool = False
) -> Optional[str]:
"""Create a new version of text section content"""
version_id = str(uuid.uuid4())
version = TextSectionVersion(
version_id=version_id,
content=content,
timestamp=datetime.now(),
author=author,
change_summary=change_summary,
generated_by_ai=generated_by_ai
)
if self.db.save_text_section_version(version, text_section_id):
return version_id
return None
def get_text_section_versions(self, text_section_id: str) -> List[TextSectionVersion]:
"""Get all versions for a text section"""
return self.db.get_text_section_versions(text_section_id)
def revert_to_version(self, text_section_id: str, version_id: str, author: str) -> bool:
"""Revert text section to a specific version"""
versions = self.get_text_section_versions(text_section_id)
target_version = next((v for v in versions if v.version_id == version_id), None)
if target_version:
return self.update_text_section_content(
text_section_id,
target_version.content,
author,
f"Reverted to version {version_id}",
False
)
return False
def update_chat_configuration(self, section_id: str, config: ChatConfiguration) -> bool:
"""Update chat configuration for a text section"""
text_section = self.get_text_section(section_id)
if not text_section:
return False
text_section.chat_configuration = config
text_section.updated_at = datetime.now()
return self.db.save_text_section(text_section)
def add_chat_message(
self,
section_id: str,
role: str,
content: str,
references: List[Dict] = None
) -> bool:
"""Add a chat message to a text section"""
text_section = self.get_text_section(section_id)
if not text_section:
return False
message = ChatMessage(
id=str(uuid.uuid4()),
role=role,
content=content,
timestamp=datetime.now(),
references=references or []
)
text_section.chat_messages.append(message)
# Update last references if it's an AI response
if role == 'assistant' and references:
text_section.last_references = references
text_section.updated_at = datetime.now()
return self.db.save_text_section(text_section)
def clear_chat_history(self, section_id: str) -> bool:
"""Clear chat history for a text section"""
text_section = self.get_text_section(section_id)
if not text_section:
return False
text_section.chat_messages = []
text_section.updated_at = datetime.now()
return self.db.save_text_section(text_section)
def duplicate_text_section(self, section_id: str, new_owner: str, new_title: str = None) -> Optional[TextSection]:
"""Create a duplicate of an existing text section with new UUID"""
original = self.get_text_section(section_id)
if not original:
return None
# Create new text section with same content but new ID
new_section = self.create_text_section(
owner=new_owner,
title=new_title or f"Copy of {original.title}",
section_type=original.section_type,
level=original.level,
initial_content=original.current_content
)
# Copy chat configuration but not chat history
new_section.chat_configuration = ChatConfiguration.from_dict(
original.chat_configuration.to_dict()
)
# Copy tags and metadata
new_section.tags = original.tags.copy()
new_section.metadata = original.metadata.copy()
self.db.save_text_section(new_section)
return new_section
def delete_text_section(self, section_id: str) -> bool:
"""Delete a text section and all its versions"""
return self.db.delete_text_section(section_id)
def update_chat_session_id(self, section_id: str, chat_session_id: str) -> bool:
"""Update the chat session ID for a text section"""
try:
print(f"🔄 DEBUG: Updating chat_session_id for section {section_id} to {chat_session_id}")
# Get the section first
section = self.get_text_section(section_id)
if not section:
print(f"❌ DEBUG: Section {section_id} not found")
return False
print(f"🔍 DEBUG: Section found, current chat_session_id: {section.chat_session_id}")
# Update the chat session ID
section.chat_session_id = chat_session_id
print(f"🔄 DEBUG: Set new chat_session_id: {section.chat_session_id}")
# Save using the database manager
success = self.db.save_text_section(section)
print(f"💾 DEBUG: Save result: {success}")
# Verify the save by re-reading the section
if success:
verification_section = self.get_text_section(section_id)
if verification_section:
print(f"✅ DEBUG: Verification - chat_session_id now: {verification_section.chat_session_id}")
else:
print(f"⚠️ DEBUG: Could not verify save - section not found on re-read")
return success
except Exception as e:
print(f"❌ DEBUG: Error updating chat session ID: {e}")
return False
def search_text_sections(
self,
owner: str,
query: str = "",
section_type: SectionType = None,
tags: List[str] = None
) -> List[TextSection]:
"""Search text sections by various criteria"""
sections = self.get_user_text_sections(owner)
if query:
query_lower = query.lower()
sections = [
s for s in sections
if query_lower in s.title.lower() or query_lower in s.current_content.lower()
]
if section_type:
sections = [s for s in sections if s.section_type == section_type]
if tags:
sections = [
s for s in sections
if any(tag in s.tags for tag in tags)
]
return sections
def get_user_text_sections_with_documents(self, owner: str) -> List[Dict]:
"""Get all text sections for a user with document information"""
sections = self.get_user_text_sections(owner)
result = []
for section in sections:
# Get documents that contain this section
documents = self.db.get_documents_containing_section(section.id)
section_dict = section.to_dict()
section_dict['documents'] = [{'id': doc.id, 'title': doc.title} for doc in documents] if documents else []
section_dict['document_count'] = len(documents) if documents else 0
result.append(section_dict)
return result
def get_unique_user_text_sections(self, owner: str) -> List[Dict]:
"""Get unique text sections for a user (latest versions only) with document information, excluding headers"""
# Get all sections grouped by title/content similarity to identify duplicates
all_sections = self.get_user_text_sections_with_documents(owner)
# Filter out header types - only show text/content sections
filtered_sections = [
section for section in all_sections
if section.get('section_type') in ['text', 'content']
]
# Group by title and keep only the most recent
unique_sections = {}
for section in filtered_sections:
title = section['title']
created_at = datetime.fromisoformat(section['created_at'])
if title not in unique_sections or created_at > datetime.fromisoformat(unique_sections[title]['created_at']):
unique_sections[title] = section
return list(unique_sections.values())
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
db_manager: An instance of DatabaseManager that handles all database operations for persisting and retrieving TextSection, TextSectionVersion, and related entities. This is the only required dependency for instantiation.
Return Value
Instantiation returns a TextSectionService object. Methods return various types: TextSection objects for creation/retrieval operations, bool for success/failure of update/delete operations, Optional[str] for version IDs, List[TextSection] for queries returning multiple sections, List[Dict] for sections with additional metadata, and Optional[TextSection] for operations that may not find the requested section.
Class Interface
Methods
__init__(self, db_manager: DatabaseManager)
Purpose: Initialize the TextSectionService with a database manager
Parameters:
db_manager: DatabaseManager instance for persistence operations
Returns: None
create_text_section(self, owner: str, title: str, section_type: SectionType = SectionType.TEXT, level: int = 1, initial_content: str = '') -> TextSection
Purpose: Create a new text section with optional initial content and automatic version creation
Parameters:
owner: User ID or identifier who owns this sectiontitle: Title of the text sectionsection_type: Type of section (default: SectionType.TEXT)level: Hierarchical level of the section (default: 1)initial_content: Initial content for the section (default: empty string)
Returns: Newly created TextSection object with generated UUID and initial version if content provided
get_text_section(self, section_id: str) -> Optional[TextSection]
Purpose: Retrieve a text section by its ID
Parameters:
section_id: UUID string of the section to retrieve
Returns: TextSection object if found, None otherwise
get_user_text_sections(self, owner: str) -> List[TextSection]
Purpose: Retrieve all text sections belonging to a specific user
Parameters:
owner: User ID to filter sections by
Returns: List of TextSection objects owned by the user (empty list if none found)
update_text_section_content(self, section_id: str, new_content: str, author: str, change_summary: str = '', generated_by_ai: bool = False) -> bool
Purpose: Update section content and automatically create a new version with metadata
Parameters:
section_id: UUID of the section to updatenew_content: New content to setauthor: User ID who made the changechange_summary: Optional description of what changedgenerated_by_ai: Flag indicating if content was AI-generated (default: False)
Returns: True if update successful, False if section not found or save failed
update_text_section_title(self, section_id: str, new_title: str) -> bool
Purpose: Update only the title of a text section without creating a new version
Parameters:
section_id: UUID of the section to updatenew_title: New title to set
Returns: True if update successful, False if section not found or save failed
create_version(self, text_section_id: str, content: str, author: str, change_summary: str = '', generated_by_ai: bool = False) -> Optional[str]
Purpose: Create a new version record for a text section with timestamp and metadata
Parameters:
text_section_id: UUID of the section this version belongs tocontent: Content snapshot for this versionauthor: User ID who created this versionchange_summary: Optional description of changesgenerated_by_ai: Flag indicating if content was AI-generated
Returns: Version ID (UUID string) if successful, None if save failed
get_text_section_versions(self, text_section_id: str) -> List[TextSectionVersion]
Purpose: Retrieve all version history for a text section
Parameters:
text_section_id: UUID of the section to get versions for
Returns: List of TextSectionVersion objects ordered by timestamp (empty list if none found)
revert_to_version(self, text_section_id: str, version_id: str, author: str) -> bool
Purpose: Restore section content to a previous version, creating a new version record for the revert
Parameters:
text_section_id: UUID of the section to revertversion_id: UUID of the version to restoreauthor: User ID performing the revert
Returns: True if revert successful, False if section or version not found
update_chat_configuration(self, section_id: str, config: ChatConfiguration) -> bool
Purpose: Update the chat configuration settings for a text section
Parameters:
section_id: UUID of the section to updateconfig: ChatConfiguration object with new settings
Returns: True if update successful, False if section not found or save failed
add_chat_message(self, section_id: str, role: str, content: str, references: List[Dict] = None) -> bool
Purpose: Add a chat message to a section's conversation history with optional references
Parameters:
section_id: UUID of the section to add message torole: Role of message sender ('user' or 'assistant')content: Message content textreferences: Optional list of reference dictionaries for citations
Returns: True if message added successfully, False if section not found or save failed
clear_chat_history(self, section_id: str) -> bool
Purpose: Remove all chat messages from a section's conversation history
Parameters:
section_id: UUID of the section to clear chat history for
Returns: True if cleared successfully, False if section not found or save failed
duplicate_text_section(self, section_id: str, new_owner: str, new_title: str = None) -> Optional[TextSection]
Purpose: Create a complete copy of a text section with new UUID, preserving content and configuration but not chat history
Parameters:
section_id: UUID of the section to duplicatenew_owner: User ID who will own the duplicatenew_title: Optional custom title (default: 'Copy of [original title]')
Returns: New TextSection object if successful, None if original section not found
delete_text_section(self, section_id: str) -> bool
Purpose: Delete a text section and all its associated versions
Parameters:
section_id: UUID of the section to delete
Returns: True if deletion successful, False otherwise
update_chat_session_id(self, section_id: str, chat_session_id: str) -> bool
Purpose: Update the chat session ID for a text section with extensive debug logging
Parameters:
section_id: UUID of the section to updatechat_session_id: New chat session ID to associate
Returns: True if update successful with verification, False if section not found or save failed
search_text_sections(self, owner: str, query: str = '', section_type: SectionType = None, tags: List[str] = None) -> List[TextSection]
Purpose: Search user's text sections by query string, type, and tags with in-memory filtering
Parameters:
owner: User ID to search withinquery: Optional search string to match in title or content (case-insensitive)section_type: Optional SectionType to filter bytags: Optional list of tags to filter by (matches if any tag present)
Returns: List of matching TextSection objects (empty list if no matches)
get_user_text_sections_with_documents(self, owner: str) -> List[Dict]
Purpose: Retrieve all user sections with additional document relationship information
Parameters:
owner: User ID to get sections for
Returns: List of dictionaries containing section data plus 'documents' list and 'document_count' fields
get_unique_user_text_sections(self, owner: str) -> List[Dict]
Purpose: Get deduplicated text sections (latest version by title) excluding headers, with document information
Parameters:
owner: User ID to get sections for
Returns: List of dictionaries with unique sections (by title), filtered to only 'text' or 'content' types, keeping most recent created_at
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
db |
DatabaseManager | Database manager instance used for all persistence operations throughout the service lifecycle | instance |
Dependencies
uuidtypingdatetime
Required Imports
import uuid
from typing import List, Dict, Optional, Any, Tuple
from datetime import datetime
from models import TextSection, DataSection, Document, DocumentSection, TextSectionVersion, ChatConfiguration, ChatMessage, ChatSession, SectionType, ContentStatus, DatabaseManager, DocumentVersion
Usage Example
from models import DatabaseManager, SectionType
from text_section_service import TextSectionService
# Initialize service with database manager
db_manager = DatabaseManager(connection_string='your_db_connection')
service = TextSectionService(db_manager)
# Create a new text section
section = service.create_text_section(
owner='user123',
title='Introduction',
section_type=SectionType.TEXT,
level=1,
initial_content='This is the introduction.'
)
# Update content (creates new version automatically)
success = service.update_text_section_content(
section_id=section.id,
new_content='Updated introduction text.',
author='user123',
change_summary='Improved clarity'
)
# Get all versions
versions = service.get_text_section_versions(section.id)
# Add chat message
service.add_chat_message(
section_id=section.id,
role='user',
content='Can you improve this section?'
)
# Search sections
results = service.search_text_sections(
owner='user123',
query='introduction',
section_type=SectionType.TEXT
)
# Duplicate section
new_section = service.duplicate_text_section(
section_id=section.id,
new_owner='user456',
new_title='Copy of Introduction'
)
# Delete section
service.delete_text_section(section.id)
Best Practices
- Always instantiate with a valid DatabaseManager that has an active database connection
- Content updates automatically create new versions - use update_text_section_content() rather than directly modifying TextSection objects
- Check return values for None/False to handle cases where sections don't exist or operations fail
- Use revert_to_version() to safely restore previous content while maintaining version history
- Chat messages are stored in the TextSection object - use add_chat_message() to maintain proper timestamps and structure
- When duplicating sections, chat history is intentionally not copied but configuration is preserved
- The service maintains referential integrity - deleting a section also deletes all its versions
- Search operations are performed in-memory after retrieval - for large datasets, consider database-level filtering
- Version IDs and section IDs are UUIDs generated automatically - don't attempt to create custom IDs
- The update_chat_session_id method includes extensive debug logging - monitor these logs in production
- Use get_unique_user_text_sections() to avoid showing duplicate sections to users, as it filters by title and excludes headers
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class TextSection 79.3% similar
-
class DocumentService 78.1% similar
-
class DataSectionService 73.4% similar
-
class ChatSessionService 72.8% similar
-
class DocumentSection 64.5% similar