edsl 0.1.50__py3-none-any.whl → 0.1.52__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.
- edsl/__init__.py +45 -34
- edsl/__version__.py +1 -1
- edsl/base/base_exception.py +2 -2
- edsl/buckets/bucket_collection.py +1 -1
- edsl/buckets/exceptions.py +32 -0
- edsl/buckets/token_bucket_api.py +26 -10
- edsl/caching/cache.py +5 -2
- edsl/caching/remote_cache_sync.py +5 -5
- edsl/caching/sql_dict.py +12 -11
- edsl/config/__init__.py +1 -1
- edsl/config/config_class.py +4 -2
- edsl/conversation/Conversation.py +9 -5
- edsl/conversation/car_buying.py +1 -3
- edsl/conversation/mug_negotiation.py +2 -6
- edsl/coop/__init__.py +11 -8
- edsl/coop/coop.py +15 -13
- edsl/coop/coop_functions.py +1 -1
- edsl/coop/ep_key_handling.py +1 -1
- edsl/coop/price_fetcher.py +2 -2
- edsl/coop/utils.py +2 -2
- edsl/dataset/dataset.py +144 -63
- edsl/dataset/dataset_operations_mixin.py +14 -6
- edsl/dataset/dataset_tree.py +3 -3
- edsl/dataset/display/table_renderers.py +6 -3
- edsl/dataset/file_exports.py +4 -4
- edsl/dataset/r/ggplot.py +3 -3
- edsl/inference_services/available_model_fetcher.py +2 -2
- edsl/inference_services/data_structures.py +5 -5
- edsl/inference_services/inference_service_abc.py +1 -1
- edsl/inference_services/inference_services_collection.py +1 -1
- edsl/inference_services/service_availability.py +3 -3
- edsl/inference_services/services/azure_ai.py +3 -3
- edsl/inference_services/services/google_service.py +1 -1
- edsl/inference_services/services/test_service.py +1 -1
- edsl/instructions/change_instruction.py +5 -4
- edsl/instructions/instruction.py +1 -0
- edsl/instructions/instruction_collection.py +5 -4
- edsl/instructions/instruction_handler.py +10 -8
- edsl/interviews/answering_function.py +20 -21
- edsl/interviews/exception_tracking.py +3 -2
- edsl/interviews/interview.py +1 -1
- edsl/interviews/interview_status_dictionary.py +1 -1
- edsl/interviews/interview_task_manager.py +7 -4
- edsl/interviews/request_token_estimator.py +3 -2
- edsl/interviews/statistics.py +2 -2
- edsl/invigilators/invigilators.py +34 -6
- edsl/jobs/__init__.py +39 -2
- edsl/jobs/async_interview_runner.py +1 -1
- edsl/jobs/check_survey_scenario_compatibility.py +5 -5
- edsl/jobs/data_structures.py +2 -2
- edsl/jobs/html_table_job_logger.py +494 -257
- edsl/jobs/jobs.py +2 -2
- edsl/jobs/jobs_checks.py +5 -5
- edsl/jobs/jobs_component_constructor.py +2 -2
- edsl/jobs/jobs_pricing_estimation.py +1 -1
- edsl/jobs/jobs_runner_asyncio.py +2 -2
- edsl/jobs/jobs_status_enums.py +1 -0
- edsl/jobs/remote_inference.py +47 -13
- edsl/jobs/results_exceptions_handler.py +2 -2
- edsl/language_models/language_model.py +151 -145
- edsl/notebooks/__init__.py +24 -1
- edsl/notebooks/exceptions.py +82 -0
- edsl/notebooks/notebook.py +7 -3
- edsl/notebooks/notebook_to_latex.py +1 -1
- edsl/prompts/__init__.py +23 -2
- edsl/prompts/prompt.py +1 -1
- edsl/questions/__init__.py +4 -4
- edsl/questions/answer_validator_mixin.py +0 -5
- edsl/questions/compose_questions.py +2 -2
- edsl/questions/descriptors.py +1 -1
- edsl/questions/question_base.py +32 -3
- edsl/questions/question_base_prompts_mixin.py +4 -4
- edsl/questions/question_budget.py +503 -102
- edsl/questions/question_check_box.py +658 -156
- edsl/questions/question_dict.py +176 -2
- edsl/questions/question_extract.py +401 -61
- edsl/questions/question_free_text.py +77 -9
- edsl/questions/question_functional.py +118 -9
- edsl/questions/{derived/question_likert_five.py → question_likert_five.py} +2 -2
- edsl/questions/{derived/question_linear_scale.py → question_linear_scale.py} +3 -4
- edsl/questions/question_list.py +246 -26
- edsl/questions/question_matrix.py +586 -73
- edsl/questions/question_multiple_choice.py +213 -47
- edsl/questions/question_numerical.py +360 -29
- edsl/questions/question_rank.py +401 -124
- edsl/questions/question_registry.py +3 -3
- edsl/questions/{derived/question_top_k.py → question_top_k.py} +3 -3
- edsl/questions/{derived/question_yes_no.py → question_yes_no.py} +3 -4
- edsl/questions/register_questions_meta.py +2 -1
- edsl/questions/response_validator_abc.py +6 -2
- edsl/questions/response_validator_factory.py +10 -12
- edsl/results/report.py +1 -1
- edsl/results/result.py +7 -4
- edsl/results/results.py +500 -271
- edsl/results/results_selector.py +2 -2
- edsl/scenarios/construct_download_link.py +3 -3
- edsl/scenarios/scenario.py +1 -2
- edsl/scenarios/scenario_list.py +41 -23
- edsl/surveys/survey_css.py +3 -3
- edsl/surveys/survey_simulator.py +2 -1
- edsl/tasks/__init__.py +22 -2
- edsl/tasks/exceptions.py +72 -0
- edsl/tasks/task_history.py +48 -11
- edsl/templates/error_reporting/base.html +37 -4
- edsl/templates/error_reporting/exceptions_table.html +105 -33
- edsl/templates/error_reporting/interview_details.html +130 -126
- edsl/templates/error_reporting/overview.html +21 -25
- edsl/templates/error_reporting/report.css +215 -46
- edsl/templates/error_reporting/report.js +122 -20
- edsl/tokens/__init__.py +27 -1
- edsl/tokens/exceptions.py +37 -0
- edsl/tokens/interview_token_usage.py +3 -2
- edsl/tokens/token_usage.py +4 -3
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/METADATA +1 -1
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/RECORD +118 -116
- edsl/questions/derived/__init__.py +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/LICENSE +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/WHEEL +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/entry_points.txt +0 -0
@@ -1,25 +1,127 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
// Toggle functionality for exception details
|
2
|
+
function toggleExceptionDetail(header) {
|
3
|
+
const detail = header.closest('.exception-detail');
|
4
|
+
const content = detail.querySelector('.exception-content');
|
5
|
+
const expanded = header.getAttribute('aria-expanded') === 'true';
|
6
|
+
|
7
|
+
if (expanded) {
|
8
|
+
content.classList.remove('expanded');
|
9
|
+
header.setAttribute('aria-expanded', 'false');
|
10
|
+
} else {
|
11
|
+
content.classList.add('expanded');
|
12
|
+
header.setAttribute('aria-expanded', 'true');
|
13
|
+
}
|
14
|
+
}
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
16
|
+
// Copy code functionality
|
17
|
+
function copyCode(button) {
|
18
|
+
console.log("Copy button clicked");
|
19
|
+
|
20
|
+
// Find the code block - look for pre/code elements after the button's parent
|
21
|
+
const section = button.closest('div');
|
22
|
+
const codeBlock = section.nextElementSibling;
|
23
|
+
|
24
|
+
if (codeBlock) {
|
25
|
+
// Get the text content
|
26
|
+
let textToCopy = '';
|
27
|
+
if (codeBlock.tagName === 'PRE') {
|
28
|
+
textToCopy = codeBlock.textContent || '';
|
29
|
+
} else if (codeBlock.tagName === 'TEXTAREA') {
|
30
|
+
textToCopy = codeBlock.value || '';
|
31
|
+
}
|
32
|
+
|
33
|
+
// Use clipboard API if available, fallback to execCommand
|
34
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
35
|
+
navigator.clipboard.writeText(textToCopy)
|
36
|
+
.then(() => {
|
37
|
+
console.log("Text copied to clipboard successfully");
|
38
|
+
showCopiedFeedback(button);
|
39
|
+
})
|
40
|
+
.catch(err => {
|
41
|
+
console.error("Failed to copy text: ", err);
|
42
|
+
fallbackCopy(textToCopy, button);
|
12
43
|
});
|
13
|
-
}
|
14
|
-
|
15
|
-
}
|
44
|
+
} else {
|
45
|
+
fallbackCopy(textToCopy, button);
|
46
|
+
}
|
47
|
+
} else {
|
48
|
+
console.error("Code block not found");
|
49
|
+
}
|
50
|
+
}
|
16
51
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
52
|
+
// Fallback copy method using document.execCommand
|
53
|
+
function fallbackCopy(text, button) {
|
54
|
+
// Create temporary textarea
|
55
|
+
const textarea = document.createElement('textarea');
|
56
|
+
textarea.value = text;
|
57
|
+
textarea.style.position = 'fixed'; // Avoid scrolling to bottom
|
58
|
+
document.body.appendChild(textarea);
|
59
|
+
textarea.select();
|
60
|
+
|
61
|
+
try {
|
62
|
+
const successful = document.execCommand('copy');
|
63
|
+
if (successful) {
|
64
|
+
console.log("Fallback copy successful");
|
65
|
+
showCopiedFeedback(button);
|
66
|
+
} else {
|
67
|
+
console.error("Fallback copy failed");
|
68
|
+
}
|
69
|
+
} catch (err) {
|
70
|
+
console.error("Fallback copy error:", err);
|
71
|
+
}
|
72
|
+
|
73
|
+
document.body.removeChild(textarea);
|
74
|
+
}
|
22
75
|
|
23
|
-
|
24
|
-
|
76
|
+
// Show copied feedback on button
|
77
|
+
function showCopiedFeedback(button) {
|
78
|
+
const originalText = button.textContent;
|
79
|
+
button.textContent = 'Copied!';
|
80
|
+
button.disabled = true;
|
81
|
+
|
82
|
+
setTimeout(() => {
|
83
|
+
button.textContent = originalText;
|
84
|
+
button.disabled = false;
|
85
|
+
}, 2000);
|
25
86
|
}
|
87
|
+
|
88
|
+
// Initialize all headers on page load
|
89
|
+
document.addEventListener('DOMContentLoaded', function() {
|
90
|
+
console.log("DOM loaded, initializing exception toggles");
|
91
|
+
|
92
|
+
// Set initial states for all exception contents
|
93
|
+
const exceptionContents = document.querySelectorAll('.exception-content');
|
94
|
+
console.log(`Found ${exceptionContents.length} exception contents`);
|
95
|
+
|
96
|
+
exceptionContents.forEach(content => {
|
97
|
+
content.classList.remove('expanded');
|
98
|
+
});
|
99
|
+
|
100
|
+
// Set aria attributes on headers and add click events
|
101
|
+
const exceptionHeaders = document.querySelectorAll('.exception-header');
|
102
|
+
console.log(`Found ${exceptionHeaders.length} exception headers`);
|
103
|
+
|
104
|
+
exceptionHeaders.forEach(header => {
|
105
|
+
header.setAttribute('aria-expanded', 'false');
|
106
|
+
|
107
|
+
// Add click listener
|
108
|
+
header.addEventListener('click', function(e) {
|
109
|
+
console.log("Header clicked, toggling exception detail");
|
110
|
+
toggleExceptionDetail(this);
|
111
|
+
});
|
112
|
+
});
|
113
|
+
|
114
|
+
// Set up copy buttons
|
115
|
+
const copyButtons = document.querySelectorAll('.copy-button');
|
116
|
+
console.log(`Found ${copyButtons.length} copy buttons`);
|
117
|
+
|
118
|
+
copyButtons.forEach(button => {
|
119
|
+
// Add click listener
|
120
|
+
button.addEventListener('click', function(e) {
|
121
|
+
console.log("Copy button clicked");
|
122
|
+
e.preventDefault();
|
123
|
+
e.stopPropagation();
|
124
|
+
copyCode(this);
|
125
|
+
});
|
126
|
+
});
|
127
|
+
});
|
edsl/tokens/__init__.py
CHANGED
@@ -1,4 +1,30 @@
|
|
1
|
+
"""
|
2
|
+
The tokens module provides functionality for tracking and analyzing token usage in EDSL.
|
3
|
+
|
4
|
+
This module implements classes for tracking and reporting token usage across various
|
5
|
+
components of EDSL, particularly for language model calls. It supports aggregation,
|
6
|
+
cost calculation, and reporting of token usage metrics.
|
7
|
+
|
8
|
+
Key components:
|
9
|
+
1. TokenUsage - Tracks prompt and completion tokens for a single operation
|
10
|
+
2. InterviewTokenUsage - Aggregates token usage across an entire interview
|
11
|
+
3. Exception classes for handling token-related errors
|
12
|
+
|
13
|
+
The token tracking system helps with:
|
14
|
+
- Cost estimation and billing
|
15
|
+
- Resource utilization analysis
|
16
|
+
- Cache effectiveness measurement
|
17
|
+
- API quota management
|
18
|
+
"""
|
19
|
+
|
1
20
|
from .token_usage import TokenUsage
|
2
21
|
from .interview_token_usage import InterviewTokenUsage
|
22
|
+
from .exceptions import TokenError, TokenUsageError, TokenCostError
|
3
23
|
|
4
|
-
__all__ = [
|
24
|
+
__all__ = [
|
25
|
+
"TokenUsage",
|
26
|
+
"InterviewTokenUsage",
|
27
|
+
"TokenError",
|
28
|
+
"TokenUsageError",
|
29
|
+
"TokenCostError"
|
30
|
+
]
|
@@ -0,0 +1,37 @@
|
|
1
|
+
"""
|
2
|
+
This module defines the exception hierarchy for the tokens module.
|
3
|
+
|
4
|
+
All exceptions related to token usage tracking and cost calculations are defined here.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from ..base import BaseException
|
8
|
+
|
9
|
+
|
10
|
+
class TokenError(BaseException):
|
11
|
+
"""
|
12
|
+
Base exception for all token-related errors.
|
13
|
+
|
14
|
+
This is the parent class for all exceptions raised within the tokens module.
|
15
|
+
It inherits from BaseException to ensure proper error tracking and reporting.
|
16
|
+
"""
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class TokenUsageError(TokenError):
|
21
|
+
"""
|
22
|
+
Raised when there is an error in token usage operations.
|
23
|
+
|
24
|
+
This exception is raised for issues related to token usage tracking,
|
25
|
+
such as invalid token counts or incompatible token usage types.
|
26
|
+
"""
|
27
|
+
pass
|
28
|
+
|
29
|
+
|
30
|
+
class TokenCostError(TokenError):
|
31
|
+
"""
|
32
|
+
Raised when there is an error in token cost calculations.
|
33
|
+
|
34
|
+
This exception is used for issues with cost calculations, such as
|
35
|
+
missing or invalid pricing information.
|
36
|
+
"""
|
37
|
+
pass
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from typing import Optional
|
2
2
|
|
3
3
|
from .token_usage import TokenUsage
|
4
|
-
from
|
4
|
+
from ..enums import TokenPricing
|
5
|
+
from .exceptions import TokenUsageError
|
5
6
|
|
6
7
|
class InterviewTokenUsage:
|
7
8
|
"""A class to represent the token usage of an interview."""
|
@@ -24,7 +25,7 @@ class InterviewTokenUsage:
|
|
24
25
|
>>> usage3 = usage1 + usage2
|
25
26
|
"""
|
26
27
|
if not isinstance(other, InterviewTokenUsage):
|
27
|
-
raise
|
28
|
+
raise TokenUsageError(f"Can't add {type(other)} to InterviewTokenSummary")
|
28
29
|
return InterviewTokenUsage(
|
29
30
|
new_token_usage=self.new_token_usage + other.new_token_usage,
|
30
31
|
cached_token_usage=self.cached_token_usage + other.cached_token_usage,
|
edsl/tokens/token_usage.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from ..enums import TokenPricing
|
2
|
+
from .exceptions import TokenUsageError, TokenCostError
|
2
3
|
|
3
4
|
|
4
5
|
class TokenUsage:
|
@@ -15,9 +16,9 @@ class TokenUsage:
|
|
15
16
|
|
16
17
|
def __add__(self, other):
|
17
18
|
if not isinstance(other, TokenUsage):
|
18
|
-
raise
|
19
|
+
raise TokenUsageError(f"Can't add {type(other)} to InterviewTokenUsage")
|
19
20
|
if self.from_cache != other.from_cache:
|
20
|
-
raise
|
21
|
+
raise TokenUsageError("Can't add token usages from different sources")
|
21
22
|
return TokenUsage(
|
22
23
|
from_cache=self.from_cache,
|
23
24
|
prompt_tokens=self.prompt_tokens + other.prompt_tokens,
|