Add data-driven dynamic question mode
This commit is contained in:
@@ -33,6 +33,36 @@ const CORE_MIN_TARGET_SECONDS := 45.0
|
||||
const CORE_MAX_TARGET_SECONDS := 150.0
|
||||
const CORE_RETRY_TARGET_SECONDS := 30.0
|
||||
|
||||
|
||||
func start_dynamic_question(question: Dictionary) -> bool:
|
||||
if question.is_empty():
|
||||
return false
|
||||
system_name = str(question.get("system", "All Systems"))
|
||||
mode = "Tutor"
|
||||
session_kind = "dynamic"
|
||||
active_questions = [_prepare_question_choices(question)]
|
||||
answers = [null]
|
||||
current_index = 0
|
||||
seconds_remaining = 0.0
|
||||
session_initial_seconds = 90.0
|
||||
current_question_started_at = Time.get_ticks_msec() / 1000.0
|
||||
current_question_pause_started_at = 0.0
|
||||
block_started = true
|
||||
session_changed.emit()
|
||||
return true
|
||||
|
||||
|
||||
func replace_dynamic_question(question: Dictionary) -> bool:
|
||||
if session_kind != "dynamic" or question.is_empty():
|
||||
return false
|
||||
active_questions = [_prepare_question_choices(question)]
|
||||
answers = [null]
|
||||
current_index = 0
|
||||
current_question_started_at = Time.get_ticks_msec() / 1000.0
|
||||
current_question_pause_started_at = 0.0
|
||||
session_changed.emit()
|
||||
return true
|
||||
|
||||
func start_block(selected_system: String, block_size: int, selected_mode: String) -> void:
|
||||
system_name = selected_system
|
||||
mode = selected_mode
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
extends Node
|
||||
|
||||
const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd")
|
||||
const DEFAULT_API_URL := "https://us3q.ranaze.com/api/dynamic-questions"
|
||||
|
||||
signal status_loaded(status: Dictionary)
|
||||
signal question_loaded(question: Dictionary)
|
||||
signal attempt_completed(result: Dictionary)
|
||||
signal report_submitted(question_id: String, report_id: String)
|
||||
signal report_failed(question_id: String, message: String)
|
||||
signal request_failed(message: String)
|
||||
|
||||
var api_url := DEFAULT_API_URL
|
||||
var run_token := ""
|
||||
var generation_token := ""
|
||||
var current_envelope := {}
|
||||
var _request: HTTPRequest
|
||||
var _operation := ""
|
||||
var _report_question_id := ""
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
api_url = EndpointConfig.resolve(
|
||||
str(ProjectSettings.get_setting("step3/dynamic_questions_api_url", DEFAULT_API_URL)),
|
||||
"/api/dynamic-questions")
|
||||
_request = HTTPRequest.new()
|
||||
_request.timeout = 30.0
|
||||
_request.request_completed.connect(_on_completed)
|
||||
add_child(_request)
|
||||
|
||||
|
||||
func load_status() -> void:
|
||||
_send("status", HTTPClient.METHOD_GET, "/status", {})
|
||||
|
||||
|
||||
func load_next() -> void:
|
||||
_send("next", HTTPClient.METHOD_POST, "/next", {"runToken": run_token})
|
||||
|
||||
|
||||
func submit_attempt(choice_id: String, duration_seconds: int, is_skip := false) -> void:
|
||||
_send("attempt", HTTPClient.METHOD_POST, "/attempt", {
|
||||
"generationToken": generation_token,
|
||||
"choiceId": choice_id,
|
||||
"isSkip": is_skip,
|
||||
"durationSeconds": duration_seconds
|
||||
})
|
||||
|
||||
|
||||
func submit_report(question_id: String, category: String, details: String) -> void:
|
||||
_report_question_id = question_id
|
||||
_send("report", HTTPClient.METHOD_POST, "/report", {
|
||||
"generationToken": generation_token,
|
||||
"category": category,
|
||||
"details": details
|
||||
})
|
||||
|
||||
|
||||
func reset_run() -> void:
|
||||
run_token = ""
|
||||
generation_token = ""
|
||||
current_envelope = {}
|
||||
|
||||
|
||||
func _send(operation: String, method: int, suffix: String, payload: Dictionary) -> void:
|
||||
if not AuthState.can_send_authenticated_request():
|
||||
request_failed.emit("Log in to use Dynamic Questions.")
|
||||
return
|
||||
if _request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
_operation = operation
|
||||
var headers := PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer %s" % AuthState.access_token
|
||||
])
|
||||
var body := "" if method == HTTPClient.METHOD_GET else JSON.stringify(payload)
|
||||
var error := _request.request(api_url + suffix, headers, method, body)
|
||||
if error != OK:
|
||||
_operation = ""
|
||||
request_failed.emit("Could not connect to Dynamic Questions.")
|
||||
|
||||
|
||||
func _on_completed(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
var operation := _operation
|
||||
_operation = ""
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if response_code < 200 or response_code >= 300 or typeof(parsed) != TYPE_DICTIONARY:
|
||||
var message := str(parsed) if parsed != null else "Dynamic Questions request failed."
|
||||
if operation == "report":
|
||||
report_failed.emit(_report_question_id, message)
|
||||
else:
|
||||
request_failed.emit(message)
|
||||
return
|
||||
var data: Dictionary = parsed
|
||||
match operation:
|
||||
"status":
|
||||
status_loaded.emit(data)
|
||||
"next":
|
||||
run_token = str(data.get("runToken", ""))
|
||||
generation_token = str(data.get("generationToken", ""))
|
||||
current_envelope = data
|
||||
var question := QuestionBankService.normalize_api_question(data.get("question", {}))
|
||||
question["_dynamic_objective_id"] = str(data.get("objectiveId", ""))
|
||||
question["_dynamic_objective_title"] = str(data.get("objectiveTitle", ""))
|
||||
question_loaded.emit(question)
|
||||
"attempt":
|
||||
attempt_completed.emit(data)
|
||||
"report":
|
||||
report_submitted.emit(_report_question_id, str(data.get("id", "")))
|
||||
@@ -0,0 +1 @@
|
||||
uid://b8u2b8km7k6t
|
||||
Reference in New Issue
Block a user