diff --git a/README.md b/README.md index 80b16ff..5e70b90 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ Currently supported providers: - Multiple provider integration - Customizable +![image](https://github.com/user-attachments/assets/7e3bd46a-08f7-4778-8b56-2648388d6fb5) + ## Known Limitations - Tested only on 7.52 & ABAP 2022 - **experimental** downport available in branch 702 diff --git a/src/yy_llm_ide.prog.abap b/src/yy_llm_ide.prog.abap new file mode 100644 index 0000000..18df5b3 --- /dev/null +++ b/src/yy_llm_ide.prog.abap @@ -0,0 +1,694 @@ +*&---------------------------------------------------------------------* +*& Include YY_LLM_IDE +*&---------------------------------------------------------------------* + +CONSTANTS: + c_llm_untitled TYPE programm VALUE 'Untitled LLM Model', + c_new_abap_editor TYPE flag VALUE abap_true, + c_source_type TYPE string VALUE 'LISP'. + +DATA g_ok_code TYPE syucomm. + +INTERFACE lif_unit_test. +ENDINTERFACE. + +TYPES: BEGIN OF ts_settings, + stack TYPE string_table, + new_editor TYPE flag, + END OF ts_settings. + +CLASS lcl_stack DEFINITION FRIENDS lif_unit_test. + PUBLIC SECTION. + TYPES tv_data TYPE string. + + METHODS constructor IMPORTING it_stack TYPE string_table OPTIONAL. + METHODS previous RETURNING VALUE(rv_data) TYPE tv_data. + METHODS next RETURNING VALUE(rv_data) TYPE tv_data. + + METHODS push IMPORTING iv_key TYPE tv_data. + + METHODS serialize RETURNING VALUE(rt_string) TYPE string_table. + METHODS deserialize IMPORTING it_string TYPE string_table. + PROTECTED SECTION. + DATA mt_stack TYPE string_table. + DATA mv_index TYPE i. +ENDCLASS. + +CLASS lcl_stack IMPLEMENTATION. + + METHOD constructor. + mt_stack = it_stack. + ENDMETHOD. + + METHOD push. + CHECK iv_key IS NOT INITIAL. + APPEND iv_key TO mt_stack. + mv_index = lines( mt_stack ). + ENDMETHOD. + + METHOD previous. + IF mv_index GT 1. + mv_index = mv_index - 1. + ENDIF. + rv_data = VALUE #( mt_stack[ mv_index ] OPTIONAL ). + ENDMETHOD. + + METHOD next. + IF mv_index LT lines( mt_stack ). + mv_index = mv_index + 1. + ENDIF. + rv_data = VALUE #( mt_stack[ mv_index ] OPTIONAL ). + ENDMETHOD. + + METHOD deserialize. + mt_stack = it_string. + mv_index = lines( mt_stack ). + ENDMETHOD. + + METHOD serialize. + rt_string = mt_stack. + ENDMETHOD. + +ENDCLASS. + +INTERFACE lif_source_editor. + METHODS clear. + METHODS push_text. + METHODS previous. + METHODS next. + METHODS to_string RETURNING VALUE(rv_text) TYPE string. + METHODS update_status IMPORTING iv_string TYPE string. + METHODS setup IMPORTING is_settings TYPE ts_settings. + + METHODS set_focus. + METHODS free RETURNING VALUE(rt_string) TYPE string_table. +ENDINTERFACE. + +*----------------------------------------------------------------------* +* CLASS lcl_editor DEFINITION +*----------------------------------------------------------------------* +CLASS lcl_editor DEFINITION INHERITING FROM cl_gui_textedit. + PUBLIC SECTION. + CONSTANTS c_max_line_count TYPE i VALUE 10000. + + METHODS constructor IMPORTING io_container TYPE REF TO cl_gui_container + iv_read_only TYPE flag DEFAULT abap_true + iv_toolbar TYPE flag DEFAULT abap_false. + METHODS append_source IMPORTING iv_text TYPE string. + + INTERFACES lif_source_editor. + + METHODS append_string IMPORTING iv_text TYPE string. + PROTECTED SECTION. + DATA mv_counter TYPE i. + DATA mo_stack TYPE REF TO lcl_stack. + + METHODS format_input IMPORTING query TYPE string + RETURNING VALUE(rv_text) TYPE string. +ENDCLASS. + +*----------------------------------------------------------------------* +* CLASS lcl_editor IMPLEMENTATION +*----------------------------------------------------------------------* +CLASS lcl_editor IMPLEMENTATION. + + METHOD constructor. + DATA mode TYPE i. + io_container->set_visible( abap_true ). + super->constructor( io_container ). + IF iv_toolbar EQ abap_true. + mode = 1. + ELSE. + mode = 0. + ENDIF. + set_toolbar_mode( mode ). + cl_gui_cfw=>flush( ). + + IF iv_read_only EQ abap_true. + set_readonly_mode( cl_gui_textedit=>true ). + mode = 0. + ELSE. + mode = 1. + ENDIF. + set_statusbar_mode( mode ). +* Work around to avoid NO DATA dump on first read + lif_source_editor~clear( ). + mo_stack = NEW #( ). + ENDMETHOD. "constructor + + METHOD lif_source_editor~clear. + delete_text( ). + ENDMETHOD. "append_string + + METHOD append_string. + DATA lv_text TYPE string. + lv_text = lif_source_editor~to_string( ). + CONCATENATE lv_text iv_text INTO lv_text RESPECTING BLANKS. + set_textstream( lv_text ). + go_to_line( c_max_line_count ). + ENDMETHOD. + + METHOD format_input. + ADD 1 TO mv_counter. + rv_text = | ${ mv_counter }> { query }\n|. + ENDMETHOD. "format_input + + METHOD append_source. + append_string( format_input( iv_text ) ). + ENDMETHOD. "append_string + + METHOD lif_source_editor~to_string. + get_textstream( IMPORTING text = rv_text + EXCEPTIONS OTHERS = 1 ). + CHECK sy-subrc EQ 0. + cl_gui_cfw=>flush( ). + ENDMETHOD. "to_string + + METHOD lif_source_editor~update_status. + DATA lv_text TYPE char72. + lv_text = iv_string. + set_status_text( lv_text ). + ENDMETHOD. "update_status + + METHOD lif_source_editor~push_text. + DATA code TYPE string. + code = lif_source_editor~to_string( ). + CHECK code NE space. + mo_stack->push( code ). + lif_source_editor~clear( ). + ENDMETHOD. + + METHOD lif_source_editor~previous. + lif_source_editor~clear( ). + append_string( mo_stack->previous( ) ). + ENDMETHOD. + + METHOD lif_source_editor~next. + lif_source_editor~clear( ). + append_string( mo_stack->next( ) ). + ENDMETHOD. + + METHOD lif_source_editor~set_focus. + set_focus( EXPORTING control = me + EXCEPTIONS OTHERS = 0 ). + ENDMETHOD. + + METHOD lif_source_editor~free. + free( ). + rt_string = mo_stack->serialize( ). + ENDMETHOD. + + METHOD lif_source_editor~setup. + mo_stack->deserialize( is_settings-stack ). + ENDMETHOD. + +ENDCLASS. "lcl_editor IMPLEMENTATION + +CLASS lcl_console DEFINITION INHERITING FROM lcl_editor. + PUBLIC SECTION. + METHODS constructor IMPORTING io_container TYPE REF TO cl_gui_container + iv_toolbar TYPE flag DEFAULT abap_false. + METHODS set_textstream REDEFINITION. + METHODS lif_source_editor~to_string REDEFINITION. + PROTECTED SECTION. + PRIVATE SECTION. + DATA mv_content TYPE string. +ENDCLASS. + + +CLASS lcl_console IMPLEMENTATION. + + METHOD constructor. + super->constructor( io_container = io_container + iv_read_only = abap_true + iv_toolbar = iv_toolbar ). + ENDMETHOD. + + METHOD set_textstream. + super->set_textstream( text ). + mv_content = text. + ENDMETHOD. + + METHOD lif_source_editor~to_string. + rv_text = mv_content. + ENDMETHOD. "to_string + +ENDCLASS. + +CLASS lcl_source DEFINITION INHERITING FROM cl_gui_sourceedit. + PUBLIC SECTION. + METHODS constructor IMPORTING io_container TYPE REF TO cl_gui_container + iv_read_only TYPE flag DEFAULT abap_false + iv_toolbar TYPE flag DEFAULT abap_false + iv_title TYPE string. + INTERFACES lif_source_editor. + PRIVATE SECTION. + DATA mo_stack TYPE REF TO lcl_stack. +ENDCLASS. + +CLASS lcl_source IMPLEMENTATION. + + METHOD constructor. + DATA mode TYPE i. + DATA exception_name TYPE string. + + io_container->set_visible( abap_true ). + super->constructor( + EXPORTING + parent = io_container + max_number_chars = '255' + EXCEPTIONS + error_cntl_create = 1 + error_dp_create = 2 + gui_type_not_supported = 3 + error_cntl_init = 4 ). + + IF sy-subrc NE 0. + CASE sy-subrc. + WHEN 1. + exception_name = 'ERROR_CNTL_CREATE'. + WHEN 2. + exception_name = 'ERROR_DP_CREATE'. + WHEN 3. + exception_name = 'GUI_TYPE_NOT_SUPPORTED'. + WHEN 4. + exception_name = 'ERROR_CNTL_INIT'. + ENDCASE. + RAISE EXCEPTION TYPE cx_coverage_api_adapter. + ENDIF. + + set_source_type( c_source_type ). + IF iv_toolbar EQ abap_true. + mode = 1. + ELSE. + mode = 0. + ENDIF. + set_toolbar_mode( mode ). + cl_gui_cfw=>flush( ). + + IF iv_read_only EQ abap_true. + set_readonly_mode( cl_gui_textedit=>true ). + mode = 0. + ELSE. + mode = 1. + ENDIF. + set_statusbar_mode( mode ). + set_actual_name( CONV syrepid( iv_title ) ). + upload_properties( EXCEPTIONS OTHERS = 1 ). + IF sy-subrc <> 0. +* MESSAGE e215(ed). + ENDIF. + create_document( ). + +* Work around to avoid NO DATA dump on first read + lif_source_editor~clear( ). + + CREATE OBJECT mo_stack. + ENDMETHOD. "constructor + + METHOD lif_source_editor~set_focus. + set_focus( EXPORTING control = me + EXCEPTIONS OTHERS = 0 ). + ENDMETHOD. + + METHOD lif_source_editor~free. + free( ). + rt_string = mo_stack->serialize( ). + ENDMETHOD. + + METHOD lif_source_editor~setup. + mo_stack->deserialize( is_settings-stack ). + ENDMETHOD. + + METHOD lif_source_editor~to_string. + DATA lt_text TYPE STANDARD TABLE OF string. + + get_text( IMPORTING table = lt_text + EXCEPTIONS OTHERS = 0 ). + "cl_gui_cfw=>flush( ). + rv_text = concat_lines_of( table = lt_text sep = |\n| ). + ENDMETHOD. "to_string + + METHOD lif_source_editor~update_status. + MESSAGE iv_string TYPE 'S'. + ENDMETHOD. "update_status + + METHOD lif_source_editor~clear. + DATA lt_text TYPE STANDARD TABLE OF string. + + set_text( EXPORTING table = lt_text + EXCEPTIONS OTHERS = 0 ). + ENDMETHOD. + + METHOD lif_source_editor~push_text. + DATA code TYPE string. + code = lif_source_editor~to_string( ). + CHECK code NE space. + mo_stack->push( code ). + lif_source_editor~clear( ). + ENDMETHOD. + + METHOD lif_source_editor~previous. + DATA lt_text TYPE STANDARD TABLE OF string. + + APPEND mo_stack->previous( ) TO lt_text. + set_text( EXPORTING table = lt_text + EXCEPTIONS OTHERS = 0 ). + ENDMETHOD. + + METHOD lif_source_editor~next. + DATA lt_text TYPE STANDARD TABLE OF string. + + APPEND mo_stack->next( ) TO lt_text. + set_text( EXPORTING table = lt_text + EXCEPTIONS OTHERS = 0 ). + ENDMETHOD. + +ENDCLASS. + +*----------------------------------------------------------------------* +* CLASS lcl_container DEFINITION +*----------------------------------------------------------------------* +CLASS lcl_container DEFINITION. + PUBLIC SECTION. + METHODS constructor. + METHODS free_controls. + DATA mo_input TYPE REF TO cl_gui_container READ-ONLY. + DATA mo_output TYPE REF TO cl_gui_container READ-ONLY. + DATA mo_console TYPE REF TO cl_gui_container READ-ONLY. + PRIVATE SECTION. + DATA mo_splitter_h TYPE REF TO cl_gui_splitter_container. + DATA mo_splitter_v TYPE REF TO cl_gui_splitter_container. + DATA mo_left TYPE REF TO cl_gui_container. +ENDCLASS. + +CLASS lcl_container IMPLEMENTATION. + METHOD constructor. + " Splitter Container + mo_splitter_v = NEW #( link_dynnr = '0100' + link_repid = sy-repid + parent = cl_gui_container=>screen0 + rows = 1 + columns = 2 ). + mo_splitter_v->set_border( border = cl_gui_cfw=>false ). + + mo_splitter_v->set_column_mode( mode = mo_splitter_v->mode_absolute ). + mo_splitter_v->set_column_width( id = 1 + width = 750 ). + mo_left = mo_splitter_v->get_container( row = 1 + column = 1 ). + mo_console = mo_splitter_v->get_container( row = 1 + column = 2 ). + + mo_splitter_h = NEW #( parent = mo_left + rows = 2 + columns = 1 ). + mo_splitter_h->set_border( border = cl_gui_cfw=>false ). + mo_splitter_h->set_row_mode( mode = mo_splitter_v->mode_relative ). + + mo_input = mo_splitter_h->get_container( row = 1 + column = 1 ). + mo_output = mo_splitter_h->get_container( row = 2 + column = 1 ). + + ENDMETHOD. + + METHOD free_controls. + FREE: mo_input, + mo_output, + mo_console. + FREE mo_left. + FREE mo_splitter_h. + FREE mo_splitter_v. + ENDMETHOD. "free_controls + +ENDCLASS. "lcl_container IMPLEMENTATION + +CLASS lcl_app DEFINITION. + PUBLIC SECTION. + DATA mv_title TYPE string VALUE c_llm_untitled READ-ONLY. + + CLASS-METHODS: + chat, + free, + default_model RETURNING VALUE(rd_model) TYPE zllm_clnt_config-provider_model, + pbo, + pai IMPORTING id_code TYPE syucomm + RETURNING VALUE(rd_flag) TYPE flag. + + METHODS constructor. + METHODS first_output. + METHODS free_controls. + METHODS handle_user_command IMPORTING ucomm TYPE sy-ucomm + RETURNING VALUE(rd_flag) TYPE flag. + + PRIVATE SECTION. + CLASS-DATA app TYPE REF TO lcl_app. + + DATA mv_first TYPE flag VALUE abap_true. + DATA mo_cont TYPE REF TO lcl_container. + DATA mi_source TYPE REF TO lif_source_editor. + DATA mo_output TYPE REF TO lcl_editor. + DATA mo_console TYPE REF TO lcl_console. + DATA ms_settings TYPE ts_settings. + + CLASS-METHODS call_transaction IMPORTING id_transaction TYPE tcode. + METHODS welcome RETURNING VALUE(text) TYPE string. + METHODS console_header RETURNING VALUE(text) TYPE string. + METHODS refresh. + + METHODS new_source_editor IMPORTING io_cont TYPE REF TO cl_gui_container + RETURNING VALUE(ri_source) TYPE REF TO lif_source_editor. + METHODS previous. + METHODS next. + METHODS evaluate. + + DATA runtime TYPE i. + + METHODS read_time RETURNING VALUE(rd_time) TYPE i. +ENDCLASS. + +*&---------------------------------------------------------------------* +*& Module STATUS_0100 OUTPUT +*&---------------------------------------------------------------------* +MODULE status_0100 OUTPUT. + lcl_app=>pbo( ). +ENDMODULE. +*&---------------------------------------------------------------------* +*& Module USER_COMMAND_0100 INPUT +*&---------------------------------------------------------------------* +MODULE user_command_0100 INPUT. + CHECK lcl_app=>pai( g_ok_code ). + CLEAR g_ok_code. +ENDMODULE. + +MODULE cancel_0100 INPUT. + lcl_app=>free( ). + LEAVE PROGRAM. +ENDMODULE. + +CLASS lcl_app IMPLEMENTATION. + + METHOD constructor. + super->constructor( ). + mv_title = model. + + CREATE OBJECT: + mo_cont, + + mo_output + EXPORTING + io_container = mo_cont->mo_output + iv_toolbar = abap_true, + mo_console + EXPORTING + io_container = mo_cont->mo_console. + + mi_source = new_source_editor( io_cont = mo_cont->mo_input ). + refresh( ). + ENDMETHOD. + + METHOD read_time. + GET RUN TIME FIELD rd_time. + ENDMETHOD. + + METHOD first_output. + CHECK mv_first EQ abap_true. + CLEAR mv_first. + mi_source->set_focus( ). + mo_output->append_string( |{ welcome( ) }\n| ). + mo_console->append_string( console_header( ) ). + ENDMETHOD. + + METHOD free_controls. + mo_console->free( ). + mo_output->free( ). + ms_settings-stack = mi_source->free( ). + mo_cont->free_controls( ). + "save_settings( ). + ENDMETHOD. + + METHOD welcome. + text = |==> Welcome to LLM Chat!\n|. + ENDMETHOD. "welcome + + METHOD console_header. + text = |==> LLM -- Console { sy-uname } -- { sy-datlo DATE = ENVIRONMENT } { sy-uzeit TIME = ENVIRONMENT }\n|. + ENDMETHOD. + + METHOD new_source_editor. + DATA gui_support TYPE boolean. +* Check for frontend support for the new ABAP Editor + cl_gui_frontend_services=>check_gui_support( + EXPORTING + component = 'abapeditor' "#EC NOTEXT + feature_name = 'ab4' "#EC NOTEXT + RECEIVING + result = gui_support + EXCEPTIONS + cntl_error = 1 + error_no_gui = 2 + wrong_parameter = 3 + not_supported_by_gui = 4 + unknown_error = 5 + OTHERS = 6 ). + IF sy-subrc NE 0 OR gui_support NE abap_true OR c_new_abap_editor NE abap_true. + ri_source = NEW lcl_editor( + io_container = io_cont + iv_read_only = abap_false + iv_toolbar = abap_true ). + + ELSE. + ri_source = NEW lcl_source( + io_container = io_cont + iv_read_only = abap_false + iv_toolbar = abap_true + iv_title = mv_title ). + ENDIF. + ri_source->setup( ms_settings ). + + ENDMETHOD. + + METHOD previous. + mi_source->previous( ). + ENDMETHOD. + + METHOD next. + mi_source->next( ). + ENDMETHOD. + + METHOD refresh. + mi_source->clear( ). + mo_output->delete_text( ). + mo_console->delete_text( ). + ENDMETHOD. "refresh + + METHOD pbo. + SET PF-STATUS '0100'. + SET TITLEBAR '0100' WITH app->mv_title. + app->first_output( ). + ENDMETHOD. + + METHOD pai. + rd_flag = app->handle_user_command( id_code ). + ENDMETHOD. + + METHOD free. + app->free_controls( ). + ENDMETHOD. + + + METHOD chat. + app = NEW #( ). + CALL SCREEN 100. + ENDMETHOD. + + METHOD default_model. + SELECT provider_model FROM zllm_clnt_config UP TO 1 ROWS INTO @rd_Model. + ENDSELECT. + ENDMETHOD. + + METHOD handle_user_command. + rd_flag = abap_false. + + CASE ucomm. + WHEN 'EXECUTE'. + evaluate( ). " get_response( ). + WHEN 'CLEAR'. + refresh( ). + WHEN 'PREV'. + previous( ). + WHEN 'NEXT'. + next( ). + + WHEN 'SM59'. + TRY. + CALL TRANSACTION 'SM59' WITH AUTHORITY-CHECK. + CATCH cx_sy_authorization_error INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + WHEN 'PROVIDERS'. + call_transaction( 'ZLLM_PROVIDER_CONFIG' ). + + WHEN 'MODELS'. + call_transaction( 'ZLLM_CLIENT_CONFIG' ). + + WHEN 'STATS'. + call_transaction( 'ZLLM_SYSTEM_CONF' ). + + WHEN OTHERS. + RETURN. + ENDCASE. + + rd_flag = abap_true. + ENDMETHOD. + + METHOD call_transaction. + TRY. + CALL TRANSACTION id_transaction WITH AUTHORITY-CHECK. + CATCH cx_sy_authorization_error INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. + + METHOD evaluate. + DATA query TYPE string. + DATA response TYPE string. + DATA output TYPE string. + DATA lx_root TYPE REF TO cx_root. + TRY. + query = mi_source->to_string( ). + + IF query IS INITIAL. + MESSAGE 'Please enter a message.'(003) TYPE 'I' DISPLAY LIKE 'W'. + RETURN. + ENDIF. + + DATA(ld_start_time) = read_time( ). + + DATA(client) = zcl_llm_factory=>get_client( model ). + DATA(resp) = client->execute( user_message = query ). + + runtime = read_time( ) - ld_start_time. + + IF resp-error-error_text IS NOT INITIAL. + mo_console->append_source( resp-error-error_text && |\n| ). + ENDIF. + + response = resp-choice-message-content. + + mi_source->push_text( ). + mi_source->update_status( |[ { runtime } µs ] { response }| ). + + CATCH zcx_llm_authorization. + mo_console->append_source( 'Not authorized.'(005) && |\n| ). + + CATCH cx_root INTO lx_root. + response = lx_root->get_text( ). + mi_source->update_status( response ). + ENDTRY. + + mo_output->append_source( |{ query }\n=> { response }\n| ). + ENDMETHOD. + +ENDCLASS. diff --git a/src/yy_llm_ide.prog.xml b/src/yy_llm_ide.prog.xml new file mode 100644 index 0000000..1d0eca3 --- /dev/null +++ b/src/yy_llm_ide.prog.xml @@ -0,0 +1,21 @@ + + + + + + YY_LLM_IDE + I + K + E + X + + + + R + Include YY_LLM_IDE + 18 + + + + + diff --git a/src/zllm_chat_example.prog.abap b/src/zllm_chat_example.prog.abap index 478fc38..3b20b8f 100644 --- a/src/zllm_chat_example.prog.abap +++ b/src/zllm_chat_example.prog.abap @@ -4,157 +4,13 @@ *& *&---------------------------------------------------------------------* REPORT zllm_chat_example. -DATA model TYPE zllm_model. -DATA user_message TYPE string. -CLASS lcl_app DEFINITION. - PUBLIC SECTION. - METHODS display. - METHODS handle_user_command IMPORTING ucomm TYPE sy-ucomm. - METHODS initialize_text_editors. +PARAMETERS model TYPE zllm_model MATCHCODE OBJECT zllm_model. - PRIVATE SECTION. - DATA: text_editor_input TYPE REF TO cl_gui_textedit, - text_editor_output TYPE REF TO cl_gui_textedit, - custom_container_in TYPE REF TO cl_gui_custom_container, - custom_container_out TYPE REF TO cl_gui_custom_container. - - - METHODS get_response. - METHODS set_output_text IMPORTING text TYPE string. - METHODS cleanup_controls. -ENDCLASS. - -CLASS lcl_app IMPLEMENTATION. - METHOD display. - CALL SCREEN 100. - ENDMETHOD. - - METHOD handle_user_command. - CASE ucomm. - WHEN 'SEND'. - get_response( ). - WHEN 'BACK' OR 'CANCEL' OR 'EXIT'. " Consistent handling - cleanup_controls( ). - LEAVE TO SCREEN 0. " Exit the program - ENDCASE. - ENDMETHOD. - - METHOD initialize_text_editors. - IF text_editor_input IS NOT BOUND. " Only initialize if not already done - custom_container_in = NEW #( container_name = 'INPUT_CONTAINER' ). - text_editor_input = NEW #( parent = custom_container_in ). - - " Settings for input editor - text_editor_input->set_toolbar_mode( cl_gui_textedit=>false ). - text_editor_input->set_statusbar_mode( cl_gui_textedit=>false ). - text_editor_input->set_wordwrap_behavior( wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position - wordwrap_position = 100 ). - ENDIF. - - IF text_editor_output IS NOT BOUND. - custom_container_out = NEW #( container_name = 'OUTPUT_CONTAINER' ). - text_editor_output = NEW #( parent = custom_container_out ). - - " Settings for output editor - text_editor_output->set_toolbar_mode( cl_gui_textedit=>false ). - text_editor_output->set_statusbar_mode( cl_gui_textedit=>false ). - text_editor_output->set_wordwrap_behavior( wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position - wordwrap_position = 100 ). - text_editor_output->set_readonly_mode( 1 ). " Make output read-only - ENDIF. - - " Flush operations so controls are sent to the frontend immediately! - cl_gui_cfw=>flush( ). - ENDMETHOD. - - METHOD get_response. - " Error Handling first! - IF model IS INITIAL. - MESSAGE 'Please select a model.'(002) TYPE 'I' DISPLAY LIKE 'E'. - RETURN. - ENDIF. - - " Get user input text - DATA texts TYPE STANDARD TABLE OF char255. - - text_editor_input->get_text_as_stream( IMPORTING text = texts ). - - user_message = concat_lines_of( table = texts - sep = cl_abap_char_utilities=>cr_lf ). - - IF user_message IS INITIAL. - MESSAGE 'Please enter a message.'(003) TYPE 'I' DISPLAY LIKE 'E'. - RETURN. - ENDIF. - - TRY. - DATA(client) = zcl_llm_factory=>get_client( model ). - DATA(response) = client->execute( user_message = user_message ). - set_output_text( response-choice-message-content ). - - CATCH zcx_llm_authorization. - MESSAGE 'Not authorized.'(005) TYPE 'I' DISPLAY LIKE 'E'. - ENDTRY. - ENDMETHOD. - - METHOD set_output_text. - DATA texts TYPE STANDARD TABLE OF char255. - - " Convert the string to table of fixed-length strings - DATA(remaining_text) = text. - WHILE strlen( remaining_text ) > 0. - DATA(line) = substring( val = remaining_text - len = COND #( - WHEN strlen( remaining_text ) > 255 - THEN 255 - ELSE strlen( remaining_text ) ) ). - APPEND line TO texts. - remaining_text = substring( val = remaining_text - off = strlen( line ) - len = strlen( remaining_text ) - strlen( line ) ). - ENDWHILE. - - text_editor_output->set_text_as_stream( texts ). - cl_gui_cfw=>flush( ). - ENDMETHOD. - - METHOD cleanup_controls. - IF text_editor_input IS BOUND. - text_editor_input->free( ). - ENDIF. - IF text_editor_output IS BOUND. - text_editor_output->free( ). - ENDIF. - - IF custom_container_in IS BOUND. - custom_container_in->free( ). - ENDIF. - IF custom_container_out IS BOUND. - custom_container_out->free( ). - ENDIF. - ENDMETHOD. -ENDCLASS. - -DATA app TYPE REF TO lcl_app. +INCLUDE yy_llm_ide. INITIALIZATION. - app = NEW #( ). + model = lcl_app=>default_model( ). START-OF-SELECTION. - app->display( ). - -*&---------------------------------------------------------------------* -*& Module STATUS_0100 OUTPUT -*&---------------------------------------------------------------------* -MODULE status_0100 OUTPUT. - SET PF-STATUS '0100'. - SET TITLEBAR '0100'. - app->initialize_text_editors( ). -ENDMODULE. -*&---------------------------------------------------------------------* -*& Module USER_COMMAND_0100 INPUT -*&---------------------------------------------------------------------* -MODULE user_command_0100 INPUT. - app->handle_user_command( sy-ucomm ). -ENDMODULE. + lcl_app=>chat( ). diff --git a/src/zllm_chat_example.prog.screen_0100.abap b/src/zllm_chat_example.prog.screen_0100.abap index 0adce5b..ae683e2 100644 --- a/src/zllm_chat_example.prog.screen_0100.abap +++ b/src/zllm_chat_example.prog.screen_0100.abap @@ -2,4 +2,5 @@ PROCESS BEFORE OUTPUT. MODULE status_0100. PROCESS AFTER INPUT. + MODULE cancel_0100 AT EXIT-COMMAND. MODULE user_command_0100. diff --git a/src/zllm_chat_example.prog.xml b/src/zllm_chat_example.prog.xml index 48dac03..099373a 100644 --- a/src/zllm_chat_example.prog.xml +++ b/src/zllm_chat_example.prog.xml @@ -19,7 +19,7 @@ N 0100 038 - 213 + 214 @@ -78,23 +78,6 @@ X ZLLM_MODEL - - SCREEN - SCREEN - PUSH - SEND - SEND___ - ICON_MAIL - X - 001 - 112 - 012 - 010 - 001 - SEND - CHAR - N - SCREEN SCREEN @@ -127,6 +110,7 @@ SCREEN SCREEN OKCODE + G_OK_CODE ____________________ 020 020 @@ -140,7 +124,7 @@ 000001 - 000001 + 000003 000001 @@ -157,22 +141,86 @@ BACK 001 + E S Back CANCEL 001 + E S Exit + + CLEAR + 001 + S + ICON_DELETE + @11@ + Refresh + Refresh + Refresh + E + + + EVALUATE + 001 + S + Evaluate + V + + + EXECUTE + 001 + S + ICON_SYSTEM_PLAY + @I6@ + Send + Evaluate + Evaluate + EXIT 001 + E S ICON_CANCEL @0W@ Cancel + A + + + MODELS + 001 + S + Modell Configuration + + + NEXT + 001 + S + ICON_ARROW_RIGHT + @9T@ + Next + Next + Next query + + + PREV + 001 + S + ICON_ARROW_LEFT + @9S@ + Previous + Previous + Previous query + + + PROVIDERS + 001 + S + Providers SEND @@ -181,13 +229,72 @@ SEND S + + SM59 + 001 + S + RFC Destinations + + + STATS + 001 + S + Statistics / Logs + 000001 01 F - SEND + EVALUATE + 001 + + + 000001 + 02 + S + + + 000001 + 03 + F + CLEAR + 001 + + + 000001 + 04 + F + EXIT + 001 + + + 000003 + 01 + F + SM59 + 001 + + + 000003 + 02 + F + PROVIDERS + 001 + + + 000003 + 03 + F + MODELS + 001 + + + 000003 + 04 + F + STATS 001 @@ -195,8 +302,19 @@ 000001 S - SEND - S + User Interface + U + + + 000002 + S + Modell + M + + + 000003 + S + Customizing @@ -205,7 +323,38 @@ 01 000001 + + 000001 + 02 + 000003 + + + + 000001 + 0001 + 01 + 08 + + + 000001 + 0001 + 02 + 13 + + + 000001 + 0001 + 03 + 14 + + + 000001 + 0001 + 04 + 16 + + 000001 @@ -213,18 +362,42 @@ BACK 001 + + 000001 + 08 + EXECUTE + 001 + 000001 12 EXIT 001 + + 000001 + 13 + PREV + 001 + + + 000001 + 14 + NEXT + 001 + 000001 15 CANCEL 001 + + 000001 + 16 + CLEAR + 001 + @@ -235,14 +408,50 @@ 0100 CANCEL + + 0100 + CLEAR + + + 0100 + EVALUATE + + + 0100 + EXECUTE + 0100 EXIT + + 0100 + MODELS + + + 0100 + NEXT + + + 0100 + PREV + + + 0100 + PROVIDERS + 0100 SEND + + 0100 + SM59 + + + 0100 + STATS + @@ -268,7 +477,7 @@ 0100 - Chat Example + Chat Example - Model &1 @@ -296,6 +505,13 @@ LLM Chat Example report 23 + + S + MODEL + . + 9 + D +