tallyfy 1.0.16__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 (52) hide show
  1. tallyfy/__init__.py +27 -0
  2. tallyfy/__pycache__/__init__.cpython-310.pyc +0 -0
  3. tallyfy/__pycache__/core.cpython-310.pyc +0 -0
  4. tallyfy/__pycache__/form_fields_management.cpython-310.pyc +0 -0
  5. tallyfy/__pycache__/models.cpython-310.pyc +0 -0
  6. tallyfy/__pycache__/task_management.cpython-310.pyc +0 -0
  7. tallyfy/__pycache__/template_management.cpython-310.pyc +0 -0
  8. tallyfy/__pycache__/user_management.cpython-310.pyc +0 -0
  9. tallyfy/core.py +361 -0
  10. tallyfy/form_fields_management/__init__.py +70 -0
  11. tallyfy/form_fields_management/__pycache__/__init__.cpython-310.pyc +0 -0
  12. tallyfy/form_fields_management/__pycache__/base.cpython-310.pyc +0 -0
  13. tallyfy/form_fields_management/__pycache__/crud_operations.cpython-310.pyc +0 -0
  14. tallyfy/form_fields_management/__pycache__/options_management.cpython-310.pyc +0 -0
  15. tallyfy/form_fields_management/__pycache__/suggestions.cpython-310.pyc +0 -0
  16. tallyfy/form_fields_management/base.py +109 -0
  17. tallyfy/form_fields_management/crud_operations.py +234 -0
  18. tallyfy/form_fields_management/options_management.py +222 -0
  19. tallyfy/form_fields_management/suggestions.py +411 -0
  20. tallyfy/models.py +1464 -0
  21. tallyfy/organization_management/__init__.py +26 -0
  22. tallyfy/organization_management/base.py +76 -0
  23. tallyfy/organization_management/retrieval.py +39 -0
  24. tallyfy/task_management/__init__.py +81 -0
  25. tallyfy/task_management/__pycache__/__init__.cpython-310.pyc +0 -0
  26. tallyfy/task_management/__pycache__/base.cpython-310.pyc +0 -0
  27. tallyfy/task_management/__pycache__/creation.cpython-310.pyc +0 -0
  28. tallyfy/task_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  29. tallyfy/task_management/__pycache__/search.cpython-310.pyc +0 -0
  30. tallyfy/task_management/base.py +125 -0
  31. tallyfy/task_management/creation.py +221 -0
  32. tallyfy/task_management/retrieval.py +252 -0
  33. tallyfy/task_management/search.py +198 -0
  34. tallyfy/template_management/__init__.py +85 -0
  35. tallyfy/template_management/analysis.py +1099 -0
  36. tallyfy/template_management/automation.py +469 -0
  37. tallyfy/template_management/base.py +56 -0
  38. tallyfy/template_management/basic_operations.py +479 -0
  39. tallyfy/template_management/health_assessment.py +793 -0
  40. tallyfy/user_management/__init__.py +70 -0
  41. tallyfy/user_management/__pycache__/__init__.cpython-310.pyc +0 -0
  42. tallyfy/user_management/__pycache__/base.cpython-310.pyc +0 -0
  43. tallyfy/user_management/__pycache__/invitation.cpython-310.pyc +0 -0
  44. tallyfy/user_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  45. tallyfy/user_management/base.py +146 -0
  46. tallyfy/user_management/invitation.py +286 -0
  47. tallyfy/user_management/retrieval.py +381 -0
  48. tallyfy-1.0.16.dist-info/METADATA +742 -0
  49. tallyfy-1.0.16.dist-info/RECORD +52 -0
  50. tallyfy-1.0.16.dist-info/WHEEL +5 -0
  51. tallyfy-1.0.16.dist-info/licenses/LICENSE +21 -0
  52. tallyfy-1.0.16.dist-info/top_level.txt +1 -0
@@ -0,0 +1,411 @@
1
+ """
2
+ AI-powered form field suggestions
3
+ """
4
+
5
+ from typing import List, Dict, Any, Optional
6
+ from .base import FormFieldManagerBase
7
+ from ..models import Step, TallyfyError
8
+
9
+
10
+ class FormFieldSuggestions(FormFieldManagerBase):
11
+ """Handles AI-powered form field suggestions based on step content"""
12
+
13
+ def suggest_form_fields_for_step(self, org_id: str, template_id: str, step_id: str) -> List[Dict[str, Any]]:
14
+ """
15
+ AI-powered suggestions for relevant form fields based on step content.
16
+
17
+ Args:
18
+ org_id: Organization ID
19
+ template_id: Template ID
20
+ step_id: Step ID to analyze
21
+
22
+ Returns:
23
+ List of suggested form field configurations
24
+
25
+ Raises:
26
+ TallyfyError: If the request fails
27
+ """
28
+ self._validate_org_id(org_id)
29
+ self._validate_template_id(template_id)
30
+ self._validate_step_id(step_id)
31
+
32
+ try:
33
+ # Get the step details to analyze
34
+ step = self._get_step_details(org_id, template_id, step_id)
35
+ if not step:
36
+ raise TallyfyError(f"Step {step_id} not found")
37
+
38
+ # Get template context for better suggestions
39
+ template = self.sdk.get_template(org_id, template_id)
40
+ if not template:
41
+ raise TallyfyError(f"Template {template_id} not found")
42
+
43
+ # Analyze step content for intelligent suggestions
44
+ step_title = step.title.lower() if step.title else ''
45
+ step_summary = step.summary.lower() if step.summary else ''
46
+ step_type = step.step_type or 'task'
47
+ existing_fields = step.captures or []
48
+
49
+ # Combined text for analysis
50
+ step_text = f"{step_title} {step_summary}".strip()
51
+
52
+ suggestions = []
53
+
54
+ # Get field patterns for analysis
55
+ field_patterns = self._get_field_patterns()
56
+
57
+ # Check existing field types to avoid duplicates
58
+ existing_field_types = set()
59
+ existing_field_labels = set()
60
+ for field in existing_fields:
61
+ if hasattr(field, 'field_type'):
62
+ existing_field_types.add(field.field_type)
63
+ if hasattr(field, 'label'):
64
+ existing_field_labels.add(field.label.lower())
65
+
66
+ # Analyze step content against patterns
67
+ matched_patterns = []
68
+ for pattern_name, pattern_data in field_patterns.items():
69
+ keyword_matches = sum(1 for keyword in pattern_data['keywords'] if keyword in step_text)
70
+ if keyword_matches > 0:
71
+ matched_patterns.append((pattern_name, keyword_matches, pattern_data))
72
+
73
+ # Sort by relevance (number of keyword matches)
74
+ matched_patterns.sort(key=lambda x: x[1], reverse=True)
75
+
76
+ # Generate suggestions from matched patterns
77
+ suggested_count = 0
78
+ max_suggestions = 5
79
+
80
+ for pattern_name, matches, pattern_data in matched_patterns:
81
+ if suggested_count >= max_suggestions:
82
+ break
83
+
84
+ for field_config in pattern_data['fields']:
85
+ if suggested_count >= max_suggestions:
86
+ break
87
+
88
+ # Skip if similar field already exists
89
+ field_label_lower = field_config['label'].lower()
90
+ if field_label_lower in existing_field_labels:
91
+ continue
92
+
93
+ # Add suggestion with metadata
94
+ suggestion = {
95
+ 'field_config': field_config.copy(),
96
+ 'confidence': min(0.9, 0.3 + (matches * 0.2)), # Confidence based on keyword matches
97
+ 'pattern_matched': pattern_name,
98
+ 'keyword_matches': matches,
99
+ 'priority': 'high' if matches >= 2 else 'medium' if matches >= 1 else 'low'
100
+ }
101
+
102
+ # Add position suggestion
103
+ suggestion['field_config']['position'] = len(existing_fields) + suggested_count + 1
104
+
105
+ suggestions.append(suggestion)
106
+ suggested_count += 1
107
+
108
+ # If no specific patterns matched, provide generic useful fields
109
+ if not suggestions:
110
+ suggestions = self._get_generic_suggestions(existing_fields)
111
+
112
+ # Add implementation guidance
113
+ for suggestion in suggestions:
114
+ suggestion['implementation'] = {
115
+ 'method': 'add_form_field_to_step',
116
+ 'parameters': {
117
+ 'org_id': org_id,
118
+ 'template_id': template_id,
119
+ 'step_id': step_id,
120
+ 'field_data': suggestion['field_config']
121
+ }
122
+ }
123
+
124
+ return suggestions
125
+
126
+ except TallyfyError:
127
+ raise
128
+ except Exception as e:
129
+ self._handle_api_error(e, "suggest form fields for step", org_id=org_id, template_id=template_id, step_id=step_id)
130
+
131
+ def _get_step_details(self, org_id: str, template_id: str, step_id: str) -> Optional[Step]:
132
+ """
133
+ Get step details using CRUD operations to avoid circular imports.
134
+
135
+ Args:
136
+ org_id: Organization ID
137
+ template_id: Template ID
138
+ step_id: Step ID
139
+
140
+ Returns:
141
+ Step object or None if not found
142
+ """
143
+ from .crud_operations import FormFieldCRUD
144
+ crud = FormFieldCRUD(self.sdk)
145
+ return crud.get_step(org_id, template_id, step_id)
146
+
147
+ def _get_field_patterns(self) -> Dict[str, Dict[str, Any]]:
148
+ """
149
+ Get predefined field patterns for content analysis.
150
+
151
+ Returns:
152
+ Dictionary of field patterns with keywords and suggested fields
153
+ """
154
+ return {
155
+ # Approval and Review patterns
156
+ 'approval': {
157
+ 'keywords': ['approve', 'review', 'sign off', 'accept', 'reject', 'confirm'],
158
+ 'fields': [
159
+ {
160
+ 'field_type': 'dropdown',
161
+ 'label': 'Decision',
162
+ 'options': [
163
+ {'value': 'approved', 'label': 'Approved'},
164
+ {'value': 'rejected', 'label': 'Rejected'},
165
+ {'value': 'needs_revision', 'label': 'Needs Revision'}
166
+ ],
167
+ 'required': True,
168
+ 'reasoning': 'Approval steps typically need a decision field'
169
+ },
170
+ {
171
+ 'field_type': 'textarea',
172
+ 'label': 'Comments',
173
+ 'required': False,
174
+ 'reasoning': 'Comments are useful for providing feedback'
175
+ }
176
+ ]
177
+ },
178
+
179
+ # Contact and Communication patterns
180
+ 'contact': {
181
+ 'keywords': ['contact', 'call', 'email', 'phone', 'reach out', 'communicate'],
182
+ 'fields': [
183
+ {
184
+ 'field_type': 'text',
185
+ 'label': 'Contact Method',
186
+ 'required': True,
187
+ 'reasoning': 'Track how contact was made'
188
+ },
189
+ {
190
+ 'field_type': 'date',
191
+ 'label': 'Contact Date',
192
+ 'required': True,
193
+ 'reasoning': 'Record when contact was made'
194
+ },
195
+ {
196
+ 'field_type': 'textarea',
197
+ 'label': 'Contact Notes',
198
+ 'required': False,
199
+ 'reasoning': 'Document the conversation or interaction'
200
+ }
201
+ ]
202
+ },
203
+
204
+ # Document and File patterns
205
+ 'document': {
206
+ 'keywords': ['document', 'file', 'upload', 'attach', 'report', 'contract', 'agreement'],
207
+ 'fields': [
208
+ {
209
+ 'field_type': 'file',
210
+ 'label': 'Document Upload',
211
+ 'required': True,
212
+ 'reasoning': 'File upload for document-related steps'
213
+ },
214
+ {
215
+ 'field_type': 'text',
216
+ 'label': 'Document Title',
217
+ 'required': False,
218
+ 'reasoning': 'Name or title of the document'
219
+ },
220
+ {
221
+ 'field_type': 'textarea',
222
+ 'label': 'Document Description',
223
+ 'required': False,
224
+ 'reasoning': 'Brief description of the document'
225
+ }
226
+ ]
227
+ },
228
+
229
+ # Payment and Financial patterns
230
+ 'payment': {
231
+ 'keywords': ['payment', 'invoice', 'cost', 'price', 'amount', 'bill', 'expense'],
232
+ 'fields': [
233
+ {
234
+ 'field_type': 'number',
235
+ 'label': 'Amount',
236
+ 'required': True,
237
+ 'reasoning': 'Financial steps need amount tracking'
238
+ },
239
+ {
240
+ 'field_type': 'dropdown',
241
+ 'label': 'Currency',
242
+ 'options': [
243
+ {'value': 'USD', 'label': 'USD'},
244
+ {'value': 'EUR', 'label': 'EUR'},
245
+ {'value': 'GBP', 'label': 'GBP'}
246
+ ],
247
+ 'required': True,
248
+ 'reasoning': 'Specify currency for financial transactions'
249
+ },
250
+ {
251
+ 'field_type': 'date',
252
+ 'label': 'Payment Date',
253
+ 'required': False,
254
+ 'reasoning': 'Track when payment was made'
255
+ }
256
+ ]
257
+ },
258
+
259
+ # Quality and Testing patterns
260
+ 'quality': {
261
+ 'keywords': ['test', 'quality', 'check', 'verify', 'validate', 'inspect'],
262
+ 'fields': [
263
+ {
264
+ 'field_type': 'dropdown',
265
+ 'label': 'Test Result',
266
+ 'options': [
267
+ {'value': 'pass', 'label': 'Pass'},
268
+ {'value': 'fail', 'label': 'Fail'},
269
+ {'value': 'partial', 'label': 'Partial Pass'}
270
+ ],
271
+ 'required': True,
272
+ 'reasoning': 'Quality steps need result tracking'
273
+ },
274
+ {
275
+ 'field_type': 'textarea',
276
+ 'label': 'Test Notes',
277
+ 'required': False,
278
+ 'reasoning': 'Document test findings and issues'
279
+ },
280
+ {
281
+ 'field_type': 'number',
282
+ 'label': 'Score',
283
+ 'required': False,
284
+ 'reasoning': 'Numerical rating for quality assessment'
285
+ }
286
+ ]
287
+ },
288
+
289
+ # Schedule and Time patterns
290
+ 'schedule': {
291
+ 'keywords': ['schedule', 'meeting', 'appointment', 'deadline', 'due', 'time'],
292
+ 'fields': [
293
+ {
294
+ 'field_type': 'datetime',
295
+ 'label': 'Scheduled Time',
296
+ 'required': True,
297
+ 'reasoning': 'Scheduling steps need date and time'
298
+ },
299
+ {
300
+ 'field_type': 'text',
301
+ 'label': 'Location',
302
+ 'required': False,
303
+ 'reasoning': 'Meeting location or venue'
304
+ },
305
+ {
306
+ 'field_type': 'textarea',
307
+ 'label': 'Agenda',
308
+ 'required': False,
309
+ 'reasoning': 'Meeting agenda or notes'
310
+ }
311
+ ]
312
+ }
313
+ }
314
+
315
+ def _get_generic_suggestions(self, existing_fields: List) -> List[Dict[str, Any]]:
316
+ """
317
+ Get generic form field suggestions when no specific patterns match.
318
+
319
+ Args:
320
+ existing_fields: List of existing form fields on the step
321
+
322
+ Returns:
323
+ List of generic field suggestions
324
+ """
325
+ return [
326
+ {
327
+ 'field_config': {
328
+ 'field_type': 'textarea',
329
+ 'label': 'Notes',
330
+ 'required': False,
331
+ 'position': len(existing_fields) + 1
332
+ },
333
+ 'confidence': 0.6,
334
+ 'pattern_matched': 'generic',
335
+ 'keyword_matches': 0,
336
+ 'priority': 'medium',
337
+ 'reasoning': 'Notes field is useful for most steps to capture additional information'
338
+ },
339
+ {
340
+ 'field_config': {
341
+ 'field_type': 'dropdown',
342
+ 'label': 'Status',
343
+ 'options': [
344
+ {'value': 'completed', 'label': 'Completed'},
345
+ {'value': 'in_progress', 'label': 'In Progress'},
346
+ {'value': 'blocked', 'label': 'Blocked'}
347
+ ],
348
+ 'required': False,
349
+ 'position': len(existing_fields) + 2
350
+ },
351
+ 'confidence': 0.5,
352
+ 'pattern_matched': 'generic',
353
+ 'keyword_matches': 0,
354
+ 'priority': 'low',
355
+ 'reasoning': 'Status tracking can be helpful for workflow management'
356
+ }
357
+ ]
358
+
359
+ def suggest_field_improvements(self, org_id: str, template_id: str, step_id: str, field_id: str) -> List[Dict[str, Any]]:
360
+ """
361
+ Suggest improvements for an existing form field.
362
+
363
+ Args:
364
+ org_id: Organization ID
365
+ template_id: Template ID
366
+ step_id: Step ID
367
+ field_id: Form field ID to analyze
368
+
369
+ Returns:
370
+ List of improvement suggestions
371
+
372
+ Raises:
373
+ TallyfyError: If the request fails
374
+ """
375
+ try:
376
+ # Get current field options using options management
377
+ from .options_management import FormFieldOptions
378
+ options_manager = FormFieldOptions(self.sdk)
379
+
380
+ current_options = options_manager.get_dropdown_options(org_id, template_id, step_id, field_id)
381
+
382
+ improvements = []
383
+
384
+ # Analyze dropdown options if applicable
385
+ if current_options:
386
+ # Check for common improvements
387
+ if len(current_options) > 10:
388
+ improvements.append({
389
+ 'type': 'reduce_options',
390
+ 'priority': 'medium',
391
+ 'description': 'Consider reducing the number of dropdown options for better usability',
392
+ 'recommendation': 'Group similar options or use a search-enabled dropdown',
393
+ 'current_count': len(current_options)
394
+ })
395
+
396
+ # Check for inconsistent naming
397
+ option_lengths = [len(opt) for opt in current_options]
398
+ if max(option_lengths) - min(option_lengths) > 20:
399
+ improvements.append({
400
+ 'type': 'normalize_options',
401
+ 'priority': 'low',
402
+ 'description': 'Option labels have inconsistent lengths',
403
+ 'recommendation': 'Standardize option label lengths for better visual consistency'
404
+ })
405
+
406
+ return improvements
407
+
408
+ except TallyfyError:
409
+ raise
410
+ except Exception as e:
411
+ self._handle_api_error(e, "suggest field improvements", org_id=org_id, template_id=template_id, step_id=step_id, field_id=field_id)