Nora / app /user_config.py
GitHub Action
Deploy clean version of Nora
59bd45e
"""User configuration management for Voice Text Processor.
This module handles user-specific configurations, including
the generated cat character image settings.
Requirements: PRD - AI形象生成模块
"""
import json
import os
from typing import Optional, Dict, List
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class UserConfig:
"""User configuration manager.
This class manages user-specific settings, particularly
the generated cat character image configuration.
Attributes:
config_dir: Directory for storing user configurations
config_file: Path to the user config JSON file
"""
def __init__(self, config_dir: str = "data"):
"""Initialize user configuration manager.
Args:
config_dir: Directory for storing configurations
"""
self.config_dir = config_dir
self.config_file = os.path.join(config_dir, "user_config.json")
# 确保目录存在
os.makedirs(config_dir, exist_ok=True)
# 初始化配置文件
if not os.path.exists(self.config_file):
self._init_config_file()
def _init_config_file(self):
"""Initialize the configuration file with default values."""
default_config = {
"user_id": "default_user",
"created_at": datetime.utcnow().isoformat() + "Z",
"character": {
"image_url": "", # 空字符串,前端会显示占位符
"prompt": "默认治愈系小猫形象",
"revised_prompt": "一只薰衣草紫色的温柔猫咪,治愈系风格,温暖的陪伴者",
"preferences": {
"color": "薰衣草紫",
"personality": "温柔",
"appearance": "无配饰",
"role": "陪伴式朋友"
},
"generated_at": datetime.utcnow().isoformat() + "Z",
"generation_count": 0
},
"settings": {
"theme": "light",
"language": "zh-CN"
}
}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(default_config, f, ensure_ascii=False, indent=2)
logger.info(f"Initialized user config file: {self.config_file}")
def load_config(self) -> Dict:
"""Load user configuration from file.
Returns:
Dictionary containing user configuration
"""
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
return config
except Exception as e:
logger.error(f"Failed to load user config: {str(e)}")
# 返回默认配置
self._init_config_file()
return self.load_config()
def save_config(self, config: Dict):
"""Save user configuration to file.
Args:
config: Configuration dictionary to save
"""
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
logger.info("User config saved successfully")
except Exception as e:
logger.error(f"Failed to save user config: {str(e)}")
raise
def get_character_config(self) -> Dict:
"""Get character configuration.
Returns:
Dictionary containing character settings
"""
config = self.load_config()
return config.get("character", {})
def save_character_image(
self,
image_url: str,
prompt: str,
revised_prompt: Optional[str] = None,
preferences: Optional[Dict] = None
):
"""Save generated character image configuration.
Args:
image_url: URL of the generated image
prompt: Prompt used for generation
revised_prompt: AI-revised prompt (optional)
preferences: User preferences used (optional)
"""
config = self.load_config()
# 更新角色配置
config["character"]["image_url"] = image_url
config["character"]["prompt"] = prompt
config["character"]["revised_prompt"] = revised_prompt or prompt
config["character"]["generated_at"] = datetime.utcnow().isoformat() + "Z"
config["character"]["generation_count"] += 1
if preferences:
config["character"]["preferences"] = preferences
self.save_config(config)
logger.info(f"Character image saved: {image_url[:50]}...")
def get_character_image_url(self) -> Optional[str]:
"""Get the current character image URL.
Returns:
Image URL or None if not set
"""
character = self.get_character_config()
return character.get("image_url")
def get_character_preferences(self) -> Dict:
"""Get character generation preferences.
Returns:
Dictionary containing color, personality, appearance, role
"""
character = self.get_character_config()
return character.get("preferences", {
"color": "温暖粉",
"personality": "温柔",
"appearance": "无配饰",
"role": "陪伴式朋友"
})
def update_character_preferences(
self,
color: Optional[str] = None,
personality: Optional[str] = None,
appearance: Optional[str] = None,
role: Optional[str] = None
):
"""Update character generation preferences.
Args:
color: Color preference (optional)
personality: Personality trait (optional)
appearance: Appearance feature (optional)
role: Character role (optional)
"""
config = self.load_config()
preferences = config["character"]["preferences"]
if color:
preferences["color"] = color
if personality:
preferences["personality"] = personality
if appearance:
preferences["appearance"] = appearance
if role:
preferences["role"] = role
self.save_config(config)
logger.info("Character preferences updated")
def get_generation_count(self) -> int:
"""Get the number of times character has been generated.
Returns:
Generation count
"""
character = self.get_character_config()
return character.get("generation_count", 0)
def has_character_image(self) -> bool:
"""Check if user has a character image set.
Returns:
True if character image exists, False otherwise
"""
return self.get_character_image_url() is not None