tc043 commited on
Commit
0b80cf0
·
1 Parent(s): c8f975e

refactor: optimize inference with async locking, prompt engineering, and input post-processing while adding comprehensive testing suites

Browse files
Files changed (9) hide show
  1. app.py +60 -12
  2. print_template.py +4 -0
  3. semantic_test.py +38 -0
  4. stress_test.py +51 -0
  5. test_extract.py +16 -0
  6. test_minicpm.py +8 -0
  7. test_nem_out.txt +4 -0
  8. test_nemotron.py +9 -0
  9. test_ws.py +11 -0
app.py CHANGED
@@ -55,11 +55,15 @@ if not MOCK_MODE:
55
  nemotron = Llama(model_path=NEMOTRON_MODEL_PATH, n_ctx=1024)
56
  minicpm = Llama(model_path=MINICPM_MODEL_PATH, n_ctx=1024)
57
 
 
58
 
59
  async def run_blocking(func, *args, **kwargs):
60
- return await asyncio.to_thread(func, *args, **kwargs)
 
61
 
62
- async def generate_atomic_task(goal: str, previous_failures: int, completed_count: int = 0) -> str:
 
 
63
  if MOCK_MODE:
64
  await asyncio.sleep(1) # Simulate inference latency
65
  demo_steps = [
@@ -70,20 +74,51 @@ async def generate_atomic_task(goal: str, previous_failures: int, completed_coun
70
  ]
71
  if previous_failures == 1:
72
  return "Move your mouse to the browser icon."
73
- return demo_steps[min(completed_count, len(demo_steps) - 1)]
74
 
75
  else:
76
  # REAL INFERENCE
77
- prompt = f"Goal: {goal}. Failures: {previous_failures}. Output a single physical action verb under 8 words."
 
 
 
 
 
 
 
 
 
 
 
78
  response = await run_blocking(
79
  nemotron,
80
- prompt,
81
  max_tokens=20,
82
- grammar=grammar,
83
  temperature=0.1,
 
84
  )
85
- task_json = json.loads(response['choices'][0]['text'])
86
- return task_json.get("task", "Focus on the screen.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  async def apply_activation_style(task: str, style="direct") -> str:
89
  if MOCK_MODE:
@@ -96,9 +131,22 @@ async def apply_activation_style(task: str, style="direct") -> str:
96
 
97
  else:
98
  # REAL INFERENCE
99
- prompt = f"Rewrite this task in a {style} tone. Keep it under 2 sentences: {task}"
100
- response = await run_blocking(minicpm, prompt, max_tokens=40, temperature=0.7)
101
- return response['choices'][0]['text'].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  @app.get("/")
104
  async def get():
@@ -182,7 +230,7 @@ async def websocket_endpoint(websocket: WebSocket):
182
  raw_task = await generate_atomic_task(
183
  state["goal"],
184
  state["too_hard_count"],
185
- completed_count=len(state["history"]),
186
  )
187
  styled_task = await apply_activation_style(raw_task, state["style"])
188
  state["current_task"] = styled_task
 
55
  nemotron = Llama(model_path=NEMOTRON_MODEL_PATH, n_ctx=1024)
56
  minicpm = Llama(model_path=MINICPM_MODEL_PATH, n_ctx=1024)
57
 
58
+ llama_lock = asyncio.Lock()
59
 
60
  async def run_blocking(func, *args, **kwargs):
61
+ async with llama_lock:
62
+ return await asyncio.to_thread(func, *args, **kwargs)
63
 
64
+ async def generate_atomic_task(goal: str, previous_failures: int, history: list = None) -> str:
65
+ if history is None:
66
+ history = []
67
  if MOCK_MODE:
68
  await asyncio.sleep(1) # Simulate inference latency
69
  demo_steps = [
 
74
  ]
75
  if previous_failures == 1:
76
  return "Move your mouse to the browser icon."
77
+ return demo_steps[min(len(history), len(demo_steps) - 1)]
78
 
79
  else:
80
  # REAL INFERENCE
81
+ system_msg = "You are a cognitive pacemaker. Break down goals into extremely tiny, atomic physical actions under 8 words."
82
+
83
+ prompt = f"<extra_id_0>System\n{system_msg}\n\n"
84
+ prompt += f"<extra_id_1>User\nGoal: write an essay\nCompleted Tasks: None\nFailures: 0\nOutput the NEXT step.\n"
85
+ prompt += f"<extra_id_1>Assistant\nOpen your laptop.\n"
86
+ prompt += f"<extra_id_1>User\nGoal: write an essay\nCompleted Tasks: - Open your laptop.\nFailures: 0\nOutput the NEXT step.\n"
87
+ prompt += f"<extra_id_1>Assistant\nOpen a blank document.\n"
88
+ prompt += f"<extra_id_1>User\nGoal: wash dishes\nCompleted Tasks: - Put dishes in sink.\nFailures: 1\nOutput the NEXT step.\n"
89
+ prompt += f"<extra_id_1>Assistant\nPick up a sponge.\n"
90
+ prompt += f"<extra_id_1>User\nGoal: {goal}\nCompleted Tasks: {history_str}\nFailures: {previous_failures}\nOutput the NEXT step.\n"
91
+ prompt += f"<extra_id_1>Assistant\n"
92
+
93
  response = await run_blocking(
94
  nemotron,
95
+ prompt,
96
  max_tokens=20,
 
97
  temperature=0.1,
98
+ stop=["\n", "<extra_id_1>"]
99
  )
100
+ content = response['choices'][0]['text'].strip()
101
+
102
+ # POST-PROCESSING: 4B models often ignore constraints and try to output lists.
103
+ # Force it to be atomic by taking the first item before a comma or " and ".
104
+ if "," in content:
105
+ content = content.split(",")[0].strip()
106
+ if " and " in content.lower():
107
+ content = content.split(" and ")[0].strip()
108
+
109
+ content = content.strip('"\' ,.-1234567890)')
110
+
111
+ # POST-PROCESSING: 4B models often ignore constraints and try to output lists.
112
+ # Force it to be atomic by taking the first item before a comma or " and ".
113
+ if "," in content:
114
+ content = content.split(",")[0].strip()
115
+ if " and " in content.lower():
116
+ content = content.split(" and ")[0].strip()
117
+
118
+ content = content.strip('"\' ,.-1234567890)')
119
+
120
+ print(f"NEMOTRON RAW OUT: {content}", flush=True)
121
+ return content or "Focus on the screen."
122
 
123
  async def apply_activation_style(task: str, style="direct") -> str:
124
  if MOCK_MODE:
 
131
 
132
  else:
133
  # REAL INFERENCE
134
+ if style == "direct":
135
+ return f"{task.capitalize()}."
136
+
137
+ messages = [
138
+ {"role": "system", "content": f"You are a helpful assistant. Rewrite the following task into a {style} tone. Only output the final task text and nothing else."},
139
+ {"role": "user", "content": f"Task: {task}"}
140
+ ]
141
+ response = await run_blocking(
142
+ minicpm.create_chat_completion,
143
+ messages=messages,
144
+ max_tokens=40,
145
+ temperature=0.2
146
+ )
147
+ content = response['choices'][0]['message']['content'].strip()
148
+ print(f"MINICPM RAW OUT: {content}", flush=True)
149
+ return content
150
 
151
  @app.get("/")
152
  async def get():
 
230
  raw_task = await generate_atomic_task(
231
  state["goal"],
232
  state["too_hard_count"],
233
+ history=state["history"],
234
  )
235
  styled_task = await apply_activation_style(raw_task, state["style"])
236
  state["current_task"] = styled_task
print_template.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from llama_cpp import Llama
2
+ import json
3
+ nem = Llama(model_path="./models/nemotron-mini-4b.gguf", n_ctx=1024, verbose=False)
4
+ print("TEMPLATE:", nem.metadata.get("tokenizer.chat_template"))
semantic_test.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import websockets
3
+ import json
4
+
5
+ GOALS = [
6
+ "clean my messy bedroom",
7
+ "write a python script to parse a csv",
8
+ "i feel overwhelmed by my taxes",
9
+ "cook dinner for 4 people",
10
+ "learn to play the guitar",
11
+ "i don't know what to do",
12
+ "read a 500 page book",
13
+ "plan a vacation to japan"
14
+ ]
15
+
16
+ async def semantic_test():
17
+ uri = "ws://127.0.0.1:7860/ws"
18
+
19
+ print("Running Semantic Stress Test...\n")
20
+
21
+ for goal in GOALS:
22
+ async with websockets.connect(uri) as ws:
23
+ # Action: Start
24
+ await ws.send(json.dumps({"action": "start", "goal": goal, "style": "direct"}))
25
+ resp1 = await ws.recv()
26
+ task1 = json.loads(resp1)['task']
27
+
28
+ # Action: Done (Get the NEXT logical step)
29
+ await ws.send(json.dumps({"action": "done", "last_task": task1}))
30
+ resp2 = await ws.recv()
31
+ task2 = json.loads(resp2)['task']
32
+
33
+ print(f"GOAL: '{goal}'")
34
+ print(f" -> STEP 1: {task1}")
35
+ print(f" -> STEP 2: {task2}\n")
36
+
37
+ if __name__ == "__main__":
38
+ asyncio.run(semantic_test())
stress_test.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import websockets
3
+ import json
4
+ import time
5
+
6
+ async def stress_test():
7
+ uri = "ws://127.0.0.1:7860/ws"
8
+
9
+ print("Connecting to WebSocket...")
10
+ async with websockets.connect(uri) as ws:
11
+ # Scenario 1: Direct style, "clean the house"
12
+ print("\n--- SCENARIO 1: Direct Style ---")
13
+ await ws.send(json.dumps({"action": "start", "goal": "clean the house", "style": "direct"}))
14
+ resp = await ws.recv()
15
+ print(f"[START] {json.loads(resp)['task']}")
16
+
17
+ # Simulate "too_hard"
18
+ await ws.send(json.dumps({"action": "too_hard"}))
19
+ resp = await ws.recv()
20
+ print(f"[TOO HARD 1] {json.loads(resp)['task']}")
21
+
22
+ # Simulate "done"
23
+ await ws.send(json.dumps({"action": "done", "last_task": json.loads(resp)['task']}))
24
+ resp = await ws.recv()
25
+ print(f"[DONE] {json.loads(resp)['task']}")
26
+
27
+ async with websockets.connect(uri) as ws:
28
+ # Scenario 2: Calm style, "write my thesis"
29
+ print("\n--- SCENARIO 2: Calm Style ---")
30
+ await ws.send(json.dumps({"action": "start", "goal": "write my thesis", "style": "calm"}))
31
+ resp = await ws.recv()
32
+ print(f"[START] {json.loads(resp)['task']}")
33
+
34
+ async with websockets.connect(uri) as ws:
35
+ # Scenario 3: Encouraging style, "exercise"
36
+ print("\n--- SCENARIO 3: Encouraging Style ---")
37
+ await ws.send(json.dumps({"action": "start", "goal": "exercise", "style": "encouraging"}))
38
+ resp = await ws.recv()
39
+ print(f"[START] {json.loads(resp)['task']}")
40
+
41
+ # Trigger circuit breaker (too hard x3)
42
+ for i in range(3):
43
+ await ws.send(json.dumps({"action": "too_hard"}))
44
+ resp = await ws.recv()
45
+ data = json.loads(resp)
46
+ print(f"[TOO HARD {i+1}] {data['task']} (Breaker: {data['is_breaker']})")
47
+
48
+ print("\nStress test completed successfully.")
49
+
50
+ if __name__ == "__main__":
51
+ asyncio.run(stress_test())
test_extract.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ from llama_cpp import Llama
3
+
4
+ minicpm = Llama(model_path="./models/minicpm-3-4b.gguf", n_ctx=1024, verbose=False)
5
+
6
+ def extract(text):
7
+ messages = [
8
+ {"role": "system", "content": "You extract the very first physical action from the user's text. Return ONLY a single physical action under 8 words. Do not include any other words."},
9
+ {"role": "user", "content": f"Text: {text}"}
10
+ ]
11
+ response = minicpm.create_chat_completion(messages=messages, max_tokens=15, temperature=0.1)
12
+ return response['choices'][0]['message']['content'].strip()
13
+
14
+ print("1:", extract("Clean bedroom floor, tidy bed, organize drawers, dust surfaces, vacuum carpet."))
15
+ print("2:", extract("Sure, here's a python script that uses the pandas library to parse a csv file:"))
16
+ print("3:", extract("Fail to identify goal."))
test_minicpm.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from llama_cpp import Llama
2
+ minicpm = Llama(model_path="./models/minicpm-3-4b.gguf", n_ctx=1024, verbose=False)
3
+ messages = [
4
+ {"role": "system", "content": "Rewrite the user's task in a direct tone. Keep it under 2 sentences. Output only the rewritten task."},
5
+ {"role": "user", "content": "Task: do some chores"}
6
+ ]
7
+ response = minicpm.create_chat_completion(messages=messages, max_tokens=40, temperature=0.7)
8
+ print("RESPONSE:", repr(response['choices'][0]['message']['content']))
test_nem_out.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Error in sitecustomize; set PYTHONVERBOSE for traceback:
2
+ ModuleNotFoundError: No module named 'wrapt'
3
+ llama_context: n_ctx_seq (1024) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
4
+ NEMOTRON: '{\n "task": "vacuum, dust, mop, clean bathroom, clean kitchen,'
test_nemotron.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from llama_cpp import Llama
3
+ nemotron = Llama(model_path="./models/nemotron-mini-4b.gguf", n_ctx=1024, verbose=False)
4
+ messages = [
5
+ {"role": "system", "content": "You are a cognitive pacemaker. Break down goals into extremely tiny, atomic physical actions under 8 words. Return ONLY a JSON object with a 'task' key."},
6
+ {"role": "user", "content": "Goal: clean the house. Failures: 0."}
7
+ ]
8
+ response = nemotron.create_chat_completion(messages=messages, max_tokens=20, temperature=0.1, response_format={"type": "json_object"})
9
+ print("NEMOTRON:", repr(response['choices'][0]['message']['content']))
test_ws.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import websockets
3
+ import json
4
+
5
+ async def test():
6
+ async with websockets.connect("ws://127.0.0.1:7860/ws") as websocket:
7
+ await websocket.send(json.dumps({"action": "start", "goal": "clean the house", "style": "direct"}))
8
+ response = await websocket.recv()
9
+ print(f"WS RESPONSE: {response}")
10
+
11
+ asyncio.run(test())