koji commited on
Commit
62a70e4
·
1 Parent(s): 8edddab

initial commit

Browse files
Files changed (6) hide show
  1. .DS_Store +0 -0
  2. .gitignore +2 -0
  3. Dockerfile +10 -0
  4. README.md +56 -11
  5. app/main.py +103 -0
  6. requirements.txt +3 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .DS_Store
2
+ app/.DS_Store
Dockerfile ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9-slim
2
+
3
+ # need to force reinstall because of dependeincies
4
+ RUN pip install --no-cache-dir --upgrade pip && \
5
+ pip install --no-cache-dir fastapi uvicorn && \
6
+ pip install --no-cache-dir --force-reinstall opentrons
7
+
8
+ COPY ./app /app
9
+
10
+
README.md CHANGED
@@ -1,11 +1,56 @@
1
- ---
2
- title: Simulator
3
- emoji: 📚
4
- colorFrom: purple
5
- colorTo: red
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # api-for-simulator
2
+
3
+ api server for opentrons-simulator
4
+
5
+ ## how to run locally
6
+
7
+ ```shell
8
+ pip install -r requirements.txt
9
+
10
+ cd app
11
+ uvicorn main:app --reload
12
+ ```
13
+
14
+ ### docs
15
+
16
+ ```shell
17
+ uvicorn main:app
18
+ ```
19
+
20
+ Then go to http://localhost:8000/docs to check the api doc.
21
+
22
+ `/protocol/id` does not work since it is a dummy function right now.
23
+
24
+ ## How to run the server with Dockerfile
25
+
26
+ ```shell
27
+ git clone https://github.com/koji/api-for-simulator.git
28
+ cd api-for-simulator
29
+ docker build -t simulator-api:1.0.0 .
30
+ ```
31
+
32
+ After building the image
33
+
34
+ ```shell
35
+ docker run -d --name simulator-api-container -p 80:80 simulator-api:1.0.0
36
+ ```
37
+
38
+ Check the container
39
+
40
+ ```shell
41
+ docker ps -q -f "name=simulator-api-container" | xargs docker logs -f
42
+ ```
43
+
44
+ Test the api server with curl or postman/httpie
45
+
46
+ ```shell
47
+ curl localhost:80
48
+ ```
49
+
50
+ ## Tool
51
+
52
+ - postman: https://www.postman.com/
53
+ - httpie: https://httpie.io/
54
+
55
+ - orbstack https://orbstack.dev/
56
+ A GUI app for Docker which is better than Docker Desktop
app/main.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+ from opentrons.simulate import simulate, format_runlog, get_protocol_api
4
+ import os
5
+ import io
6
+ import subprocess
7
+
8
+ app = FastAPI()
9
+
10
+
11
+ @app.get("/")
12
+ async def root():
13
+ return {"message": "this is a test api server"}
14
+
15
+
16
+ @app.get("/protocols")
17
+ def read_protocols():
18
+ protocols = get_file_names()
19
+ if len(protocols) == 0:
20
+ return "no stored protocol"
21
+ sorted_protocols = sorted(protocols)
22
+ return {"protocols": sorted_protocols}
23
+
24
+
25
+ def get_file_names():
26
+ folder_path = 'storage'
27
+ # Check if the storage folder exists
28
+ if not os.path.exists(folder_path):
29
+ # Create the storage folder
30
+ os.makedirs(folder_path)
31
+ return []
32
+
33
+ file_names = []
34
+ for root, dirs, files in os.walk(folder_path):
35
+ for file in files:
36
+ file_names.append(file)
37
+
38
+ return file_names
39
+
40
+
41
+ # @app.get("/protocols/{protocol_id}")
42
+ # def read_protocol(protocol_id: int, q: str = None):
43
+ # # ToDo search folder and display a protocol file if there is a target protocol
44
+ # if q:
45
+ # return {"protocol_id": protocol_id, "q": q}
46
+ # return {"protocol_id": protocol_id}
47
+
48
+
49
+ class Protocol(BaseModel):
50
+ name: str
51
+ content: str
52
+
53
+
54
+ @app.post("/protocol")
55
+ def upload_protocol(protocol: Protocol):
56
+ file_path = 'storage/' + protocol.name
57
+ save_result = save_text_as_file(protocol.content, file_path)
58
+
59
+ if type(save_result) == str:
60
+ # response = run_protocol_on_simulator(protocol.content)
61
+ response = call_opentrons_simulate(file_path)
62
+ print('response', response)
63
+ if response["status"] == "success":
64
+ return {"protocol_name": protocol.name, "run_log": response['run_log']}
65
+ else:
66
+ return {"error_message": response['error_message']}
67
+ else:
68
+ return {"error_message": "something wrong while saving a protocol"}
69
+
70
+
71
+ def call_opentrons_simulate(protocol_path: str):
72
+ command = f"opentrons_simulate {protocol_path}"
73
+
74
+ result = subprocess.run(command, shell=True,
75
+ capture_output=True, text=True)
76
+
77
+ if result.returncode == 0:
78
+ # print("Command executed successfully! Output:")
79
+ # print(result.stdout)
80
+ return {"status": "success", "run_log": result.stdout}
81
+ else:
82
+ print("Command failed. Error message:")
83
+ # print(result.stderr)
84
+ return {"status": "error", "error_message": result.stderr}
85
+
86
+
87
+ def save_text_as_file(text, file_path):
88
+ base = os.path.splitext(file_path)[0]
89
+ ext = os.path.splitext(file_path)[1]
90
+ counter = 1
91
+
92
+ while os.path.exists(file_path):
93
+ file_path = base + "_" + str(counter) + ext
94
+ counter += 1
95
+
96
+ try:
97
+ with open(file_path, 'w') as file:
98
+ file.write(text)
99
+ print("Text saved successfully as", file_path)
100
+ return file_path
101
+ except Exception as e:
102
+ print("An error occurred while saving the file:", str(e))
103
+ return False
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi
2
+ opentrons
3
+ uvicorn