ivoryOS 0.1.0__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.
Potentially problematic release.
This version of ivoryOS might be problematic. Click here for more details.
- example/__init__.py +0 -0
- example/abstract_robot_classes/__init__.py +0 -0
- example/abstract_robot_classes/abclocation.py +6 -0
- example/abstract_robot_classes/arm.py +22 -0
- example/abstract_robot_classes/chemical.py +5 -0
- example/abstract_robot_classes/container.py +15 -0
- example/abstract_robot_classes/handler.py +13 -0
- example/abstract_robot_classes/moveable.py +18 -0
- example/abstract_robot_classes/moveableconfig.py +13 -0
- example/dummy_ur/__init__.py +0 -0
- example/dummy_ur/dummy_balance.py +10 -0
- example/dummy_ur/dummy_deck.py +113 -0
- example/dummy_ur/dummy_pump.py +8 -0
- example/kinova_deck/__init__.py +0 -0
- example/kinova_deck/chemicals.py +15 -0
- example/kinova_deck/components/__init__.py +0 -0
- example/kinova_deck/components/balance.py +49 -0
- example/kinova_deck/components/capper.py +68 -0
- example/kinova_deck/components/europa_control.py +634 -0
- example/kinova_deck/components/needlewash.py +17 -0
- example/kinova_deck/components/shaker.py +28 -0
- example/kinova_deck/components/solenoid.py +52 -0
- example/kinova_deck/experiment.py +30 -0
- example/kinova_deck/kinova_arm.py +124 -0
- example/kinova_deck/kinova_deck_setup.py +123 -0
- example/kinova_deck/kinova_location.py +52 -0
- example/kinova_deck/moveable/__init__.py +0 -0
- example/kinova_deck/moveable/europa.py +50 -0
- example/kinova_deck/moveable/vial.py +19 -0
- example/kinova_deck/moving/__init__.py +0 -0
- example/kinova_deck/moving/kinova_movable_config.py +21 -0
- example/kinova_deck/webui_data/__init__.py +0 -0
- example/kinova_deck/webui_data/scripts/__init__.py +0 -0
- example/kinova_deck/webui_data/scripts/untitled.py +13 -0
- example/test.py +90 -0
- ivoryOS-0.1.0.dist-info/LICENSE +21 -0
- ivoryOS-0.1.0.dist-info/METADATA +77 -0
- ivoryOS-0.1.0.dist-info/RECORD +48 -0
- ivoryOS-0.1.0.dist-info/WHEEL +5 -0
- ivoryOS-0.1.0.dist-info/top_level.txt +2 -0
- ivoryos/__init__.py +0 -0
- ivoryos/app.py +996 -0
- ivoryos/utils/__init__.py +0 -0
- ivoryos/utils/form.py +304 -0
- ivoryos/utils/llm_agent.py +171 -0
- ivoryos/utils/model.py +415 -0
- ivoryos/utils/openai_agent.py +144 -0
- ivoryos/utils/utils.py +477 -0
example/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from example.abstract_robot_classes.abclocation import ABCLocation
|
|
5
|
+
from example.abstract_robot_classes.moveable import Moveable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Arm(ABC):
|
|
9
|
+
def __init__(self, name: str):
|
|
10
|
+
self.name = name
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def move(self, from_loc: ABCLocation, to_loc: ABCLocation, moveable: Optional[Moveable] = None):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def pick_up(self, moveable: Moveable, location: ABCLocation):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def put_down(self, moveable: Moveable, location: ABCLocation):
|
|
22
|
+
pass
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from example.abstract_robot_classes.chemical import Chemical
|
|
5
|
+
from example.abstract_robot_classes.moveable import Moveable
|
|
6
|
+
from example.kinova_deck.moving.kinova_movable_config import KinovaMoveableConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Container(Moveable, ABC):
|
|
10
|
+
def __init__(self, name: str, config: Optional[KinovaMoveableConfig] = None):
|
|
11
|
+
super().__init__(name, config)
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def update_contents(self, chemical: Chemical, amount_ul: int):
|
|
15
|
+
pass
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from .arm import Arm
|
|
4
|
+
from .chemical import Chemical
|
|
5
|
+
from .container import Container
|
|
6
|
+
from .abclocation import ABCLocation
|
|
7
|
+
from .moveable import Moveable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Handler(Moveable, ABC):
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def dispense(self, chemical: Chemical, container: Container, location: ABCLocation, arm: Arm):
|
|
13
|
+
pass
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from example.abstract_robot_classes.moveableconfig import MoveableConfig
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Moveable(ABC):
|
|
8
|
+
def __init__(self, name: str,
|
|
9
|
+
config: Optional[MoveableConfig] = None,
|
|
10
|
+
offset_x: float = 0,
|
|
11
|
+
offset_y: float = 0,
|
|
12
|
+
offset_z: float = 0):
|
|
13
|
+
self.name = name
|
|
14
|
+
self.gripped = False
|
|
15
|
+
self.config: Optional[MoveableConfig] = config
|
|
16
|
+
self.offset_x = offset_x
|
|
17
|
+
self.offset_y = offset_y
|
|
18
|
+
self.offset_z = offset_z
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class DummyBalance:
|
|
2
|
+
|
|
3
|
+
def __init__(self, com_port: str):
|
|
4
|
+
self.com_port = com_port
|
|
5
|
+
|
|
6
|
+
def weigh_sample(self):
|
|
7
|
+
print(f"Weighing sample using {self.com_port}")
|
|
8
|
+
|
|
9
|
+
def dose_solid(self, amount_in_mg: float):
|
|
10
|
+
print(f"Dosing {amount_in_mg} mg using {self.com_port}")
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from example.dummy_ur.dummy_balance import DummyBalance
|
|
4
|
+
from example.dummy_ur.dummy_pump import DummyPump
|
|
5
|
+
|
|
6
|
+
# some constant values
|
|
7
|
+
a = {"a": 1, "b": 3}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DummySDLDeck:
|
|
11
|
+
def __init__(self, pump: DummyPump, balance: DummyBalance):
|
|
12
|
+
self.pump = pump
|
|
13
|
+
self.balance = balance
|
|
14
|
+
|
|
15
|
+
def dose_solvent(self, name: str, amount_in_ml: float = 5, rate_ml_per_minute: float = 1):
|
|
16
|
+
self.pump.dose_liquid(amount_in_ml=amount_in_ml, rate_ml_per_minute=rate_ml_per_minute)
|
|
17
|
+
self.balance.weigh_sample()
|
|
18
|
+
print("dosing solvent")
|
|
19
|
+
|
|
20
|
+
def dose_solid(self, amount_in_mg: float = 5, bring_in: bool = False):
|
|
21
|
+
"""dose current chemical"""
|
|
22
|
+
self.balance.dose_solid(amount_in_mg=amount_in_mg)
|
|
23
|
+
self.balance.weigh_sample()
|
|
24
|
+
print("dosing solid")
|
|
25
|
+
|
|
26
|
+
def equilibrate(self, temp: float, duration: float):
|
|
27
|
+
print("equilibrate")
|
|
28
|
+
|
|
29
|
+
def sample(self, sample_volume: float = 10):
|
|
30
|
+
print("sample")
|
|
31
|
+
|
|
32
|
+
def dilute(self, solvent: str, factor: float):
|
|
33
|
+
print("dilute")
|
|
34
|
+
|
|
35
|
+
def analyze(self):
|
|
36
|
+
print("analyze")
|
|
37
|
+
|
|
38
|
+
def filtration(self):
|
|
39
|
+
print("filtration")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
balance = DummyBalance("Fake com port 1")
|
|
43
|
+
pump = DummyPump("Fake com port 2")
|
|
44
|
+
deck = DummySDLDeck(pump, balance)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DummyExperiment:
|
|
48
|
+
def __init__(self, deck):
|
|
49
|
+
self.deck = deck
|
|
50
|
+
|
|
51
|
+
def cooling_crystal(self,
|
|
52
|
+
low_temp: float,
|
|
53
|
+
temp_diff: float,
|
|
54
|
+
cooling_rate: float,
|
|
55
|
+
mass_mg: float,
|
|
56
|
+
solvent_A: str,
|
|
57
|
+
solvent_B: str,
|
|
58
|
+
solvent_ratio: float
|
|
59
|
+
):
|
|
60
|
+
print(type(mass_mg))
|
|
61
|
+
|
|
62
|
+
def reslurry(self):
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def solubility(self,
|
|
66
|
+
temp: float,
|
|
67
|
+
temp_time_min: float,
|
|
68
|
+
duplicates:int,
|
|
69
|
+
):
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
def calibration_curve(self,
|
|
73
|
+
mass_in_mg: float,
|
|
74
|
+
temp: float,
|
|
75
|
+
temp_time_min: float,
|
|
76
|
+
initial_volume_ml: float,
|
|
77
|
+
sample_volume_ml: float,
|
|
78
|
+
dilution_factor: int,
|
|
79
|
+
number_of_dilutions: int,
|
|
80
|
+
):
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
cryst_co = DummyExperiment(deck)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ShakerDemo:
|
|
88
|
+
def __init__(self, deck):
|
|
89
|
+
self.deck = deck
|
|
90
|
+
|
|
91
|
+
def move_sample_to_shaker(self, location:str="A1"):
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
def shake_for_duration(self, duration: float):
|
|
95
|
+
time.sleep(duration)
|
|
96
|
+
|
|
97
|
+
def move_vial_to_tray(self, location:str="A1"):
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
vial_shaker = ShakerDemo(deck)
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
from ivoryos.app import ivoryos
|
|
104
|
+
ivoryos(__name__, model="llama3.1", llm_server='localhost',)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ivoryos(__name__, model="gpt-3.5-turbo")
|
|
108
|
+
|
|
109
|
+
"""add 10 mg of acetaminophen, dose 1 ml of methanol, equilibrate for 10 minute at 50 degrees, filter the sample and analyze with HPLC"""
|
|
110
|
+
"""i want to run a cooling crystal experiment, with low temperature being 20, and high temperature being 40, cooling rate being 0.1, I want to dose 11 mg of my sample, and use
|
|
111
|
+
water as solvent a and isopropanol for solvent b, the solvent ratio being 0.1"""
|
|
112
|
+
|
|
113
|
+
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from example.abstract_robot_classes.chemical import Chemical
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Liquid(Chemical):
|
|
5
|
+
def __init__(self, name: str, formula: str, density: float = -1):
|
|
6
|
+
self.name = name
|
|
7
|
+
self.formula = formula
|
|
8
|
+
self.density: float = density
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Solid(Chemical):
|
|
12
|
+
def __init__(self, name: str, formula: str, density: float = -1):
|
|
13
|
+
self.name = name
|
|
14
|
+
self.formula = formula
|
|
15
|
+
self.density: float = density
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from serial import Serial
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Balance:
|
|
5
|
+
def __init__(self, port: str):
|
|
6
|
+
self.port = port
|
|
7
|
+
self.ser = Serial(port)
|
|
8
|
+
|
|
9
|
+
def stable_weight(self):
|
|
10
|
+
response = self.send_command("S")
|
|
11
|
+
return self.get_reading(response)
|
|
12
|
+
|
|
13
|
+
def weight_immediately(self):
|
|
14
|
+
response = self.send_command("SI")
|
|
15
|
+
return self.get_reading(response)
|
|
16
|
+
|
|
17
|
+
def tare(self):
|
|
18
|
+
response = self.send_command("T")
|
|
19
|
+
return self.get_reading(response)
|
|
20
|
+
|
|
21
|
+
def zero(self):
|
|
22
|
+
self.send_command("Z")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
def tare_immediately(self):
|
|
26
|
+
response = self.ser.write("TI")
|
|
27
|
+
return self.get_reading(response)
|
|
28
|
+
|
|
29
|
+
def zero_immediately(self):
|
|
30
|
+
self.send_command("ZI")
|
|
31
|
+
|
|
32
|
+
def send_command(self, command):
|
|
33
|
+
if not command.endswith("\n\r"):
|
|
34
|
+
command += "\n\r"
|
|
35
|
+
self.ser.write(command.encode())
|
|
36
|
+
response = self.ser.readline()
|
|
37
|
+
return response.decode().strip()
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def get_reading(response):
|
|
41
|
+
_, _, number, unit = response.split()
|
|
42
|
+
return (float(number))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
b = Balance("COM7")
|
|
47
|
+
w = b.stable_weight()
|
|
48
|
+
print(w)
|
|
49
|
+
print()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from ftdi_serial import Serial
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
decapper
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
class Capper:
|
|
8
|
+
def __init__(self, port, baud=115200, bytesize=8, timeout=20):
|
|
9
|
+
# self.somatic = serial_.Serial(port=port, baudrate=baud, bytesize=bytesize,
|
|
10
|
+
# timeout=timeout, stopbits=serial_.STOPBITS_ONE)
|
|
11
|
+
self.capper = Serial(device_port=port, baudrate=baud, data_bits=bytesize, read_timeout=timeout)
|
|
12
|
+
|
|
13
|
+
print(f"Established connection with {self.capper} at {port}")
|
|
14
|
+
|
|
15
|
+
def connect(self):
|
|
16
|
+
self.capper.__init__()
|
|
17
|
+
|
|
18
|
+
def disconnect(self):
|
|
19
|
+
# put capper in its default state of "closed" before closing connection
|
|
20
|
+
# self.home()
|
|
21
|
+
self.capper.close()
|
|
22
|
+
print("Disconnected capper")
|
|
23
|
+
|
|
24
|
+
def open(self):
|
|
25
|
+
cmd = f"open"
|
|
26
|
+
self._execute(cmd)
|
|
27
|
+
|
|
28
|
+
def close(self):
|
|
29
|
+
cmd = "close"
|
|
30
|
+
self._execute(cmd)
|
|
31
|
+
|
|
32
|
+
def tighten(self):
|
|
33
|
+
cmd = "tighten"
|
|
34
|
+
self._execute(cmd)
|
|
35
|
+
|
|
36
|
+
def loosen(self):
|
|
37
|
+
cmd = "loosen"
|
|
38
|
+
self._execute(cmd)
|
|
39
|
+
|
|
40
|
+
def home(self):
|
|
41
|
+
cmd = "home"
|
|
42
|
+
self._execute(cmd)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _execute(self, cmd, wait=True):
|
|
46
|
+
ans = None
|
|
47
|
+
self.capper.write(cmd.encode())
|
|
48
|
+
|
|
49
|
+
# Serial device returns "-4" when action complete
|
|
50
|
+
while True:
|
|
51
|
+
# ans = self.somatic.readline().decode("ascii").strip()
|
|
52
|
+
ans = self.capper.read_line().decode("ascii").strip()
|
|
53
|
+
if ans == "1":
|
|
54
|
+
break
|
|
55
|
+
return ans
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
capper = Capper("COM9")
|
|
60
|
+
capper.home()
|
|
61
|
+
capper.open()
|
|
62
|
+
capper.close()
|
|
63
|
+
# x.loosen()
|
|
64
|
+
# x.tighten()
|
|
65
|
+
# time.sleep(3)
|
|
66
|
+
# x.home()
|
|
67
|
+
|
|
68
|
+
|