create or replace FUNCTION fnc_26ai_rag_aiagent(p_query VARCHAR2, 
                                          p_top_k IN NUMBER ,
                                          p_prompt_length out number,
                                          p_credential in varchar2 default 'OCI_CRED',
                                          p_app_user in varchar2 default V('APP_USER') ) 
RETURN CLOB IS
/*

  Criado por: fernando.leal@oracle.com
  Data: Oct/2025
  Objetivo: demonstrar casos de uso do Oracle AI Database 26ai

  v1 - funcao de RAG para estudo explorar "fale com seus dados" (quando nao ter AgentAI disponivel para exibicao) - leal

*/
   v_context  CLOB;
   v_pre_prompt clob;
   v_prompt clob;
   v_pre_prompt2 clob;
   params_genai CLOB;
   output CLOB;
   query_vec VECTOR;
   -- https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/dbms_vector_chain1.html#GUID-017C9002-194C-48E5-B59B-EF5C60BC8405
   v_llm varchar2(20) := 'LLAMA4'; -- [ LLAMA4 | OPENAI  ]

BEGIN


  -- embedding do prompt para dedicated
  query_vec := to_vector(  fnc_26ai_embed ( p_string => p_query, p_emb_type => 'COHERE' ) );

  
  for message_cursor in (
                        select lv.ID as DOCID, 
                               lv.EMBED_DATA  as BODY, 
                               vector_distance(lv.EMBED_VECTOR, query_vec, cosine ) AS SCORE,
							   lv.FILE_NAME
                        from TB_26AI_AIAGENT_VECTOR lv
                        where lower(p_query) <> 'oi' 
                         and lower(p_query) <> 'ola' 
                         and lower(p_query) <> 'olá' 
                         and lower(p_query) <> 'bom dia' 
                         and lower(p_query) <> 'boa tarde' 
                         and lower(p_query) <> 'teste' 
                        -- and vector_distance(lv.EMBED_VECTOR, query_vec, cosine )  >= 8/10
                        and ( upper(USER_NAME) like 'ADMIN%' or upper(USER_NAME) = upper(p_app_user) )
                        order by SCORE 
                        FETCH EXACT FIRST p_top_k ROWS ONLY    
                    ) loop


        v_context := v_context || '"' || replace(replace(replace(replace(message_cursor.BODY || ' - Citations: ' || message_cursor.file_name ,
		                                 chr(10),null),chr(13),null),'"',''),'''','') || '",' ;

   end loop;

  
  -- 
  -- pre requisito sao as credenciais definidas com nome OCI_CRED criadas a partir de dbms_vector.create_credential
  --
  -- para montar request body abaixo:  https://docs.oracle.com/en-us/iaas/api/#/en/generative-ai-inference/20231130/datatypes/GenerateTextDetails
  --
  if v_llm = 'LLAMA4' then

    params_genai := '{
		"provider" : "ocigenai",
     	"credential_name" : "' || p_credential || '",
		"url" : "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/chat",
		"model": "meta.llama-4-maverick-17b-128e-instruct-fp8"}';

  elsif v_llm = 'OPENAI' then  

    params_genai := '{
        "provider" : "openai",
        "credential_name" : "CRED_OPENAI",
        "url" : "https://api.openai.com/v1/chat/completions",  
        "model" : "gpt-4.1-mini",
        "temperature": 0.4
        }';

  end if;

  -- augmented prompt atraves do vetor criado no banco
  v_pre_prompt := '"messages": [
            {
                "role": "system",
                "content": "Objetivo
Resgate informações dos documentos de modo a trazer explicações claras e objetivas.
Escopo
	•	Responda apenas sobre informações contidas em documentos.
	•	Se a pergunta não estiver nesse escopo, retorne com recusa educada.
    •	Se o prompt tiver um"oi", "olá", "bom dia", ou qualquer tipo de saudação, retorne apenas "Como posso lhe ajudar?"
    •	Sempre cite a origem da resposta, descrita em "Citations" (nome do arquivo PDF, DOC ou imagem PNG, JPG, etc)
Formato da resposta 
	•	A saída deve ser obrigatoriamente em listas e tópicos, nunca em parágrafos corridos.
	•	Estrutura fixa da resposta:
	•	Título curto com o insight principal.
	•	Resumo em 3 bullets (curtos, diretos).
	•	Principais insights: lista não ordenada (•) para destaques gerais.
	•	Rankings ou comparações: lista ordenada (1, 2, 3).
	•	É proibido escrever respostas fora desse formato.
	•	Use negrito para informações críticas e itálico para sinais preliminares ou hipóteses.
    •	Nunca resposnda com um JSON na resposta. Respostas são para usuários finais, devem ser respostas claras confoirme "Formato da resposta"
Guardrails
	•	Nunca exponha PII.
	•	Se não houver evidências suficientes, declare claramente essa limitação no mesmo formato de lista.
Linguagem
	•	Sempre em português claro, executivo e direto.
	•	Evite jargões técnicos.
	•	Valores monetários em BRL.",';


    v_pre_prompt2 := '{ "role": "user","content": "Contexto:"' || v_context  || ' "Pergunta": ' || p_query   || '"}' ; -- sem ]'
 
    v_prompt := v_pre_prompt || v_pre_prompt2 || ']';

    -- para LLama, a contabilizacao é por caracteres
    p_prompt_length := fnc_26ai_char_count(v_prompt);
 
    output := dbms_vector_chain.utl_to_generate_text(  replace(replace(replace(replace(v_prompt,chr(10),null),chr(13),null),'"',''),'''','')  , json(params_genai));

   RETURN output;

END;
/