@@ -6,8 +6,11 @@ use leptos::prelude::*;
66use leptos_dom:: helpers:: event_target_value;
77
88use crate :: api:: load_client_llm_text_fields_from_storage;
9- use crate :: app_prefs:: { status_bar_effective_api_base, status_bar_effective_model} ;
10- use crate :: chat_session_state:: ChatStreamBusyMemos ;
9+ use crate :: app_prefs:: {
10+ status_bar_effective_api_base, status_bar_effective_llm_context_tokens,
11+ status_bar_effective_model,
12+ } ;
13+ use crate :: chat_session_state:: { ChatSessionSignals , ChatStreamBusyMemos } ;
1114
1215use super :: app_shell_ctx:: StatusBarFooterSignals ;
1316use super :: shell_runtime_context:: expect_chat_shell_ctx;
@@ -50,6 +53,115 @@ struct StatusBarChipsSignals {
5053 locale : RwSignal < Locale > ,
5154}
5255
56+ fn status_bar_context_chip_visible ( chat : ChatSessionSignals ) -> bool {
57+ let Some ( snap) = chat. conversation_prompt_tokens . get ( ) else {
58+ return false ;
59+ } ;
60+ let aid = chat. active_id . get ( ) ;
61+ chat. sessions . with ( |list| {
62+ list. iter ( ) . find ( |s| s. id == aid) . is_some_and ( |s| {
63+ s. trimmed_server_conversation_id ( )
64+ . is_some_and ( |c| c == snap. conversation_id . as_str ( ) )
65+ } )
66+ } )
67+ }
68+
69+ fn status_bar_context_cap_and_used (
70+ chat : ChatSessionSignals ,
71+ st : StatusTasksSignals ,
72+ client_llm_storage_tick : RwSignal < u64 > ,
73+ ) -> ( u32 , Option < u32 > ) {
74+ let _tick = client_llm_storage_tick. get ( ) ;
75+ let sd = st. status_data . get ( ) ;
76+ let ( _, _, _, stored_ctx, _) = load_client_llm_text_fields_from_storage ( ) ;
77+ let cap = status_bar_effective_llm_context_tokens ( sd. as_ref ( ) , stored_ctx. as_str ( ) ) ;
78+ let used = chat
79+ . conversation_prompt_tokens
80+ . get ( )
81+ . and_then ( |s| s. tiktoken . as_ref ( ) . map ( |t| t. prompt_tokens ) ) ;
82+ ( cap, used)
83+ }
84+
85+ fn status_bar_context_value_text ( cap : u32 , used : Option < u32 > ) -> String {
86+ match ( used, cap > 0 ) {
87+ ( Some ( u) , true ) => {
88+ let pct = ( u as f64 / cap as f64 ) * 100.0 ;
89+ format ! ( "{u} / {cap} ({:.1}%)" , pct. min( 999.9 ) )
90+ }
91+ ( Some ( u) , false ) => format ! ( "{u}" ) ,
92+ ( None , true ) => format ! ( "— / {cap}" ) ,
93+ ( None , false ) => "—" . to_string ( ) ,
94+ }
95+ }
96+
97+ #[ component]
98+ fn StatusBarContextChip (
99+ st : StatusTasksSignals ,
100+ chat : ChatSessionSignals ,
101+ client_llm_storage_tick : RwSignal < u64 > ,
102+ locale : RwSignal < Locale > ,
103+ ) -> impl IntoView {
104+ view ! {
105+ <Show when=move || status_bar_context_chip_visible( chat) >
106+ <span
107+ class="status-chip status-chip-context"
108+ prop: title=move || i18n:: status_chip_context_tooltip( locale. get( ) )
109+ >
110+ <span class="status-chip-context-row" >
111+ <span class="status-chip-label" >
112+ { move || i18n:: status_chip_context( locale. get( ) ) }
113+ </span>
114+ <span class="status-chip-value" >{ move || {
115+ let ( cap, used) = status_bar_context_cap_and_used(
116+ chat,
117+ st,
118+ client_llm_storage_tick,
119+ ) ;
120+ status_bar_context_value_text( cap, used)
121+ } } </span>
122+ </span>
123+ <Show when=move || {
124+ let ( cap, used) = status_bar_context_cap_and_used(
125+ chat,
126+ st,
127+ client_llm_storage_tick,
128+ ) ;
129+ cap > 0 && used. is_some( )
130+ } >
131+ <div
132+ class="status-context-meter"
133+ style=move || {
134+ let ( cap, used) = status_bar_context_cap_and_used(
135+ chat,
136+ st,
137+ client_llm_storage_tick,
138+ ) ;
139+ let u = used. unwrap_or( 0 ) ;
140+ let pct = ( ( u as f64 / cap as f64 ) * 100.0 ) . min( 100.0 ) ;
141+ format!( "--status-context-pct: {pct:.2}%" )
142+ }
143+ >
144+ <div class=move || {
145+ let ( cap, used) = status_bar_context_cap_and_used(
146+ chat,
147+ st,
148+ client_llm_storage_tick,
149+ ) ;
150+ let u = used. unwrap_or( 0 ) ;
151+ let pct = ( u as f64 / cap as f64 ) * 100.0 ;
152+ if pct >= 90.0 {
153+ "status-context-meter-fill status-context-meter-fill--warn"
154+ } else {
155+ "status-context-meter-fill"
156+ }
157+ } ></div>
158+ </div>
159+ </Show >
160+ </span>
161+ </Show >
162+ }
163+ }
164+
53165#[ component]
54166fn StatusBarChipsSkeleton ( locale : RwSignal < Locale > ) -> impl IntoView {
55167 view ! {
@@ -162,6 +274,12 @@ fn StatusBarChipsLoaded(
162274 } }
163275 </select>
164276 </label>
277+ <StatusBarContextChip
278+ st=st
279+ chat=chat
280+ client_llm_storage_tick=client_llm_storage_tick
281+ locale=locale
282+ />
165283 </>
166284 }
167285}
0 commit comments