bizy-ai 1.0.0__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.
agent/planner.py ADDED
@@ -0,0 +1,363 @@
1
+ from datetime import datetime, timedelta
2
+ from sqlalchemy import and_
3
+ from agent.models import Goal, BusinessPlan, Task, get_session
4
+ from agent.tasks import TaskManager
5
+ import anthropic
6
+ import os
7
+ import json
8
+
9
+ class BusinessPlanner:
10
+ def __init__(self):
11
+ self.session = get_session()
12
+ self.task_mgr = TaskManager()
13
+ self.client = anthropic.Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY'))
14
+ self.model = "claude-sonnet-4-20250514"
15
+
16
+ # === Business Plan Management ===
17
+
18
+ def create_business_plan(self, vision, mission, value_proposition,
19
+ target_market, revenue_model, key_resources=None,
20
+ key_activities=None, key_partnerships=None,
21
+ cost_structure=None, version="1.0"):
22
+ """Create a new business plan"""
23
+ # Deactivate old plans
24
+ old_plans = self.session.query(BusinessPlan).filter(
25
+ BusinessPlan.is_active == True
26
+ ).all()
27
+ for plan in old_plans:
28
+ plan.is_active = False
29
+
30
+ plan = BusinessPlan(
31
+ version=version,
32
+ vision=vision,
33
+ mission=mission,
34
+ value_proposition=value_proposition,
35
+ target_market=target_market,
36
+ revenue_model=revenue_model,
37
+ key_resources=key_resources or {},
38
+ key_activities=key_activities or [],
39
+ key_partnerships=key_partnerships or [],
40
+ cost_structure=cost_structure or {},
41
+ is_active=True
42
+ )
43
+ self.session.add(plan)
44
+ self.session.commit()
45
+ return plan
46
+
47
+ def get_active_business_plan(self):
48
+ """Get the current active business plan"""
49
+ return self.session.query(BusinessPlan).filter(
50
+ BusinessPlan.is_active == True
51
+ ).first()
52
+
53
+ # === Goal Management ===
54
+
55
+ def create_goal(self, title, description, horizon, target_date=None,
56
+ success_criteria=None, parent_goal_id=None, metrics=None):
57
+ """Create a new goal"""
58
+ goal = Goal(
59
+ title=title,
60
+ description=description,
61
+ horizon=horizon,
62
+ target_date=target_date,
63
+ success_criteria=success_criteria,
64
+ parent_goal_id=parent_goal_id,
65
+ metrics=metrics or {}
66
+ )
67
+ self.session.add(goal)
68
+ self.session.commit()
69
+ return goal
70
+
71
+ def get_goal(self, goal_id):
72
+ """Get a specific goal"""
73
+ return self.session.query(Goal).filter(Goal.id == goal_id).first()
74
+
75
+ def get_active_goals(self):
76
+ """Get all active goals"""
77
+ return self.session.query(Goal).filter(
78
+ Goal.status == 'active'
79
+ ).order_by(Goal.horizon, Goal.target_date).all()
80
+
81
+ def get_goals_by_horizon(self, horizon):
82
+ """Get goals for a specific time horizon"""
83
+ return self.session.query(Goal).filter(
84
+ and_(
85
+ Goal.horizon == horizon,
86
+ Goal.status == 'active'
87
+ )
88
+ ).order_by(Goal.target_date).all()
89
+
90
+ def update_goal_progress(self, goal_id, progress_percentage):
91
+ """Update goal progress"""
92
+ goal = self.get_goal(goal_id)
93
+ if goal:
94
+ goal.progress_percentage = progress_percentage
95
+ goal.updated_at = datetime.now()
96
+
97
+ # Auto-complete if 100%
98
+ if progress_percentage >= 100:
99
+ goal.status = 'completed'
100
+
101
+ self.session.commit()
102
+ return goal
103
+
104
+ def calculate_goal_progress(self, goal_id):
105
+ """Calculate goal progress based on completed tasks"""
106
+ tasks = self.task_mgr.get_tasks_by_goal(goal_id)
107
+ if not tasks:
108
+ return 0
109
+
110
+ completed = len([t for t in tasks if t.status == 'completed'])
111
+ progress = (completed / len(tasks)) * 100
112
+
113
+ # Update the goal
114
+ self.update_goal_progress(goal_id, progress)
115
+ return progress
116
+
117
+ # === Goal Breakdown (AI-Powered) ===
118
+
119
+ def break_down_goal(self, goal_id):
120
+ """Use AI to break down a goal into actionable tasks"""
121
+ goal = self.get_goal(goal_id)
122
+ if not goal:
123
+ return None
124
+
125
+ business_plan = self.get_active_business_plan()
126
+ context = ""
127
+ if business_plan:
128
+ context = f"""
129
+ Business Context:
130
+ - Vision: {business_plan.vision}
131
+ - Mission: {business_plan.mission}
132
+ - Value Proposition: {business_plan.value_proposition}
133
+ """
134
+
135
+ prompt = f"""{context}
136
+
137
+ I need help breaking down this business goal into actionable tasks:
138
+
139
+ GOAL: {goal.title}
140
+ DESCRIPTION: {goal.description}
141
+ TIME HORIZON: {goal.horizon}
142
+ TARGET DATE: {goal.target_date.strftime('%Y-%m-%d') if goal.target_date else 'Not set'}
143
+ SUCCESS CRITERIA: {goal.success_criteria or 'Not defined'}
144
+
145
+ Please break this goal down into 5-10 specific, actionable tasks that would help achieve this goal. For each task, provide:
146
+
147
+ 1. Title (clear, action-oriented)
148
+ 2. Description (what needs to be done)
149
+ 3. Estimated hours
150
+ 4. Priority (1-5, where 1 is highest)
151
+ 5. Category (development, marketing, operations, finance, etc.)
152
+ 6. Dependencies (if any, reference other task numbers)
153
+
154
+ Format your response as a JSON array of tasks:
155
+ [
156
+ {{
157
+ "title": "Task title",
158
+ "description": "Detailed description",
159
+ "estimated_hours": 2.5,
160
+ "priority": 1,
161
+ "category": "development",
162
+ "dependencies": []
163
+ }},
164
+ ...
165
+ ]
166
+
167
+ Only return the JSON array, no additional text."""
168
+
169
+ try:
170
+ message = self.client.messages.create(
171
+ model=self.model,
172
+ max_tokens=3000,
173
+ messages=[{"role": "user", "content": prompt}]
174
+ )
175
+
176
+ response_text = message.content[0].text.strip()
177
+
178
+ # Remove markdown code blocks if present
179
+ if response_text.startswith('```'):
180
+ response_text = response_text.split('```')[1]
181
+ if response_text.startswith('json'):
182
+ response_text = response_text[4:]
183
+ response_text = response_text.strip()
184
+
185
+ tasks_data = json.loads(response_text)
186
+
187
+ # Create tasks in database
188
+ created_tasks = []
189
+ task_id_mapping = {} # Map array index to actual task ID
190
+
191
+ for i, task_data in enumerate(tasks_data):
192
+ # Calculate due date based on goal target date
193
+ due_date = None
194
+ if goal.target_date:
195
+ # Distribute tasks evenly before target date
196
+ days_until_target = (goal.target_date - datetime.now()).days
197
+ task_offset = (days_until_target / len(tasks_data)) * (i + 1)
198
+ due_date = datetime.now() + timedelta(days=task_offset)
199
+
200
+ task = self.task_mgr.create_task(
201
+ title=task_data['title'],
202
+ description=task_data['description'],
203
+ estimated_hours=task_data.get('estimated_hours'),
204
+ priority=task_data.get('priority', 3),
205
+ category=task_data.get('category'),
206
+ due_date=due_date,
207
+ parent_goal_id=goal_id,
208
+ dependencies=[] # Will update after all tasks created
209
+ )
210
+ created_tasks.append(task)
211
+ task_id_mapping[i] = task.id
212
+
213
+ # Update dependencies
214
+ for i, task_data in enumerate(tasks_data):
215
+ if task_data.get('dependencies'):
216
+ dep_ids = [task_id_mapping[dep_idx] for dep_idx in task_data['dependencies']
217
+ if dep_idx in task_id_mapping]
218
+ created_tasks[i].dependencies = dep_ids
219
+
220
+ self.session.commit()
221
+ return created_tasks
222
+
223
+ except Exception as e:
224
+ print(f"Error breaking down goal: {e}")
225
+ return None
226
+
227
+ def suggest_next_tasks(self, goal_id, num_tasks=3):
228
+ """Use AI to suggest next tasks based on current progress"""
229
+ goal = self.get_goal(goal_id)
230
+ if not goal:
231
+ return None
232
+
233
+ existing_tasks = self.task_mgr.get_tasks_by_goal(goal_id)
234
+ completed_tasks = [t for t in existing_tasks if t.status == 'completed']
235
+ pending_tasks = [t for t in existing_tasks if t.status in ['pending', 'in_progress']]
236
+
237
+ completed_str = "\n".join([f"- {t.title}" for t in completed_tasks[:10]])
238
+ pending_str = "\n".join([f"- {t.title} ({t.status})" for t in pending_tasks[:10]])
239
+
240
+ prompt = f"""Given this goal and current progress, suggest {num_tasks} next actionable tasks:
241
+
242
+ GOAL: {goal.title}
243
+ DESCRIPTION: {goal.description}
244
+ PROGRESS: {goal.progress_percentage}%
245
+
246
+ COMPLETED TASKS:
247
+ {completed_str or 'None yet'}
248
+
249
+ PENDING/IN-PROGRESS TASKS:
250
+ {pending_str or 'None'}
251
+
252
+ Suggest {num_tasks} new tasks that would best advance this goal right now. Consider:
253
+ - What's already been accomplished
254
+ - What's currently in progress
255
+ - Natural next steps
256
+ - Quick wins vs. strategic moves
257
+
258
+ Return as JSON array with same format as before."""
259
+
260
+ try:
261
+ message = self.client.messages.create(
262
+ model=self.model,
263
+ max_tokens=2000,
264
+ messages=[{"role": "user", "content": prompt}]
265
+ )
266
+
267
+ response_text = message.content[0].text.strip()
268
+ if response_text.startswith('```'):
269
+ response_text = response_text.split('```')[1]
270
+ if response_text.startswith('json'):
271
+ response_text = response_text[4:]
272
+ response_text = response_text.strip()
273
+
274
+ tasks_data = json.loads(response_text)
275
+
276
+ created_tasks = []
277
+ for task_data in tasks_data:
278
+ task = self.task_mgr.create_task(
279
+ title=task_data['title'],
280
+ description=task_data['description'],
281
+ estimated_hours=task_data.get('estimated_hours'),
282
+ priority=task_data.get('priority', 3),
283
+ category=task_data.get('category'),
284
+ parent_goal_id=goal_id
285
+ )
286
+ created_tasks.append(task)
287
+
288
+ return created_tasks
289
+
290
+ except Exception as e:
291
+ print(f"Error suggesting tasks: {e}")
292
+ return None
293
+
294
+ def create_goal_hierarchy(self, yearly_goal_title, yearly_goal_description):
295
+ """Create a full goal hierarchy: yearly -> quarterly -> monthly"""
296
+ # Create yearly goal
297
+ yearly_goal = self.create_goal(
298
+ title=yearly_goal_title,
299
+ description=yearly_goal_description,
300
+ horizon='yearly',
301
+ target_date=datetime.now() + timedelta(days=365)
302
+ )
303
+
304
+ # Use AI to break into quarterly goals
305
+ prompt = f"""Break down this yearly goal into 4 quarterly goals:
306
+
307
+ YEARLY GOAL: {yearly_goal_title}
308
+ DESCRIPTION: {yearly_goal_description}
309
+
310
+ Create 4 quarterly milestones (Q1, Q2, Q3, Q4) that would logically lead to achieving this yearly goal.
311
+
312
+ Return as JSON:
313
+ [
314
+ {{
315
+ "title": "Q1 goal title",
316
+ "description": "What to achieve in Q1",
317
+ "success_criteria": "How to measure success"
318
+ }},
319
+ ...
320
+ ]"""
321
+
322
+ try:
323
+ message = self.client.messages.create(
324
+ model=self.model,
325
+ max_tokens=2000,
326
+ messages=[{"role": "user", "content": prompt}]
327
+ )
328
+
329
+ response_text = message.content[0].text.strip()
330
+ if response_text.startswith('```'):
331
+ response_text = response_text.split('```')[1]
332
+ if response_text.startswith('json'):
333
+ response_text = response_text[4:]
334
+ response_text = response_text.strip()
335
+
336
+ quarterly_goals_data = json.loads(response_text)
337
+
338
+ quarterly_goals = []
339
+ for i, qgoal_data in enumerate(quarterly_goals_data):
340
+ target = datetime.now() + timedelta(days=90 * (i + 1))
341
+ qgoal = self.create_goal(
342
+ title=qgoal_data['title'],
343
+ description=qgoal_data['description'],
344
+ horizon='quarterly',
345
+ target_date=target,
346
+ success_criteria=qgoal_data.get('success_criteria'),
347
+ parent_goal_id=yearly_goal.id
348
+ )
349
+ quarterly_goals.append(qgoal)
350
+
351
+ return {
352
+ 'yearly': yearly_goal,
353
+ 'quarterly': quarterly_goals
354
+ }
355
+
356
+ except Exception as e:
357
+ print(f"Error creating goal hierarchy: {e}")
358
+ return {'yearly': yearly_goal, 'quarterly': []}
359
+
360
+ def close(self):
361
+ """Close database session"""
362
+ self.session.close()
363
+ self.task_mgr.close()
agent/research.py ADDED
@@ -0,0 +1,199 @@
1
+ import anthropic
2
+ import os
3
+ from datetime import datetime
4
+ from agent.models import ResearchItem, get_session
5
+
6
+ class ResearchAgent:
7
+ def __init__(self):
8
+ api_key = os.getenv('ANTHROPIC_API_KEY')
9
+ if not api_key:
10
+ raise ValueError("ANTHROPIC_API_KEY environment variable not set")
11
+
12
+ self.client = anthropic.Anthropic(api_key=api_key)
13
+ self.model = "claude-sonnet-4-20250514"
14
+ self.session = get_session()
15
+
16
+ def research_topic(self, topic, business_goal, depth="standard"):
17
+ """Research a topic using Claude's web search capability"""
18
+
19
+ depth_guidance = {
20
+ "quick": "Use 1-2 web searches to get a quick overview",
21
+ "standard": "Use 3-5 web searches to get comprehensive information",
22
+ "deep": "Use 5-10 web searches for thorough, multi-angle research"
23
+ }
24
+
25
+ prompt = f"""Research this topic for my business:
26
+
27
+ TOPIC: {topic}
28
+
29
+ BUSINESS GOAL: {business_goal}
30
+
31
+ RESEARCH DEPTH: {depth_guidance.get(depth, depth_guidance['standard'])}
32
+
33
+ Please research this topic and provide:
34
+
35
+ 1. **Key Findings** - Most important insights (3-5 bullet points)
36
+ 2. **Trends** - Current trends or patterns
37
+ 3. **Opportunities** - How this could benefit my business
38
+ 4. **Risks/Challenges** - What to watch out for
39
+ 5. **Action Items** - 2-3 specific next steps I should take
40
+ 6. **Sources** - List the key sources you used
41
+
42
+ Use web search to gather current information. Be thorough and practical."""
43
+
44
+ try:
45
+ message = self.client.messages.create(
46
+ model=self.model,
47
+ max_tokens=4000,
48
+ messages=[{"role": "user", "content": prompt}]
49
+ )
50
+
51
+ research_text = message.content[0].text
52
+
53
+ # Save to database
54
+ research_item = ResearchItem(
55
+ title=topic,
56
+ summary=research_text,
57
+ category="general",
58
+ date_found=datetime.now(),
59
+ raw_data={"prompt": prompt, "depth": depth}
60
+ )
61
+ self.session.add(research_item)
62
+ self.session.commit()
63
+
64
+ return {
65
+ 'research_id': research_item.id,
66
+ 'topic': topic,
67
+ 'findings': research_text,
68
+ 'date': datetime.now()
69
+ }
70
+
71
+ except Exception as e:
72
+ return {
73
+ 'error': str(e),
74
+ 'topic': topic
75
+ }
76
+
77
+ def research_competitors(self, business_domain, your_offering):
78
+ """Research competitive landscape"""
79
+
80
+ prompt = f"""Research the competitive landscape for my business:
81
+
82
+ MY BUSINESS DOMAIN: {business_domain}
83
+ MY OFFERING: {your_offering}
84
+
85
+ Use web search to find and analyze:
86
+
87
+ 1. **Top 5-7 Competitors**
88
+ - Company name
89
+ - What they offer
90
+ - Their key strengths
91
+ - Pricing approach (if public)
92
+ - Market position
93
+
94
+ 2. **Competitive Gaps**
95
+ - What are competitors NOT doing well?
96
+ - Underserved customer needs
97
+ - Opportunities for differentiation
98
+
99
+ 3. **Market Trends**
100
+ - Where is this market heading?
101
+ - Emerging technologies or approaches
102
+ - Changing customer expectations
103
+
104
+ 4. **Strategic Recommendations**
105
+ - How should we position ourselves?
106
+ - What should we focus on?
107
+ - What should we avoid?
108
+
109
+ Be specific and cite sources where possible."""
110
+
111
+ try:
112
+ message = self.client.messages.create(
113
+ model=self.model,
114
+ max_tokens=5000,
115
+ messages=[{"role": "user", "content": prompt}]
116
+ )
117
+
118
+ research_text = message.content[0].text
119
+
120
+ # Save to database
121
+ research_item = ResearchItem(
122
+ title=f"Competitive Analysis: {business_domain}",
123
+ summary=research_text,
124
+ category="competitor",
125
+ date_found=datetime.now(),
126
+ raw_data={
127
+ "domain": business_domain,
128
+ "offering": your_offering
129
+ }
130
+ )
131
+ self.session.add(research_item)
132
+ self.session.commit()
133
+
134
+ return {
135
+ 'research_id': research_item.id,
136
+ 'findings': research_text,
137
+ 'date': datetime.now()
138
+ }
139
+
140
+ except Exception as e:
141
+ return {'error': str(e)}
142
+
143
+ def get_research_history(self, category=None, limit=10):
144
+ """Retrieve past research"""
145
+ query = self.session.query(ResearchItem)
146
+
147
+ if category:
148
+ query = query.filter(ResearchItem.category == category)
149
+
150
+ items = query.order_by(ResearchItem.date_found.desc()).limit(limit).all()
151
+ return [item.to_dict() for item in items]
152
+
153
+ def weekly_intelligence_report(self, business_focus_areas):
154
+ """Generate a weekly intelligence digest"""
155
+ from datetime import timedelta
156
+ week_ago = datetime.now() - timedelta(days=7)
157
+
158
+ recent_research = self.session.query(ResearchItem).filter(
159
+ ResearchItem.date_found >= week_ago
160
+ ).all()
161
+
162
+ research_summary = "\n".join([
163
+ f"- {r.title} ({r.category})"
164
+ for r in recent_research[:10]
165
+ ])
166
+
167
+ prompt = f"""Create a weekly intelligence report for my business:
168
+
169
+ FOCUS AREAS: {', '.join(business_focus_areas)}
170
+
171
+ RECENT RESEARCH CONDUCTED:
172
+ {research_summary or 'No research this week'}
173
+
174
+ Generate a concise intelligence brief covering:
175
+
176
+ 1. **Key Insights** - Top 3 takeaways from this week
177
+ 2. **Trending Topics** - What's gaining attention in our space
178
+ 3. **Competitive Intelligence** - Notable competitor moves
179
+ 4. **Opportunities** - What we should act on
180
+ 5. **Threats** - What we should watch
181
+ 6. **Next Week's Research Priorities** - What to investigate next
182
+
183
+ Keep it scannable and actionable."""
184
+
185
+ try:
186
+ message = self.client.messages.create(
187
+ model=self.model,
188
+ max_tokens=3000,
189
+ messages=[{"role": "user", "content": prompt}]
190
+ )
191
+
192
+ return message.content[0].text
193
+
194
+ except Exception as e:
195
+ return f"Error generating intelligence report: {e}"
196
+
197
+ def close(self):
198
+ """Close database session"""
199
+ self.session.close()