diff --git a/src/interface/web/chat.html b/src/interface/web/chat.html new file mode 100644 index 00000000..07253b06 --- /dev/null +++ b/src/interface/web/chat.html @@ -0,0 +1,261 @@ + + + + + Khoj + + + + + + + + +

Khoj

+ + +
+ + + + + + + diff --git a/src/processor/conversation/gpt.py b/src/processor/conversation/gpt.py index 5f312b78..c67739d1 100644 --- a/src/processor/conversation/gpt.py +++ b/src/processor/conversation/gpt.py @@ -31,7 +31,7 @@ Summarize the below notes about {user_query}: {text} -Summarize the notes in second person perspective and use past tense:''' +Summarize the notes in second person perspective:''' # Get Response from GPT response = openai.Completion.create( @@ -210,20 +210,31 @@ def message_to_prompt(user_message, conversation_history="", gpt_message=None, s return f"{conversation_history}{restart_sequence} {user_message}{start_sequence}{gpt_message}" -def message_to_log(user_message, user_message_metadata, gpt_message, conversation_log=[]): +def message_to_log(user_message, gpt_message, user_message_metadata={}, conversation_log=[]): """Create json logs from messages, metadata for conversation log""" + default_user_message_metadata = { + "intent": { + "type": "remember", + "memory-type": "notes", + "query": user_message + }, + "trigger-emotion": "calm" + } + current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + # Create json log from Human's message - human_log = user_message_metadata + human_log = user_message_metadata or default_user_message_metadata human_log["message"] = user_message - human_log["by"] = "Human" - human_log["created"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + human_log["by"] = "you" + human_log["created"] = current_dt # Create json log from GPT's response - ai_log = {"message": gpt_message, "by": "AI", "created": datetime.now().strftime("%Y-%m-%d %H:%M:%S")} + khoj_log = {"message": gpt_message, "by": "khoj", "created": current_dt} - conversation_log.extend([human_log, ai_log]) + conversation_log.extend([human_log, khoj_log]) return conversation_log + def extract_summaries(metadata): """Extract summaries from metadata""" return ''.join( diff --git a/src/routers/api_beta.py b/src/routers/api_beta.py index a92443db..021e7e9a 100644 --- a/src/routers/api_beta.py +++ b/src/routers/api_beta.py @@ -4,13 +4,14 @@ import logging from typing import Optional # External Packages +import schedule from fastapi import APIRouter # Internal Packages from src.routers.api import search from src.processor.conversation.gpt import converse, extract_search_type, message_to_log, message_to_prompt, understand, summarize from src.utils.config import SearchType -from src.utils.helpers import get_absolute_path, get_from_dict +from src.utils.helpers import get_from_dict, resolve_absolute_path from src.utils import state @@ -46,6 +47,10 @@ def summarize_beta(q: str): model = state.processor_config.conversation.model api_key = state.processor_config.conversation.openai_api_key + # Load Conversation History + chat_session = state.processor_config.conversation.chat_session + meta_log = state.processor_config.conversation.meta_log + # Converse with OpenAI GPT result_list = search(q, n=1, t=SearchType.Org, r=True) collated_result = "\n".join([item.entry for item in result_list]) @@ -57,11 +62,15 @@ def summarize_beta(q: str): gpt_response = str(e) status = 'error' + # Update Conversation History + state.processor_config.conversation.chat_session = message_to_prompt(q, chat_session, gpt_message=gpt_response) + state.processor_config.conversation.meta_log['chat'] = message_to_log(q, gpt_response, conversation_log=meta_log.get('chat', [])) + return {'status': status, 'response': gpt_response} @api_beta.get('/chat') -def chat(q: str): +def chat(q: Optional[str]=None): # Initialize Variables model = state.processor_config.conversation.model api_key = state.processor_config.conversation.openai_api_key @@ -70,6 +79,10 @@ def chat(q: str): chat_session = state.processor_config.conversation.chat_session meta_log = state.processor_config.conversation.meta_log + # If user query is empty, return chat history + if not q: + return {'status': 'ok', 'response': meta_log["chat"]} + # Converse with OpenAI GPT metadata = understand(q, model=model, api_key=api_key, verbose=state.verbose) logger.debug(f'Understood: {get_from_dict(metadata, "intent")}') @@ -95,17 +108,16 @@ def chat(q: str): # Update Conversation History state.processor_config.conversation.chat_session = message_to_prompt(q, chat_session, gpt_message=gpt_response) - state.processor_config.conversation.meta_log['chat'] = message_to_log(q, metadata, gpt_response, meta_log.get('chat', [])) + state.processor_config.conversation.meta_log['chat'] = message_to_log(q, gpt_response, metadata, meta_log.get('chat', [])) return {'status': status, 'response': gpt_response} -@api_beta.on_event('shutdown') -def shutdown_event(): +@schedule.repeat(schedule.every(5).minutes) +def save_chat_session(): # No need to create empty log file - if not (state.processor_config and state.processor_config.conversation and state.processor_config.conversation.meta_log): + if not (state.processor_config and state.processor_config.conversation and state.processor_config.conversation.meta_log and state.processor_config.conversation.chat_session): return - logger.debug('INFO:\tSaving conversation logs to disk...') # Summarize Conversation Logs for this Session chat_session = state.processor_config.conversation.chat_session @@ -121,10 +133,13 @@ def shutdown_event(): conversation_log['session'].append(session) else: conversation_log['session'] = [session] + logger.info('Added new chat session to conversation logs') # Save Conversation Metadata Logs to Disk - conversation_logfile = get_absolute_path(state.processor_config.conversation.conversation_logfile) + conversation_logfile = resolve_absolute_path(state.processor_config.conversation.conversation_logfile) + conversation_logfile.parent.mkdir(parents=True, exist_ok=True) # create conversation directory if doesn't exist with open(conversation_logfile, "w+", encoding='utf-8') as logfile: json.dump(conversation_log, logfile) - logger.info('INFO:\tConversation logs saved to disk.') + state.processor_config.conversation.chat_session = None + logger.info('Saved updated conversation logs to disk.') diff --git a/src/routers/web_client.py b/src/routers/web_client.py index 0c2b8628..4a22e7f7 100644 --- a/src/routers/web_client.py +++ b/src/routers/web_client.py @@ -21,3 +21,7 @@ def index(): @web_client.get('/config', response_class=HTMLResponse) def config_page(request: Request): return templates.TemplateResponse("config.html", context={'request': request}) + +@web_client.get("/chat", response_class=FileResponse) +def chat_page(): + return FileResponse(constants.web_directory / "chat.html") \ No newline at end of file