q-bot 1.3.0__tar.gz

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.
q_bot-1.3.0/PKG-INFO ADDED
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: q-bot
3
+ Version: 1.3.0
4
+ Summary: An LLM-powered programming copilot from the comfort of your command line
5
+ Author-email: Tushar Khan <tushar.54k@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/tk755/q
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: colorama==0.4.6
11
+ Requires-Dist: openai==1.82.0
12
+ Requires-Dist: pyperclip==1.9.0
13
+ Requires-Dist: termcolor==2.5.0
14
+
15
+ # Overview
16
+ `q` is an LLM-powered programming copilot from the comfort of your command line. It can generate code snippets, shell commands, technical explanations, web searches, and even images. Through multi-turn conversations, it can build, debug, and refine complex solutions iteratively. It even saves generated code and commands to your clipboard, so you can paste it wherever you need it.
17
+
18
+ Currently `q` uses the OpenAI API, but support for other LLM providers is planned in the future.
19
+
20
+ # Installation
21
+
22
+ Install from PyPI using pipx (recommended for CLI tools):
23
+
24
+ ```bash
25
+ pipx install q-cli
26
+ ```
27
+
28
+ Or using pip:
29
+
30
+ ```bash
31
+ pip install q-cli
32
+ ```
33
+
34
+ Requires Python 3.8+.
35
+
36
+ # Usage
37
+
38
+ The basic syntax is `q [command] TEXT [options]`. `q` accepts at most one command and any number of options. Any arguments between the command and options is treated as the input text.
39
+
40
+ `q` saves generated code snippets and shell commands to your clipboard so you can paste it wherever you need it. This only works on non-headless environments (no VMs and Docker containers); check [here](https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error) if it doesn't work.
41
+
42
+ For a full list of commands and options, run `q -h`.
43
+
44
+ > The first time `q` is prompted, you will be asked for an OpenAI API key which you can create [here](https://platform.openai.com/api-keys).
45
+
46
+ ## Commands
47
+
48
+ Each command runs a tailored LLM prompt using the OpenAI API and returns the parsed response.
49
+
50
+ ### Generate Code
51
+
52
+ Use the `-c` or `--code` command to generate code snippets:
53
+
54
+ ```
55
+ $ q -c copy user input to clipboard
56
+ import pyperclip
57
+
58
+ user_input = input("Enter text to copy to clipboard: ")
59
+ pyperclip.copy(user_input)
60
+ ```
61
+
62
+ By default this generates Python code, but you can specify a different programming language in the prompt itself (or [modify the default value](#modifying-default-values)):
63
+
64
+ ```
65
+ $ q -c copy user input to clipboard in rust
66
+ use std::io::{self, Write};
67
+ use clipboard::{ClipboardContext, ClipboardProvider};
68
+
69
+ fn main() {
70
+ let mut input = String::new();
71
+ print!("Enter text to copy to clipboard: ");
72
+ io::stdout().flush().unwrap();
73
+ io::stdin().read_line(&mut input).unwrap();
74
+
75
+ let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
76
+ ctx.set_contents(input.trim().to_string()).unwrap();
77
+ }
78
+ ```
79
+
80
+ You can redirect the output to a file and run it instantly:
81
+
82
+ ```
83
+ $ q -c fib function w main function > fib.py && python3 fib.py
84
+ Enter a number: 10
85
+ Fibonacci number at position 10 is 55
86
+ ```
87
+
88
+ ### Generate Shell Commands
89
+
90
+ Use the `-s` or `--shell` command to generate shell commands:
91
+
92
+ ```
93
+ $ q -s add README.md to prev commit and push changes
94
+ git add README.md && git commit --amend --no-edit && git push --force-with-lease
95
+ ```
96
+
97
+ By default this generates Bash commands for a Linux system, but you can specify a different shell or OS in the prompt itself (or [modify the default value](#modifying-default-values)):
98
+
99
+ ```
100
+ $ q -s auto hide the dock on macos
101
+ defaults write com.apple.dock autohide -bool true; killall Dock
102
+ ```
103
+
104
+ You can pipe the output to the shell interpreter to run it instantly:
105
+
106
+ ```
107
+ $ q -s count line numbers in fib.py | bash
108
+ 12 fib.py
109
+ ```
110
+
111
+ ### Explain
112
+
113
+ Use the `-e` or `--explain` command to generate a concise explanation for code or shell commands:
114
+
115
+ ```
116
+ $ q -e 'print(os.getcwd())'
117
+ `print(os.getcwd())` outputs the current working directory of the Python process by calling `os.getcwd()`, which returns the absolute path as a string, and then prints it to the standard output.
118
+ ```
119
+
120
+ This is particularly useful for understanding complex code or shell commands you may not be familiar with:
121
+
122
+ ```
123
+ $ q -e 'find . -type d -name .git -exec dirname {} \; | sort'
124
+ This command searches recursively from the current directory for directories named `.git`, then uses `dirname` to output their parent directory paths, effectively listing all Git repository root directories. The results are then sorted alphabetically.
125
+ ```
126
+
127
+ It can even generate explanations about technical concepts:
128
+
129
+ ```
130
+ $ q -e neuroevolution
131
+ Neuroevolution is a technique that applies evolutionary algorithms to optimize artificial neural networks, typically evolving their weights, architectures, or learning rules. Instead of using gradient-based methods like backpropagation, neuroevolution treats network parameters as genomes and iteratively improves them through selection, mutation, and crossover, enabling the discovery of novel network topologies and solutions, especially useful in reinforcement learning and problems with non-differentiable objectives.
132
+ ```
133
+
134
+ ### Search the Web
135
+
136
+ Use the `-w` or `--web` command to search the web for up-to-date information (note: this is slightly expensive):
137
+
138
+ ```
139
+ $ q -w highest qbit computer
140
+ As of July 2025, the quantum computer with the highest number of qubits is Atom Computing's processor, which has 1,180 qubits. (spinquanta.com)
141
+ ```
142
+
143
+ ### Generate Images
144
+
145
+ Use the `-i` or `--image` command to generate 1024x1024 images (note: this is very expensive):
146
+
147
+ ```
148
+ $ q -i george washington riding a harley through the american civil war
149
+ Image saved to q_george_washington_riding_a_harley_through_the_american_civil_war.png.
150
+ ```
151
+
152
+ ## Multi-Turn Conversations
153
+
154
+ Use `q` without specifying a command to build on the previous response conversationally:
155
+
156
+ ```
157
+ $ q -w nba champions
158
+ The Oklahoma City Thunder won the 2025 NBA Finals, defeating the Indiana Pacers 4-3. (nba.com)
159
+ $ q final game score
160
+ The Oklahoma City Thunder defeated the Indiana Pacers 103-91 in Game 7 of the 2025 NBA Finals on June 22, 2025. (espn.com)
161
+ ```
162
+
163
+ This is very useful for iteratively refining generated code or shell commands:
164
+
165
+ ```
166
+ $ q -s get cuda version
167
+ nvcc --version
168
+ $ nvcc --version
169
+ bash: nvcc: command not found
170
+ $ q command not found
171
+ cat /usr/local/cuda/version.txt
172
+ $ cat /usr/local/cuda/version.txt
173
+ cat: /usr/local/cuda/version.txt: No such file or directory
174
+ $ q file not found
175
+ nvidia-smi | grep "CUDA Version"
176
+ $ nvidia-smi | grep "CUDA Version"
177
+ | NVIDIA-SMI 560.35.02 Driver Version: 560.94 CUDA Version: 12.6 |
178
+ ```
179
+
180
+ And ask follow-up questions about the previous response:
181
+
182
+ ```
183
+ $ q -c function to merge two dictionaries x and y
184
+ def merge_dictionaries(x, y):
185
+ return {**x, **y}
186
+ $ q what is the time complexity
187
+ The time complexity of merging two dictionaries using `{**x, **y}` is O(n + m), where n is the number of elements in dictionary `x` and m is the number of elements in dictionary `y`.
188
+ ```
189
+
190
+ You can even refine generated images:
191
+
192
+ ```
193
+ $ q -i low poly rubber duck
194
+ Image saved to q_low_poly_rubber_duck.png.
195
+ $ q make it float in a high res bathtub
196
+ Image saved to q_make_it_float_in_a_high_res_bathtub.png.
197
+ ```
198
+
199
+ ## Options
200
+
201
+ Options are boolean flags that modify the behavior of `q`:
202
+
203
+ - Use the `-o` or `--overwrite` option to overwrite the previous command.
204
+ - Use the `-n` or `--no-clip` option to disable automatically storing responses to the clipboard.
205
+ - Use the `-v` or `--verbose` option to print the model parameters and message history.
206
+
207
+ You can combine multiple options using their abbreviated forms following a single hyphen:
208
+
209
+ ```
210
+ $ q -p knock knock
211
+ Who's there?
212
+ $ q apple
213
+ Apple who?
214
+ $ q orange -vo
215
+
216
+ MODEL PARAMETERS:
217
+ model: gpt-4o
218
+ max_tokens: 256
219
+ temperature: 0.25
220
+ frequency_penalty: 0
221
+ presence_penalty: 0
222
+ top_p: 1
223
+
224
+ MESSAGES:
225
+ System: You are a helpful and knowledgeable AI assistant.
226
+ User: knock knock
227
+ Assistant: Who's there?
228
+ User: orange
229
+ Assistant: Orange who?
230
+ ```
231
+
232
+ # Customization
233
+
234
+ `q` was designed to be easily customizable to suit any programmer's needs.
235
+
236
+ ## Modifying Default Values
237
+
238
+ The following constants can be modified in the script to change the default behavior of `q`:
239
+ - `MINI_LLM`: the default model for fast and cheap responses.
240
+ - `FULL_LLM`: the default model for long and detailed responses.
241
+ - `DEFAULT_MODEL_ARGS`: the default model arguments used by all commands if not overrided.
242
+ - `DEFAULT_CODE`: the default language for code generation used by the `-c` command.
243
+ - `DEFAULT_SHELL`: the default system for shell command generation used by the `-s` command.
244
+
245
+ ## Adding New Commands
246
+
247
+ Add a new command to `q` by inserting a new dictionary in the `COMMANDS` list with the following keys:
248
+ - `flags` *(required)*: a list of flags to invoke the command.
249
+ - `description` *(required)*: a brief description of the command shown in the help message.
250
+ - `messages` *(required)*: the instructions sent to the LLM, using `{text}` as a placeholder for the input text.
251
+ - `model_args` *(optional)*: override default model arguments set in `DEFAULT_MODEL_ARGS` or set new arguments.
252
+ - `clip_output` *(optional)*: set to `True` to copy the output to the clipboard; `False` by default.
253
+
254
+ Refer to the existing commands in the script for examples.
q_bot-1.3.0/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # Overview
2
+ `q` is an LLM-powered programming copilot from the comfort of your command line. It can generate code snippets, shell commands, technical explanations, web searches, and even images. Through multi-turn conversations, it can build, debug, and refine complex solutions iteratively. It even saves generated code and commands to your clipboard, so you can paste it wherever you need it.
3
+
4
+ Currently `q` uses the OpenAI API, but support for other LLM providers is planned in the future.
5
+
6
+ # Installation
7
+
8
+ Install from PyPI using pipx (recommended for CLI tools):
9
+
10
+ ```bash
11
+ pipx install q-cli
12
+ ```
13
+
14
+ Or using pip:
15
+
16
+ ```bash
17
+ pip install q-cli
18
+ ```
19
+
20
+ Requires Python 3.8+.
21
+
22
+ # Usage
23
+
24
+ The basic syntax is `q [command] TEXT [options]`. `q` accepts at most one command and any number of options. Any arguments between the command and options is treated as the input text.
25
+
26
+ `q` saves generated code snippets and shell commands to your clipboard so you can paste it wherever you need it. This only works on non-headless environments (no VMs and Docker containers); check [here](https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error) if it doesn't work.
27
+
28
+ For a full list of commands and options, run `q -h`.
29
+
30
+ > The first time `q` is prompted, you will be asked for an OpenAI API key which you can create [here](https://platform.openai.com/api-keys).
31
+
32
+ ## Commands
33
+
34
+ Each command runs a tailored LLM prompt using the OpenAI API and returns the parsed response.
35
+
36
+ ### Generate Code
37
+
38
+ Use the `-c` or `--code` command to generate code snippets:
39
+
40
+ ```
41
+ $ q -c copy user input to clipboard
42
+ import pyperclip
43
+
44
+ user_input = input("Enter text to copy to clipboard: ")
45
+ pyperclip.copy(user_input)
46
+ ```
47
+
48
+ By default this generates Python code, but you can specify a different programming language in the prompt itself (or [modify the default value](#modifying-default-values)):
49
+
50
+ ```
51
+ $ q -c copy user input to clipboard in rust
52
+ use std::io::{self, Write};
53
+ use clipboard::{ClipboardContext, ClipboardProvider};
54
+
55
+ fn main() {
56
+ let mut input = String::new();
57
+ print!("Enter text to copy to clipboard: ");
58
+ io::stdout().flush().unwrap();
59
+ io::stdin().read_line(&mut input).unwrap();
60
+
61
+ let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
62
+ ctx.set_contents(input.trim().to_string()).unwrap();
63
+ }
64
+ ```
65
+
66
+ You can redirect the output to a file and run it instantly:
67
+
68
+ ```
69
+ $ q -c fib function w main function > fib.py && python3 fib.py
70
+ Enter a number: 10
71
+ Fibonacci number at position 10 is 55
72
+ ```
73
+
74
+ ### Generate Shell Commands
75
+
76
+ Use the `-s` or `--shell` command to generate shell commands:
77
+
78
+ ```
79
+ $ q -s add README.md to prev commit and push changes
80
+ git add README.md && git commit --amend --no-edit && git push --force-with-lease
81
+ ```
82
+
83
+ By default this generates Bash commands for a Linux system, but you can specify a different shell or OS in the prompt itself (or [modify the default value](#modifying-default-values)):
84
+
85
+ ```
86
+ $ q -s auto hide the dock on macos
87
+ defaults write com.apple.dock autohide -bool true; killall Dock
88
+ ```
89
+
90
+ You can pipe the output to the shell interpreter to run it instantly:
91
+
92
+ ```
93
+ $ q -s count line numbers in fib.py | bash
94
+ 12 fib.py
95
+ ```
96
+
97
+ ### Explain
98
+
99
+ Use the `-e` or `--explain` command to generate a concise explanation for code or shell commands:
100
+
101
+ ```
102
+ $ q -e 'print(os.getcwd())'
103
+ `print(os.getcwd())` outputs the current working directory of the Python process by calling `os.getcwd()`, which returns the absolute path as a string, and then prints it to the standard output.
104
+ ```
105
+
106
+ This is particularly useful for understanding complex code or shell commands you may not be familiar with:
107
+
108
+ ```
109
+ $ q -e 'find . -type d -name .git -exec dirname {} \; | sort'
110
+ This command searches recursively from the current directory for directories named `.git`, then uses `dirname` to output their parent directory paths, effectively listing all Git repository root directories. The results are then sorted alphabetically.
111
+ ```
112
+
113
+ It can even generate explanations about technical concepts:
114
+
115
+ ```
116
+ $ q -e neuroevolution
117
+ Neuroevolution is a technique that applies evolutionary algorithms to optimize artificial neural networks, typically evolving their weights, architectures, or learning rules. Instead of using gradient-based methods like backpropagation, neuroevolution treats network parameters as genomes and iteratively improves them through selection, mutation, and crossover, enabling the discovery of novel network topologies and solutions, especially useful in reinforcement learning and problems with non-differentiable objectives.
118
+ ```
119
+
120
+ ### Search the Web
121
+
122
+ Use the `-w` or `--web` command to search the web for up-to-date information (note: this is slightly expensive):
123
+
124
+ ```
125
+ $ q -w highest qbit computer
126
+ As of July 2025, the quantum computer with the highest number of qubits is Atom Computing's processor, which has 1,180 qubits. (spinquanta.com)
127
+ ```
128
+
129
+ ### Generate Images
130
+
131
+ Use the `-i` or `--image` command to generate 1024x1024 images (note: this is very expensive):
132
+
133
+ ```
134
+ $ q -i george washington riding a harley through the american civil war
135
+ Image saved to q_george_washington_riding_a_harley_through_the_american_civil_war.png.
136
+ ```
137
+
138
+ ## Multi-Turn Conversations
139
+
140
+ Use `q` without specifying a command to build on the previous response conversationally:
141
+
142
+ ```
143
+ $ q -w nba champions
144
+ The Oklahoma City Thunder won the 2025 NBA Finals, defeating the Indiana Pacers 4-3. (nba.com)
145
+ $ q final game score
146
+ The Oklahoma City Thunder defeated the Indiana Pacers 103-91 in Game 7 of the 2025 NBA Finals on June 22, 2025. (espn.com)
147
+ ```
148
+
149
+ This is very useful for iteratively refining generated code or shell commands:
150
+
151
+ ```
152
+ $ q -s get cuda version
153
+ nvcc --version
154
+ $ nvcc --version
155
+ bash: nvcc: command not found
156
+ $ q command not found
157
+ cat /usr/local/cuda/version.txt
158
+ $ cat /usr/local/cuda/version.txt
159
+ cat: /usr/local/cuda/version.txt: No such file or directory
160
+ $ q file not found
161
+ nvidia-smi | grep "CUDA Version"
162
+ $ nvidia-smi | grep "CUDA Version"
163
+ | NVIDIA-SMI 560.35.02 Driver Version: 560.94 CUDA Version: 12.6 |
164
+ ```
165
+
166
+ And ask follow-up questions about the previous response:
167
+
168
+ ```
169
+ $ q -c function to merge two dictionaries x and y
170
+ def merge_dictionaries(x, y):
171
+ return {**x, **y}
172
+ $ q what is the time complexity
173
+ The time complexity of merging two dictionaries using `{**x, **y}` is O(n + m), where n is the number of elements in dictionary `x` and m is the number of elements in dictionary `y`.
174
+ ```
175
+
176
+ You can even refine generated images:
177
+
178
+ ```
179
+ $ q -i low poly rubber duck
180
+ Image saved to q_low_poly_rubber_duck.png.
181
+ $ q make it float in a high res bathtub
182
+ Image saved to q_make_it_float_in_a_high_res_bathtub.png.
183
+ ```
184
+
185
+ ## Options
186
+
187
+ Options are boolean flags that modify the behavior of `q`:
188
+
189
+ - Use the `-o` or `--overwrite` option to overwrite the previous command.
190
+ - Use the `-n` or `--no-clip` option to disable automatically storing responses to the clipboard.
191
+ - Use the `-v` or `--verbose` option to print the model parameters and message history.
192
+
193
+ You can combine multiple options using their abbreviated forms following a single hyphen:
194
+
195
+ ```
196
+ $ q -p knock knock
197
+ Who's there?
198
+ $ q apple
199
+ Apple who?
200
+ $ q orange -vo
201
+
202
+ MODEL PARAMETERS:
203
+ model: gpt-4o
204
+ max_tokens: 256
205
+ temperature: 0.25
206
+ frequency_penalty: 0
207
+ presence_penalty: 0
208
+ top_p: 1
209
+
210
+ MESSAGES:
211
+ System: You are a helpful and knowledgeable AI assistant.
212
+ User: knock knock
213
+ Assistant: Who's there?
214
+ User: orange
215
+ Assistant: Orange who?
216
+ ```
217
+
218
+ # Customization
219
+
220
+ `q` was designed to be easily customizable to suit any programmer's needs.
221
+
222
+ ## Modifying Default Values
223
+
224
+ The following constants can be modified in the script to change the default behavior of `q`:
225
+ - `MINI_LLM`: the default model for fast and cheap responses.
226
+ - `FULL_LLM`: the default model for long and detailed responses.
227
+ - `DEFAULT_MODEL_ARGS`: the default model arguments used by all commands if not overrided.
228
+ - `DEFAULT_CODE`: the default language for code generation used by the `-c` command.
229
+ - `DEFAULT_SHELL`: the default system for shell command generation used by the `-s` command.
230
+
231
+ ## Adding New Commands
232
+
233
+ Add a new command to `q` by inserting a new dictionary in the `COMMANDS` list with the following keys:
234
+ - `flags` *(required)*: a list of flags to invoke the command.
235
+ - `description` *(required)*: a brief description of the command shown in the help message.
236
+ - `messages` *(required)*: the instructions sent to the LLM, using `{text}` as a placeholder for the input text.
237
+ - `model_args` *(optional)*: override default model arguments set in `DEFAULT_MODEL_ARGS` or set new arguments.
238
+ - `clip_output` *(optional)*: set to `True` to copy the output to the clipboard; `False` by default.
239
+
240
+ Refer to the existing commands in the script for examples.
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "q-bot"
7
+ dynamic = ["version"]
8
+ description = "An LLM-powered programming copilot from the comfort of your command line"
9
+ requires-python = ">=3.8"
10
+ dependencies = [
11
+ "colorama==0.4.6",
12
+ "openai==1.82.0",
13
+ "pyperclip==1.9.0",
14
+ "termcolor==2.5.0",
15
+ ]
16
+ authors = [
17
+ {name = "Tushar Khan", email = "tushar.54k@gmail.com"}
18
+ ]
19
+ readme = "README.md"
20
+ license = "MIT"
21
+
22
+ [project.scripts]
23
+ q = "q:main"
24
+
25
+ [project.urls]
26
+ Repository = "https://github.com/tk755/q"
27
+
28
+ [tool.setuptools.dynamic]
29
+ version = {attr = "q.__version__"}
30
+
31
+
q_bot-1.3.0/q.py ADDED
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # standard library imports
4
+ import base64
5
+ import getpass
6
+ import json
7
+ import os
8
+ import re
9
+ import string
10
+ import sys
11
+ from typing import Any, Dict, List, Tuple
12
+
13
+ # third-party imports
14
+ import openai
15
+ import pyperclip
16
+ from colorama import just_fix_windows_console
17
+ from termcolor import colored, cprint
18
+
19
+ # module metadata
20
+ __version__ = '1.3.0'
21
+ DESCRIPTION = 'An LLM-powered programming copilot from the comfort of your command line'
22
+
23
+ # command parameters
24
+ DEFAULT_CODE = 'python' # default language for code generation
25
+ DEFAULT_SHELL = 'debian+bash' # default system for shell command generation
26
+
27
+ # model variants
28
+ MINI_LLM = 'gpt-4.1-mini' # cheap and fast
29
+ FULL_LLM = 'gpt-4.1' # expensive and more powerful
30
+
31
+ # model parameters
32
+ DEFAULT_MODEL_ARGS = {
33
+ 'model': MINI_LLM,
34
+ 'max_output_tokens': 1024,
35
+ 'temperature': 0.0
36
+ }
37
+
38
+ # program resources
39
+ RESOURCE_PATH = os.path.join(os.path.expanduser('~'), '.q', 'resources.json')
40
+ os.makedirs(os.path.dirname(RESOURCE_PATH), exist_ok=True)
41
+
42
+ def _load_resource(name: str, default: Any) -> Any:
43
+ try:
44
+ with open(RESOURCE_PATH) as f:
45
+ return json.load(f)[name]
46
+ except:
47
+ return default
48
+
49
+ def _save_resource(name: str, value: Any):
50
+ try:
51
+ with open(RESOURCE_PATH) as f:
52
+ resources = json.load(f)
53
+ except:
54
+ resources = {}
55
+ resources[name] = value
56
+ with open(RESOURCE_PATH, 'w') as f:
57
+ json.dump(resources, f, indent=4)
58
+
59
+ COMMANDS = [
60
+ {
61
+ 'flags': [],
62
+ 'description': 'follow-up on the previous response',
63
+ 'clip_output': _load_resource('clip_output', False),
64
+ 'model_args': _load_resource('model_args', {}),
65
+ 'messages': _load_resource('messages', []) + [
66
+ {
67
+ 'role': 'user',
68
+ 'content': '{text}'
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ 'flags': ['-e', '--explain'],
74
+ 'description': 'explain code, commands, or a technical concept',
75
+ 'model_args' : {
76
+ 'model': MINI_LLM,
77
+ },
78
+ 'messages': [
79
+ {
80
+ 'role': 'developer',
81
+ 'content': 'You are a programming assistant. Given a shell command, code snippet, or technical concept, provide a concise and technical explanation. Assume the reader is an experienced developer. Avoid restating the code or command. Avoid explaining obvious syntax. Avoid breaking the answer into bullet points unless necessary. The response should be a single short paragraph optimized for clarity.',
82
+ },
83
+ {
84
+ 'role': 'user',
85
+ 'content': 'Explain: {text}'
86
+ }
87
+ ]
88
+ },
89
+ {
90
+ 'flags': ['-c', '--code'],
91
+ 'description': f'generate a code snippet (default: {DEFAULT_CODE})',
92
+ 'clip_output': True,
93
+ 'model_args': {
94
+ 'model': FULL_LLM,
95
+ },
96
+ 'messages': [
97
+ {
98
+ 'role': 'developer',
99
+ 'content': f'You are a coding assistant. Given a natural language description, generate a code snippet that accomplishes the requested task. The code should be correct, efficient, concise, and idiomatic. Respond with only the code snippet, without explanations, additional text, or formatting. Assume the programming language is {DEFAULT_CODE} unless otherwise specified.'
100
+ },
101
+ {
102
+ 'role': 'user',
103
+ 'content': 'Generate a code snippet to accomplish the following task: {text}. Respond only with the code, without explanation or additional text.'
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ 'flags': ['-s', '--shell'],
109
+ 'description': f'generate a shell command (default: {DEFAULT_SHELL})',
110
+ 'clip_output': True,
111
+ 'messages': [
112
+ {
113
+ 'role': 'developer',
114
+ 'content': f'You are a command-line assistant. Given a natural language task description, generate the simplest single shell command that accomplishes the task. Favor minimal, commonly available commands with no extra formatting or piping. Avoid commands that could delete, overwrite, or modify important files or system settings (e.g., rm -rf, dd, mkfs, chmod -R, chown, kill -9). Respond with only the command, without explanations, additional text, or formatting. Assume a {DEFAULT_SHELL} shell unless otherwise specified.'
115
+ },
116
+ {
117
+ 'role': 'user',
118
+ 'content': 'Generate a single shell command to accomplish the following task: {text}. Respond with only the command, without explanation or additional text.'
119
+ }
120
+ ]
121
+ },
122
+ {
123
+ 'flags': ['-i', '--image'],
124
+ 'description': 'generate an image (very expensive)',
125
+ 'model_args': {
126
+ 'model': MINI_LLM,
127
+ 'tools': [{
128
+ 'type': 'image_generation',
129
+ 'size': '1024x1024',
130
+ 'quality': 'auto' # low, medium, high
131
+ }],
132
+ },
133
+ 'messages': [
134
+ {
135
+ 'role': 'user',
136
+ 'content': 'Generate an image of the following: {text}.'
137
+ }
138
+ ]
139
+ },
140
+ {
141
+ 'flags': ['-w', '--web'],
142
+ 'description': 'search the internet (expensive)',
143
+ 'model_args' : {
144
+ 'model': MINI_LLM,
145
+ 'tools': [{
146
+ 'type': 'web_search_preview',
147
+ 'search_context_size': 'low'
148
+ }],
149
+ },
150
+ 'messages': [
151
+ {
152
+ 'role': 'developer',
153
+ 'content': 'You fetch real-time data from the internet. Always respond with only the data requested. Do not provide additional information in the form of context, background, or links. The response should be less than a single sentence.'
154
+ },
155
+ {
156
+ 'role': 'user',
157
+ 'content': 'Fetch the following information: {text}.'
158
+ }
159
+ ]
160
+ },
161
+ ]
162
+
163
+ OPTIONS = [
164
+ {
165
+ 'name': 'overwrite',
166
+ 'flags': ['-o', '--overwrite'],
167
+ 'description': 'overwrite the previous command',
168
+ },
169
+ {
170
+ 'name': 'no-clip',
171
+ 'flags': ['-n', '--no-clip'],
172
+ 'description': 'do not copy the output to the clipboard',
173
+ },
174
+ {
175
+ 'name': 'verbose',
176
+ 'flags': ['-v', '--verbose'],
177
+ 'description': 'print the model parameters and message history',
178
+ },
179
+ ]
180
+
181
+ def get_client() -> openai.OpenAI:
182
+ api_key =_load_resource('openai_key', None)
183
+
184
+ if api_key is None:
185
+ cprint(f'Error: OpenAI API key not found. Please paste your API key: ', 'red', end='', flush=True, file=sys.stderr)
186
+ api_key = getpass.getpass(prompt='')
187
+ _save_resource('openai_key', api_key)
188
+
189
+ while True:
190
+ try:
191
+ client = openai.OpenAI(api_key=api_key)
192
+ client.models.list() # test the API key
193
+ return client
194
+
195
+ except openai.APIError:
196
+ cprint(f'Error: OpenAI API key not valid. Please paste your API key: ', 'red', end='', flush=True, file=sys.stderr)
197
+ api_key = getpass.getpass(prompt='')
198
+ _save_resource('openai_key', api_key)
199
+
200
+ def process_text_response(text_response: str) -> str:
201
+ # remove markdown formatting from code responses
202
+ text_response = re.sub(r'^```.*?\n(.*)\n```$', r'\1', text_response, flags=re.DOTALL)
203
+
204
+ # shorten links from web search responses
205
+ text_response = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text_response).strip()
206
+
207
+ # convert bash code blocks into colored text with $ prefix
208
+ text_response = re.sub(r'```bash\n?(.*?)```', lambda m: colored('\n'.join('$ ' + line for line in m.group(1).strip().split('\n')), 'cyan'), text_response, flags=re.DOTALL)
209
+
210
+ # convert non-bash code blocks into colored text
211
+ text_response = re.sub(r'```(?:\w+\n?)?(.*?)```', lambda m: colored(m.group(1).strip(), 'cyan'), text_response, flags=re.DOTALL)
212
+
213
+ # convert inline-code into colored text
214
+ text_response = re.sub(r'`([^`]+)`', lambda m: colored(m.group(1), 'cyan'), text_response)
215
+
216
+ # convert two-plus newlines into only two
217
+ text_response = re.sub(r'\n{2,}', '\n\n', text_response)
218
+
219
+ return text_response
220
+
221
+ def prompt_model(model_args: Dict, messages: List[Dict]) -> Tuple[str, str]:
222
+ response = get_client().responses.create(
223
+ input=messages,
224
+ **model_args
225
+ )
226
+
227
+ # extract and process text response
228
+ text_response = process_text_response(response.output_text)
229
+
230
+ # extract image response
231
+ image_response = None
232
+ for output in response.output:
233
+ if output.type == 'image_generation_call':
234
+ image_response = output
235
+ break
236
+
237
+ return text_response, image_response
238
+
239
+ def run_command(cmd: Dict, text: str, **opt_args):
240
+ # load model and messages from command
241
+ model_args = {**DEFAULT_MODEL_ARGS, **cmd.get('model_args', {})}
242
+ messages = [ { role : content.replace('{text}', text) for role, content in msg.items() } for msg in cmd.get('messages', []) ]
243
+
244
+ # save model args for follow-up commands
245
+ _save_resource('model_args', model_args)
246
+ # save command args for follow-up commands
247
+ _save_resource('clip_output', cmd.get('clip_output', False))
248
+
249
+ # overwrite previous follow-up command
250
+ if opt_args.get('overwrite', False):
251
+ # remove messages from second-to-last user message to last user message
252
+ user_msg_indices = [i for i, msg in enumerate(messages) if msg.get('role') == 'user']
253
+ if len(user_msg_indices) > 1:
254
+ messages = messages[:user_msg_indices[-2]] + messages[user_msg_indices[-1]:]
255
+ else:
256
+ cprint(f'Error: No previous command to overwrite.', 'red', file=sys.stderr)
257
+ sys.exit(1)
258
+
259
+ # prompt the model
260
+ text_response, image_response = prompt_model(model_args, messages)
261
+
262
+ # save messages for follow-up commands
263
+ if image_response:
264
+ messages.append({'type': 'image_generation_call', 'id': image_response.id})
265
+ else:
266
+ messages.append({'role': 'assistant', 'content': text_response})
267
+ _save_resource('messages', messages)
268
+
269
+ # print output
270
+ if opt_args.get('verbose', False):
271
+ # model parameters
272
+ cprint('MODEL PARAMETERS:', 'red', file=sys.stderr)
273
+ for arg in model_args:
274
+ print(colored(f'{arg}:', 'green'), model_args[arg], file=sys.stderr)
275
+ # message history
276
+ cprint('\n'+'MESSAGES:', 'red', file=sys.stderr)
277
+ for message in messages:
278
+ if message.get('role'):
279
+ print(colored(f'{message["role"].capitalize()}:', 'green'), message['content'], file=sys.stderr)
280
+ elif message.get('type'):
281
+ print(colored(f'{message["type"]}:', 'green'), message['id'], file=sys.stderr)
282
+ elif not image_response:
283
+ print(text_response)
284
+
285
+ # copy text response to clipboard
286
+ if not image_response and not opt_args.get('no-clip', False) and cmd.get('clip_output', False):
287
+ try:
288
+ pyperclip.copy(text_response)
289
+ cprint(f'Output copied to clipboard.', 'yellow', file=sys.stderr)
290
+ except pyperclip.PyperclipException:
291
+ pass # ignore clipboard errors
292
+
293
+ # save image to file
294
+ if image_response:
295
+ image_file = 'q_' + ''.join(c for c in text if c not in string.punctuation).replace(' ', '_') + '.png'
296
+ with open(image_file, 'wb') as f:
297
+ f.write(base64.b64decode(image_response.result))
298
+ cprint(f'Image saved to {image_file}.', 'yellow', file=sys.stderr)
299
+
300
+ def validate_commands():
301
+ # check if there is a default command
302
+ if len([cmd for cmd in COMMANDS if not cmd['flags']]) == 0:
303
+ cprint(f'Error: No default command found.', 'red', file=sys.stderr)
304
+ sys.exit(1)
305
+
306
+ # check if there is more than one default command
307
+ if len([cmd for cmd in COMMANDS if not cmd['flags']]) > 1:
308
+ cprint(f'Error: More than one default command found. If a custom command was added, it is missing a flag.', 'red', file=sys.stderr)
309
+ sys.exit(1)
310
+
311
+ # check if there are duplicate commands
312
+ cmd_flags = [flag for cmd in COMMANDS for flag in cmd['flags']]
313
+ dup_flags = set(flag for flag in cmd_flags if cmd_flags.count(flag) > 1)
314
+ if dup_flags:
315
+ cprint(f'Error: Duplicate commands found: {", ".join(dup_flags)}.', 'red', file=sys.stderr)
316
+ sys.exit(1)
317
+
318
+ def print_help():
319
+ tab_spaces, flag_len = 4, max(len(', '.join(cmd['flags'])) for cmd in COMMANDS + OPTIONS) + 2
320
+ help_text = f'q {__version__} - {DESCRIPTION}'
321
+ help_text += '\n\nUsage: ' + colored('q [command] TEXT [options]', 'green')
322
+ help_text += '\n\nCommands (one required):\n'
323
+ help_text += '\n'.join([' '*tab_spaces + colored(f'{", ".join(cmd["flags"]) if cmd["flags"] else "TEXT":<{flag_len}}', 'green') + f'{cmd["description"]}' for cmd in COMMANDS])
324
+ help_text += '\n\nOptions:\n'
325
+ help_text += '\n'.join([' '*tab_spaces + colored(f'{", ".join(opt["flags"]):<{flag_len}}', 'green') + f'{opt["description"]}' for opt in OPTIONS])
326
+
327
+ print(help_text)
328
+
329
+ def main():
330
+ # fix ANSI escape codes on Windows
331
+ just_fix_windows_console()
332
+
333
+ # validate custom commands
334
+ validate_commands()
335
+
336
+ # get command line arguments
337
+ args = sys.argv
338
+
339
+ # print help text if no arguments or -h/--help flag is provided
340
+ if len(args) == 1 or args[1] in ['-h', '--help']:
341
+ print_help()
342
+ sys.exit(0)
343
+
344
+ # check if there is more than one command
345
+ cmd_flags = [flag for cmd in COMMANDS for flag in cmd['flags']]
346
+ if len([arg for arg in args[1:] if arg in cmd_flags]) > 1:
347
+ cprint(f'Error: Only one command may be provided.', 'red', file=sys.stderr)
348
+ sys.exit(1)
349
+
350
+ # check if there is a command that is not the first argument
351
+ if len([arg for arg in args[1:] if arg in cmd_flags]) == 1 and args[1] not in cmd_flags:
352
+ cprint(f'Error: Command must be the first argument.', 'red', file=sys.stderr)
353
+ sys.exit(1)
354
+
355
+ # check if the first argument is an invalid command
356
+ if args[1].startswith('-') and args[1] not in cmd_flags:
357
+ cprint(f'Error: Invalid command "{args[1]}".', 'red', file=sys.stderr)
358
+ sys.exit(1)
359
+
360
+ # check if there is no text provided for a command
361
+ if args[1] in cmd_flags and len(args) < 3:
362
+ cprint(f'Error: No text provided.', 'red', file=sys.stderr)
363
+ sys.exit(1)
364
+
365
+ # extract options and remove them from the text
366
+ opt_args = {opt['name']: False for opt in OPTIONS}
367
+ opt_flags = [flag for opt in OPTIONS for flag in opt['flags']]
368
+ while args[-1].startswith('-') and args[-1] != '-':
369
+ # individual flags (e.g. -v -n)
370
+ if args[-1] in opt_flags:
371
+ flag = args.pop()
372
+ for opt in OPTIONS:
373
+ if flag in opt['flags']:
374
+ opt_args[opt['name']] = True
375
+ # combined flags (e.g. -vn)
376
+ else:
377
+ flags = args.pop()[1:]
378
+ for flag in flags:
379
+ for opt in OPTIONS:
380
+ if f'-{flag}' in opt['flags']:
381
+ opt_args[opt['name']] = True
382
+ break
383
+ else:
384
+ cprint(f'Error: Invalid option "-{flags}".', 'red', file=sys.stderr)
385
+ sys.exit(1)
386
+
387
+ # mask stderr if stdout is being piped
388
+ if not sys.stdout.isatty():
389
+ sys.stderr = open(os.devnull, 'w')
390
+
391
+ # run command
392
+ for cmd in COMMANDS:
393
+ if args[1] in cmd['flags']:
394
+ run_command(cmd, ' '.join(args[2:]), **opt_args)
395
+ sys.exit(0)
396
+ # run default command
397
+ else:
398
+ # already validated there is exactly one default command
399
+ cmd = [cmd for cmd in COMMANDS if not cmd['flags']][0]
400
+ run_command(cmd, ' '.join(args[1:]), **opt_args)
401
+
402
+ if __name__ == '__main__':
403
+ main()
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: q-bot
3
+ Version: 1.3.0
4
+ Summary: An LLM-powered programming copilot from the comfort of your command line
5
+ Author-email: Tushar Khan <tushar.54k@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/tk755/q
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: colorama==0.4.6
11
+ Requires-Dist: openai==1.82.0
12
+ Requires-Dist: pyperclip==1.9.0
13
+ Requires-Dist: termcolor==2.5.0
14
+
15
+ # Overview
16
+ `q` is an LLM-powered programming copilot from the comfort of your command line. It can generate code snippets, shell commands, technical explanations, web searches, and even images. Through multi-turn conversations, it can build, debug, and refine complex solutions iteratively. It even saves generated code and commands to your clipboard, so you can paste it wherever you need it.
17
+
18
+ Currently `q` uses the OpenAI API, but support for other LLM providers is planned in the future.
19
+
20
+ # Installation
21
+
22
+ Install from PyPI using pipx (recommended for CLI tools):
23
+
24
+ ```bash
25
+ pipx install q-cli
26
+ ```
27
+
28
+ Or using pip:
29
+
30
+ ```bash
31
+ pip install q-cli
32
+ ```
33
+
34
+ Requires Python 3.8+.
35
+
36
+ # Usage
37
+
38
+ The basic syntax is `q [command] TEXT [options]`. `q` accepts at most one command and any number of options. Any arguments between the command and options is treated as the input text.
39
+
40
+ `q` saves generated code snippets and shell commands to your clipboard so you can paste it wherever you need it. This only works on non-headless environments (no VMs and Docker containers); check [here](https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error) if it doesn't work.
41
+
42
+ For a full list of commands and options, run `q -h`.
43
+
44
+ > The first time `q` is prompted, you will be asked for an OpenAI API key which you can create [here](https://platform.openai.com/api-keys).
45
+
46
+ ## Commands
47
+
48
+ Each command runs a tailored LLM prompt using the OpenAI API and returns the parsed response.
49
+
50
+ ### Generate Code
51
+
52
+ Use the `-c` or `--code` command to generate code snippets:
53
+
54
+ ```
55
+ $ q -c copy user input to clipboard
56
+ import pyperclip
57
+
58
+ user_input = input("Enter text to copy to clipboard: ")
59
+ pyperclip.copy(user_input)
60
+ ```
61
+
62
+ By default this generates Python code, but you can specify a different programming language in the prompt itself (or [modify the default value](#modifying-default-values)):
63
+
64
+ ```
65
+ $ q -c copy user input to clipboard in rust
66
+ use std::io::{self, Write};
67
+ use clipboard::{ClipboardContext, ClipboardProvider};
68
+
69
+ fn main() {
70
+ let mut input = String::new();
71
+ print!("Enter text to copy to clipboard: ");
72
+ io::stdout().flush().unwrap();
73
+ io::stdin().read_line(&mut input).unwrap();
74
+
75
+ let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
76
+ ctx.set_contents(input.trim().to_string()).unwrap();
77
+ }
78
+ ```
79
+
80
+ You can redirect the output to a file and run it instantly:
81
+
82
+ ```
83
+ $ q -c fib function w main function > fib.py && python3 fib.py
84
+ Enter a number: 10
85
+ Fibonacci number at position 10 is 55
86
+ ```
87
+
88
+ ### Generate Shell Commands
89
+
90
+ Use the `-s` or `--shell` command to generate shell commands:
91
+
92
+ ```
93
+ $ q -s add README.md to prev commit and push changes
94
+ git add README.md && git commit --amend --no-edit && git push --force-with-lease
95
+ ```
96
+
97
+ By default this generates Bash commands for a Linux system, but you can specify a different shell or OS in the prompt itself (or [modify the default value](#modifying-default-values)):
98
+
99
+ ```
100
+ $ q -s auto hide the dock on macos
101
+ defaults write com.apple.dock autohide -bool true; killall Dock
102
+ ```
103
+
104
+ You can pipe the output to the shell interpreter to run it instantly:
105
+
106
+ ```
107
+ $ q -s count line numbers in fib.py | bash
108
+ 12 fib.py
109
+ ```
110
+
111
+ ### Explain
112
+
113
+ Use the `-e` or `--explain` command to generate a concise explanation for code or shell commands:
114
+
115
+ ```
116
+ $ q -e 'print(os.getcwd())'
117
+ `print(os.getcwd())` outputs the current working directory of the Python process by calling `os.getcwd()`, which returns the absolute path as a string, and then prints it to the standard output.
118
+ ```
119
+
120
+ This is particularly useful for understanding complex code or shell commands you may not be familiar with:
121
+
122
+ ```
123
+ $ q -e 'find . -type d -name .git -exec dirname {} \; | sort'
124
+ This command searches recursively from the current directory for directories named `.git`, then uses `dirname` to output their parent directory paths, effectively listing all Git repository root directories. The results are then sorted alphabetically.
125
+ ```
126
+
127
+ It can even generate explanations about technical concepts:
128
+
129
+ ```
130
+ $ q -e neuroevolution
131
+ Neuroevolution is a technique that applies evolutionary algorithms to optimize artificial neural networks, typically evolving their weights, architectures, or learning rules. Instead of using gradient-based methods like backpropagation, neuroevolution treats network parameters as genomes and iteratively improves them through selection, mutation, and crossover, enabling the discovery of novel network topologies and solutions, especially useful in reinforcement learning and problems with non-differentiable objectives.
132
+ ```
133
+
134
+ ### Search the Web
135
+
136
+ Use the `-w` or `--web` command to search the web for up-to-date information (note: this is slightly expensive):
137
+
138
+ ```
139
+ $ q -w highest qbit computer
140
+ As of July 2025, the quantum computer with the highest number of qubits is Atom Computing's processor, which has 1,180 qubits. (spinquanta.com)
141
+ ```
142
+
143
+ ### Generate Images
144
+
145
+ Use the `-i` or `--image` command to generate 1024x1024 images (note: this is very expensive):
146
+
147
+ ```
148
+ $ q -i george washington riding a harley through the american civil war
149
+ Image saved to q_george_washington_riding_a_harley_through_the_american_civil_war.png.
150
+ ```
151
+
152
+ ## Multi-Turn Conversations
153
+
154
+ Use `q` without specifying a command to build on the previous response conversationally:
155
+
156
+ ```
157
+ $ q -w nba champions
158
+ The Oklahoma City Thunder won the 2025 NBA Finals, defeating the Indiana Pacers 4-3. (nba.com)
159
+ $ q final game score
160
+ The Oklahoma City Thunder defeated the Indiana Pacers 103-91 in Game 7 of the 2025 NBA Finals on June 22, 2025. (espn.com)
161
+ ```
162
+
163
+ This is very useful for iteratively refining generated code or shell commands:
164
+
165
+ ```
166
+ $ q -s get cuda version
167
+ nvcc --version
168
+ $ nvcc --version
169
+ bash: nvcc: command not found
170
+ $ q command not found
171
+ cat /usr/local/cuda/version.txt
172
+ $ cat /usr/local/cuda/version.txt
173
+ cat: /usr/local/cuda/version.txt: No such file or directory
174
+ $ q file not found
175
+ nvidia-smi | grep "CUDA Version"
176
+ $ nvidia-smi | grep "CUDA Version"
177
+ | NVIDIA-SMI 560.35.02 Driver Version: 560.94 CUDA Version: 12.6 |
178
+ ```
179
+
180
+ And ask follow-up questions about the previous response:
181
+
182
+ ```
183
+ $ q -c function to merge two dictionaries x and y
184
+ def merge_dictionaries(x, y):
185
+ return {**x, **y}
186
+ $ q what is the time complexity
187
+ The time complexity of merging two dictionaries using `{**x, **y}` is O(n + m), where n is the number of elements in dictionary `x` and m is the number of elements in dictionary `y`.
188
+ ```
189
+
190
+ You can even refine generated images:
191
+
192
+ ```
193
+ $ q -i low poly rubber duck
194
+ Image saved to q_low_poly_rubber_duck.png.
195
+ $ q make it float in a high res bathtub
196
+ Image saved to q_make_it_float_in_a_high_res_bathtub.png.
197
+ ```
198
+
199
+ ## Options
200
+
201
+ Options are boolean flags that modify the behavior of `q`:
202
+
203
+ - Use the `-o` or `--overwrite` option to overwrite the previous command.
204
+ - Use the `-n` or `--no-clip` option to disable automatically storing responses to the clipboard.
205
+ - Use the `-v` or `--verbose` option to print the model parameters and message history.
206
+
207
+ You can combine multiple options using their abbreviated forms following a single hyphen:
208
+
209
+ ```
210
+ $ q -p knock knock
211
+ Who's there?
212
+ $ q apple
213
+ Apple who?
214
+ $ q orange -vo
215
+
216
+ MODEL PARAMETERS:
217
+ model: gpt-4o
218
+ max_tokens: 256
219
+ temperature: 0.25
220
+ frequency_penalty: 0
221
+ presence_penalty: 0
222
+ top_p: 1
223
+
224
+ MESSAGES:
225
+ System: You are a helpful and knowledgeable AI assistant.
226
+ User: knock knock
227
+ Assistant: Who's there?
228
+ User: orange
229
+ Assistant: Orange who?
230
+ ```
231
+
232
+ # Customization
233
+
234
+ `q` was designed to be easily customizable to suit any programmer's needs.
235
+
236
+ ## Modifying Default Values
237
+
238
+ The following constants can be modified in the script to change the default behavior of `q`:
239
+ - `MINI_LLM`: the default model for fast and cheap responses.
240
+ - `FULL_LLM`: the default model for long and detailed responses.
241
+ - `DEFAULT_MODEL_ARGS`: the default model arguments used by all commands if not overrided.
242
+ - `DEFAULT_CODE`: the default language for code generation used by the `-c` command.
243
+ - `DEFAULT_SHELL`: the default system for shell command generation used by the `-s` command.
244
+
245
+ ## Adding New Commands
246
+
247
+ Add a new command to `q` by inserting a new dictionary in the `COMMANDS` list with the following keys:
248
+ - `flags` *(required)*: a list of flags to invoke the command.
249
+ - `description` *(required)*: a brief description of the command shown in the help message.
250
+ - `messages` *(required)*: the instructions sent to the LLM, using `{text}` as a placeholder for the input text.
251
+ - `model_args` *(optional)*: override default model arguments set in `DEFAULT_MODEL_ARGS` or set new arguments.
252
+ - `clip_output` *(optional)*: set to `True` to copy the output to the clipboard; `False` by default.
253
+
254
+ Refer to the existing commands in the script for examples.
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ q.py
4
+ q_bot.egg-info/PKG-INFO
5
+ q_bot.egg-info/SOURCES.txt
6
+ q_bot.egg-info/dependency_links.txt
7
+ q_bot.egg-info/entry_points.txt
8
+ q_bot.egg-info/requires.txt
9
+ q_bot.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ q = q:main
@@ -0,0 +1,4 @@
1
+ colorama==0.4.6
2
+ openai==1.82.0
3
+ pyperclip==1.9.0
4
+ termcolor==2.5.0
@@ -0,0 +1 @@
1
+ q
q_bot-1.3.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+