fusesell 1.3.42__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. fusesell-1.3.42.dist-info/METADATA +873 -0
  2. fusesell-1.3.42.dist-info/RECORD +35 -0
  3. fusesell-1.3.42.dist-info/WHEEL +5 -0
  4. fusesell-1.3.42.dist-info/entry_points.txt +2 -0
  5. fusesell-1.3.42.dist-info/licenses/LICENSE +21 -0
  6. fusesell-1.3.42.dist-info/top_level.txt +2 -0
  7. fusesell.py +20 -0
  8. fusesell_local/__init__.py +37 -0
  9. fusesell_local/api.py +343 -0
  10. fusesell_local/cli.py +1480 -0
  11. fusesell_local/config/__init__.py +11 -0
  12. fusesell_local/config/default_email_templates.json +34 -0
  13. fusesell_local/config/default_prompts.json +19 -0
  14. fusesell_local/config/default_scoring_criteria.json +154 -0
  15. fusesell_local/config/prompts.py +245 -0
  16. fusesell_local/config/settings.py +277 -0
  17. fusesell_local/pipeline.py +978 -0
  18. fusesell_local/stages/__init__.py +19 -0
  19. fusesell_local/stages/base_stage.py +603 -0
  20. fusesell_local/stages/data_acquisition.py +1820 -0
  21. fusesell_local/stages/data_preparation.py +1238 -0
  22. fusesell_local/stages/follow_up.py +1728 -0
  23. fusesell_local/stages/initial_outreach.py +2972 -0
  24. fusesell_local/stages/lead_scoring.py +1452 -0
  25. fusesell_local/utils/__init__.py +36 -0
  26. fusesell_local/utils/agent_context.py +552 -0
  27. fusesell_local/utils/auto_setup.py +361 -0
  28. fusesell_local/utils/birthday_email_manager.py +467 -0
  29. fusesell_local/utils/data_manager.py +4857 -0
  30. fusesell_local/utils/event_scheduler.py +959 -0
  31. fusesell_local/utils/llm_client.py +342 -0
  32. fusesell_local/utils/logger.py +203 -0
  33. fusesell_local/utils/output_helpers.py +2443 -0
  34. fusesell_local/utils/timezone_detector.py +914 -0
  35. fusesell_local/utils/validators.py +436 -0
@@ -0,0 +1,277 @@
1
+ """
2
+ Configuration Manager for FuseSell Local
3
+ Handles team-specific settings, prompts, and business rules
4
+ """
5
+
6
+ import json
7
+ from typing import Dict, Any, Optional
8
+ from pathlib import Path
9
+ import logging
10
+
11
+
12
+ class ConfigManager:
13
+ """
14
+ Manages configuration settings for FuseSell Local.
15
+ Handles team-specific prompts, scoring criteria, and business rules.
16
+ """
17
+
18
+ def __init__(self, data_dir: str = "./fusesell_data"):
19
+ """
20
+ Initialize configuration manager.
21
+
22
+ Args:
23
+ data_dir: Directory containing configuration files
24
+ """
25
+ self.data_dir = Path(data_dir)
26
+ self.config_dir = self.data_dir / "config"
27
+ self.logger = logging.getLogger("fusesell.config")
28
+
29
+ # Ensure config directory exists
30
+ self.config_dir.mkdir(parents=True, exist_ok=True)
31
+
32
+ # Cache for loaded configurations
33
+ self._cache = {}
34
+
35
+ def get_prompts(self, team_id: Optional[str] = None, language: str = "english") -> Dict[str, Any]:
36
+ """
37
+ Get LLM prompts for stages, with team and language customization.
38
+
39
+ Args:
40
+ team_id: Optional team ID for team-specific prompts
41
+ language: Language for prompts
42
+
43
+ Returns:
44
+ Dictionary of prompts organized by stage
45
+ """
46
+ cache_key = f"prompts_{team_id}_{language}"
47
+
48
+ if cache_key in self._cache:
49
+ return self._cache[cache_key]
50
+
51
+ # Load base prompts
52
+ base_prompts = self._load_json_config("prompts.json", {})
53
+
54
+ # Apply team customizations if available
55
+ if team_id:
56
+ team_prompts = self._load_team_prompts(team_id, language)
57
+ base_prompts = self._merge_configs(base_prompts, team_prompts)
58
+
59
+ # Apply language customizations
60
+ if language != "english":
61
+ lang_prompts = self._load_language_prompts(language)
62
+ base_prompts = self._merge_configs(base_prompts, lang_prompts)
63
+
64
+ self._cache[cache_key] = base_prompts
65
+ return base_prompts
66
+
67
+ def get_scoring_criteria(self, team_id: Optional[str] = None) -> Dict[str, Any]:
68
+ """
69
+ Get lead scoring criteria with team customization.
70
+
71
+ Args:
72
+ team_id: Optional team ID for team-specific criteria
73
+
74
+ Returns:
75
+ Dictionary of scoring criteria and weights
76
+ """
77
+ cache_key = f"scoring_{team_id}"
78
+
79
+ if cache_key in self._cache:
80
+ return self._cache[cache_key]
81
+
82
+ # Load base scoring criteria
83
+ base_criteria = self._load_json_config("scoring_criteria.json", {})
84
+
85
+ # Apply team customizations if available
86
+ if team_id:
87
+ team_criteria = self._load_team_scoring(team_id)
88
+ base_criteria = self._merge_configs(base_criteria, team_criteria)
89
+
90
+ self._cache[cache_key] = base_criteria
91
+ return base_criteria
92
+
93
+ def get_email_templates(self, team_id: Optional[str] = None, language: str = "english") -> Dict[str, Any]:
94
+ """
95
+ Get email templates with team and language customization.
96
+
97
+ Args:
98
+ team_id: Optional team ID for team-specific templates
99
+ language: Language for templates
100
+
101
+ Returns:
102
+ Dictionary of email templates
103
+ """
104
+ cache_key = f"templates_{team_id}_{language}"
105
+
106
+ if cache_key in self._cache:
107
+ return self._cache[cache_key]
108
+
109
+ # Load base templates
110
+ base_templates = self._load_json_config("email_templates.json", {})
111
+
112
+ # Apply team customizations if available
113
+ if team_id:
114
+ team_templates = self._load_team_templates(team_id, language)
115
+ base_templates = self._merge_configs(base_templates, team_templates)
116
+
117
+ # Apply language customizations
118
+ if language != "english":
119
+ lang_templates = self._load_language_templates(language)
120
+ base_templates = self._merge_configs(base_templates, lang_templates)
121
+
122
+ self._cache[cache_key] = base_templates
123
+ return base_templates
124
+
125
+ def get_business_rules(self, team_id: Optional[str] = None) -> Dict[str, Any]:
126
+ """
127
+ Get business rules and pipeline behavior settings.
128
+
129
+ Args:
130
+ team_id: Optional team ID for team-specific rules
131
+
132
+ Returns:
133
+ Dictionary of business rules
134
+ """
135
+ cache_key = f"rules_{team_id}"
136
+
137
+ if cache_key in self._cache:
138
+ return self._cache[cache_key]
139
+
140
+ # Default business rules based on original system
141
+ default_rules = {
142
+ "pipeline": {
143
+ "stop_on_website_fail": True,
144
+ "wait_after_draft_generation": True,
145
+ "max_operations": 10,
146
+ "max_simultaneous_operations": 1,
147
+ "sequential_execution_only": True
148
+ },
149
+ "data_acquisition": {
150
+ "min_execution_time_seconds": 100,
151
+ "required_sources": ["website"],
152
+ "optional_sources": ["business_card", "linkedin", "facebook"]
153
+ },
154
+ "initial_outreach": {
155
+ "actions": ["draft_write", "draft_rewrite", "send", "close"],
156
+ "default_action": "draft_write",
157
+ "require_human_approval": True,
158
+ "one_action_per_trigger": True
159
+ },
160
+ "follow_up": {
161
+ "actions": ["draft_write", "draft_rewrite", "send"],
162
+ "require_explicit_trigger": True,
163
+ "analyze_previous_interactions": True
164
+ }
165
+ }
166
+
167
+ # Apply team customizations if available
168
+ if team_id:
169
+ team_rules = self._load_team_rules(team_id)
170
+ default_rules = self._merge_configs(default_rules, team_rules)
171
+
172
+ self._cache[cache_key] = default_rules
173
+ return default_rules
174
+
175
+ def _load_json_config(self, filename: str, default: Dict[str, Any]) -> Dict[str, Any]:
176
+ """Load JSON configuration file with fallback to default."""
177
+ try:
178
+ config_file = self.config_dir / filename
179
+ if config_file.exists():
180
+ with open(config_file, 'r', encoding='utf-8') as f:
181
+ return json.load(f)
182
+ except Exception as e:
183
+ self.logger.warning(f"Failed to load {filename}: {str(e)}")
184
+
185
+ return default.copy()
186
+
187
+ def _load_team_prompts(self, team_id: str, language: str) -> Dict[str, Any]:
188
+ """Load team-specific prompts."""
189
+ team_file = self.config_dir / f"team_{team_id}_prompts_{language}.json"
190
+ return self._load_json_config(team_file.name, {})
191
+
192
+ def _load_team_scoring(self, team_id: str) -> Dict[str, Any]:
193
+ """Load team-specific scoring criteria."""
194
+ team_file = self.config_dir / f"team_{team_id}_scoring.json"
195
+ return self._load_json_config(team_file.name, {})
196
+
197
+ def _load_team_templates(self, team_id: str, language: str) -> Dict[str, Any]:
198
+ """Load team-specific email templates."""
199
+ team_file = self.config_dir / f"team_{team_id}_templates_{language}.json"
200
+ return self._load_json_config(team_file.name, {})
201
+
202
+ def _load_team_rules(self, team_id: str) -> Dict[str, Any]:
203
+ """Load team-specific business rules."""
204
+ team_file = self.config_dir / f"team_{team_id}_rules.json"
205
+ return self._load_json_config(team_file.name, {})
206
+
207
+ def _load_language_prompts(self, language: str) -> Dict[str, Any]:
208
+ """Load language-specific prompts."""
209
+ lang_file = self.config_dir / f"prompts_{language}.json"
210
+ return self._load_json_config(lang_file.name, {})
211
+
212
+ def _load_language_templates(self, language: str) -> Dict[str, Any]:
213
+ """Load language-specific email templates."""
214
+ lang_file = self.config_dir / f"templates_{language}.json"
215
+ return self._load_json_config(lang_file.name, {})
216
+
217
+ def _merge_configs(self, base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
218
+ """
219
+ Recursively merge configuration dictionaries.
220
+
221
+ Args:
222
+ base: Base configuration
223
+ override: Override configuration
224
+
225
+ Returns:
226
+ Merged configuration
227
+ """
228
+ result = base.copy()
229
+
230
+ for key, value in override.items():
231
+ if key in result and isinstance(result[key], dict) and isinstance(value, dict):
232
+ result[key] = self._merge_configs(result[key], value)
233
+ else:
234
+ result[key] = value
235
+
236
+ return result
237
+
238
+ def save_team_config(self, team_id: str, config_type: str, config_data: Dict[str, Any], language: str = "english") -> None:
239
+ """
240
+ Save team-specific configuration.
241
+
242
+ Args:
243
+ team_id: Team identifier
244
+ config_type: Type of config (prompts, scoring, templates, rules)
245
+ config_data: Configuration data to save
246
+ language: Language for prompts/templates
247
+ """
248
+ try:
249
+ if config_type in ["prompts", "templates"]:
250
+ filename = f"team_{team_id}_{config_type}_{language}.json"
251
+ else:
252
+ filename = f"team_{team_id}_{config_type}.json"
253
+
254
+ config_file = self.config_dir / filename
255
+
256
+ with open(config_file, 'w', encoding='utf-8') as f:
257
+ json.dump(config_data, f, indent=2, ensure_ascii=False)
258
+
259
+ # Clear cache for this team
260
+ self._clear_team_cache(team_id)
261
+
262
+ self.logger.info(f"Saved team configuration: {filename}")
263
+
264
+ except Exception as e:
265
+ self.logger.error(f"Failed to save team config {config_type} for {team_id}: {str(e)}")
266
+ raise
267
+
268
+ def _clear_team_cache(self, team_id: str) -> None:
269
+ """Clear cached configurations for a specific team."""
270
+ keys_to_remove = [key for key in self._cache.keys() if team_id in key]
271
+ for key in keys_to_remove:
272
+ del self._cache[key]
273
+
274
+ def clear_cache(self) -> None:
275
+ """Clear all cached configurations."""
276
+ self._cache.clear()
277
+ self.logger.debug("Configuration cache cleared")