feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(ai_eff): AI Effort Prediction API changes - #95

Open
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion
Open

feat(ai_eff): AI Effort Prediction API changes#95
SteveDala wants to merge 33 commits into
thoth-tech:Feature/AI-Suggestionfrom
SteveDala:Feature/AI-Suggestion

Conversation

@SteveDala

@SteveDalaSteveDala commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Background and Context

Currently, the task definition object contained a weighting field which, when populated, assisted students in understanding how much of their unit they had completed by finishing the task. This measure is implemented in a visualisation called the Progress Burndown Chart:

image

Unfortunately, weighting is not always filled out accurately or at all by tutors when creating task definitions. This leads to the chart feeling bad for students by way of inconsistency; sometimes submitting a Pass task reduces this Burndown chart by the same amount that a Distinction task does, even if much more effort was put into the distinction task.

The AI effort prediction feature aims to solve this task effort evaluation with an intelligent regressor trained on data from previous Task Definitions in OnTrack.

Description

This pull request introduces the necessary API changes to introduce intelligent effort prediction of tasks to OnTrack.

  • changes the weighting field throughout the repo to estimated_hours to give meaning to the integer value in the task definition
  • introduces the predicted_effort field to store the effort predicted by the intelligent regressor service.
  • introduces a new Sidekiq job definition to send prediction jobs to the intelligent regressor service, available from the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Dependencies

This PR has no additional dependencies on its own. To test the integration with the intelligent regressor service, the doubtfire-effort-predict service will need to be available at ML_SERVICE_URL (if configured from the superproject, this will be http://effort-predictor:8080/)

How Has This Been Tested?

If the ML service is running and the ML_SERVICE_URL is defined (easiest setup is to use the superproject in VSCode dev containers), the API can be tested from either the OpenAPI doc page /api/docs or from the rails c console.

Test A

Open localhost:3000/api/docs, send this payload to the /api/auth endpoint:

{
"username": "aadmin",
"password": "password"
}

Retrieve the auth_token from the response and note it down. Then, send these parameters (or any alternative that matches unit_id with task_def_id) to the /api/units/:unit_id/task_definitions/:task_def_id/predict_effort endpoint:

  • unit_id: 1
  • task_def_id: 1
  • Username: aadmin
  • Auth_Token: (your noted auth token)

When the response gives a Sidekiq job_id, note that ID down. Then send it as a parameter to the /api/sidekiq/{id} endpoint:

  • id: (your noted Sidekiq ID)
  • Username: aadmin
  • Auth_Token: (your noted auth token)

You should receive a response like the following:

{
"id": (Sidekiq ID),"status": "complete",
"pct_complete": null,
"message": null,
"processed_count": null,
"total_count": null,
"created_at": null,
"updated_at": (Unix timestamp),"job_class": "PredictEffortJob",
"result": "{\"predicted_effort\" => (The predicted effort value from the service)}"
}

Test B

Open Rails console (rails c from the root of the API repo inside the container).

Use the following commands to perform a job and get it's status:

jid=PredictEffortJob.perform_async(2,1)# where 2 = task_def_id, 1 = user_idSidekiq::Status.get_all(jid)

Use the following commands to check the predicted_effort and estimated_hours field sagainst task_def_id = 2:

task=TaskDefinition.find_by(id: 2)[task&.predicted_effort,task&.estimated_hours]

The effort value should match from the above Sidekiq job status.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if appropriate
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have created or extended unit tests to address my new additions
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

SteveDalaand others added 11 commits November 30, 2025 13:29
The document still said "documentaion". Nuts. I have also added
the doc version number. I defaulted to the version of the branch.
This commit is inspired by PR#87 and PR#85 that attempts
to implement the AI Task Effort prediction feature.
Co-authored-by: jtalev <jtalev@users.noreply.github.com>
Co-authored-by: officialid130-13e13 <officialid130-13e13@users.noreply.github.com>
Also, the addition of the default value to any record
that has null values in the column.

@jtalevjtalev left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@officialid130-13e13officialid130-13e13 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the changes and the FastAPI/Sidekiq refactor looks good overall.
The CI build is failing during the TeXLive image build. This is the same issue I hit earlier — the pdfmanagement-testphase package is no longer available. Can you please remove pdfmanagement-testphase from the install list in the texlive-builder Dockerfile. After removing that package, the build should pass again.

joshtalevand others added 17 commits May 5, 2026 20:47
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* return job ID from prediction endpoint
* error handling on prediction job enqueue
* add initiator to sidekiq job
- adding an initiator to the job allows the user who enqueued the job
to retrieve info about the job to aid in polling for results after
initial enqueueing takes place
* More error handling
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
* add allow prediction flag on units migration
* expose allow_effort_predictions in entity
* add allow_effort_prediction to crud endpoints
---------
Co-authored-by: josh.talev <josh.talev@cabinetsbycomputer.com>
@SteveDalaSteveDala changed the title feat(ai_eff): api changesfeat(ai_eff): AI Effort Prediction API changesMay 17, 2026
@SteveDalaSteveDala added the enhancement New feature or request label May 17, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@SteveDala@jtalev@officialid130-13e13@joshtalev