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.

Files changed (48) hide show
  1. example/__init__.py +0 -0
  2. example/abstract_robot_classes/__init__.py +0 -0
  3. example/abstract_robot_classes/abclocation.py +6 -0
  4. example/abstract_robot_classes/arm.py +22 -0
  5. example/abstract_robot_classes/chemical.py +5 -0
  6. example/abstract_robot_classes/container.py +15 -0
  7. example/abstract_robot_classes/handler.py +13 -0
  8. example/abstract_robot_classes/moveable.py +18 -0
  9. example/abstract_robot_classes/moveableconfig.py +13 -0
  10. example/dummy_ur/__init__.py +0 -0
  11. example/dummy_ur/dummy_balance.py +10 -0
  12. example/dummy_ur/dummy_deck.py +113 -0
  13. example/dummy_ur/dummy_pump.py +8 -0
  14. example/kinova_deck/__init__.py +0 -0
  15. example/kinova_deck/chemicals.py +15 -0
  16. example/kinova_deck/components/__init__.py +0 -0
  17. example/kinova_deck/components/balance.py +49 -0
  18. example/kinova_deck/components/capper.py +68 -0
  19. example/kinova_deck/components/europa_control.py +634 -0
  20. example/kinova_deck/components/needlewash.py +17 -0
  21. example/kinova_deck/components/shaker.py +28 -0
  22. example/kinova_deck/components/solenoid.py +52 -0
  23. example/kinova_deck/experiment.py +30 -0
  24. example/kinova_deck/kinova_arm.py +124 -0
  25. example/kinova_deck/kinova_deck_setup.py +123 -0
  26. example/kinova_deck/kinova_location.py +52 -0
  27. example/kinova_deck/moveable/__init__.py +0 -0
  28. example/kinova_deck/moveable/europa.py +50 -0
  29. example/kinova_deck/moveable/vial.py +19 -0
  30. example/kinova_deck/moving/__init__.py +0 -0
  31. example/kinova_deck/moving/kinova_movable_config.py +21 -0
  32. example/kinova_deck/webui_data/__init__.py +0 -0
  33. example/kinova_deck/webui_data/scripts/__init__.py +0 -0
  34. example/kinova_deck/webui_data/scripts/untitled.py +13 -0
  35. example/test.py +90 -0
  36. ivoryOS-0.1.0.dist-info/LICENSE +21 -0
  37. ivoryOS-0.1.0.dist-info/METADATA +77 -0
  38. ivoryOS-0.1.0.dist-info/RECORD +48 -0
  39. ivoryOS-0.1.0.dist-info/WHEEL +5 -0
  40. ivoryOS-0.1.0.dist-info/top_level.txt +2 -0
  41. ivoryos/__init__.py +0 -0
  42. ivoryos/app.py +996 -0
  43. ivoryos/utils/__init__.py +0 -0
  44. ivoryos/utils/form.py +304 -0
  45. ivoryos/utils/llm_agent.py +171 -0
  46. ivoryos/utils/model.py +415 -0
  47. ivoryos/utils/openai_agent.py +144 -0
  48. ivoryos/utils/utils.py +477 -0
example/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ from abc import ABC
2
+
3
+
4
+ class ABCLocation(ABC):
5
+ def __init__(self, robot_movement_information):
6
+ self.robot_movement_information = robot_movement_information
@@ -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,5 @@
1
+ from abc import ABC
2
+
3
+
4
+ class Chemical(ABC):
5
+ 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
@@ -0,0 +1,13 @@
1
+ from abc import ABC
2
+ from dataclasses import dataclass
3
+
4
+ # TODO: replace any
5
+ @dataclass
6
+ class MoveableSequence(ABC):
7
+ location_A: any
8
+ location_B: any
9
+
10
+
11
+ @dataclass
12
+ class MoveableConfig(ABC):
13
+ safe_moves: list[MoveableSequence]
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
+
@@ -0,0 +1,8 @@
1
+ class DummyPump:
2
+
3
+ def __init__(self, com_port: str):
4
+ self.com_port = com_port
5
+
6
+ def dose_liquid(self, amount_in_ml: float, rate_ml_per_minute:float):
7
+ print(f"pretending dosing {amount_in_ml} at {rate_ml_per_minute} ml/min")
8
+
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
+