badnet 0.1.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.
badnet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,4 @@
1
+ Metadata-Version: 2.4
2
+ Name: badnet
3
+ Version: 0.1.0
4
+ Requires-Dist: openai
@@ -0,0 +1,4 @@
1
+ Metadata-Version: 2.4
2
+ Name: badnet
3
+ Version: 0.1.0
4
+ Requires-Dist: openai
@@ -0,0 +1,8 @@
1
+ badnet.py
2
+ pyproject.toml
3
+ badnet.egg-info/PKG-INFO
4
+ badnet.egg-info/SOURCES.txt
5
+ badnet.egg-info/dependency_links.txt
6
+ badnet.egg-info/entry_points.txt
7
+ badnet.egg-info/requires.txt
8
+ badnet.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ badnet = badnet:main
@@ -0,0 +1 @@
1
+ openai
@@ -0,0 +1 @@
1
+ badnet
badnet-0.1.0/badnet.py ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env python3
2
+ """badnet - консольный ассистент DeepSeek с доступом к терминалу."""
3
+ import json
4
+ import os
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ from openai import OpenAI
9
+
10
+ CONFIG_DIR = Path.home() / ".badnet"
11
+ CONFIG_FILE = CONFIG_DIR / "config.json"
12
+ BASE_URL = "https://api.deepseek.com"
13
+ DEFAULT_MODEL = "deepseek-chat"
14
+ MODELS = ["deepseek-chat", "deepseek-reasoner"]
15
+ MAX_OUTPUT = 8000
16
+
17
+ SYSTEM_PROMPT = (
18
+ "Ты badnet, консольный ассистент с доступом к терминалу пользователя. "
19
+ "Когда нужно что-то проверить или сделать, вызывай инструмент run_shell. "
20
+ "Отвечай по-русски, кратко и по делу."
21
+ )
22
+
23
+ TOOLS = [{
24
+ "type": "function",
25
+ "function": {
26
+ "name": "run_shell",
27
+ "description": "Выполнить shell-команду в терминале и вернуть вывод",
28
+ "parameters": {
29
+ "type": "object",
30
+ "properties": {
31
+ "command": {"type": "string", "description": "Команда для выполнения"}
32
+ },
33
+ "required": ["command"],
34
+ },
35
+ },
36
+ }]
37
+
38
+ # Буквы из блоков: каждая строка одной буквы имеет одинаковую ширину (5 символов)
39
+ LETTERS = {
40
+ "B": ["████ ", "█ █", "████ ", "█ █", "████ "],
41
+ "A": [" ███ ", "█ █", "█████", "█ █", "█ █"],
42
+ "D": ["████ ", "█ █", "█ █", "█ █", "████ "],
43
+ "N": ["█ █", "██ █", "█ █ █", "█ ██", "█ █"],
44
+ "E": ["█████", "█ ", "████ ", "█ ", "█████"],
45
+ "T": ["█████", " █ ", " █ ", " █ ", " █ "],
46
+ }
47
+
48
+
49
+ def print_banner():
50
+ word = "BADNET"
51
+ for row in range(5):
52
+ print(" " + " ".join(LETTERS[ch][row] for ch in word))
53
+ print(" консольный ассистент DeepSeek | /help - список команд\n")
54
+
55
+
56
+ def load_config():
57
+ if CONFIG_FILE.exists():
58
+ return json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
59
+ return {}
60
+
61
+
62
+ def save_config(cfg):
63
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
64
+ CONFIG_FILE.write_text(json.dumps(cfg, ensure_ascii=False, indent=2), encoding="utf-8")
65
+
66
+
67
+ def run_shell(command):
68
+ try:
69
+ p = subprocess.run(
70
+ command, shell=True, capture_output=True, text=True,
71
+ timeout=120, cwd=os.getcwd(),
72
+ )
73
+ out = (p.stdout + p.stderr).strip() or "(нет вывода)"
74
+ except subprocess.TimeoutExpired:
75
+ return "Ошибка: команда превысила таймаут 120 секунд"
76
+ if len(out) > MAX_OUTPUT:
77
+ out = out[:MAX_OUTPUT] + "\n...[вывод обрезан]"
78
+ print(out)
79
+ return f"exit={p.returncode}\n{out}"
80
+
81
+
82
+ def ask_model(client, cfg, messages, state):
83
+ while True:
84
+ resp = client.chat.completions.create(
85
+ model=cfg["model"], messages=messages, tools=TOOLS
86
+ )
87
+ msg = resp.choices[0].message
88
+ messages.append(msg.model_dump(exclude_none=True))
89
+
90
+ if not msg.tool_calls:
91
+ print(msg.content or "")
92
+ return
93
+
94
+ if msg.content:
95
+ print(msg.content)
96
+
97
+ for call in msg.tool_calls:
98
+ args = json.loads(call.function.arguments or "{}")
99
+ command = args.get("command", "")
100
+ print(f"\n$ {command}")
101
+
102
+ if state["auto"]:
103
+ result = run_shell(command)
104
+ else:
105
+ answer = input("Выполнить? [y - да / a - да и всегда / n - нет]: ").strip().lower()
106
+ if answer in ("a", "а"):
107
+ state["auto"] = True
108
+ print("Автовыполнение включено (/auto - выключить)")
109
+ answer = "y"
110
+ if answer in ("y", "д", "да", "yes"):
111
+ result = run_shell(command)
112
+ else:
113
+ result = "Пользователь отклонил выполнение команды."
114
+ print(result)
115
+
116
+ messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
117
+
118
+
119
+ HELP = """Команды:
120
+ /put КЛЮЧ сохранить API-ключ DeepSeek
121
+ /mod [МОДЕЛЬ] выбрать модель (без аргумента - показать список)
122
+ /clear очистить контекст диалога
123
+ /run КОМАНДА выполнить команду в терминале без участия модели
124
+ /cd ПУТЬ сменить рабочую папку
125
+ /cwd показать текущую папку
126
+ /auto вкл/выкл автовыполнение команд модели
127
+ /help эта справка
128
+ /exit выход"""
129
+
130
+
131
+ def main():
132
+ cfg = load_config()
133
+ cfg.setdefault("model", DEFAULT_MODEL)
134
+ client = OpenAI(api_key=cfg["api_key"], base_url=BASE_URL) if cfg.get("api_key") else None
135
+
136
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
137
+ state = {"auto": False}
138
+
139
+ print_banner()
140
+
141
+ while True:
142
+ try:
143
+ user = input(f"[{cfg['model']}] badnet> ").strip()
144
+ except (EOFError, KeyboardInterrupt):
145
+ print()
146
+ break
147
+
148
+ if not user:
149
+ continue
150
+
151
+ if user.startswith("/"):
152
+ cmd, _, arg = user.partition(" ")
153
+ arg = arg.strip()
154
+
155
+ if cmd == "/exit":
156
+ break
157
+ elif cmd == "/help":
158
+ print(HELP)
159
+ elif cmd == "/put":
160
+ if not arg:
161
+ print("Использование: /put КЛЮЧ")
162
+ continue
163
+ cfg["api_key"] = arg
164
+ save_config(cfg)
165
+ client = OpenAI(api_key=arg, base_url=BASE_URL)
166
+ print("Ключ сохранён в", CONFIG_FILE)
167
+ elif cmd == "/mod":
168
+ if not arg:
169
+ print("Текущая модель:", cfg["model"])
170
+ print("Доступно:", ", ".join(MODELS))
171
+ else:
172
+ cfg["model"] = arg
173
+ save_config(cfg)
174
+ print("Модель:", arg)
175
+ elif cmd == "/clear":
176
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
177
+ print("Контекст очищен")
178
+ elif cmd == "/run":
179
+ if not arg:
180
+ print("Использование: /run КОМАНДА")
181
+ else:
182
+ run_shell(arg)
183
+ elif cmd == "/cd":
184
+ try:
185
+ os.chdir(os.path.expanduser(arg or "~"))
186
+ print("Папка:", os.getcwd())
187
+ except OSError as e:
188
+ print("Ошибка:", e)
189
+ elif cmd == "/cwd":
190
+ print(os.getcwd())
191
+ elif cmd == "/auto":
192
+ state["auto"] = not state["auto"]
193
+ print("Автовыполнение:", "вкл" if state["auto"] else "выкл")
194
+ else:
195
+ print(f"Неизвестная команда: {cmd}. Список - /help")
196
+ continue
197
+
198
+ if client is None:
199
+ print("Сначала задай ключ: /put КЛЮЧ")
200
+ continue
201
+
202
+ messages.append({"role": "user", "content": user})
203
+ try:
204
+ ask_model(client, cfg, messages, state)
205
+ except Exception as e:
206
+ print(f"Ошибка API: {e}")
207
+
208
+
209
+ if __name__ == "__main__":
210
+ main()
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "badnet"
3
+ version = "0.1.0"
4
+ dependencies = ["openai"]
5
+
6
+ [project.scripts]
7
+ badnet = "badnet:main"
8
+
9
+ [build-system]
10
+ requires = ["setuptools"]
11
+ build-backend = "setuptools.build_meta"
12
+
13
+ [tool.setuptools]
14
+ py-modules = ["badnet"]
badnet-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+