yaicli 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyproject.toml +66 -0
- {yaicli-0.0.7.dist-info → yaicli-0.0.8.dist-info}/METADATA +6 -1
- yaicli-0.0.8.dist-info/RECORD +7 -0
- yaicli.py +67 -7
- yaicli-0.0.7.dist-info/RECORD +0 -6
- {yaicli-0.0.7.dist-info → yaicli-0.0.8.dist-info}/WHEEL +0 -0
- {yaicli-0.0.7.dist-info → yaicli-0.0.8.dist-info}/entry_points.txt +0 -0
- {yaicli-0.0.7.dist-info → yaicli-0.0.8.dist-info}/licenses/LICENSE +0 -0
pyproject.toml
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
[project]
|
2
|
+
name = "yaicli"
|
3
|
+
version = "0.0.8"
|
4
|
+
description = "A simple CLI tool to interact with LLM"
|
5
|
+
authors = [{ name = "belingud", email = "im.victor@qq.com" }]
|
6
|
+
readme = "README.md"
|
7
|
+
requires-python = ">=3.9"
|
8
|
+
license = { file = "LICENSE" }
|
9
|
+
classifiers = [
|
10
|
+
"Programming Language :: Python :: 3",
|
11
|
+
"License :: OSI Approved :: MIT License",
|
12
|
+
"Operating System :: OS Independent",
|
13
|
+
]
|
14
|
+
keywords = [
|
15
|
+
"cli",
|
16
|
+
"llm",
|
17
|
+
"ai",
|
18
|
+
"chatgpt",
|
19
|
+
"openai",
|
20
|
+
"gpt",
|
21
|
+
"llms",
|
22
|
+
"openai",
|
23
|
+
"terminal",
|
24
|
+
"interactive",
|
25
|
+
"interact",
|
26
|
+
"interact with llm",
|
27
|
+
"interact with chatgpt",
|
28
|
+
"interact with openai",
|
29
|
+
"interact with gpt",
|
30
|
+
"interact with llms",
|
31
|
+
]
|
32
|
+
dependencies = [
|
33
|
+
"distro>=1.9.0",
|
34
|
+
"jmespath>=1.0.1",
|
35
|
+
"prompt-toolkit>=3.0.50",
|
36
|
+
"requests>=2.32.3",
|
37
|
+
"rich>=13.9.4",
|
38
|
+
"typer>=0.15.2",
|
39
|
+
]
|
40
|
+
[project.urls]
|
41
|
+
Homepage = "https://github.com/belingud/yaicli"
|
42
|
+
Repository = "https://github.com/belingud/yaicli"
|
43
|
+
Documentation = "https://github.com/belingud/yaicli"
|
44
|
+
|
45
|
+
[project.scripts]
|
46
|
+
ai = "yaicli:app"
|
47
|
+
|
48
|
+
[tool.uv]
|
49
|
+
resolution = "highest"
|
50
|
+
|
51
|
+
[dependency-groups]
|
52
|
+
dev = ["bump2version>=1.0.1", "pytest>=8.3.5", "ruff>=0.11.2"]
|
53
|
+
|
54
|
+
[tool.ruff]
|
55
|
+
line-length = 120
|
56
|
+
select = ["E", "F", "W", "I", "B", "C90"]
|
57
|
+
ignore = ["E501"]
|
58
|
+
|
59
|
+
|
60
|
+
[build-system]
|
61
|
+
requires = ["hatchling>=1.18.0"]
|
62
|
+
build-backend = "hatchling.build"
|
63
|
+
|
64
|
+
[tool.hatch.build]
|
65
|
+
exclude = ["test_*.py", "tests/*", ".gitignore"]
|
66
|
+
include = ["yaicli.py", "pyproject.toml"]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: yaicli
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.8
|
4
4
|
Summary: A simple CLI tool to interact with LLM
|
5
5
|
Project-URL: Homepage, https://github.com/belingud/yaicli
|
6
6
|
Project-URL: Repository, https://github.com/belingud/yaicli
|
@@ -223,6 +223,11 @@ Description-Content-Type: text/markdown
|
|
223
223
|
|
224
224
|
# YAICLI - Your AI Command Line Interface
|
225
225
|
|
226
|
+
[](https://pypi.org/project/yaicli/)
|
227
|
+

|
228
|
+

|
229
|
+

|
230
|
+
|
226
231
|
YAICLI is a powerful command-line AI assistant tool that enables you to interact with Large Language Models (LLMs) like ChatGPT's gpt-4o through your terminal. It offers multiple operation modes for everyday conversations, generating and executing shell commands, and one-shot quick queries.
|
227
232
|
|
228
233
|
> [!WARNING]
|
@@ -0,0 +1,7 @@
|
|
1
|
+
pyproject.toml,sha256=0ri15toylKhtFhwAemgdMReD72wetPZIISWhJtpsqe8,1450
|
2
|
+
yaicli.py,sha256=E6QRi9KgMBoDU-KQ1V7N1SVTAg5PIVIfCMWXLn3taE4,16877
|
3
|
+
yaicli-0.0.8.dist-info/METADATA,sha256=OIArk-08C1L-hW8Hu9RfGby7PVm0G_C16_DA_peaoxM,23489
|
4
|
+
yaicli-0.0.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
+
yaicli-0.0.8.dist-info/entry_points.txt,sha256=gdduQwAuu_LeDqnDU81Fv3NPmD2tRQ1FffvolIP3S1Q,34
|
6
|
+
yaicli-0.0.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
7
|
+
yaicli-0.0.8.dist-info/RECORD,,
|
yaicli.py
CHANGED
@@ -71,6 +71,7 @@ class CasePreservingConfigParser(configparser.RawConfigParser):
|
|
71
71
|
class CLI:
|
72
72
|
CONFIG_PATH = Path("~/.config/yaicli/config.ini").expanduser()
|
73
73
|
DEFAULT_CONFIG_INI = """[core]
|
74
|
+
PROVIDER=openai
|
74
75
|
BASE_URL=https://api.openai.com/v1
|
75
76
|
API_KEY=
|
76
77
|
MODEL=gpt-4o
|
@@ -166,6 +167,50 @@ STREAM=true"""
|
|
166
167
|
return "powershell.exe" if is_powershell else "cmd.exe"
|
167
168
|
return basename(getenv("SHELL", "/bin/sh"))
|
168
169
|
|
170
|
+
def _filter_command(self, command: str) -> Optional[str]:
|
171
|
+
"""Filter out unwanted characters from command
|
172
|
+
|
173
|
+
The LLM may return commands in markdown format with code blocks.
|
174
|
+
This method removes markdown formatting from the command.
|
175
|
+
It handles various formats including:
|
176
|
+
- Commands surrounded by ``` (plain code blocks)
|
177
|
+
- Commands with language specifiers like ```bash, ```zsh, etc.
|
178
|
+
- Commands with specific examples like ```ls -al```
|
179
|
+
|
180
|
+
example:
|
181
|
+
```bash\nls -la\n``` ==> ls -al
|
182
|
+
```zsh\nls -la\n``` ==> ls -al
|
183
|
+
```ls -al``` ==> ls -al
|
184
|
+
ls -al ==> ls -al
|
185
|
+
```\ncd /tmp\nls -la\n``` ==> cd /tmp\nls -la
|
186
|
+
```bash\ncd /tmp\nls -la\n``` ==> cd /tmp\nls -la
|
187
|
+
"""
|
188
|
+
if not command or not command.strip():
|
189
|
+
return ""
|
190
|
+
|
191
|
+
# Handle commands that are already without code blocks
|
192
|
+
if "```" not in command:
|
193
|
+
return command.strip()
|
194
|
+
|
195
|
+
# Handle code blocks with or without language specifiers
|
196
|
+
lines = command.strip().split("\n")
|
197
|
+
|
198
|
+
# Check if it's a single-line code block like ```ls -al```
|
199
|
+
if len(lines) == 1 and lines[0].startswith("```") and lines[0].endswith("```"):
|
200
|
+
return lines[0][3:-3].strip()
|
201
|
+
|
202
|
+
# Handle multi-line code blocks
|
203
|
+
if lines[0].startswith("```"):
|
204
|
+
# Remove the opening ``` line (with or without language specifier)
|
205
|
+
content_lines = lines[1:]
|
206
|
+
|
207
|
+
# If the last line is a closing ```, remove it
|
208
|
+
if content_lines and content_lines[-1].strip() == "```":
|
209
|
+
content_lines = content_lines[:-1]
|
210
|
+
|
211
|
+
# Join the remaining lines and strip any extra whitespace
|
212
|
+
return "\n".join(line.strip() for line in content_lines if line.strip())
|
213
|
+
|
169
214
|
def post(self, message: list[dict[str, str]]) -> requests.Response:
|
170
215
|
"""Post message to LLM API and return response"""
|
171
216
|
url = self.config.get("BASE_URL", "").rstrip("/") + "/" + self.config.get("COMPLETION_PATH", "").lstrip("/")
|
@@ -238,6 +283,11 @@ STREAM=true"""
|
|
238
283
|
qmark = ""
|
239
284
|
return [("class:qmark", qmark), ("class:question", " {} ".format(">"))]
|
240
285
|
|
286
|
+
def _check_history_len(self) -> None:
|
287
|
+
"""Check history length and remove oldest messages if necessary"""
|
288
|
+
if len(self.history) > self.max_history_length:
|
289
|
+
self.history = self.history[-self.max_history_length :]
|
290
|
+
|
241
291
|
def _run_repl(self) -> None:
|
242
292
|
"""Run REPL loop, handling user input and generating responses, saving history, and executing commands"""
|
243
293
|
# Show REPL instructions
|
@@ -280,27 +330,33 @@ STREAM=true"""
|
|
280
330
|
# Get response from LLM
|
281
331
|
response = self.post(message)
|
282
332
|
self.console.print("\n[bold green]Assistant:[/bold green]")
|
283
|
-
|
333
|
+
try:
|
334
|
+
content = self._print(response, stream=self.config["STREAM"] == "true")
|
335
|
+
except Exception as e:
|
336
|
+
self.console.print(f"[red]Error: {e}[/red]")
|
337
|
+
continue
|
284
338
|
|
285
339
|
# Add user input and assistant response to history
|
286
340
|
self.history.append({"role": "user", "content": user_input})
|
287
341
|
self.history.append({"role": "assistant", "content": content})
|
288
342
|
|
289
343
|
# Trim history if needed
|
290
|
-
|
291
|
-
self.history = self.history[-self.max_history_length * 2 :]
|
344
|
+
self._check_history_len()
|
292
345
|
|
293
346
|
# Handle command execution in exec mode
|
294
347
|
if self.current_mode == EXEC_MODE:
|
348
|
+
content = self._filter_command(content)
|
349
|
+
if not content:
|
350
|
+
self.console.print("[bold red]No command generated[/bold red]")
|
351
|
+
continue
|
295
352
|
self.console.print(f"\n[bold magenta]Generated command:[/bold magenta] {content}")
|
296
353
|
if Confirm.ask("Execute this command?", default=False):
|
297
|
-
|
298
|
-
if returncode != 0:
|
299
|
-
self.console.print(f"[bold red]Command failed with return code {returncode}[/bold red]")
|
354
|
+
subprocess.call(content, shell=True)
|
300
355
|
|
301
356
|
self.console.print("[bold green]Exiting...[/bold green]")
|
302
357
|
|
303
358
|
def run(self, chat: bool, shell: bool, prompt: str) -> None:
|
359
|
+
"""Run the CLI"""
|
304
360
|
self.load_config()
|
305
361
|
if not self.config.get("API_KEY"):
|
306
362
|
self.console.print("[bold red]API key not set[/bold red]")
|
@@ -330,10 +386,14 @@ STREAM=true"""
|
|
330
386
|
# Get response from LLM
|
331
387
|
response = self.post(message)
|
332
388
|
self.console.print("\n[bold green]Assistant:[/bold green]")
|
333
|
-
content = self._print(response, stream=
|
389
|
+
content = self._print(response, stream=self.config["STREAM"] == "true")
|
334
390
|
|
335
391
|
# Handle shell mode execution
|
336
392
|
if shell:
|
393
|
+
content = self._filter_command(content)
|
394
|
+
if not content:
|
395
|
+
self.console.print("[bold red]No command generated[/bold red]")
|
396
|
+
return
|
337
397
|
self.console.print(f"\n[bold magenta]Generated command:[/bold magenta] {content}")
|
338
398
|
if Confirm.ask("Execute this command?", default=False):
|
339
399
|
returncode = subprocess.call(content, shell=True)
|
yaicli-0.0.7.dist-info/RECORD
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
yaicli.py,sha256=Wsi6VWGw3FfCkl8d6AR6p3nY8QbdZM0bx8JXFNrfZP8,14538
|
2
|
-
yaicli-0.0.7.dist-info/METADATA,sha256=EHpi_s3X6a31V6z2EuGQ9hOgh1Karxi07f-H6Vbeekg,23101
|
3
|
-
yaicli-0.0.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4
|
-
yaicli-0.0.7.dist-info/entry_points.txt,sha256=gdduQwAuu_LeDqnDU81Fv3NPmD2tRQ1FffvolIP3S1Q,34
|
5
|
-
yaicli-0.0.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
6
|
-
yaicli-0.0.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|