Files
t-deckard/app/llmchat.py
T

172 lines
4.9 KiB
Python
Raw Normal View History

2025-12-20 18:28:43 +02:00
# LLM chat for T-Deck CicruitPython version
2025-12-21 08:42:07 +02:00
# (also can be run on MicroPython and usual CPython)
2025-12-20 18:28:43 +02:00
# On the T-Deck, requires to be run from tdeck_repl for the
# keyboard to work correctly
# Usage: from llmchat import llmchat
2025-12-20 18:28:43 +02:00
# Created by Luxferre in 2025, released into public domain
2025-12-20 22:37:45 +02:00
from deck.chat import DeckChat
from deck.llm import LLMChat
from app.ed import edbuf
2025-12-20 18:28:43 +02:00
CONFIG_FILE = 'llmcfg.json'
2025-12-20 22:37:45 +02:00
# chat handlers
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def send_msg(msg, state):
print("Please wait for the answer...")
status, ans = state.get_completion(msg)
return ans, state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def set_sys_prompt(prompt, state):
if prompt:
state.config['system_prompt'] = prompt
state.save_config()
state.reset_context()
return 'System prompt updated', state
else:
return f"System: {state.config['system_prompt']}", state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def set_temp(temp, state):
if temp:
state.config['temperature'] = float(temp)
state.save_config()
return 'Temperature updated', state
else:
return f"Temperature: {state.config['temperature']}", state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def set_prov(prov, state):
if prov and prov in state.config.get('providers', {}):
state.config['active_provider'] = prov
state.setup_provider()
state.save_config()
state.reset_context()
return 'Provider updated', state
else:
return f"Active provider: {state.config['active_provider']}", state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def set_model(model, state):
if model:
state.provider['model'] = model
state.save_config()
return 'Model updated', state
else:
return f"Active model: {state.provider.get('model')}", state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def list_models(stub, state):
status, mlist = state.list_models()
if status:
resp = f"Model list for {state.config['active_provider']}:"
for m in mlist:
resp += f'\n- {m}'
else:
resp = mlist
return resp, state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def list_providers(stub, state):
resp = 'Provider list:'
for p in state.config.get('providers', {}):
resp += f'\n - {p}'
return resp, state
2025-12-20 18:28:43 +02:00
def save_conversation(fname, state):
resp = ''
status, cnv = state.export()
try:
with open(fname, 'w') as f:
f.write(cnv)
resp = 'Conversation saved'
except:
resp = 'Error saving conversation'
return resp, state
def save_last_msg(fname, state):
resp = ''
status, cnv = state.get_last_response()
try:
with open(fname, 'w') as f:
f.write(cnv)
resp = 'Response saved'
except:
resp = 'Error saving response'
return resp, state
def extract_code_block(text, start_marker="```", end_marker="```"):
extracted_parts = []
search_index = 0
while True:
block_start = text.find(start_marker, search_index)
if block_start == -1:
break
content_start = block_start + len(start_marker)
if start_marker == "```":
newline_after_start = text.find("\n", content_start)
if newline_after_start != -1:
potential_end = text.find(end_marker, content_start)
if potential_end == -1 or newline_after_start < potential_end:
content_start = newline_after_start + 1
block_end = text.find(end_marker, content_start)
if block_end == -1:
break
extracted_block = text[content_start:block_end].strip()
if extracted_block:
extracted_parts.append(extracted_block)
search_index = block_end + len(end_marker)
return "\n\n".join(extracted_parts)
def save_last_msg_code(fname, state):
resp = ''
status, cnv = state.get_last_response()
cnv = extract_code_block(cnv)
try:
with open(fname, 'w') as f:
f.write(cnv)
resp = 'Code saved'
except:
resp = 'Error saving code'
return resp, state
def edit_last_msg_code(fname, state):
resp = ''
status, cnv = state.get_last_response()
cnv = extract_code_block(cnv)
try:
edbuf(cnv)
except:
resp = 'Error extracting code'
return resp, state
def add_file(fname, state):
status, resp = state.add_file(fname)
return resp, state
2025-12-20 22:37:45 +02:00
def display_help(stub, state):
resp = "/clear, /system, /temp, /prov, /model, /modellist, /provlist, /add, /saveconv, /savelast, /savecode, /edcode, /exit, /quit"
2025-12-20 22:37:45 +02:00
return resp, state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
def clear_ctx(stub, state):
state.reset_context()
return 'Context reset', state
2025-12-20 18:28:43 +02:00
2025-12-20 22:37:45 +02:00
# main initialization
def llmchat():
llm = LLMChat(config_file=CONFIG_FILE, message_limit=20)
chat = DeckChat(start_state=llm, chat_prefix='> ')
chat.command('default', send_msg)
chat.command('clear', clear_ctx)
chat.command('system', set_sys_prompt)
chat.command('temp', set_temp)
chat.command('prov', set_prov)
chat.command('model', set_model)
chat.command('modellist', list_models)
chat.command('provlist', list_providers)
chat.command('add', add_file)
chat.command('saveconv', save_conversation)
chat.command('savelast', save_last_msg)
chat.command('savecode', save_last_msg_code)
chat.command('edcode', edit_last_msg_code)
chat.command('help', display_help)
chat.command('exit', lambda m,s: ('Exiting...', None))
chat.command('quit', lambda m,s: ('Exiting...', None))
chat.start()