next_card_data mediasrv function

This commit is contained in:
Luc Mcgrady 2025-10-21 15:05:02 +01:00
parent b77ee225e5
commit 6d62fcc096
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
4 changed files with 56 additions and 16 deletions

View file

@ -13,6 +13,7 @@ import "anki/decks.proto";
import "anki/collection.proto";
import "anki/config.proto";
import "anki/deck_config.proto";
import "anki/card_rendering.proto";
service SchedulerService {
rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards);
@ -298,9 +299,18 @@ message NextCardDataResponse {
message NextCardData {
QueuedCards queue = 1;
string front = 2;
string back = 3;
repeated AnswerButton answer_buttons = 4;
repeated AnswerButton answer_buttons = 2;
// TODO: We can probably make this a little faster by using oneof and
// preventing the partial_front and back being sent to svelte where it isn't
// used Alternatively we can use a completely different message for both
// Rust -> Python and the Python -> Svelte though this would be more
// complicated to implement.
string front = 3;
string back = 4;
repeated card_rendering.RenderedTemplateNode partial_front = 5;
repeated card_rendering.RenderedTemplateNode partial_back = 6;
}
optional NextCardData next_card = 1;

View file

@ -28,9 +28,16 @@ import aqt
import aqt.main
import aqt.operations
from anki import hooks
from anki.cards import Card
from anki.collection import OpChanges, OpChangesOnly, Progress, SearchNode
from anki.decks import UpdateDeckConfigs
from anki.scheduler.v3 import SchedulingStatesWithContext, SetSchedulingStatesRequest
from anki.scheduler_pb2 import NextCardDataResponse
from anki.template import (
PartiallyRenderedCard,
TemplateRenderContext,
apply_custom_filters,
)
from anki.utils import dev_mode
from aqt.changenotetype import ChangeNotetypeDialog
from aqt.deckoptions import DeckOptionsDialog
@ -638,6 +645,31 @@ def save_custom_colours() -> bytes:
return b""
def next_card_data() -> bytes:
raw = aqt.mw.col._backend.next_card_data_raw(request.data)
data = NextCardDataResponse.FromString(raw)
backend_card = data.next_card.queue.cards[0].card
card = Card(aqt.mw.col, backend_card=backend_card)
ctx = TemplateRenderContext.from_existing_card(card, False)
qside = apply_custom_filters(
PartiallyRenderedCard.nodes_from_proto(data.next_card.partial_front),
ctx,
None,
)
aside = apply_custom_filters(
PartiallyRenderedCard.nodes_from_proto(data.next_card.partial_back),
ctx,
qside,
)
data.next_card.front = qside
data.next_card.back = aside
return data.SerializeToString()
post_handler_list = [
congrats_info,
get_deck_configs_for_update,
@ -654,6 +686,7 @@ post_handler_list = [
deck_options_require_close,
deck_options_ready,
save_custom_colours,
next_card_data,
]
@ -696,7 +729,6 @@ exposed_backend_list = [
"get_optimal_retention_parameters",
"simulate_fsrs_review",
"simulate_fsrs_workload",
"next_card_data",
# DeckConfigService
"get_ignored_before_count",
"get_retention_workload",

View file

@ -180,7 +180,7 @@ impl crate::services::CardRenderingService for Collection {
}
}
fn rendered_nodes_to_proto(
pub(crate) fn rendered_nodes_to_proto(
nodes: Vec<RenderedNode>,
) -> Vec<anki_proto::card_rendering::RenderedTemplateNode> {
nodes

View file

@ -27,6 +27,7 @@ use fsrs::FSRSReview;
use fsrs::FSRS;
use crate::backend::Backend;
use crate::card_rendering::service::rendered_nodes_to_proto;
use crate::prelude::*;
use crate::scheduler::fsrs::params::ComputeParamsRequest;
use crate::scheduler::new::NewCardDueOrder;
@ -34,7 +35,6 @@ use crate::scheduler::states::CardState;
use crate::scheduler::states::SchedulingStates;
use crate::search::SortMode;
use crate::stats::studied_today;
use crate::text::encode_iri_paths;
impl crate::services::SchedulerService for Collection {
/// This behaves like _updateCutoff() in older code - it also unburies at
@ -397,8 +397,8 @@ impl crate::services::SchedulerService for Collection {
if let Some(next_card) = next_card {
let cid = next_card.card.id;
let render = self.render_existing_card(cid, false, false)?;
let style = format!("<style>{}</style>", render.css);
let render = self.render_existing_card(cid, false, true)?;
//let style = format!("<style>{}</style>", render.css);
let answer_buttons = self
.describe_next_states(&next_card.states)?
@ -410,17 +410,15 @@ impl crate::services::SchedulerService for Collection {
})
.collect();
let prepare_card_text_for_display = |html: &str| {
let html = [style.clone(), html.to_string()].concat();
let html = encode_iri_paths(&html).to_string();
html
};
Ok(NextCardDataResponse {
next_card: Some(NextCardData {
queue: Some(queue.into()),
front: prepare_card_text_for_display(&render.question()),
back: prepare_card_text_for_display(&render.answer()),
front: "".to_string(),
back: "".to_string(),
partial_front: rendered_nodes_to_proto(render.qnodes),
partial_back: rendered_nodes_to_proto(render.anodes),
answer_buttons,
}),