File size: 5,159 Bytes
4106305
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""
Base classes for the persona system.
"""

import json
import os
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from langchain_core.documents import Document

class PersonaReasoning(ABC):
    """Base class for all persona reasoning types"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.id = config.get("id")
        self.name = config.get("name")
        self.traits = config.get("traits", [])
        self.system_prompt = config.get("system_prompt", "")
        self.examples = config.get("examples", [])
        self.is_personality = not config.get("is_persona_type", True)
        
    @abstractmethod
    def generate_perspective(self, query: str, context: Optional[List[Document]] = None) -> str:
        """Generate a perspective response based on query and optional context"""
        pass
        
    def get_system_prompt(self) -> str:
        """Get the system prompt for this persona"""
        return self.system_prompt
        
    def get_examples(self) -> List[str]:
        """Get example responses for this persona"""
        return self.examples

class PersonaFactory:
    """Factory for creating persona instances from config files"""
    
    def __init__(self, config_dir="persona_configs"):
        self.config_dir = config_dir
        self.configs = {}
        self.load_configs()
        
    def load_configs(self):
        """Load all JSON config files"""
        if not os.path.exists(self.config_dir):
            print(f"Warning: Config directory {self.config_dir} not found")
            return
            
        for filename in os.listdir(self.config_dir):
            if filename.endswith(".json"):
                try:
                    with open(os.path.join(self.config_dir, filename), "r") as f:
                        config = json.load(f)
                        if "id" in config:
                            self.configs[config["id"]] = config
                except Exception as e:
                    print(f"Error loading config file {filename}: {e}")
                        
    def get_config(self, persona_id: str) -> Optional[Dict[str, Any]]:
        """Get config for a persona"""
        return self.configs.get(persona_id)
    
    def get_available_personas(self) -> List[Dict[str, Any]]:
        """Get list of all available personas with basic info"""
        result = []
        for persona_id, config in self.configs.items():
            result.append({
                "id": persona_id,
                "name": config.get("name", persona_id.capitalize()),
                "description": config.get("description", ""),
                "is_persona_type": config.get("is_persona_type", True),
                "parent_type": config.get("parent_type", "")
            })
        return result
        
    def create_persona(self, persona_id: str) -> Optional[PersonaReasoning]:
        """Create a persona instance based on ID"""
        config = self.get_config(persona_id)
        if not config:
            return None
            
        # Lazily import implementations to avoid circular imports
        try:
            if config.get("is_persona_type", True):
                # This is a persona type
                persona_type = config.get("type")
                if persona_type == "analytical":
                    from .impl import AnalyticalReasoning
                    return AnalyticalReasoning(config)
                elif persona_type == "scientific":
                    from .impl import ScientificReasoning
                    return ScientificReasoning(config)
                elif persona_type == "philosophical":
                    from .impl import PhilosophicalReasoning
                    return PhilosophicalReasoning(config)
                elif persona_type == "factual":
                    from .impl import FactualReasoning
                    return FactualReasoning(config)
                elif persona_type == "metaphorical":
                    from .impl import MetaphoricalReasoning
                    return MetaphoricalReasoning(config)
                elif persona_type == "futuristic":
                    from .impl import FuturisticReasoning
                    return FuturisticReasoning(config)
            else:
                # This is a personality
                parent_type = config.get("parent_type")
                parent_config = self.get_config(parent_type)
                if parent_config:
                    if persona_id == "holmes":
                        from .impl import HolmesReasoning
                        return HolmesReasoning(config, parent_config)
                    elif persona_id == "feynman":
                        from .impl import FeynmanReasoning
                        return FeynmanReasoning(config, parent_config)
                    elif persona_id == "fry":
                        from .impl import FryReasoning
                        return FryReasoning(config, parent_config)
        except Exception as e:
            print(f"Error creating persona {persona_id}: {e}")
                    
        return None