@@ -15,6 +15,7 @@ use rayon::iter::IntoParallelRefIterator;
1515use rayon:: iter:: ParallelIterator ;
1616use rayon:: slice:: ParallelSliceMut ;
1717
18+ use crate :: ai;
1819use crate :: app:: ToApp ;
1920use crate :: app:: ToApps ;
2021use crate :: app:: WINDOW_WIDTH ;
@@ -26,9 +27,10 @@ use crate::app::menubar::menu_icon;
2627use crate :: app:: tile:: AppIndex ;
2728use crate :: app:: { Message , Page , tile:: Tile } ;
2829use crate :: calculator:: Expr ;
30+ use crate :: clipboard:: ClipBoardContentType ;
2931use crate :: commands:: Function ;
3032use crate :: commands:: search_for_file;
31- use crate :: config:: Config ;
33+ use crate :: config:: { AiConfig , Config } ;
3234use crate :: unit_conversion;
3335use crate :: utils:: is_valid_url;
3436use crate :: { app:: ArrowKey , platform:: focus_this_app} ;
@@ -431,6 +433,51 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
431433 Task :: none ( )
432434 }
433435
436+ Message :: AiQuery ( query) => {
437+ info ! ( "AI query: {query}" ) ;
438+ tile. results = vec ! [ App {
439+ ranking: 0 ,
440+ open_command: AppCommand :: Display ,
441+ desc: "AI Query" . to_string( ) ,
442+ icons: None ,
443+ display_name: "Thinking..." . to_string( ) ,
444+ search_name: String :: new( ) ,
445+ } ] ;
446+ let ai_config = tile. config . ai . clone ( ) ;
447+ Task :: perform (
448+ async move {
449+ tokio:: task:: spawn_blocking ( move || ai:: query_ai ( & ai_config, & query) )
450+ . await
451+ . unwrap_or_else ( |e| format ! ( "Error: {e}" ) )
452+ } ,
453+ Message :: AiResponse ,
454+ )
455+ }
456+
457+ Message :: AiResponse ( response) => {
458+ info ! ( "AI response received" ) ;
459+ tile. results = vec ! [ App {
460+ ranking: 0 ,
461+ open_command: AppCommand :: Function ( Function :: CopyToClipboard (
462+ ClipBoardContentType :: Text ( response. clone( ) ) ,
463+ ) ) ,
464+ desc: "AI Response (click to copy)" . to_string( ) ,
465+ icons: None ,
466+ display_name: response,
467+ search_name: String :: new( ) ,
468+ } ] ;
469+ let len = tile. results . len ( ) ;
470+ let max_elem = min ( 5 , len) ;
471+ window:: latest ( )
472+ . map ( |x| x. unwrap ( ) )
473+ . map ( move |id| {
474+ Message :: ResizeWindow (
475+ id,
476+ ( ( max_elem * 55 ) + 35 + DEFAULT_WINDOW_HEIGHT as usize ) as f32 ,
477+ )
478+ } )
479+ }
480+
434481 Message :: SearchQueryChanged ( input, id) => {
435482 let mut task = Task :: none ( ) ;
436483 tile. focus_id = 0 ;
@@ -513,6 +560,24 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
513560 return Task :: batch ( [ zero_item_resize_task ( id) , task] ) ;
514561 }
515562 }
563+ query if query. starts_with ( & tile. config . ai . trigger )
564+ && query. len ( ) > tile. config . ai . trigger . len ( )
565+ && query[ tile. config . ai . trigger . len ( ) ..] . starts_with ( ' ' )
566+ && tile. page == Page :: Main =>
567+ {
568+ let ai_query = tile. query [ tile. config . ai . trigger . len ( ) ..] . trim ( ) . to_string ( ) ;
569+ if !ai_query. is_empty ( ) {
570+ tile. results = vec ! [ App {
571+ ranking: 0 ,
572+ open_command: AppCommand :: Message ( Message :: AiQuery ( ai_query. clone( ) ) ) ,
573+ desc: "AI Query" . to_string( ) ,
574+ icons: None ,
575+ display_name: format!( "Ask AI: {}" , ai_query) ,
576+ search_name: String :: new( ) ,
577+ } ] ;
578+ return single_item_resize_task ( id) ;
579+ }
580+ }
516581 query => ' a: {
517582 if !query. starts_with ( ">" ) || tile. page != Page :: Main {
518583 break ' a;
0 commit comments