Add files via upload
This commit is contained in:
@@ -106,6 +106,27 @@ class ChatCLI:
|
|||||||
|
|
||||||
return s == "\x1b" or s.strip().lower() in {"esc", ":q"}
|
return s == "\x1b" or s.strip().lower() in {"esc", ":q"}
|
||||||
|
|
||||||
|
def yes_no_prompt(self, label: str) -> bool:
|
||||||
|
yes = str(self("o_Yes") or "yes").strip().lower()
|
||||||
|
no = str(self("o_No") or "no").strip().lower()
|
||||||
|
|
||||||
|
valid_yes = {"y", "yes"}
|
||||||
|
valid_no = {"n", "no"}
|
||||||
|
|
||||||
|
if yes:
|
||||||
|
valid_yes.add(yes)
|
||||||
|
valid_yes.add(yes[0])
|
||||||
|
|
||||||
|
if no:
|
||||||
|
valid_no.add(no)
|
||||||
|
valid_no.add(no[0])
|
||||||
|
|
||||||
|
ans = self._read_input(
|
||||||
|
f"{label} ({self('o_Yes')}/{self('o_No')}): "
|
||||||
|
).strip().lower()
|
||||||
|
|
||||||
|
return ans in valid_yes
|
||||||
|
|
||||||
# ---------------- CONFIG ----------------
|
# ---------------- CONFIG ----------------
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
@@ -995,13 +1016,18 @@ class ChatCLI:
|
|||||||
providers = cfg.get("local_providers", {})
|
providers = cfg.get("local_providers", {})
|
||||||
pcfg = providers.get(provider_name, {})
|
pcfg = providers.get(provider_name, {})
|
||||||
|
|
||||||
print(f"\n={self('o_AI_Provider')}: {provider_name}=")
|
print(f"\n={self('o_AI_Providers')}: {provider_name}=")
|
||||||
|
|
||||||
for i, key in enumerate(keys, 1):
|
for i, key in enumerate(keys, 1):
|
||||||
print(f"{i}) {key}: {pcfg.get(key, '')}")
|
print(f"{i}) {key}: {pcfg.get(key, '')}")
|
||||||
|
|
||||||
print(f"{len(keys) + 1}) {self('o_Delete_Provider')}")
|
stop_num = len(keys) + 1
|
||||||
print(f"{len(keys) + 2}) {self('o_Go_Back')}")
|
delete_num = len(keys) + 2
|
||||||
|
back_num = len(keys) + 3
|
||||||
|
|
||||||
|
print(f"{stop_num}) {self('o_Stop_Provider')}")
|
||||||
|
print(f"{delete_num}) {self('o_Delete_Provider')}")
|
||||||
|
print(f"{back_num}) {self('o_Go_Back')}")
|
||||||
|
|
||||||
choice = self._read_input(f"\n{self('o_Selection')}: ").strip()
|
choice = self._read_input(f"\n{self('o_Selection')}: ").strip()
|
||||||
|
|
||||||
@@ -1010,19 +1036,54 @@ class ChatCLI:
|
|||||||
|
|
||||||
num = int(choice)
|
num = int(choice)
|
||||||
|
|
||||||
if num == len(keys) + 2:
|
if num == back_num:
|
||||||
return
|
return
|
||||||
|
|
||||||
if num == len(keys) + 1:
|
if num == stop_num:
|
||||||
confirm = self._read_input(f"{self('o_Delete')}? ({self('o_Yes')}/{self('o_No')}): ").strip().lower()
|
cmd = str(pcfg.get("stop_command") or "").strip()
|
||||||
if confirm in ("e", "evet", "y", "yes"):
|
|
||||||
|
if not cmd:
|
||||||
|
print(self("o_Provider_Command_No_Command", provider=provider_name))
|
||||||
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
p = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
shell=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
if p.returncode == 0:
|
||||||
|
print(self("o_Provider_Command_Success", provider=provider_name, command=cmd))
|
||||||
|
else:
|
||||||
|
print(self("o_Provider_Command_Failed", provider=provider_name, command=cmd, code=p.returncode))
|
||||||
|
|
||||||
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print(self("o_Provider_Command_Timeout", provider=provider_name, command=cmd))
|
||||||
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(self("o_Provider_Command_Error", provider=provider_name, error=e))
|
||||||
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
if num == delete_num:
|
||||||
|
if self.yes_no_prompt(f"{self('o_Delete_Provider')}?"):
|
||||||
providers.pop(provider_name, None)
|
providers.pop(provider_name, None)
|
||||||
cfg["local_providers"] = providers
|
cfg["local_providers"] = providers
|
||||||
self.save_config(cfg)
|
self.save_config(cfg)
|
||||||
return
|
return
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
idx = num - 1
|
idx = num - 1
|
||||||
|
|
||||||
if not (0 <= idx < len(keys)):
|
if not (0 <= idx < len(keys)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -1256,6 +1317,27 @@ class ChatCLI:
|
|||||||
|
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
def apply_op_summary_line_cli(self, op: dict) -> str:
|
||||||
|
mode = str(op.get("mode") or "").strip().lower()
|
||||||
|
find = str(op.get("find") or "").strip()
|
||||||
|
text = str(op.get("text") or "").strip()
|
||||||
|
|
||||||
|
if len(find) > 80:
|
||||||
|
find = find[:80] + "..."
|
||||||
|
|
||||||
|
if len(text) > 80:
|
||||||
|
text = text[:80] + "..."
|
||||||
|
|
||||||
|
if mode == "before":
|
||||||
|
mode_text = self("o_Apply_Mode_before")
|
||||||
|
elif mode == "after":
|
||||||
|
mode_text = self("o_Apply_Mode_after")
|
||||||
|
elif mode == "replace":
|
||||||
|
mode_text = self("o_Apply_Mode_replace")
|
||||||
|
else:
|
||||||
|
mode_text = mode or "-"
|
||||||
|
|
||||||
|
return f"{mode_text}: {find} -> {text}"
|
||||||
|
|
||||||
def handle_pending_apply_requests(self) -> bool:
|
def handle_pending_apply_requests(self) -> bool:
|
||||||
msg_index, msg, ops = self.find_pending_apply_request()
|
msg_index, msg, ops = self.find_pending_apply_request()
|
||||||
@@ -1288,12 +1370,18 @@ class ChatCLI:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
print()
|
||||||
|
for op in ops:
|
||||||
|
print(self.apply_op_summary_line_cli(op))
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(f"{self('o_Files')}:")
|
||||||
for p in paths:
|
for p in paths:
|
||||||
print(f"- {p}")
|
print(f"- {p}")
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(f"1) {self('o_Apply')}")
|
print(f"1) {self('o_Apply')}")
|
||||||
print(f"2) {self('o_Cancel')}")
|
print(f"2) {self('o_Reject')}")
|
||||||
|
|
||||||
choice = self._read_input(f"\n{self('o_Selection')}: ").strip()
|
choice = self._read_input(f"\n{self('o_Selection')}: ").strip()
|
||||||
|
|
||||||
@@ -1312,7 +1400,7 @@ class ChatCLI:
|
|||||||
|
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
self.set_apply_status_cli(msg_index, "cancel")
|
self.set_apply_status_cli(msg_index, "cancel")
|
||||||
print(f"\n⏭️ {self('o_Cancelled')}")
|
print(f"\n⏭️ {self('o_Reject')}")
|
||||||
self._read_input(f"\n{self('o_to_Menu')}")
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -1857,11 +1945,8 @@ class ChatCLI:
|
|||||||
ext = p.suffix.lower()
|
ext = p.suffix.lower()
|
||||||
|
|
||||||
if ext in (".docx", ".pdf", ".xlsx", ".txt", ".md"):
|
if ext in (".docx", ".pdf", ".xlsx", ".txt", ".md"):
|
||||||
ans = self._read_input(
|
edit_default = self.yes_no_prompt(self("o_Edit_Mode"))
|
||||||
f"{self('o_Edit_Mode')} ({self('o_Yes')}/{self('o_No')}): "
|
|
||||||
).strip().lower()
|
|
||||||
|
|
||||||
edit_default = ans in ("e", "evet", "y", "yes")
|
|
||||||
self.pending_files.append({
|
self.pending_files.append({
|
||||||
"path": str(p),
|
"path": str(p),
|
||||||
"name": p.name,
|
"name": p.name,
|
||||||
@@ -2562,9 +2647,7 @@ class ChatCLI:
|
|||||||
print(text)
|
print(text)
|
||||||
print("---")
|
print("---")
|
||||||
|
|
||||||
ans = self._read_input(f"\n{self('o_Send_Message')}? (y/n): ").strip().lower()
|
if not self.yes_no_prompt(f"\n{self('o_Send_Message')}?"):
|
||||||
|
|
||||||
if ans not in ("e", "evet", "y", "yes"):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.append_user_message(text)
|
self.append_user_message(text)
|
||||||
@@ -2719,6 +2802,20 @@ class ChatCLI:
|
|||||||
|
|
||||||
messages = self.load_chat_messages()
|
messages = self.load_chat_messages()
|
||||||
|
|
||||||
|
bot_idx = None
|
||||||
|
for i in range(len(messages) - 1, -1, -1):
|
||||||
|
msg = messages[i]
|
||||||
|
|
||||||
|
if not isinstance(msg, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if msg.get("role") in ("bot", "assistant") and msg.get("streaming"):
|
||||||
|
bot_idx = i
|
||||||
|
break
|
||||||
|
|
||||||
|
if msg.get("role") == "user":
|
||||||
|
break
|
||||||
|
|
||||||
bot_msg = {
|
bot_msg = {
|
||||||
"role": "bot",
|
"role": "bot",
|
||||||
"content": str(data.get("content") or "").strip()
|
"content": str(data.get("content") or "").strip()
|
||||||
@@ -2846,7 +2943,12 @@ class ChatCLI:
|
|||||||
if clean_files:
|
if clean_files:
|
||||||
bot_msg["generated_files"] = clean_files
|
bot_msg["generated_files"] = clean_files
|
||||||
|
|
||||||
messages.append(bot_msg)
|
if bot_idx is not None:
|
||||||
|
bot_msg.pop("streaming", None)
|
||||||
|
messages[bot_idx] = bot_msg
|
||||||
|
else:
|
||||||
|
messages.append(bot_msg)
|
||||||
|
|
||||||
self.save_chat_messages(messages)
|
self.save_chat_messages(messages)
|
||||||
return bot_msg
|
return bot_msg
|
||||||
|
|
||||||
@@ -2885,6 +2987,52 @@ class ChatCLI:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def begin_cli_ai_stream_placeholder(self):
|
||||||
|
data = self.load_chat_data_cli()
|
||||||
|
messages = data.get("messages", [])
|
||||||
|
|
||||||
|
# Zaten son tarafta streaming bot varsa yenisini açma
|
||||||
|
for msg in reversed(messages):
|
||||||
|
if not isinstance(msg, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if msg.get("role") in ("bot", "assistant") and msg.get("streaming"):
|
||||||
|
self.save_chat_data_cli(data)
|
||||||
|
return
|
||||||
|
|
||||||
|
if msg.get("role") == "user":
|
||||||
|
break
|
||||||
|
|
||||||
|
messages.append({
|
||||||
|
"role": "bot",
|
||||||
|
"content": "",
|
||||||
|
"streaming": True
|
||||||
|
})
|
||||||
|
|
||||||
|
data["messages"] = messages
|
||||||
|
self.save_chat_data_cli(data)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_cli_ai_stream_placeholder(self):
|
||||||
|
data = self.load_chat_data_cli()
|
||||||
|
messages = data.get("messages", [])
|
||||||
|
|
||||||
|
for i in range(len(messages) - 1, -1, -1):
|
||||||
|
msg = messages[i]
|
||||||
|
|
||||||
|
if not isinstance(msg, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if msg.get("role") in ("bot", "assistant") and msg.get("streaming"):
|
||||||
|
messages.pop(i)
|
||||||
|
break
|
||||||
|
|
||||||
|
if msg.get("role") == "user":
|
||||||
|
break
|
||||||
|
|
||||||
|
data["messages"] = messages
|
||||||
|
self.save_chat_data_cli(data)
|
||||||
|
|
||||||
def call_ai(self):
|
def call_ai(self):
|
||||||
selected_arg = ""
|
selected_arg = ""
|
||||||
|
|
||||||
@@ -2913,6 +3061,8 @@ class ChatCLI:
|
|||||||
context_mode,
|
context_mode,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.begin_cli_ai_stream_placeholder()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["PYTHONUTF8"] = "1"
|
env["PYTHONUTF8"] = "1"
|
||||||
@@ -2938,6 +3088,7 @@ class ChatCLI:
|
|||||||
partial = ""
|
partial = ""
|
||||||
stderr_chunks = []
|
stderr_chunks = []
|
||||||
json_mode = False
|
json_mode = False
|
||||||
|
apply_mode = False
|
||||||
|
|
||||||
out_fd = proc.stdout.fileno()
|
out_fd = proc.stdout.fileno()
|
||||||
err_fd = proc.stderr.fileno()
|
err_fd = proc.stderr.fileno()
|
||||||
@@ -2999,8 +3150,13 @@ class ChatCLI:
|
|||||||
if stripped.startswith("{") or stripped.startswith("["):
|
if stripped.startswith("{") or stripped.startswith("["):
|
||||||
json_mode = True
|
json_mode = True
|
||||||
else:
|
else:
|
||||||
with stream_lock:
|
# apply bloğu başladıysa terminale basma
|
||||||
stream_buffer.append(text)
|
if re.search(r"(?m)^\s*apply\s*$", partial):
|
||||||
|
apply_mode = True
|
||||||
|
|
||||||
|
if not apply_mode:
|
||||||
|
with stream_lock:
|
||||||
|
stream_buffer.append(text)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -3026,7 +3182,7 @@ class ChatCLI:
|
|||||||
if tail:
|
if tail:
|
||||||
partial += tail
|
partial += tail
|
||||||
|
|
||||||
if not json_mode:
|
if not json_mode and not apply_mode:
|
||||||
with stream_lock:
|
with stream_lock:
|
||||||
stream_buffer.append(tail)
|
stream_buffer.append(tail)
|
||||||
|
|
||||||
@@ -3084,6 +3240,8 @@ class ChatCLI:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def handle_ai_error(self, error_text):
|
def handle_ai_error(self, error_text):
|
||||||
|
self.remove_cli_ai_stream_placeholder()
|
||||||
|
|
||||||
messages = self.load_chat_messages()
|
messages = self.load_chat_messages()
|
||||||
|
|
||||||
messages.append({
|
messages.append({
|
||||||
@@ -3127,7 +3285,16 @@ class ChatCLI:
|
|||||||
params = {}
|
params = {}
|
||||||
return self(str(msg.get("i18n_key")), **params)
|
return self(str(msg.get("i18n_key")), **params)
|
||||||
|
|
||||||
return str(msg.get("content") or "")
|
text = str(msg.get("content") or "")
|
||||||
|
|
||||||
|
# apply bloğu mesaj içinde kalsın ama history/chat görünümünde gösterilmesin
|
||||||
|
text = re.sub(
|
||||||
|
r"(?ms)\n?\s*apply\s*\n.*?\n\s*apply\s*$",
|
||||||
|
"",
|
||||||
|
text
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
def extract_links_from_text(self, text: str) -> list[str]:
|
def extract_links_from_text(self, text: str) -> list[str]:
|
||||||
@@ -3651,7 +3818,20 @@ class ChatCLI:
|
|||||||
self.clear_screen()
|
self.clear_screen()
|
||||||
print(f"{self('o_AI_Response')}\n")
|
print(f"{self('o_AI_Response')}\n")
|
||||||
|
|
||||||
self.call_ai()
|
bot_msg = self.call_ai()
|
||||||
|
|
||||||
|
# AI hata verdiyse apply/web aramaya çalışma
|
||||||
|
if not bot_msg:
|
||||||
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Regen sonrası web search isteği oluştuysa hemen göster
|
||||||
|
if self.handle_pending_web_search_requests():
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Regen sonrası apply isteği oluştuysa hemen göster
|
||||||
|
if self.handle_pending_apply_requests():
|
||||||
|
return True
|
||||||
|
|
||||||
self._read_input(f"\n{self('o_to_Menu')}")
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
return True
|
return True
|
||||||
@@ -3816,6 +3996,12 @@ class ChatCLI:
|
|||||||
show_usage = bool(cfg.get("show_usage", False))
|
show_usage = bool(cfg.get("show_usage", False))
|
||||||
|
|
||||||
text = str(bot_msg.get("content") or "").strip()
|
text = str(bot_msg.get("content") or "").strip()
|
||||||
|
text = re.sub(
|
||||||
|
r"(?ms)\n?\s*apply\s*\n.*?\n\s*apply\s*$",
|
||||||
|
"",
|
||||||
|
text
|
||||||
|
).strip()
|
||||||
|
|
||||||
if text:
|
if text:
|
||||||
print(f"\n{self('o_Assistant')}:")
|
print(f"\n{self('o_Assistant')}:")
|
||||||
print(text)
|
print(text)
|
||||||
@@ -4009,10 +4195,8 @@ class ChatCLI:
|
|||||||
if not (0 <= idx < len(chats)):
|
if not (0 <= idx < len(chats)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f'{self("o_Delete")}("{chats[idx].stem}")? (e/h): ')
|
print(f'{self("o_Delete_Chat_Confirm")}')
|
||||||
confirm = input(f'({self("o_Delete_Chat_Confirm")})').strip().lower()
|
if self.yes_no_prompt(f'{self("o_Delete")} "{chats[idx].stem}"?'):
|
||||||
|
|
||||||
if confirm == "e":
|
|
||||||
self.delete_chat(chats[idx])
|
self.delete_chat(chats[idx])
|
||||||
self._read_input(f"\n{self('o_to_Menu')}")
|
self._read_input(f"\n{self('o_to_Menu')}")
|
||||||
|
|
||||||
@@ -4105,11 +4289,7 @@ class ChatCLI:
|
|||||||
if not model_id:
|
if not model_id:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
is_local_raw = self._read_input(
|
is_local = self.yes_no_prompt(f"{self('o_Local_Model')}?")
|
||||||
f"{self('o_Local_Model')}? ({self('o_Yes')}/{self('o_No')}): "
|
|
||||||
).strip().lower()
|
|
||||||
|
|
||||||
is_local = is_local_raw in ("e", "evet", "y", "yes", "1", "true", "on")
|
|
||||||
|
|
||||||
self.set_chat_model(self.current_chat, model_id, is_local)
|
self.set_chat_model(self.current_chat, model_id, is_local)
|
||||||
|
|
||||||
@@ -4151,11 +4331,7 @@ class ChatCLI:
|
|||||||
if not model_id:
|
if not model_id:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
confirm = self._read_input(
|
if not self.yes_no_prompt(f'{self("o_Delete")} "{model_id}"?'):
|
||||||
f'{self("o_Delete")}("{model_id}")? ({self("o_Yes")}/{self("o_No")}): '
|
|
||||||
).strip().lower()
|
|
||||||
|
|
||||||
if confirm not in ("e", "evet", "y", "yes"):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
models2 = [
|
models2 = [
|
||||||
|
|||||||
Reference in New Issue
Block a user