fusesell 1.2.8__tar.gz → 1.2.9__tar.gz
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.
Potentially problematic release.
This version of fusesell might be problematic. Click here for more details.
- {fusesell-1.2.8 → fusesell-1.2.9}/CHANGELOG.md +242 -231
- {fusesell-1.2.8/fusesell.egg-info → fusesell-1.2.9}/PKG-INFO +1 -1
- {fusesell-1.2.8 → fusesell-1.2.9/fusesell.egg-info}/PKG-INFO +1 -1
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/__init__.py +1 -1
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/initial_outreach.py +78 -4
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/event_scheduler.py +42 -14
- {fusesell-1.2.8 → fusesell-1.2.9}/pyproject.toml +1 -1
- {fusesell-1.2.8 → fusesell-1.2.9}/LICENSE +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/MANIFEST.in +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/README.md +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.egg-info/SOURCES.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.egg-info/dependency_links.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.egg-info/entry_points.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.egg-info/requires.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.egg-info/top_level.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/api.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/cli.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/config/__init__.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/config/prompts.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/config/settings.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/pipeline.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/__init__.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/base_stage.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/data_acquisition.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/data_preparation.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/follow_up.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/stages/lead_scoring.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/conftest.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/test_api.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/test_cli.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/test_data_manager_products.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/test_data_manager_sales_process.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/tests/test_data_manager_teams.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/__init__.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/birthday_email_manager.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/data_manager.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/llm_client.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/logger.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/timezone_detector.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/fusesell_local/utils/validators.py +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/requirements.txt +0 -0
- {fusesell-1.2.8 → fusesell-1.2.9}/setup.cfg +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to FuseSell Local will be documented in this file.
|
|
4
4
|
|
|
5
|
+
# [1.2.9] - 2025-10-24
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Primary sales rep metadata from gs_team_rep now flows into draft prompts, reminders, and signatures so outreach reflects the configured sender.
|
|
9
|
+
- Reminder scheduling stores the Unix timestamp (cron_ts) alongside the ISO string for easier downstream filtering.
|
|
10
|
+
- Greeting sanitizer standardises the first paragraph and removes duplicate salutations while keeping HTML formatting intact.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Removed [Your ...] placeholder leftovers inside LLM responses and ensured drafts remain valid HTML even when the model mixes plain text and bullet lists.
|
|
14
|
+
- Reminder creation no longer fails when the data acquisition stage supplies the email address, and follow-up reminders inherit the same customer metadata.
|
|
15
|
+
|
|
5
16
|
# [1.2.8] - 2025-10-24
|
|
6
17
|
|
|
7
18
|
### Changed
|
|
@@ -57,7 +68,7 @@ All notable changes to FuseSell Local will be documented in this file.
|
|
|
57
68
|
|
|
58
69
|
### Fixed
|
|
59
70
|
- Default team settings seeding now targets the `gs_team_*` columns, preventing initialization failures on fresh databases.
|
|
60
|
-
|
|
71
|
+
|
|
61
72
|
# [1.2.1] - 2025-10-21
|
|
62
73
|
|
|
63
74
|
### Changed
|
|
@@ -71,234 +82,234 @@ All notable changes to FuseSell Local will be documented in this file.
|
|
|
71
82
|
### Added
|
|
72
83
|
- Packaged CLI access via `FuseSellCLI` export to support embedded runtimes and automated tests.
|
|
73
84
|
- pytest coverage (`fusesell_local/tests/test_cli.py`) ensuring the CLI dry-run path remains stable.
|
|
74
|
-
|
|
75
|
-
### Changed
|
|
76
|
-
- Distribution renamed to `fusesell` to align with upcoming PyPI publication; console entry point now resolves to `fusesell_local.cli:main`.
|
|
77
|
-
- CLI implementation moved into `fusesell_local/cli.py`, with top-level `fusesell.py` delegating for backward compatibility.
|
|
78
|
-
- Documentation refreshed to instruct `pip install fusesell` and demonstrate programmatic CLI reuse.
|
|
79
|
-
- Published version `1.2.0` to PyPI under the `fusesell` distribution name.
|
|
80
|
-
|
|
81
|
-
### Fixed
|
|
82
|
-
- Ensured package metadata includes the CLI module so installations via pip expose the `fusesell` console script.
|
|
83
|
-
|
|
84
|
-
## [1.1.0] - 2025-10-20
|
|
85
|
-
|
|
86
|
-
### Added
|
|
87
|
-
- Library-first API (`fusesell_local.api`) exposing `build_config`, `execute_pipeline`, and supporting helpers for embedding FuseSell in external runtimes.
|
|
88
|
-
- Public exports in `fusesell_local.__init__` so consumers can import `FuseSellPipeline` and the new helpers directly.
|
|
89
|
-
- Programmatic configuration validation error (`ConfigValidationError`) for clearer failures in host applications.
|
|
90
|
-
|
|
91
|
-
### Changed
|
|
92
|
-
- CLI now delegates configuration/build/validation/logging to the shared library utilities, ensuring consistent behaviour across CLI and embedded usage.
|
|
93
|
-
- Pipeline context now forwards scheduling preferences (timezone, send_immediately, business hour fields) from configuration to stages.
|
|
94
|
-
|
|
95
|
-
### Fixed
|
|
96
|
-
- Continuation validation correctly requires `selected_draft_id` when performing `draft_rewrite` or `send` actions.
|
|
97
|
-
|
|
98
|
-
## [1.0.0] - 2025-01-07
|
|
99
|
-
|
|
100
|
-
### Added - Core Infrastructure Complete
|
|
101
|
-
|
|
102
|
-
#### CLI Interface
|
|
103
|
-
- Complete command-line interface with 25+ configuration options
|
|
104
|
-
- Comprehensive argument validation and error handling
|
|
105
|
-
- Multiple output formats (JSON, YAML, text)
|
|
106
|
-
- Dry-run mode for safe testing
|
|
107
|
-
- Process continuation support for resuming executions
|
|
108
|
-
|
|
109
|
-
#### Pipeline Engine
|
|
110
|
-
- Full pipeline orchestration with stage control
|
|
111
|
-
- Business logic validation extracted from original YAML workflows
|
|
112
|
-
- Sequential stage execution with data flow management
|
|
113
|
-
- Human-in-the-loop controls and approval points
|
|
114
|
-
- Comprehensive error handling and recovery mechanisms
|
|
115
|
-
- Execution tracking and detailed logging
|
|
116
|
-
|
|
117
|
-
#### Data Management
|
|
118
|
-
- SQLite database with complete schema for all data entities
|
|
119
|
-
- CRUD operations for executions, customers, lead scores, and email drafts
|
|
120
|
-
- Data export/import functionality for backup and migration
|
|
121
|
-
- Local data storage ensuring complete data ownership
|
|
122
|
-
|
|
123
|
-
#### Configuration System
|
|
124
|
-
- Team-specific configuration management
|
|
125
|
-
- Customizable LLM prompts for all stages
|
|
126
|
-
- Configurable scoring criteria and email templates
|
|
127
|
-
- JSON-based configuration files with validation
|
|
128
|
-
|
|
129
|
-
#### LLM Integration
|
|
130
|
-
- OpenAI GPT-4o-mini client with error handling
|
|
131
|
-
- Structured response parsing and validation
|
|
132
|
-
- Token usage tracking and optimization
|
|
133
|
-
- Response caching and retry mechanisms
|
|
134
|
-
|
|
135
|
-
#### Documentation
|
|
136
|
-
- Comprehensive README with installation and usage instructions
|
|
137
|
-
- Technical documentation covering architecture and APIs
|
|
138
|
-
- Business logic documentation extracted from original system
|
|
139
|
-
- Troubleshooting guide and development workflow
|
|
140
|
-
|
|
141
|
-
### Technical Details
|
|
142
|
-
|
|
143
|
-
#### Project Structure
|
|
144
|
-
```
|
|
145
|
-
fusesell-local/
|
|
146
|
-
fusesell.py # Main CLI entry point
|
|
147
|
-
requirements.txt # Python dependencies
|
|
148
|
-
setup.py # Package installation
|
|
149
|
-
README.md # User documentation
|
|
150
|
-
TECHNICAL.md # Technical documentation
|
|
151
|
-
CHANGELOG.md # This file
|
|
152
|
-
business_logic.md # Business logic documentation
|
|
153
|
-
fusesell_local/ # Main package
|
|
154
|
-
pipeline.py # Pipeline orchestrator
|
|
155
|
-
stages/ # Pipeline stages (base implementation)
|
|
156
|
-
utils/ # Utilities (data, LLM, validation, logging)
|
|
157
|
-
config/ # Configuration management
|
|
158
|
-
fusesell_data/ # Local data storage
|
|
159
|
-
config/ # Configuration files
|
|
160
|
-
drafts/ # Generated email drafts
|
|
161
|
-
logs/ # Execution logs
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
#### Key Features Implemented
|
|
165
|
-
- **Local Execution**: Complete data ownership with no external dependencies except LLM API
|
|
166
|
-
- **Business Logic Preservation**: All orchestration intelligence from original YAML workflows
|
|
167
|
-
- **Flexible Data Sources**: Support for websites, business cards, social media, and manual input
|
|
168
|
-
- **Stage Control**: Skip stages, stop after specific stages, save intermediate results
|
|
169
|
-
- **Process Continuation**: Resume executions from any point with specific actions
|
|
170
|
-
- **Comprehensive Validation**: Input validation, configuration validation, and error handling
|
|
171
|
-
- **Extensible Architecture**: Modular design for easy customization and extension
|
|
172
|
-
|
|
173
|
-
#### Database Schema
|
|
174
|
-
- `executions`: Execution tracking and metadata
|
|
175
|
-
- `stage_results`: Individual stage outputs and status
|
|
176
|
-
- `customers`: Customer profiles and contact information
|
|
177
|
-
- `lead_scores`: Scoring results and recommendations
|
|
178
|
-
- `email_drafts`: Generated email content and variations
|
|
179
|
-
|
|
180
|
-
#### Configuration Files
|
|
181
|
-
- `prompts.json`: LLM prompts for all stages
|
|
182
|
-
- `scoring_criteria.json`: Lead scoring rules and weights
|
|
183
|
-
- `email_templates.json`: Email template variations
|
|
184
|
-
- `team_settings.json`: Team-specific configurations
|
|
185
|
-
|
|
186
|
-
### Next Phase - Stage Implementations
|
|
187
|
-
|
|
188
|
-
The core infrastructure is complete and ready for individual stage implementations:
|
|
189
|
-
|
|
190
|
-
#### Planned Stage Development
|
|
191
|
-
1. **Data Acquisition**: Website scraping, business card OCR, social media extraction
|
|
192
|
-
2. **Data Preparation**: AI-powered data structuring and pain point identification
|
|
193
|
-
3. **Lead Scoring**: Product-customer fit evaluation with detailed breakdowns
|
|
194
|
-
4. **Initial Outreach**: Personalized email generation with multiple approaches
|
|
195
|
-
5. **Follow-up**: Context-aware follow-up sequences and timing optimization
|
|
196
|
-
|
|
197
|
-
#### Development Status
|
|
198
|
-
- Core infrastructure (CLI, pipeline, database, configuration)
|
|
199
|
-
- Business logic validation and orchestration rules
|
|
200
|
-
- Process continuation and human-in-the-loop controls
|
|
201
|
-
- Comprehensive documentation and user guides
|
|
202
|
-
- Individual stage implementations (next development phase)
|
|
203
|
-
|
|
204
|
-
### Migration from Server-Based System
|
|
205
|
-
|
|
206
|
-
This release represents a complete conversion of the server-based FuseSell system to a local implementation:
|
|
207
|
-
|
|
208
|
-
#### Preserved Features
|
|
209
|
-
- All business logic and orchestration intelligence
|
|
210
|
-
- Team-specific prompts and configuration
|
|
211
|
-
- Human approval workflows and controls
|
|
212
|
-
- Comprehensive logging and execution tracking
|
|
213
|
-
- Multi-stage pipeline with flexible control
|
|
214
|
-
|
|
215
|
-
#### Enhanced Features
|
|
216
|
-
- Complete local data ownership and privacy
|
|
217
|
-
- Command-line interface with extensive options
|
|
218
|
-
- Process continuation and recovery capabilities
|
|
219
|
-
- Flexible data source handling
|
|
220
|
-
- Enhanced error handling and validation
|
|
221
|
-
|
|
222
|
-
#### Architectural Improvements
|
|
223
|
-
- Modular, extensible design
|
|
224
|
-
- Comprehensive input validation
|
|
225
|
-
- Local SQLite database for performance
|
|
226
|
-
- Configuration-driven customization
|
|
227
|
-
- Detailed technical documentation
|
|
228
|
-
|
|
229
|
-
### Installation and Usage
|
|
230
|
-
|
|
231
|
-
#### Requirements
|
|
232
|
-
- Python 3.8+
|
|
233
|
-
- OpenAI API key
|
|
234
|
-
- 50MB disk space for installation
|
|
235
|
-
- Additional space for data storage (varies by usage)
|
|
236
|
-
|
|
237
|
-
#### Quick Start
|
|
238
|
-
```bash
|
|
239
|
-
# Install dependencies
|
|
240
|
-
pip install -r requirements.txt
|
|
241
|
-
|
|
242
|
-
# Run basic execution
|
|
243
|
-
python fusesell.py --openai-api-key YOUR_API_KEY \
|
|
244
|
-
--org-id your_org \
|
|
245
|
-
--org-name "Your Company" \
|
|
246
|
-
--customer-website "https://example.com"
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
#### Advanced Usage
|
|
250
|
-
```bash
|
|
251
|
-
# Full pipeline with custom settings
|
|
252
|
-
python fusesell.py --openai-api-key sk-xxx \
|
|
253
|
-
--org-id rta \
|
|
254
|
-
--org-name "RTA Corp" \
|
|
255
|
-
--customer-website "https://example.com" \
|
|
256
|
-
--customer-name "Acme Inc" \
|
|
257
|
-
--contact-name "John Doe" \
|
|
258
|
-
--team-id sales_team_1 \
|
|
259
|
-
--language english \
|
|
260
|
-
--output-format json \
|
|
261
|
-
--data-dir ./custom_data
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Support and Development
|
|
265
|
-
|
|
266
|
-
For technical support, feature requests, or contributions:
|
|
267
|
-
- Review the technical documentation in `TECHNICAL.md`
|
|
268
|
-
- Check the troubleshooting guide for common issues
|
|
269
|
-
- Refer to the business logic documentation for workflow details
|
|
270
|
-
- Contact the development team for advanced customization needs
|
|
271
|
-
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
## Future Releases
|
|
275
|
-
|
|
276
|
-
### [1.1.0] - Planned
|
|
277
|
-
- Complete data acquisition stage implementation
|
|
278
|
-
- Website scraping with content extraction
|
|
279
|
-
- Business card OCR processing
|
|
280
|
-
- Social media profile data extraction
|
|
281
|
-
|
|
282
|
-
### [1.2.0] - Planned
|
|
283
|
-
- Complete data preparation stage implementation
|
|
284
|
-
- AI-powered customer profiling
|
|
285
|
-
- Pain point identification and analysis
|
|
286
|
-
- Financial and technology stack analysis
|
|
287
|
-
|
|
288
|
-
### [1.3.0] - Planned
|
|
289
|
-
- Complete lead scoring stage implementation
|
|
290
|
-
- Product-customer fit evaluation
|
|
291
|
-
- Detailed scoring breakdowns and recommendations
|
|
292
|
-
- Multi-product scoring capabilities
|
|
293
|
-
|
|
294
|
-
### [1.4.0] - Planned
|
|
295
|
-
- Complete initial outreach stage implementation
|
|
296
|
-
- Personalized email generation
|
|
297
|
-
- Multiple draft variations and approaches
|
|
298
|
-
- Human review workflow integration
|
|
299
|
-
|
|
300
|
-
### [1.5.0] - Planned
|
|
301
|
-
- Complete follow-up stage implementation
|
|
302
|
-
- Context-aware follow-up sequences
|
|
303
|
-
- Interaction history analysis
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
- Distribution renamed to `fusesell` to align with upcoming PyPI publication; console entry point now resolves to `fusesell_local.cli:main`.
|
|
88
|
+
- CLI implementation moved into `fusesell_local/cli.py`, with top-level `fusesell.py` delegating for backward compatibility.
|
|
89
|
+
- Documentation refreshed to instruct `pip install fusesell` and demonstrate programmatic CLI reuse.
|
|
90
|
+
- Published version `1.2.0` to PyPI under the `fusesell` distribution name.
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
- Ensured package metadata includes the CLI module so installations via pip expose the `fusesell` console script.
|
|
94
|
+
|
|
95
|
+
## [1.1.0] - 2025-10-20
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
- Library-first API (`fusesell_local.api`) exposing `build_config`, `execute_pipeline`, and supporting helpers for embedding FuseSell in external runtimes.
|
|
99
|
+
- Public exports in `fusesell_local.__init__` so consumers can import `FuseSellPipeline` and the new helpers directly.
|
|
100
|
+
- Programmatic configuration validation error (`ConfigValidationError`) for clearer failures in host applications.
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
- CLI now delegates configuration/build/validation/logging to the shared library utilities, ensuring consistent behaviour across CLI and embedded usage.
|
|
104
|
+
- Pipeline context now forwards scheduling preferences (timezone, send_immediately, business hour fields) from configuration to stages.
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
- Continuation validation correctly requires `selected_draft_id` when performing `draft_rewrite` or `send` actions.
|
|
108
|
+
|
|
109
|
+
## [1.0.0] - 2025-01-07
|
|
110
|
+
|
|
111
|
+
### Added - Core Infrastructure Complete
|
|
112
|
+
|
|
113
|
+
#### CLI Interface
|
|
114
|
+
- Complete command-line interface with 25+ configuration options
|
|
115
|
+
- Comprehensive argument validation and error handling
|
|
116
|
+
- Multiple output formats (JSON, YAML, text)
|
|
117
|
+
- Dry-run mode for safe testing
|
|
118
|
+
- Process continuation support for resuming executions
|
|
119
|
+
|
|
120
|
+
#### Pipeline Engine
|
|
121
|
+
- Full pipeline orchestration with stage control
|
|
122
|
+
- Business logic validation extracted from original YAML workflows
|
|
123
|
+
- Sequential stage execution with data flow management
|
|
124
|
+
- Human-in-the-loop controls and approval points
|
|
125
|
+
- Comprehensive error handling and recovery mechanisms
|
|
126
|
+
- Execution tracking and detailed logging
|
|
127
|
+
|
|
128
|
+
#### Data Management
|
|
129
|
+
- SQLite database with complete schema for all data entities
|
|
130
|
+
- CRUD operations for executions, customers, lead scores, and email drafts
|
|
131
|
+
- Data export/import functionality for backup and migration
|
|
132
|
+
- Local data storage ensuring complete data ownership
|
|
133
|
+
|
|
134
|
+
#### Configuration System
|
|
135
|
+
- Team-specific configuration management
|
|
136
|
+
- Customizable LLM prompts for all stages
|
|
137
|
+
- Configurable scoring criteria and email templates
|
|
138
|
+
- JSON-based configuration files with validation
|
|
139
|
+
|
|
140
|
+
#### LLM Integration
|
|
141
|
+
- OpenAI GPT-4o-mini client with error handling
|
|
142
|
+
- Structured response parsing and validation
|
|
143
|
+
- Token usage tracking and optimization
|
|
144
|
+
- Response caching and retry mechanisms
|
|
145
|
+
|
|
146
|
+
#### Documentation
|
|
147
|
+
- Comprehensive README with installation and usage instructions
|
|
148
|
+
- Technical documentation covering architecture and APIs
|
|
149
|
+
- Business logic documentation extracted from original system
|
|
150
|
+
- Troubleshooting guide and development workflow
|
|
151
|
+
|
|
152
|
+
### Technical Details
|
|
153
|
+
|
|
154
|
+
#### Project Structure
|
|
155
|
+
```
|
|
156
|
+
fusesell-local/
|
|
157
|
+
fusesell.py # Main CLI entry point
|
|
158
|
+
requirements.txt # Python dependencies
|
|
159
|
+
setup.py # Package installation
|
|
160
|
+
README.md # User documentation
|
|
161
|
+
TECHNICAL.md # Technical documentation
|
|
162
|
+
CHANGELOG.md # This file
|
|
163
|
+
business_logic.md # Business logic documentation
|
|
164
|
+
fusesell_local/ # Main package
|
|
165
|
+
pipeline.py # Pipeline orchestrator
|
|
166
|
+
stages/ # Pipeline stages (base implementation)
|
|
167
|
+
utils/ # Utilities (data, LLM, validation, logging)
|
|
168
|
+
config/ # Configuration management
|
|
169
|
+
fusesell_data/ # Local data storage
|
|
170
|
+
config/ # Configuration files
|
|
171
|
+
drafts/ # Generated email drafts
|
|
172
|
+
logs/ # Execution logs
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Key Features Implemented
|
|
176
|
+
- **Local Execution**: Complete data ownership with no external dependencies except LLM API
|
|
177
|
+
- **Business Logic Preservation**: All orchestration intelligence from original YAML workflows
|
|
178
|
+
- **Flexible Data Sources**: Support for websites, business cards, social media, and manual input
|
|
179
|
+
- **Stage Control**: Skip stages, stop after specific stages, save intermediate results
|
|
180
|
+
- **Process Continuation**: Resume executions from any point with specific actions
|
|
181
|
+
- **Comprehensive Validation**: Input validation, configuration validation, and error handling
|
|
182
|
+
- **Extensible Architecture**: Modular design for easy customization and extension
|
|
183
|
+
|
|
184
|
+
#### Database Schema
|
|
185
|
+
- `executions`: Execution tracking and metadata
|
|
186
|
+
- `stage_results`: Individual stage outputs and status
|
|
187
|
+
- `customers`: Customer profiles and contact information
|
|
188
|
+
- `lead_scores`: Scoring results and recommendations
|
|
189
|
+
- `email_drafts`: Generated email content and variations
|
|
190
|
+
|
|
191
|
+
#### Configuration Files
|
|
192
|
+
- `prompts.json`: LLM prompts for all stages
|
|
193
|
+
- `scoring_criteria.json`: Lead scoring rules and weights
|
|
194
|
+
- `email_templates.json`: Email template variations
|
|
195
|
+
- `team_settings.json`: Team-specific configurations
|
|
196
|
+
|
|
197
|
+
### Next Phase - Stage Implementations
|
|
198
|
+
|
|
199
|
+
The core infrastructure is complete and ready for individual stage implementations:
|
|
200
|
+
|
|
201
|
+
#### Planned Stage Development
|
|
202
|
+
1. **Data Acquisition**: Website scraping, business card OCR, social media extraction
|
|
203
|
+
2. **Data Preparation**: AI-powered data structuring and pain point identification
|
|
204
|
+
3. **Lead Scoring**: Product-customer fit evaluation with detailed breakdowns
|
|
205
|
+
4. **Initial Outreach**: Personalized email generation with multiple approaches
|
|
206
|
+
5. **Follow-up**: Context-aware follow-up sequences and timing optimization
|
|
207
|
+
|
|
208
|
+
#### Development Status
|
|
209
|
+
- Core infrastructure (CLI, pipeline, database, configuration)
|
|
210
|
+
- Business logic validation and orchestration rules
|
|
211
|
+
- Process continuation and human-in-the-loop controls
|
|
212
|
+
- Comprehensive documentation and user guides
|
|
213
|
+
- Individual stage implementations (next development phase)
|
|
214
|
+
|
|
215
|
+
### Migration from Server-Based System
|
|
216
|
+
|
|
217
|
+
This release represents a complete conversion of the server-based FuseSell system to a local implementation:
|
|
218
|
+
|
|
219
|
+
#### Preserved Features
|
|
220
|
+
- All business logic and orchestration intelligence
|
|
221
|
+
- Team-specific prompts and configuration
|
|
222
|
+
- Human approval workflows and controls
|
|
223
|
+
- Comprehensive logging and execution tracking
|
|
224
|
+
- Multi-stage pipeline with flexible control
|
|
225
|
+
|
|
226
|
+
#### Enhanced Features
|
|
227
|
+
- Complete local data ownership and privacy
|
|
228
|
+
- Command-line interface with extensive options
|
|
229
|
+
- Process continuation and recovery capabilities
|
|
230
|
+
- Flexible data source handling
|
|
231
|
+
- Enhanced error handling and validation
|
|
232
|
+
|
|
233
|
+
#### Architectural Improvements
|
|
234
|
+
- Modular, extensible design
|
|
235
|
+
- Comprehensive input validation
|
|
236
|
+
- Local SQLite database for performance
|
|
237
|
+
- Configuration-driven customization
|
|
238
|
+
- Detailed technical documentation
|
|
239
|
+
|
|
240
|
+
### Installation and Usage
|
|
241
|
+
|
|
242
|
+
#### Requirements
|
|
243
|
+
- Python 3.8+
|
|
244
|
+
- OpenAI API key
|
|
245
|
+
- 50MB disk space for installation
|
|
246
|
+
- Additional space for data storage (varies by usage)
|
|
247
|
+
|
|
248
|
+
#### Quick Start
|
|
249
|
+
```bash
|
|
250
|
+
# Install dependencies
|
|
251
|
+
pip install -r requirements.txt
|
|
252
|
+
|
|
253
|
+
# Run basic execution
|
|
254
|
+
python fusesell.py --openai-api-key YOUR_API_KEY \
|
|
255
|
+
--org-id your_org \
|
|
256
|
+
--org-name "Your Company" \
|
|
257
|
+
--customer-website "https://example.com"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Advanced Usage
|
|
261
|
+
```bash
|
|
262
|
+
# Full pipeline with custom settings
|
|
263
|
+
python fusesell.py --openai-api-key sk-xxx \
|
|
264
|
+
--org-id rta \
|
|
265
|
+
--org-name "RTA Corp" \
|
|
266
|
+
--customer-website "https://example.com" \
|
|
267
|
+
--customer-name "Acme Inc" \
|
|
268
|
+
--contact-name "John Doe" \
|
|
269
|
+
--team-id sales_team_1 \
|
|
270
|
+
--language english \
|
|
271
|
+
--output-format json \
|
|
272
|
+
--data-dir ./custom_data
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Support and Development
|
|
276
|
+
|
|
277
|
+
For technical support, feature requests, or contributions:
|
|
278
|
+
- Review the technical documentation in `TECHNICAL.md`
|
|
279
|
+
- Check the troubleshooting guide for common issues
|
|
280
|
+
- Refer to the business logic documentation for workflow details
|
|
281
|
+
- Contact the development team for advanced customization needs
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Future Releases
|
|
286
|
+
|
|
287
|
+
### [1.1.0] - Planned
|
|
288
|
+
- Complete data acquisition stage implementation
|
|
289
|
+
- Website scraping with content extraction
|
|
290
|
+
- Business card OCR processing
|
|
291
|
+
- Social media profile data extraction
|
|
292
|
+
|
|
293
|
+
### [1.2.0] - Planned
|
|
294
|
+
- Complete data preparation stage implementation
|
|
295
|
+
- AI-powered customer profiling
|
|
296
|
+
- Pain point identification and analysis
|
|
297
|
+
- Financial and technology stack analysis
|
|
298
|
+
|
|
299
|
+
### [1.3.0] - Planned
|
|
300
|
+
- Complete lead scoring stage implementation
|
|
301
|
+
- Product-customer fit evaluation
|
|
302
|
+
- Detailed scoring breakdowns and recommendations
|
|
303
|
+
- Multi-product scoring capabilities
|
|
304
|
+
|
|
305
|
+
### [1.4.0] - Planned
|
|
306
|
+
- Complete initial outreach stage implementation
|
|
307
|
+
- Personalized email generation
|
|
308
|
+
- Multiple draft variations and approaches
|
|
309
|
+
- Human review workflow integration
|
|
310
|
+
|
|
311
|
+
### [1.5.0] - Planned
|
|
312
|
+
- Complete follow-up stage implementation
|
|
313
|
+
- Context-aware follow-up sequences
|
|
314
|
+
- Interaction history analysis
|
|
304
315
|
- Automated timing optimization
|
|
@@ -904,6 +904,7 @@ class InitialOutreachStage(BaseStage):
|
|
|
904
904
|
first_name = name_parts[0]
|
|
905
905
|
else:
|
|
906
906
|
first_name = contact_name or ''
|
|
907
|
+
context.setdefault('customer_first_name', first_name or contact_name or '')
|
|
907
908
|
|
|
908
909
|
action = input_data.get('action', 'draft_write')
|
|
909
910
|
action_labels = {
|
|
@@ -1044,7 +1045,7 @@ class InitialOutreachStage(BaseStage):
|
|
|
1044
1045
|
return rep
|
|
1045
1046
|
return reps[0] if reps else {}
|
|
1046
1047
|
|
|
1047
|
-
def _sanitize_email_body(self, html: str, staff_name: str, rep_profile: Dict[str, Any]) -> str:
|
|
1048
|
+
def _sanitize_email_body(self, html: str, staff_name: str, rep_profile: Dict[str, Any], customer_first_name: str) -> str:
|
|
1048
1049
|
if not html:
|
|
1049
1050
|
return ''
|
|
1050
1051
|
|
|
@@ -1065,12 +1066,84 @@ class InitialOutreachStage(BaseStage):
|
|
|
1065
1066
|
else:
|
|
1066
1067
|
html = html.replace(placeholder, '')
|
|
1067
1068
|
|
|
1068
|
-
# Remove any lingering placeholder fragments such as "[Your LinkedIn Profile"
|
|
1069
1069
|
html = re.sub(r'\[Your[^<\]]+\]?', '', html, flags=re.IGNORECASE)
|
|
1070
|
-
|
|
1070
|
+
|
|
1071
|
+
if '<p' not in html.lower():
|
|
1072
|
+
lines = [line.strip() for line in html.splitlines() if line.strip()]
|
|
1073
|
+
if lines:
|
|
1074
|
+
html = ''.join(f'<p>{line}</p>' for line in lines)
|
|
1075
|
+
|
|
1076
|
+
html = self._deduplicate_greeting(html, customer_first_name or '')
|
|
1071
1077
|
html = re.sub(r'(<p>\s*</p>)+', '', html, flags=re.IGNORECASE)
|
|
1072
1078
|
return html
|
|
1073
1079
|
|
|
1080
|
+
def _deduplicate_greeting(self, html: str, customer_first_name: str) -> str:
|
|
1081
|
+
paragraphs = re.findall(r'(<p.*?>.*?</p>)', html, flags=re.IGNORECASE | re.DOTALL)
|
|
1082
|
+
if not paragraphs:
|
|
1083
|
+
return html
|
|
1084
|
+
|
|
1085
|
+
greeting_seen = False
|
|
1086
|
+
cleaned: List[str] = []
|
|
1087
|
+
for para in paragraphs:
|
|
1088
|
+
text = self._strip_html_tags(para).strip()
|
|
1089
|
+
normalized_para = para
|
|
1090
|
+
if self._looks_like_greeting(text):
|
|
1091
|
+
normalized_para = self._standardize_greeting_paragraph(para, customer_first_name)
|
|
1092
|
+
if greeting_seen:
|
|
1093
|
+
continue
|
|
1094
|
+
greeting_seen = True
|
|
1095
|
+
cleaned.append(normalized_para)
|
|
1096
|
+
|
|
1097
|
+
remainder = re.sub(r'(<p.*?>.*?</p>)', '__PARA__', html, flags=re.IGNORECASE | re.DOTALL)
|
|
1098
|
+
rebuilt = ''
|
|
1099
|
+
idx = 0
|
|
1100
|
+
for segment in remainder.split('__PARA__'):
|
|
1101
|
+
rebuilt += segment
|
|
1102
|
+
if idx < len(cleaned):
|
|
1103
|
+
rebuilt += cleaned[idx]
|
|
1104
|
+
idx += 1
|
|
1105
|
+
if idx < len(cleaned):
|
|
1106
|
+
rebuilt += ''.join(cleaned[idx:])
|
|
1107
|
+
return rebuilt
|
|
1108
|
+
|
|
1109
|
+
def _looks_like_greeting(self, text: str) -> bool:
|
|
1110
|
+
lowered = text.lower().replace('\xa0', ' ').strip()
|
|
1111
|
+
return lowered.startswith(('hi ', 'hello ', 'dear '))
|
|
1112
|
+
|
|
1113
|
+
def _standardize_greeting_paragraph(self, paragraph_html: str, customer_first_name: str) -> str:
|
|
1114
|
+
text = self._strip_html_tags(paragraph_html).strip()
|
|
1115
|
+
lowered = text.lower()
|
|
1116
|
+
first_word = next((candidate.title() for candidate in ('dear', 'hello', 'hi') if lowered.startswith(candidate)), 'Hi')
|
|
1117
|
+
|
|
1118
|
+
if customer_first_name:
|
|
1119
|
+
greeting = f"{first_word} {customer_first_name},"
|
|
1120
|
+
else:
|
|
1121
|
+
greeting = f"{first_word} there,"
|
|
1122
|
+
|
|
1123
|
+
remainder = ''
|
|
1124
|
+
match = re.match(r' *(hi|hello|dear)\b[^,]*,(.*)', text, flags=re.IGNORECASE | re.DOTALL)
|
|
1125
|
+
if match:
|
|
1126
|
+
remainder = match.group(2).lstrip()
|
|
1127
|
+
elif lowered.startswith(('hi', 'hello', 'dear')):
|
|
1128
|
+
parts = text.split(',', 1)
|
|
1129
|
+
if len(parts) > 1:
|
|
1130
|
+
remainder = parts[1].lstrip()
|
|
1131
|
+
else:
|
|
1132
|
+
remainder = text[len(text.split(' ', 1)[0]):].lstrip()
|
|
1133
|
+
|
|
1134
|
+
if remainder:
|
|
1135
|
+
sanitized_text = f"{greeting} {remainder}".strip()
|
|
1136
|
+
else:
|
|
1137
|
+
sanitized_text = greeting
|
|
1138
|
+
|
|
1139
|
+
return re.sub(
|
|
1140
|
+
r'(<p.*?>).*?(</p>)',
|
|
1141
|
+
lambda m: f"{m.group(1)}{sanitized_text}{m.group(2)}",
|
|
1142
|
+
paragraph_html,
|
|
1143
|
+
count=1,
|
|
1144
|
+
flags=re.IGNORECASE | re.DOTALL
|
|
1145
|
+
)
|
|
1146
|
+
|
|
1074
1147
|
def _extract_first_name(self, full_name: str) -> str:
|
|
1075
1148
|
if not full_name:
|
|
1076
1149
|
return ''
|
|
@@ -1177,7 +1250,8 @@ class InitialOutreachStage(BaseStage):
|
|
|
1177
1250
|
message_type = entry.get('message_type') or 'Email'
|
|
1178
1251
|
rep_profile = getattr(self, '_active_rep_profile', {}) or {}
|
|
1179
1252
|
staff_name = context.get('input_data', {}).get('staff_name') or self.config.get('staff_name', 'Sales Team')
|
|
1180
|
-
|
|
1253
|
+
first_name = context.get('customer_first_name') or context.get('input_data', {}).get('customer_name') or ''
|
|
1254
|
+
email_body = self._sanitize_email_body(email_body, staff_name, rep_profile, first_name)
|
|
1181
1255
|
|
|
1182
1256
|
metadata = {
|
|
1183
1257
|
'customer_company': customer_data.get('companyInfo', {}).get('name', 'Unknown'),
|
|
@@ -84,6 +84,7 @@ class EventScheduler:
|
|
|
84
84
|
status TEXT NOT NULL,
|
|
85
85
|
task TEXT NOT NULL,
|
|
86
86
|
cron TEXT NOT NULL,
|
|
87
|
+
cron_ts INTEGER,
|
|
87
88
|
room_id TEXT,
|
|
88
89
|
tags TEXT,
|
|
89
90
|
customextra TEXT,
|
|
@@ -115,6 +116,11 @@ class EventScheduler:
|
|
|
115
116
|
CREATE INDEX IF NOT EXISTS idx_reminder_task_cron
|
|
116
117
|
ON reminder_task(cron)
|
|
117
118
|
""")
|
|
119
|
+
|
|
120
|
+
cursor.execute("PRAGMA table_info(reminder_task)")
|
|
121
|
+
columns = {row[1] for row in cursor.fetchall()}
|
|
122
|
+
if 'cron_ts' not in columns:
|
|
123
|
+
cursor.execute("ALTER TABLE reminder_task ADD COLUMN cron_ts INTEGER")
|
|
118
124
|
|
|
119
125
|
conn.commit()
|
|
120
126
|
conn.close()
|
|
@@ -191,6 +197,19 @@ class EventScheduler:
|
|
|
191
197
|
except ValueError:
|
|
192
198
|
return value_str
|
|
193
199
|
|
|
200
|
+
def _to_unix_timestamp(self, value: Union[str, datetime, None]) -> Optional[int]:
|
|
201
|
+
"""
|
|
202
|
+
Convert a datetime-like value to a Unix timestamp (seconds).
|
|
203
|
+
"""
|
|
204
|
+
iso_value = self._format_datetime(value)
|
|
205
|
+
try:
|
|
206
|
+
parsed = datetime.fromisoformat(iso_value)
|
|
207
|
+
except ValueError:
|
|
208
|
+
return None
|
|
209
|
+
if parsed.tzinfo is None:
|
|
210
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
211
|
+
return int(parsed.timestamp())
|
|
212
|
+
|
|
194
213
|
def _build_reminder_payload(
|
|
195
214
|
self,
|
|
196
215
|
base_context: Dict[str, Any],
|
|
@@ -296,11 +315,13 @@ class EventScheduler:
|
|
|
296
315
|
|
|
297
316
|
cron_value = self._format_datetime(cron_value or send_time)
|
|
298
317
|
scheduled_time_str = self._format_datetime(scheduled_time_value or send_time)
|
|
318
|
+
cron_ts = self._to_unix_timestamp(cron_value)
|
|
299
319
|
|
|
300
320
|
return {
|
|
301
321
|
'status': status,
|
|
302
322
|
'task': task_label,
|
|
303
323
|
'cron': cron_value,
|
|
324
|
+
'cron_ts': cron_ts,
|
|
304
325
|
'room_id': room_id,
|
|
305
326
|
'tags': tags,
|
|
306
327
|
'customextra': customextra,
|
|
@@ -346,15 +367,20 @@ class EventScheduler:
|
|
|
346
367
|
conn = sqlite3.connect(self.main_db_path)
|
|
347
368
|
cursor = conn.cursor()
|
|
348
369
|
|
|
370
|
+
cron_ts = payload.get('cron_ts')
|
|
371
|
+
if cron_ts is None:
|
|
372
|
+
cron_ts = self._to_unix_timestamp(payload.get('cron'))
|
|
373
|
+
|
|
349
374
|
cursor.execute("""
|
|
350
375
|
INSERT INTO reminder_task
|
|
351
|
-
(id, status, task, cron, room_id, tags, customextra, org_id, customer_id, task_id, import_uuid, scheduled_time)
|
|
352
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
376
|
+
(id, status, task, cron, cron_ts, room_id, tags, customextra, org_id, customer_id, task_id, import_uuid, scheduled_time)
|
|
377
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
353
378
|
""", (
|
|
354
379
|
reminder_id,
|
|
355
380
|
payload.get('status', 'published'),
|
|
356
381
|
payload.get('task') or 'FuseSell Reminder',
|
|
357
382
|
self._format_datetime(payload.get('cron')),
|
|
383
|
+
cron_ts,
|
|
358
384
|
payload.get('room_id'),
|
|
359
385
|
tags_str,
|
|
360
386
|
customextra_str,
|
|
@@ -455,6 +481,7 @@ class EventScheduler:
|
|
|
455
481
|
draft_id=draft_id,
|
|
456
482
|
customer_timezone=customer_timezone
|
|
457
483
|
)
|
|
484
|
+
reminder_payload.setdefault('cron_ts', self._to_unix_timestamp(reminder_payload.get('cron')))
|
|
458
485
|
reminder_task_id = self._insert_reminder_task(reminder_payload)
|
|
459
486
|
|
|
460
487
|
# Log the scheduling
|
|
@@ -585,6 +612,7 @@ class EventScheduler:
|
|
|
585
612
|
draft_id=original_draft_id,
|
|
586
613
|
customer_timezone=event_data['customer_timezone']
|
|
587
614
|
)
|
|
615
|
+
reminder_payload.setdefault('cron_ts', self._to_unix_timestamp(reminder_payload.get('cron')))
|
|
588
616
|
reminder_task_id = self._insert_reminder_task(reminder_payload)
|
|
589
617
|
|
|
590
618
|
self.logger.info(f"Scheduled follow-up event {followup_event_id} for {follow_up_time}")
|
|
@@ -834,18 +862,18 @@ class EventScheduler:
|
|
|
834
862
|
|
|
835
863
|
# Convert to list of dictionaries
|
|
836
864
|
events = []
|
|
837
|
-
for row in rows:
|
|
838
|
-
event = dict(zip(columns, row))
|
|
839
|
-
# Parse event_data JSON
|
|
840
|
-
if event['event_data']:
|
|
841
|
-
try:
|
|
842
|
-
event['event_data'] = json.loads(event['event_data'])
|
|
843
|
-
except json.JSONDecodeError:
|
|
844
|
-
pass
|
|
845
|
-
events.append(event)
|
|
846
|
-
|
|
847
|
-
return events
|
|
848
|
-
|
|
865
|
+
for row in rows:
|
|
866
|
+
event = dict(zip(columns, row))
|
|
867
|
+
# Parse event_data JSON
|
|
868
|
+
if event['event_data']:
|
|
869
|
+
try:
|
|
870
|
+
event['event_data'] = json.loads(event['event_data'])
|
|
871
|
+
except json.JSONDecodeError:
|
|
872
|
+
pass
|
|
873
|
+
events.append(event)
|
|
874
|
+
|
|
875
|
+
return events
|
|
876
|
+
|
|
849
877
|
except Exception as e:
|
|
850
878
|
self.logger.error(f"Failed to get scheduled events: {str(e)}")
|
|
851
879
|
return []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|