npcsh 0.3.27.2__tar.gz → 0.3.27.4__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.
Files changed (70) hide show
  1. {npcsh-0.3.27.2/npcsh.egg-info → npcsh-0.3.27.4}/PKG-INFO +4 -1
  2. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/helpers.py +5 -1
  3. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/search.py +5 -1
  4. {npcsh-0.3.27.2 → npcsh-0.3.27.4/npcsh.egg-info}/PKG-INFO +4 -1
  5. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh.egg-info/SOURCES.txt +1 -0
  6. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh.egg-info/requires.txt +3 -0
  7. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/setup.py +3 -1
  8. npcsh-0.3.27.4/tests/test_tars.py +178 -0
  9. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/LICENSE +0 -0
  10. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/MANIFEST.in +0 -0
  11. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/README.md +0 -0
  12. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/__init__.py +0 -0
  13. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/audio.py +0 -0
  14. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/cli.py +0 -0
  15. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/command_history.py +0 -0
  16. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/conversation.py +0 -0
  17. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/data_models.py +0 -0
  18. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/dataframes.py +0 -0
  19. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/embeddings.py +0 -0
  20. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/image.py +0 -0
  21. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/image_gen.py +0 -0
  22. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/knowledge_graph.py +0 -0
  23. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/llm_funcs.py +0 -0
  24. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/load_data.py +0 -0
  25. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/main.py +0 -0
  26. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/model_runner.py +0 -0
  27. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_compiler.py +0 -0
  28. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_sysenv.py +0 -0
  29. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/assembly_lines/test_pipeline.py +0 -0
  30. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/corca.npc +0 -0
  31. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/foreman.npc +0 -0
  32. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/npcsh.ctx +0 -0
  33. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/sibiji.npc +0 -0
  34. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/analytics/celona.npc +0 -0
  35. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/hr_support/raone.npc +0 -0
  36. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/humanities/eriane.npc +0 -0
  37. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/it_support/lineru.npc +0 -0
  38. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/marketing/slean.npc +0 -0
  39. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/philosophy/maurawa.npc +0 -0
  40. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/sales/turnic.npc +0 -0
  41. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/templates/software/welxor.npc +0 -0
  42. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/calculator.tool +0 -0
  43. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/generic_search.tool +0 -0
  44. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/image_generation.tool +0 -0
  45. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/local_search.tool +0 -0
  46. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/screen_cap.tool +0 -0
  47. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/npc_team/tools/sql_executor.tool +0 -0
  48. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/plonk.py +0 -0
  49. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/response.py +0 -0
  50. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/serve.py +0 -0
  51. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/shell.py +0 -0
  52. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/shell_helpers.py +0 -0
  53. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/stream.py +0 -0
  54. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh/video.py +0 -0
  55. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh.egg-info/dependency_links.txt +0 -0
  56. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh.egg-info/entry_points.txt +0 -0
  57. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/npcsh.egg-info/top_level.txt +0 -0
  58. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/setup.cfg +0 -0
  59. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_chromadb.py +0 -0
  60. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_embedding_check.py +0 -0
  61. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_embedding_methods.py +0 -0
  62. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_helpers.py +0 -0
  63. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_knowledge_graph_rag.py +0 -0
  64. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_llm_funcs.py +0 -0
  65. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_networkx_vis.py +0 -0
  66. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_npc_compiler.py +0 -0
  67. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_npcsh.py +0 -0
  68. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_npcteam.py +0 -0
  69. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_shell_helpers.py +0 -0
  70. {npcsh-0.3.27.2 → npcsh-0.3.27.4}/tests/test_tool_use.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcsh
3
- Version: 0.3.27.2
3
+ Version: 0.3.27.4
4
4
  Summary: npcsh is a command line tool for integrating LLMs into everyday workflows and for orchestrating teams of NPCs.
5
5
  Home-page: https://github.com/cagostino/npcsh
6
6
  Author: Christopher Agostino
@@ -19,6 +19,7 @@ Requires-Dist: PyYAML
19
19
  Requires-Dist: pygments
20
20
  Requires-Dist: termcolor
21
21
  Requires-Dist: colorama
22
+ Requires-Dist: Pillow
22
23
  Requires-Dist: python-dotenv
23
24
  Requires-Dist: pandas
24
25
  Requires-Dist: beautifulsoup4
@@ -39,6 +40,7 @@ Requires-Dist: ollama; extra == "local"
39
40
  Requires-Dist: kuzu; extra == "local"
40
41
  Requires-Dist: chromadb; extra == "local"
41
42
  Requires-Dist: diffusers; extra == "local"
43
+ Requires-Dist: nltk; extra == "local"
42
44
  Provides-Extra: whisper
43
45
  Requires-Dist: openai-whisper; extra == "whisper"
44
46
  Requires-Dist: pyaudio; extra == "whisper"
@@ -56,6 +58,7 @@ Requires-Dist: ollama; extra == "all"
56
58
  Requires-Dist: kuzu; extra == "all"
57
59
  Requires-Dist: chromadb; extra == "all"
58
60
  Requires-Dist: diffusers; extra == "all"
61
+ Requires-Dist: nltk; extra == "all"
59
62
  Requires-Dist: openai-whisper; extra == "all"
60
63
  Requires-Dist: pyaudio; extra == "all"
61
64
  Requires-Dist: gtts; extra == "all"
@@ -5,7 +5,11 @@ import sqlite3
5
5
  import subprocess
6
6
  import platform
7
7
  import yaml
8
- import nltk
8
+
9
+ try:
10
+ import nltk
11
+ except:
12
+ print("Error importing nltk")
9
13
  import numpy as np
10
14
 
11
15
  import filecmp
@@ -5,7 +5,11 @@ import os
5
5
 
6
6
  from bs4 import BeautifulSoup
7
7
  from duckduckgo_search import DDGS
8
- from googlesearch import search
8
+
9
+ try:
10
+ from googlesearch import search
11
+ except:
12
+ pass
9
13
  from typing import List, Dict, Any, Optional, Union
10
14
  import numpy as np
11
15
  import json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcsh
3
- Version: 0.3.27.2
3
+ Version: 0.3.27.4
4
4
  Summary: npcsh is a command line tool for integrating LLMs into everyday workflows and for orchestrating teams of NPCs.
5
5
  Home-page: https://github.com/cagostino/npcsh
6
6
  Author: Christopher Agostino
@@ -19,6 +19,7 @@ Requires-Dist: PyYAML
19
19
  Requires-Dist: pygments
20
20
  Requires-Dist: termcolor
21
21
  Requires-Dist: colorama
22
+ Requires-Dist: Pillow
22
23
  Requires-Dist: python-dotenv
23
24
  Requires-Dist: pandas
24
25
  Requires-Dist: beautifulsoup4
@@ -39,6 +40,7 @@ Requires-Dist: ollama; extra == "local"
39
40
  Requires-Dist: kuzu; extra == "local"
40
41
  Requires-Dist: chromadb; extra == "local"
41
42
  Requires-Dist: diffusers; extra == "local"
43
+ Requires-Dist: nltk; extra == "local"
42
44
  Provides-Extra: whisper
43
45
  Requires-Dist: openai-whisper; extra == "whisper"
44
46
  Requires-Dist: pyaudio; extra == "whisper"
@@ -56,6 +58,7 @@ Requires-Dist: ollama; extra == "all"
56
58
  Requires-Dist: kuzu; extra == "all"
57
59
  Requires-Dist: chromadb; extra == "all"
58
60
  Requires-Dist: diffusers; extra == "all"
61
+ Requires-Dist: nltk; extra == "all"
59
62
  Requires-Dist: openai-whisper; extra == "all"
60
63
  Requires-Dist: pyaudio; extra == "all"
61
64
  Requires-Dist: gtts; extra == "all"
@@ -64,4 +64,5 @@ tests/test_npc_compiler.py
64
64
  tests/test_npcsh.py
65
65
  tests/test_npcteam.py
66
66
  tests/test_shell_helpers.py
67
+ tests/test_tars.py
67
68
  tests/test_tool_use.py
@@ -7,6 +7,7 @@ PyYAML
7
7
  pygments
8
8
  termcolor
9
9
  colorama
10
+ Pillow
10
11
  python-dotenv
11
12
  pandas
12
13
  beautifulsoup4
@@ -27,6 +28,7 @@ ollama
27
28
  kuzu
28
29
  chromadb
29
30
  diffusers
31
+ nltk
30
32
  openai-whisper
31
33
  pyaudio
32
34
  gtts
@@ -46,6 +48,7 @@ ollama
46
48
  kuzu
47
49
  chromadb
48
50
  diffusers
51
+ nltk
49
52
 
50
53
  [whisper]
51
54
  openai-whisper
@@ -63,6 +63,7 @@ base_requirements = [
63
63
  "pygments",
64
64
  "termcolor",
65
65
  "colorama",
66
+ "Pillow",
66
67
  "python-dotenv",
67
68
  "pandas",
68
69
  "beautifulsoup4",
@@ -84,6 +85,7 @@ local_requirements = [
84
85
  "kuzu",
85
86
  "chromadb",
86
87
  "diffusers",
88
+ "nltk",
87
89
  ]
88
90
 
89
91
  # Voice/Audio requirements
@@ -99,7 +101,7 @@ extra_files = package_files("npcsh/npc_team/")
99
101
 
100
102
  setup(
101
103
  name="npcsh",
102
- version="0.3.27.2",
104
+ version="0.3.27.4",
103
105
  packages=find_packages(exclude=["tests*"]),
104
106
  install_requires=base_requirements, # Only install base requirements by default
105
107
  extras_require={
@@ -0,0 +1,178 @@
1
+ import os
2
+ import base64
3
+ import requests
4
+ import json
5
+ import torch
6
+ import pyautogui # For taking screenshots
7
+ import time
8
+ from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
9
+ from screeninfo import get_monitors
10
+ from npcsh.llm_funcs import get_openai_response
11
+
12
+
13
+ def get_screen_resolution():
14
+ monitor = get_monitors()[0] # Get primary monitor
15
+ return monitor.width, monitor.height
16
+
17
+
18
+ from PIL import Image
19
+
20
+
21
+ def capture_screenshot() -> str:
22
+ """Captures a screenshot and saves it to a specified path."""
23
+ screenshot_path = "screenshot.png"
24
+ screenshot = pyautogui.screenshot()
25
+
26
+ # Resize screenshot to fit model's pixel range
27
+ desired_width = 1280 # Adjust as needed based on max_pixels range
28
+ desired_height = int(
29
+ (desired_width * screenshot.height) / screenshot.width
30
+ ) # Maintain aspect ratio
31
+ screenshot = screenshot.resize((desired_width, desired_height))
32
+
33
+ screenshot.save(screenshot_path)
34
+ return screenshot_path
35
+
36
+
37
+ # Adjust processor for specific pixel range
38
+ min_pixels = 256 * 28 * 28
39
+ max_pixels = 1280 * 28 * 28
40
+
41
+
42
+ def encode_image_to_base64(image_path: str) -> str:
43
+ """Encodes an image file to a base64 string."""
44
+ with open(image_path, "rb") as image_file:
45
+ encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
46
+ return f"data:image/png;base64,{encoded_string}"
47
+
48
+
49
+ def get_tars_response(command: str, model_name: str) -> str:
50
+ """Generates a response from the UI-TARS model based on the command and screenshot image."""
51
+ # model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
52
+ # model_name, torch_dtype="auto", device_map="auto"
53
+ # )
54
+ # processor = AutoProcessor.from_pretrained(model_name)
55
+
56
+ # capture the current screen
57
+ im = capture_screenshot()
58
+ image_data = encode_image_to_base64(im)
59
+ prompt = (
60
+ f"""You are a GUI agent. You are given a task and your action history,
61
+ with screenshots. You need to perform the next action or set of actions to complete the task.
62
+ here is the task you must complete: {command}
63
+ """
64
+ + r"""
65
+ click(start_box='<|box_start|>(x1,y1)<|box_end|>')
66
+ left_double(start_box='<|box_start|>(x1,y1)<|box_end|>')
67
+ right_single(start_box='<|box_start|>(x1,y1)<|box_end|>')
68
+ drag(start_box='<|box_start|>(x1,y1)<|box_end|>', end_box='<|box_start|>(x3,y3)<|box_end|>')
69
+ hotkey(key='')
70
+ type(content='') #If you want to submit your input, use "\
71
+ " at the end of `content`.
72
+ scroll(start_box='<|box_start|>(x1,y1)<|box_end|>', direction='down or up or right or left')
73
+ wait() #Sleep for 5s and take a screenshot to check for any changes.
74
+ finished()
75
+ call_user() # Submit the task and call the user when the task is unsolvable, or when you need the user's help.
76
+
77
+ your response should be a list of actions to perform in the order they should be performed.
78
+ Provide a single json object with the following format:
79
+ { "actions": ['action1', 'action2', 'action3'] }
80
+ Do not provide any additional text or markdown formatting.
81
+ """
82
+ )
83
+
84
+ messages = [
85
+ {
86
+ "role": "user",
87
+ "content": [
88
+ {
89
+ "type": "image_url",
90
+ "image_url": {"url": image_data},
91
+ },
92
+ {"type": "text", "text": command},
93
+ ],
94
+ }
95
+ ]
96
+
97
+ # tars:
98
+ """text = processor.apply_chat_template(
99
+ messages, tokenize=False, add_generation_prompt=True
100
+ )
101
+ inputs = processor(text=text, padding=True, return_tensors="pt").to(model.device)
102
+ generated_ids = model.generate(**inputs, max_new_tokens=128)
103
+ output_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
104
+ return output_text[0]
105
+ """
106
+ gpt4o_response = get_openai_response(
107
+ prompt, model="gpt-4o-mini", messages=messages, format="json"
108
+ )
109
+
110
+ return gpt4o_response
111
+
112
+
113
+ def execute_actions(actions: list):
114
+ """Executes the actions received from the model using pyautogui."""
115
+ for action in actions:
116
+ if action.startswith("click"):
117
+ x, y = map(int, action[action.find("(") + 1 : action.find(")")].split(","))
118
+ pyautogui.click(x, y)
119
+ elif action.startswith("left_double"):
120
+ x, y = map(int, action[action.find("(") + 1 : action.find(")")].split(","))
121
+ pyautogui.doubleClick(x, y)
122
+ elif action.startswith("right_single"):
123
+ x, y = map(int, action[action.find("(") + 1 : action.find(")")].split(","))
124
+ pyautogui.rightClick(x, y)
125
+ elif action.startswith("drag"):
126
+ coords = list(
127
+ map(
128
+ int,
129
+ action[action.find("(") + 1 : action.find(")")]
130
+ .replace("(", "")
131
+ .replace(")", "")
132
+ .split(","),
133
+ )
134
+ )
135
+ pyautogui.moveTo(coords[0], coords[1])
136
+ pyautogui.dragTo(coords[2], coords[3], duration=0.5)
137
+ elif action.startswith("type"):
138
+ text = action.split("('")[1].split("')")[0]
139
+ pyautogui.write(text, interval=0.05)
140
+ elif action.startswith("hotkey"):
141
+ key = action.split("('")[1].split("')")[0]
142
+ pyautogui.hotkey(key)
143
+ elif action.startswith("scroll"):
144
+ direction = action.split("('")[1].split("')")[0]
145
+ amount = -100 if direction == "down" else 100
146
+ pyautogui.scroll(amount)
147
+ elif action.startswith("wait"):
148
+ time.sleep(5)
149
+ elif action.startswith("finished"):
150
+ print("Task completed.")
151
+
152
+
153
+ def ui_tars_control_loop(model_name: str):
154
+ """Main loop for interacting with the user and executing commands via UI-TARS."""
155
+ print("UI-TARS Control Loop Started.")
156
+ screen_width, screen_height = get_screen_resolution()
157
+ print(f"Screen resolution: {screen_width}x{screen_height}")
158
+
159
+ while True:
160
+ command = input("Enter your command (or type 'exit' to quit): ")
161
+ if command.lower() == "exit":
162
+ print("Exiting UI-TARS Control Loop.")
163
+ break
164
+
165
+ screenshot_path = capture_screenshot()
166
+ tars_result = get_tars_response(command, screenshot_path, model_name)
167
+ print(f"UI-TARS Response: {tars_result}")
168
+
169
+ try:
170
+ actions = json.loads(tars_result).get("actions", [])
171
+ execute_actions(actions)
172
+ except json.JSONDecodeError:
173
+ print("Error parsing actions from UI-TARS response.")
174
+
175
+
176
+ if __name__ == "__main__":
177
+ MODEL_NAME = "ui-tars-7B" # Replace with your actual UI-TARS model name
178
+ ui_tars_control_loop(MODEL_NAME)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes