unitypredict 0.1.17__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.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.1
2
+ Name: unitypredict
3
+ Version: 0.1.17
4
+ Description-Content-Type: text/markdown
5
+
6
+ # UnityPredict Local App Engine Creator
7
+
8
+ ## Introduction
9
+
10
+ This library allows you to create App Engines in your local system and finetune the engines before updating it to the [ModelCentral](https://modelcentral.ai) repositories.
11
+
12
+ ## Installation
13
+ * You can use pip to install the ```UnityPredict``` library.
14
+ ```bash
15
+ pip install UnityPredict
16
+ ```
17
+
18
+ ## Usage
19
+ Use the following snippet to initialize the environment.
20
+
21
+
22
+ ### main.py
23
+
24
+ ```python
25
+
26
+ from UnityPredict import UnityPredictHost, Models
27
+ import sys
28
+ import uuid
29
+
30
+ import time
31
+
32
+ import os
33
+
34
+
35
+
36
+ if __name__ == "__main__":
37
+ platformInit = UnityPredictHost()
38
+
39
+ configStat = platformInit.isConfigInitialized()
40
+
41
+ if not configStat:
42
+ print ("Config Initialization Unsuccessful!!")
43
+ sys.exit(0)
44
+
45
+
46
+ print ("Config Initialization Successful!!")
47
+
48
+ ```
49
+
50
+ * This is the snippet to initialize the AppEngine environment.
51
+ * Run script using the following command:
52
+
53
+ ```bash
54
+ python main.py
55
+ ```
56
+
57
+ * If this script is run for the **first time**. The following Output will be shown
58
+
59
+ ```bash
60
+
61
+ Config file not detected, creating templated config file: YourScriptPath/config.json
62
+ Config Initialization Unsuccessful!!
63
+
64
+ ```
65
+ * A templated config file would be generated on the same directory as that of your main script.
66
+
67
+ ```json
68
+ {
69
+ "MODEL_DIR": "YourScriptPath/models",
70
+ "REQUEST_DIR": "YourScriptPath/requests",
71
+ "SAVE_CONTEXT": true,
72
+ "TEMP_EXEC_DIR": "YourScriptPath",
73
+ "UPT_API_KEY": ""
74
+ }
75
+
76
+ ```
77
+
78
+ * Edit the JSON as per your requirements. The various keys represent:
79
+
80
+ * **TEMP_EXEC_DIR**: Directory on which you wan the AppEngine to run
81
+
82
+ * **REQUEST_DIR**: Files or Folders to be uploaded to AppEngine for using during the execution can be added under the specified **REQUEST_DIR**
83
+
84
+ * **MODEL_DIR**: Local model files/binaries to be uploaded to AppEngine for using during the execution can be added under the specified **MODEL_DIR**
85
+
86
+ * **SAVE_CONTEXT**: Retains context across multiple requests. Disable it using ```"SAVE_CONTEXT" : false```
87
+
88
+ * **UPT_API_KEY**: API Key token generated from the ModelCentral profile of the user.
89
+
90
+ * Once configured, run the following script once again to get:
91
+
92
+ ```bash
93
+ Config Initialization Successful!!
94
+ ```
95
+
96
+ ### EntryPoint.py
97
+
98
+ * In order to run your custom AppEngine, it is necessary to create a file named ```EntryPoint.py``` which is going to contain the inference logic.
99
+
100
+ This is an Example snippet of the `EntryPoint.py`:
101
+ ```python
102
+ import json
103
+ from UnityPredict.Platform import IPlatform, InferenceRequest, InferenceResponse, OutcomeValue, InferenceContextData
104
+ from typing import List, Dict, Optional
105
+ from collections import deque
106
+ import sys
107
+ import datetime
108
+
109
+
110
+
111
+ def run_local_engine(request: InferenceRequest, platform: IPlatform) -> InferenceResponse:
112
+
113
+
114
+
115
+ platform.logMsg("Running User Code...")
116
+ response = InferenceResponse()
117
+
118
+ context: Dict[str, str] = {}
119
+
120
+ try:
121
+ prompt = request.InputValues['InputMessage']
122
+
123
+
124
+ # Saved context across requests
125
+ # Use this variable to save new context in the dict format
126
+ # request.Context.StoredMeta is of the format: Dict[str, str]
127
+ context = request.Context.StoredMeta
128
+
129
+ currentExecTime = datetime.datetime.now()
130
+ currentExecTime = currentExecTime.strftime("%d-%m-%YT%H-%M-%S")
131
+ resp_message = "Echo message: {} Time:: {}".format(prompt, currentExecTime)
132
+
133
+
134
+ # platform.getRequestFile: Fetch Files specified under the "REQUEST_DIR" in config
135
+ with platform.getRequestFile("myDetails.txt", "r") as reqFile:
136
+
137
+ resp_message += "\n{}".format("\n".join(reqFile.readlines()))
138
+
139
+
140
+ # Fill context according to your needs
141
+ context[currentExecTime] = resp_message
142
+
143
+
144
+ # platform.saveRequestFile: Creates any file type Outputs
145
+ # These files would be present under TEMP_EXEC_DIR/execTmp/outputs_<RequestLaunchTimeStamp>__<RequestId>
146
+ # TEMP_EXEC_DIR: Configured under the config.json
147
+ # execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
148
+ with platform.saveRequestFile("final_resp_{}.txt".format(currentExecTime), "w+") as outFile:
149
+
150
+ outFile.write(resp_message)
151
+
152
+
153
+ cost = len(prompt)/1000 * 0.03 + len(resp_message)/1000 * 0.06
154
+ response.AdditionalInferenceCosts = cost
155
+ response.Outcomes['OutputMessage'] = [OutcomeValue(value=resp_message, probability=1.0)]
156
+
157
+ # Set the updated context back to the response
158
+ response.Context.StoredMeta = context
159
+ except Exception as e:
160
+ response.ErrorMessages = "Entrypoint Exception Occured: {}".format(str(e))
161
+
162
+ print("Finished Running User Code...")
163
+ return response
164
+
165
+
166
+ ```
167
+
168
+ * Some APIs for using the AppEngine environment
169
+ * **request.Context.StoredMeta**:
170
+ * Saved context across requests
171
+ * Use this variable to save new context in the dict format
172
+ * request.Context.StoredMeta is of the format: Dict[str, str]
173
+
174
+ * **platform.getRequestFile**:
175
+ * Fetch Files specified under the "**REQUEST_DIR**" in config
176
+
177
+ * **platform.saveRequestFile**:
178
+ * Creates any file type Outputs
179
+ * These files would be present under **TEMP_EXEC_DIR/execTmp/*outputs_RequestLaunchTimeStamp__RequestId***
180
+ * **TEMP_EXEC_DIR**: Configured under the config.json
181
+ * execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
182
+
183
+
184
+ * Go back to the `main.py` and add the following command to run your `EntryPoint.py`
185
+
186
+ ```python
187
+ if __name__ == "__main__":
188
+
189
+ # Previous Snippet for initialization
190
+ platformInit = UnityPredictHost()
191
+
192
+ configStat = platformInit.isConfigInitialized()
193
+
194
+ if not configStat:
195
+ print ("Config Initialization Unsuccessful!!")
196
+ sys.exit(0)
197
+
198
+
199
+ print ("Config Initialization Successful!!")
200
+
201
+ #### New Snippet to run EntryPoint.py via the AppEngine
202
+
203
+ request = Models.AppEngineRequest(RequestId=str(uuid.uuid4()))
204
+ request.EngineInputData = Models.EngineInputs(InputValues={"InputMessage": "Hi, this is the message to be echoed"}, DesiredOutcomes=[])
205
+
206
+ response : Models.UnityPredictEngineResponse = platformInit.run_engine(request=request)
207
+
208
+ # Print Outputs
209
+ if (response.EngineOutputs != None):
210
+ print ("Output: {}".format(response.EngineOutputs.toJSON()))
211
+
212
+ # Print Error Messages (if any)
213
+ print ("Error Messages: {}".format(response.ErrorMessages))
214
+
215
+ ```
216
+
217
+
218
+ ## Contributing
219
+
220
+ ## License
@@ -0,0 +1,215 @@
1
+ # UnityPredict Local App Engine Creator
2
+
3
+ ## Introduction
4
+
5
+ This library allows you to create App Engines in your local system and finetune the engines before updating it to the [ModelCentral](https://modelcentral.ai) repositories.
6
+
7
+ ## Installation
8
+ * You can use pip to install the ```UnityPredict``` library.
9
+ ```bash
10
+ pip install UnityPredict
11
+ ```
12
+
13
+ ## Usage
14
+ Use the following snippet to initialize the environment.
15
+
16
+
17
+ ### main.py
18
+
19
+ ```python
20
+
21
+ from UnityPredict import UnityPredictHost, Models
22
+ import sys
23
+ import uuid
24
+
25
+ import time
26
+
27
+ import os
28
+
29
+
30
+
31
+ if __name__ == "__main__":
32
+ platformInit = UnityPredictHost()
33
+
34
+ configStat = platformInit.isConfigInitialized()
35
+
36
+ if not configStat:
37
+ print ("Config Initialization Unsuccessful!!")
38
+ sys.exit(0)
39
+
40
+
41
+ print ("Config Initialization Successful!!")
42
+
43
+ ```
44
+
45
+ * This is the snippet to initialize the AppEngine environment.
46
+ * Run script using the following command:
47
+
48
+ ```bash
49
+ python main.py
50
+ ```
51
+
52
+ * If this script is run for the **first time**. The following Output will be shown
53
+
54
+ ```bash
55
+
56
+ Config file not detected, creating templated config file: YourScriptPath/config.json
57
+ Config Initialization Unsuccessful!!
58
+
59
+ ```
60
+ * A templated config file would be generated on the same directory as that of your main script.
61
+
62
+ ```json
63
+ {
64
+ "MODEL_DIR": "YourScriptPath/models",
65
+ "REQUEST_DIR": "YourScriptPath/requests",
66
+ "SAVE_CONTEXT": true,
67
+ "TEMP_EXEC_DIR": "YourScriptPath",
68
+ "UPT_API_KEY": ""
69
+ }
70
+
71
+ ```
72
+
73
+ * Edit the JSON as per your requirements. The various keys represent:
74
+
75
+ * **TEMP_EXEC_DIR**: Directory on which you wan the AppEngine to run
76
+
77
+ * **REQUEST_DIR**: Files or Folders to be uploaded to AppEngine for using during the execution can be added under the specified **REQUEST_DIR**
78
+
79
+ * **MODEL_DIR**: Local model files/binaries to be uploaded to AppEngine for using during the execution can be added under the specified **MODEL_DIR**
80
+
81
+ * **SAVE_CONTEXT**: Retains context across multiple requests. Disable it using ```"SAVE_CONTEXT" : false```
82
+
83
+ * **UPT_API_KEY**: API Key token generated from the ModelCentral profile of the user.
84
+
85
+ * Once configured, run the following script once again to get:
86
+
87
+ ```bash
88
+ Config Initialization Successful!!
89
+ ```
90
+
91
+ ### EntryPoint.py
92
+
93
+ * In order to run your custom AppEngine, it is necessary to create a file named ```EntryPoint.py``` which is going to contain the inference logic.
94
+
95
+ This is an Example snippet of the `EntryPoint.py`:
96
+ ```python
97
+ import json
98
+ from UnityPredict.Platform import IPlatform, InferenceRequest, InferenceResponse, OutcomeValue, InferenceContextData
99
+ from typing import List, Dict, Optional
100
+ from collections import deque
101
+ import sys
102
+ import datetime
103
+
104
+
105
+
106
+ def run_local_engine(request: InferenceRequest, platform: IPlatform) -> InferenceResponse:
107
+
108
+
109
+
110
+ platform.logMsg("Running User Code...")
111
+ response = InferenceResponse()
112
+
113
+ context: Dict[str, str] = {}
114
+
115
+ try:
116
+ prompt = request.InputValues['InputMessage']
117
+
118
+
119
+ # Saved context across requests
120
+ # Use this variable to save new context in the dict format
121
+ # request.Context.StoredMeta is of the format: Dict[str, str]
122
+ context = request.Context.StoredMeta
123
+
124
+ currentExecTime = datetime.datetime.now()
125
+ currentExecTime = currentExecTime.strftime("%d-%m-%YT%H-%M-%S")
126
+ resp_message = "Echo message: {} Time:: {}".format(prompt, currentExecTime)
127
+
128
+
129
+ # platform.getRequestFile: Fetch Files specified under the "REQUEST_DIR" in config
130
+ with platform.getRequestFile("myDetails.txt", "r") as reqFile:
131
+
132
+ resp_message += "\n{}".format("\n".join(reqFile.readlines()))
133
+
134
+
135
+ # Fill context according to your needs
136
+ context[currentExecTime] = resp_message
137
+
138
+
139
+ # platform.saveRequestFile: Creates any file type Outputs
140
+ # These files would be present under TEMP_EXEC_DIR/execTmp/outputs_<RequestLaunchTimeStamp>__<RequestId>
141
+ # TEMP_EXEC_DIR: Configured under the config.json
142
+ # execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
143
+ with platform.saveRequestFile("final_resp_{}.txt".format(currentExecTime), "w+") as outFile:
144
+
145
+ outFile.write(resp_message)
146
+
147
+
148
+ cost = len(prompt)/1000 * 0.03 + len(resp_message)/1000 * 0.06
149
+ response.AdditionalInferenceCosts = cost
150
+ response.Outcomes['OutputMessage'] = [OutcomeValue(value=resp_message, probability=1.0)]
151
+
152
+ # Set the updated context back to the response
153
+ response.Context.StoredMeta = context
154
+ except Exception as e:
155
+ response.ErrorMessages = "Entrypoint Exception Occured: {}".format(str(e))
156
+
157
+ print("Finished Running User Code...")
158
+ return response
159
+
160
+
161
+ ```
162
+
163
+ * Some APIs for using the AppEngine environment
164
+ * **request.Context.StoredMeta**:
165
+ * Saved context across requests
166
+ * Use this variable to save new context in the dict format
167
+ * request.Context.StoredMeta is of the format: Dict[str, str]
168
+
169
+ * **platform.getRequestFile**:
170
+ * Fetch Files specified under the "**REQUEST_DIR**" in config
171
+
172
+ * **platform.saveRequestFile**:
173
+ * Creates any file type Outputs
174
+ * These files would be present under **TEMP_EXEC_DIR/execTmp/*outputs_RequestLaunchTimeStamp__RequestId***
175
+ * **TEMP_EXEC_DIR**: Configured under the config.json
176
+ * execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
177
+
178
+
179
+ * Go back to the `main.py` and add the following command to run your `EntryPoint.py`
180
+
181
+ ```python
182
+ if __name__ == "__main__":
183
+
184
+ # Previous Snippet for initialization
185
+ platformInit = UnityPredictHost()
186
+
187
+ configStat = platformInit.isConfigInitialized()
188
+
189
+ if not configStat:
190
+ print ("Config Initialization Unsuccessful!!")
191
+ sys.exit(0)
192
+
193
+
194
+ print ("Config Initialization Successful!!")
195
+
196
+ #### New Snippet to run EntryPoint.py via the AppEngine
197
+
198
+ request = Models.AppEngineRequest(RequestId=str(uuid.uuid4()))
199
+ request.EngineInputData = Models.EngineInputs(InputValues={"InputMessage": "Hi, this is the message to be echoed"}, DesiredOutcomes=[])
200
+
201
+ response : Models.UnityPredictEngineResponse = platformInit.run_engine(request=request)
202
+
203
+ # Print Outputs
204
+ if (response.EngineOutputs != None):
205
+ print ("Output: {}".format(response.EngineOutputs.toJSON()))
206
+
207
+ # Print Error Messages (if any)
208
+ print ("Error Messages: {}".format(response.ErrorMessages))
209
+
210
+ ```
211
+
212
+
213
+ ## Contributing
214
+
215
+ ## License
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,24 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ description = ""
4
+ with open("README.md", "r") as rdf:
5
+ description = rdf.read()
6
+
7
+ print ("Possible packages: {}".format(find_packages()))
8
+
9
+ setup (
10
+ name="unitypredict",
11
+ version="0.1.17",
12
+ packages=find_packages(),
13
+ install_requires=[
14
+ # Currently no dependencies
15
+ ],
16
+ entry_points = { # this here is the magic that binds your function into a callable script
17
+ 'console_scripts':
18
+ [
19
+ 'unitypredict=unitypredict.scripts:runcmd'
20
+ ],
21
+ },
22
+ long_description=description,
23
+ long_description_content_type="text/markdown"
24
+ )
@@ -0,0 +1,104 @@
1
+ from enum import Enum
2
+ from pydantic import BaseModel
3
+ import json
4
+
5
+ class EngineResults:
6
+ OutcomeValues: dict = {}
7
+ Outcomes: dict = {}
8
+
9
+ def __init__(self):
10
+ self.OutcomeValues = dict()
11
+ self.Outcomes = dict()
12
+
13
+ def toJSON(self):
14
+ return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
15
+
16
+ class OutcomePrediction:
17
+ Probability = 0.0
18
+ Value = None
19
+
20
+ def __init__(self):
21
+ self.Probability = 0.0
22
+ self.Value = None
23
+
24
+ class DataTypes(str, Enum):
25
+ Boolean = 'Boolean'
26
+ Integer = 'Integer'
27
+ Float = 'Float'
28
+ String = 'String'
29
+ File = 'File'
30
+ Tensor = 'Tensor'
31
+
32
+ class InputInfo (BaseModel):
33
+ Name: str = ''
34
+ InputType: DataTypes = DataTypes.Integer
35
+
36
+ class OutcomeInfo (BaseModel):
37
+ Name: str = ''
38
+ OutcomeType: DataTypes = DataTypes.Integer
39
+
40
+ class BasePredictEngineConfig (BaseModel):
41
+ # Inputs: list[InputInfo] = None
42
+ # Outcomes: list[OutcomeInfo] = None
43
+ Inputs: list
44
+ Outcomes: list
45
+
46
+ class InferenceContext (BaseModel):
47
+ ContextId: str = ''
48
+ StoredMeta: dict = {}
49
+
50
+ def toJSON(self):
51
+ return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
52
+
53
+ class EngineInputs (BaseModel):
54
+ InputValues: dict
55
+ DesiredOutcomes: list
56
+
57
+ # Note: these models will be different for every engine type
58
+ ###############################################################################################################
59
+ class AppEngineInferenceOptions (BaseModel):
60
+ pass
61
+
62
+ class AIEngineConfiguration (BasePredictEngineConfig):
63
+ InferenceOptions: AppEngineInferenceOptions = None
64
+
65
+ class AppEngineRequest (BaseModel):
66
+ RequestId: str = ''
67
+ EngineId: str = ''
68
+ RequestInputFiles: bool = False
69
+ RequestOutputFiles: bool = False
70
+ RequestFilesFolderPath: str = False
71
+ PackagesFolderPath: str = ''
72
+ PackagesFolderPath: str = ''
73
+ SourcesFolderPath: str = ''
74
+ ModelFilesFolderPath: str = ''
75
+ EngineApiKey: str = ''
76
+ PredictEndpoint: str = ''
77
+ Context: InferenceContext = None
78
+ CallbackQueue: str = ''
79
+ EngineInputData: EngineInputs = None
80
+ EngineConfig: AIEngineConfiguration = None
81
+
82
+ def toJSON(self):
83
+ return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
84
+
85
+ ###############################################################################################################
86
+
87
+ class UnityPredictEngineResponse:
88
+ RequestId: str = ''
89
+ ErrorMessages: str = ''
90
+ LogMessages: str = ''
91
+ AdditionalInferenceCosts: float = 0.0
92
+ EngineOutputs: EngineResults = None
93
+ Context: InferenceContext = None
94
+
95
+ def __init__(self):
96
+ self.RequestId = ''
97
+ self.ErrorMessages = ''
98
+ self.LogMessages = ''
99
+ self.AdditionalInferenceCosts = 0.0
100
+ self.EngineOutputs = None
101
+ self.Context = None
102
+
103
+ def toJSON(self):
104
+ return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
@@ -0,0 +1,109 @@
1
+ from abc import ABCMeta, abstractmethod
2
+ from io import BufferedReader, IOBase
3
+
4
+ class OutcomeValue:
5
+ Probability = 0.0
6
+ Value = None
7
+
8
+ def __init__(self, value: any = '', probability: float = 0.0):
9
+ self.Probability = probability
10
+ self.Value = value
11
+
12
+ class InferenceContextData:
13
+ StoredMeta: dict = {}
14
+
15
+ def __init__(self):
16
+ self.StoredMeta = {}
17
+
18
+ class InferenceRequest:
19
+ InputValues: dict
20
+ DesiredOutcomes: list
21
+ Context: InferenceContextData = None
22
+ def __init__(self):
23
+ self.Context = InferenceContextData()
24
+ self.InputValues = {}
25
+ self.DesiredOutcomes = []
26
+
27
+ class InferenceResponse:
28
+ ErrorMessages: str = ''
29
+ AdditionalInferenceCosts: float = 0.0
30
+ Context: InferenceContextData = None
31
+ OutcomeValues: dict = {}
32
+ Outcomes: dict = {}
33
+
34
+ def __init__(self):
35
+ self.ErrorMessages = ''
36
+ self.AdditionalInferenceCosts = 0.0
37
+ self.Context = InferenceContextData()
38
+ self.OutcomeValues = {}
39
+ self.Outcomes = {}
40
+
41
+ class ChainedInferenceRequest:
42
+ ContextId: str = ''
43
+ InputValues: dict
44
+ DesiredOutcomes: list
45
+
46
+ def __init__(self):
47
+ self.ContextId = ''
48
+ self.InputValues = {}
49
+ self.DesiredOutcomes = []
50
+
51
+
52
+ class ChainedInferenceResponse:
53
+ ContextId: str = ''
54
+ RequestId: str = ''
55
+ ErrorMessages: str = ''
56
+ ComputeCost: float = 0.0
57
+ OutcomeValues: dict = {}
58
+ Outcomes: dict = {}
59
+
60
+ def __init__(self):
61
+ self.ContextId = ''
62
+ self.RequestId = ''
63
+ self.ErrorMessages = ''
64
+ self.ComputeCost = 0.0
65
+ self.OutcomeValues = {}
66
+ self.Outcomes = {}
67
+
68
+ class FileTransmissionObj:
69
+ FileName: str = ''
70
+ FileHandle: IOBase = None
71
+
72
+ def __init__(self, fileName, fileHandle):
73
+ self.FileName = fileName
74
+ self.FileHandle = fileHandle
75
+
76
+ class FileReceivedObj:
77
+ FileName: str = ''
78
+ LocalFilePath: str = ''
79
+
80
+ def __init__(self, fileName, localFilePath):
81
+ self.FileName = fileName
82
+ self.LocalFilePath = localFilePath
83
+
84
+ class IPlatform:
85
+ __metaclass__ = ABCMeta
86
+
87
+ @classmethod
88
+ def version(self): return "1.0"
89
+
90
+ @abstractmethod
91
+ def getModelsFolderPath(self) -> str: raise NotImplementedError
92
+
93
+ @abstractmethod
94
+ def getModelFile(self, modelFileName: str, mode: str = 'rb') -> IOBase: raise NotImplementedError
95
+
96
+ @abstractmethod
97
+ def getRequestFile(self, modelFileName: str, mode: str = 'rb') -> IOBase: raise NotImplementedError
98
+
99
+ @abstractmethod
100
+ def saveRequestFile(self, modelFileName: str, mode: str = 'wb') -> IOBase: raise NotImplementedError
101
+
102
+ @abstractmethod
103
+ def getLocalTempFolderPath(self) -> str: raise NotImplementedError
104
+
105
+ @abstractmethod
106
+ def logMsg(self, msg: str): raise NotImplementedError
107
+
108
+ @abstractmethod
109
+ def invokeUnityPredictModel(self, modelId: str, request: ChainedInferenceRequest) -> ChainedInferenceResponse: raise NotImplementedError
@@ -0,0 +1,447 @@
1
+ import importlib
2
+ from io import BufferedReader, IOBase, StringIO
3
+
4
+ from pydantic import BaseModel
5
+ import json
6
+ import os, sys
7
+ import shutil
8
+ import datetime
9
+ import uuid
10
+ import filecmp
11
+
12
+ import requests
13
+ from .Models import AppEngineRequest, EngineResults, InferenceContext, UnityPredictEngineResponse
14
+ from .Platform import ChainedInferenceRequest, ChainedInferenceResponse, FileReceivedObj, FileTransmissionObj, IPlatform, InferenceRequest,InferenceResponse, InferenceContextData
15
+
16
+ class AppEngineConfig (BaseModel):
17
+ TEMP_EXEC_DIR: str = os.getcwd()
18
+ UPT_API_KEY: str = ""
19
+ MODEL_DIR: str = os.path.join(os.getcwd(), "models")
20
+ REQUEST_DIR: str = os.path.join(os.getcwd(), "requests")
21
+ SAVE_CONTEXT: bool = True
22
+
23
+ def toJSON(self):
24
+ return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
25
+
26
+ class UnityPredictHost(IPlatform):
27
+
28
+ Initialized = False
29
+ isConfigInit = False
30
+ LoadedEngineId = None
31
+ CurrentRequest: AppEngineRequest = None
32
+ logMsgs: str = ''
33
+
34
+ configFile = os.path.join(os.getcwd(), "config.json")
35
+ appEngineConfig: AppEngineConfig = AppEngineConfig()
36
+
37
+
38
+ execTempDir = "execTmp"
39
+ execRequestFolder: str = "requests"
40
+ execModelFolder: str = "models"
41
+ execOutputFolder: str = "outputs"
42
+
43
+ def __init__(self) -> None:
44
+
45
+ config_dict : dict = {}
46
+ if not os.path.exists(self.configFile):
47
+
48
+ print ("Config file not detected, creating templated config file: {}".format(self.configFile))
49
+
50
+ self.appEngineConfig.TEMP_EXEC_DIR = os.getcwd()
51
+
52
+ with open(self.configFile, "w+") as confFile:
53
+ confFile.write(self.appEngineConfig.toJSON())
54
+
55
+ return None
56
+
57
+ print ("Config file detected, loading data from: {}".format(self.configFile))
58
+ with open (self.configFile, "r+") as confFile:
59
+ config_dict = json.load(confFile)
60
+
61
+ self.appEngineConfig = AppEngineConfig(**config_dict)
62
+ self.CurrentRequest = AppEngineRequest()
63
+
64
+ self.workingDir = os.path.join(self.appEngineConfig.TEMP_EXEC_DIR, self.execTempDir)
65
+ self.CurrentRequest.EngineApiKey = self.appEngineConfig.UPT_API_KEY
66
+
67
+
68
+ self.CurrentRequest.ModelFilesFolderPath = os.path.join(self.workingDir, self.execModelFolder)
69
+ self.CurrentRequest.RequestFilesFolderPath = os.path.join(self.workingDir, self.execRequestFolder)
70
+
71
+
72
+ self.isConfigInit = True
73
+
74
+ return None
75
+
76
+ def isConfigInitialized(self) -> bool:
77
+
78
+ return self.isConfigInit
79
+
80
+ def isPlatformInitialized(self) -> bool:
81
+
82
+ return self.Initialized
83
+
84
+
85
+ def getModelsFolderPath(self) -> str:
86
+ # ToDo: return the correct path
87
+ return self.CurrentRequest.ModelFilesFolderPath
88
+
89
+ def getModelFile(self, modelFileName: str, mode: str = 'rb') -> IOBase:
90
+ # ToDo: return the correct file handle
91
+ absFilePath = os.path.join(self.getModelsFolderPath(), modelFileName)
92
+ fileHandler = open(absFilePath, mode)
93
+
94
+ return fileHandler
95
+
96
+
97
+ def getLocalTempFolderPath(self) -> str:
98
+ # ToDo: return the correct path
99
+ return self.workingDir
100
+
101
+ def getRequestFolderPath(self) -> str:
102
+ # ToDo: return the correct path
103
+ return self.CurrentRequest.RequestFilesFolderPath
104
+
105
+
106
+ def getRequestFile(self, requestFileName: str, mode: str = 'rb') -> IOBase:
107
+ # ToDo: return the correct file handle
108
+ absFilePath = os.path.join(self.getRequestFolderPath(), requestFileName)
109
+ fileHandler = open(absFilePath, mode)
110
+
111
+ return fileHandler
112
+
113
+ def saveRequestFile(self, requestFileName: str, mode: str = 'wb') -> IOBase:
114
+ # ToDo: return the correct file handle
115
+ absFilePath = os.path.join(self.execOutputFolder, requestFileName)
116
+ fileHandler = open(absFilePath, mode)
117
+
118
+ return fileHandler
119
+
120
+
121
+ def logMsg(self, msg: str):
122
+ self.logMsgs += "\n{}\n".format(msg)
123
+
124
+ def errorMsg(self, msg: str):
125
+ self.errorMsgs += "\n{}\n".format(msg)
126
+
127
+
128
+ def syncDirectories(self, source: str, destination: str, create_dest_if_not_present: bool = False):
129
+
130
+ if not os.path.exists(source) or not os.path.isdir(source):
131
+ print(f"Source directory '{source}' does not exist or is not a directory.")
132
+ return
133
+
134
+ if create_dest_if_not_present:
135
+ if not os.path.exists(destination):
136
+ os.makedirs(destination)
137
+ else:
138
+ if not os.path.exists(destination) or not os.path.isdir(source):
139
+ print(f"Destination directory '{destination}' does not exist or is not a directory.")
140
+ return
141
+
142
+ # Copy or update files from source to destination
143
+ for src_dir, _, files in os.walk(source):
144
+ dst_dir = src_dir.replace(source, destination, 1)
145
+ if not os.path.exists(dst_dir):
146
+ os.makedirs(dst_dir)
147
+
148
+ for file in files:
149
+ src_file = os.path.join(src_dir, file)
150
+ dst_file = os.path.join(dst_dir, file)
151
+
152
+ if not os.path.exists(dst_file) or not filecmp.cmp(src_file, dst_file, shallow=False):
153
+ shutil.copy2(src_file, dst_file) # Preserve metadata with copy2
154
+ print(f"Copied: {src_file} to {dst_file}")
155
+ else:
156
+ print(f"Skipped: {src_file} is already up to date.")
157
+
158
+ # Remove files and directories from destination that are not in source
159
+ for dst_dir, _, files in os.walk(destination, topdown=False):
160
+ src_dir = dst_dir.replace(destination, source, 1)
161
+
162
+ if not os.path.exists(src_dir):
163
+ shutil.rmtree(dst_dir)
164
+ print(f"Removed directory: {dst_dir}")
165
+ else:
166
+ for file in files:
167
+ dst_file = os.path.join(dst_dir, file)
168
+ src_file = os.path.join(src_dir, file)
169
+
170
+ if not os.path.exists(src_file):
171
+ os.remove(dst_file)
172
+ print(f"Removed file: {dst_file}")
173
+
174
+ def createPlatform(self, request: AppEngineRequest) -> bool:
175
+ if not self.isConfigInit:
176
+ return False
177
+
178
+ # Creating output folder based on RequestID
179
+ if (request.RequestId == ""):
180
+
181
+ self.errorMsg("Please provide a proper request id\n")
182
+
183
+ return False
184
+
185
+ # Create the folders
186
+ if not os.path.exists(self.workingDir):
187
+ os.mkdir(self.workingDir)
188
+
189
+ if not os.path.exists(self.CurrentRequest.ModelFilesFolderPath):
190
+ os.mkdir(self.CurrentRequest.ModelFilesFolderPath)
191
+
192
+ # Create request folder having the name of the current Timestamp
193
+ currentExecTime = datetime.datetime.now()
194
+ currentExecTime = currentExecTime.strftime("%d-%m-%YT%H-%M-%S")
195
+
196
+ self.execRequestFolder = "{}_{}__{}".format(self.execRequestFolder, currentExecTime, request.RequestId)
197
+ self.CurrentRequest.RequestFilesFolderPath = os.path.join(self.workingDir, self.execRequestFolder)
198
+
199
+ if not os.path.exists(self.CurrentRequest.RequestFilesFolderPath):
200
+ os.mkdir(self.CurrentRequest.RequestFilesFolderPath)
201
+
202
+
203
+ # Create output folder based on the request Id
204
+ self.execOutputFolder = "{}_{}__{}".format(self.execOutputFolder, currentExecTime, request.RequestId)
205
+ self.execOutputFolder = os.path.join(self.workingDir, self.execOutputFolder)
206
+ if not os.path.exists(self.execOutputFolder):
207
+ os.mkdir(self.execOutputFolder)
208
+
209
+
210
+ # TODO: Copy user configured folder contents to respective exec folders
211
+ # Sync Request Files
212
+ self.syncDirectories(self.appEngineConfig.REQUEST_DIR, self.CurrentRequest.RequestFilesFolderPath)
213
+ # Sync Model Files
214
+ self.syncDirectories(self.appEngineConfig.MODEL_DIR, self.CurrentRequest.ModelFilesFolderPath)
215
+
216
+ self.Initialized = True
217
+
218
+ return True
219
+
220
+ def run_engine(self, request: AppEngineRequest) -> UnityPredictEngineResponse:
221
+
222
+ self.logMsgs: str = ''
223
+ self.MaxlogMsgBuffer: int = 3000
224
+ self.NegMaxlogMsgBuffer: int = -1 * self.MaxlogMsgBuffer
225
+
226
+ self.errorMsgs: str = ''
227
+ self.MaxErrorMsgsBuffer: int = 3000
228
+ self.NegMaxErrorMsgsBuffer: int = -1 * self.MaxErrorMsgsBuffer
229
+
230
+ toreturn: UnityPredictEngineResponse = UnityPredictEngineResponse()
231
+ try:
232
+
233
+ # Create the platform for execution
234
+ # 1) Prepare temp folders on local directories for A) Request Files B) Model Files C) Temp Files
235
+ # 2) Put the files into the right folders
236
+ if not self.createPlatform(request=request):
237
+
238
+ self.errorMsg("Unable to create the platform")
239
+ toreturn.ErrorMessages = self.errorMsgs[self.NegMaxErrorMsgsBuffer:] # limit length of the logs
240
+ toreturn.LogMessages = self.logMsgs[self.NegMaxlogMsgBuffer:] # limit length of the logs
241
+
242
+ return toreturn
243
+
244
+
245
+ # 3) Store/Restore Context (probably using some local json file) if requested by user
246
+ # Initialize context
247
+
248
+ if (self.appEngineConfig.SAVE_CONTEXT):
249
+
250
+ contextJson = os.path.join(self.getLocalTempFolderPath(), "context.json")
251
+
252
+ context = {}
253
+ if os.path.exists(contextJson):
254
+ with open(contextJson, "r+") as ctxtf:
255
+ context = json.load(ctxtf)
256
+
257
+ request.Context = InferenceContext(**context)
258
+
259
+ # 4) Convert the AppEngineRequest to the InferenceRequest that the model needs
260
+
261
+ inferReq: InferenceRequest = InferenceRequest()
262
+ inferReq.InputValues = request.EngineInputData.InputValues
263
+ inferReq.DesiredOutcomes = request.EngineInputData.DesiredOutcomes
264
+
265
+ inferReq.Context = InferenceContextData()
266
+
267
+ if (request.Context != None):
268
+ inferReq.Context.StoredMeta = request.Context.StoredMeta
269
+ else:
270
+ inferReq.Context.StoredMeta = {}
271
+
272
+
273
+ # 5) Run EntryPoint.py
274
+ entryPoint = importlib.import_module("EntryPoint")
275
+ inferResp: InferenceResponse = entryPoint.run_local_engine(inferReq, self)
276
+
277
+ # 6) Copy InferenceResponse to UnityPredictEngineResponse
278
+
279
+ toreturn.AdditionalInferenceCosts = inferResp.AdditionalInferenceCosts
280
+ toreturn.EngineOutputs = EngineResults()
281
+
282
+ if (inferResp.Outcomes != None):
283
+ toreturn.EngineOutputs.Outcomes = inferResp.Outcomes
284
+ else:
285
+ toreturn.EngineOutputs.Outcomes = {}
286
+
287
+ if (inferResp.OutcomeValues != None):
288
+ toreturn.EngineOutputs.OutcomeValues = inferResp.OutcomeValues
289
+ else:
290
+ toreturn.EngineOutputs.OutcomeValues = {}
291
+
292
+
293
+ toreturn.EngineOutputs.OutcomeValues = inferResp.OutcomeValues
294
+ toreturn.ErrorMessages = inferResp.ErrorMessages
295
+
296
+ if (self.appEngineConfig.SAVE_CONTEXT):
297
+
298
+ toreturn.Context = InferenceContext(ContextId="")
299
+ if (request.Context != None):
300
+ toreturn.Context.ContextId = request.Context.ContextId
301
+ if (inferResp.Context == None or inferResp.Context.StoredMeta == None or inferResp.Context.StoredMeta == {}):
302
+
303
+ if (request.Context != None):
304
+ toreturn.Context.StoredMeta = inferReq.Context.StoredMeta
305
+ else:
306
+ toreturn.Context.StoredMeta = {}
307
+
308
+ else:
309
+ toreturn.Context.StoredMeta = inferResp.Context.StoredMeta
310
+
311
+ if toreturn.Context.ContextId == "":
312
+ toreturn.Context.ContextId = str(uuid.uuid4())
313
+
314
+
315
+ with open(contextJson, "w+") as ctxtf:
316
+ ctxtf.write(toreturn.Context.toJSON())
317
+
318
+
319
+ toreturn.LogMessages = self.logMsgs[self.NegMaxlogMsgBuffer:] # limit length of the logs
320
+
321
+ except Exception as e:
322
+
323
+ print ("Error occured: {}".format(str(e)))
324
+ self.errorMsg(str(e))
325
+ toreturn.ErrorMessages += self.errorMsgs[self.NegMaxErrorMsgsBuffer:] # limit length of the logs
326
+ toreturn.LogMessages = self.logMsgs[self.NegMaxlogMsgBuffer:] # limit length of the logs
327
+
328
+ return toreturn
329
+
330
+
331
+ def invokeUnityPredictModel(self, modelId: str, request: ChainedInferenceRequest) -> ChainedInferenceResponse:
332
+ results = ChainedInferenceResponse()
333
+
334
+ apiKey = self.CurrentRequest.EngineApiKey
335
+ apiBaseUrl = self.CurrentRequest.PredictEndpoint.rstrip('/')
336
+
337
+ needFileUpload: bool = False
338
+
339
+ #####
340
+ # The request can contain file objects so we need to change those to file names before sending out
341
+ #####
342
+ # first get a list of file that we'll need to upload later & update the POST obj
343
+ filesToUpload = {}
344
+ for xvarName in request.InputValues:
345
+ if isinstance(request.InputValues.get(xvarName), FileTransmissionObj):
346
+ needFileUpload = True
347
+ break
348
+
349
+ finalResponseJson: any = ''
350
+
351
+ response: requests.Response = None
352
+ if not needFileUpload:
353
+ # serialize the POST obj
354
+ jsonBody = json.dumps(request, default=vars)
355
+
356
+ # there are no files to upload so just post normally
357
+ response = requests.post(url = "{}/{}".format(apiBaseUrl, modelId), data=jsonBody, headers={"Authorization": "Bearer {}".format(apiKey)})
358
+
359
+ if response.status_code != 200:
360
+ results.ErrorMessages = 'Error from server: {}'.format(response.status_code)
361
+ return results
362
+
363
+ finalResponseJson = response.json()
364
+ else:
365
+ # we need to initialize first
366
+ response = requests.post(url = "{}/initialize/{}".format(apiBaseUrl, modelId), data="", headers={"Authorization": "Bearer {}".format(apiKey)})
367
+
368
+ requestId: str = response.json().get('requestId')
369
+
370
+ if response.status_code != 200:
371
+ results.ErrorMessages = 'Error from server: {}'.format(response.status_code)
372
+ return results
373
+
374
+ # upload the files
375
+ for xvarName in request.InputValues:
376
+ if isinstance(request.InputValues.get(xvarName), FileTransmissionObj):
377
+ fileToUpload: FileTransmissionObj = request.InputValues.get(xvarName)
378
+ response = requests.get(url = "{}/upload/{}/{}".format(apiBaseUrl, requestId, fileToUpload.FileName), headers={"Authorization": "Bearer {}".format(apiKey)})
379
+ uploadLink = response.json().get('uploadLink')
380
+ fileName = response.json().get('fileName')
381
+ request.InputValues[xvarName] = fileName # make sure that only the filename is in the request that we are going to POST
382
+ requests.put(url = uploadLink, data=fileToUpload.FileHandle)
383
+
384
+ jsonBody = json.dumps(request, default=vars)
385
+
386
+ response = requests.post(url = "{}/{}/{}".format(apiBaseUrl, modelId, requestId), data=jsonBody, headers={"Authorization": "Bearer {}".format(apiKey)})
387
+
388
+ finalResponseJson = response.json()
389
+
390
+
391
+ print(finalResponseJson)
392
+
393
+ while (finalResponseJson.get('status') == 'Processing'):
394
+ statusUrl: str = finalResponseJson.get('statusUrl')
395
+
396
+ response = requests.get(url = statusUrl, headers={"Authorization": "Bearer {}".format(apiKey)})
397
+ finalResponseJson = response.json()
398
+
399
+
400
+ finalResponseRequestId: str = finalResponseJson.get('requestId')
401
+
402
+ tempOutputFolder: str = os.path.join(self.getLocalTempFolderPath(), "chainedResults", finalResponseRequestId)
403
+ if not os.path.exists(tempOutputFolder):
404
+ os.makedirs(tempOutputFolder)
405
+
406
+ outcomeValues = finalResponseJson.get('outcomeValues')
407
+ for outputVarName in outcomeValues:
408
+ outcome: dict = outcomeValues.get(outputVarName)
409
+ if outcome.get('dataType') == 'File':
410
+ fileName = outcome.get('value')
411
+
412
+ tempFilePath = os.path.join(tempOutputFolder, fileName)
413
+ response = requests.get(url = "{}/download/{}/{}".format(apiBaseUrl, finalResponseRequestId, fileName), headers={"Authorization": "Bearer {}".format(apiKey)})
414
+ with open(tempFilePath, 'wb') as f:
415
+ f.write(response.content)
416
+
417
+ fileReceived: FileReceivedObj = FileReceivedObj(fileName, tempFilePath)
418
+ outcome['value'] = fileReceived
419
+
420
+ outcomes = finalResponseJson.get('outcomes')
421
+ for outputVarName in outcomes:
422
+ outcome: list = outcomes.get(outputVarName)
423
+ for outcomeItem in outcome:
424
+ if outcomeItem.get('dataType') == 'File':
425
+ fileName = outcomeItem.get('value')
426
+
427
+ tempFilePath = os.path.join(tempOutputFolder, fileName)
428
+ response = requests.get(url = "{}/download/{}/{}".format(apiBaseUrl, finalResponseRequestId, fileName), headers={"Authorization": "Bearer {}".format(apiKey)})
429
+ with open(tempFilePath, 'wb') as f:
430
+ f.write(response.content)
431
+
432
+ fileReceived: FileReceivedObj = FileReceivedObj(fileName, tempFilePath)
433
+ outcomeItem['value'] = fileReceived
434
+
435
+
436
+ try:
437
+ results.ComputeCost = finalResponseJson.get('computeCost')
438
+ results.OutcomeValues = outcomeValues
439
+ results.Outcomes = outcomes
440
+ results.RequestId = finalResponseRequestId
441
+ results.ContextId = finalResponseJson.get('contextId')
442
+ results.ErrorMessages = finalResponseJson.get('errorMessages')
443
+
444
+ except Exception as e:
445
+ print(e)
446
+
447
+ return results
@@ -0,0 +1 @@
1
+ from .UnityPredictLocalHost import UnityPredictHost
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ def runcmd():
4
+ cmd = sys.argv[1:]
5
+ print(f'Command = {cmd}')
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.1
2
+ Name: unitypredict
3
+ Version: 0.1.17
4
+ Description-Content-Type: text/markdown
5
+
6
+ # UnityPredict Local App Engine Creator
7
+
8
+ ## Introduction
9
+
10
+ This library allows you to create App Engines in your local system and finetune the engines before updating it to the [ModelCentral](https://modelcentral.ai) repositories.
11
+
12
+ ## Installation
13
+ * You can use pip to install the ```UnityPredict``` library.
14
+ ```bash
15
+ pip install UnityPredict
16
+ ```
17
+
18
+ ## Usage
19
+ Use the following snippet to initialize the environment.
20
+
21
+
22
+ ### main.py
23
+
24
+ ```python
25
+
26
+ from UnityPredict import UnityPredictHost, Models
27
+ import sys
28
+ import uuid
29
+
30
+ import time
31
+
32
+ import os
33
+
34
+
35
+
36
+ if __name__ == "__main__":
37
+ platformInit = UnityPredictHost()
38
+
39
+ configStat = platformInit.isConfigInitialized()
40
+
41
+ if not configStat:
42
+ print ("Config Initialization Unsuccessful!!")
43
+ sys.exit(0)
44
+
45
+
46
+ print ("Config Initialization Successful!!")
47
+
48
+ ```
49
+
50
+ * This is the snippet to initialize the AppEngine environment.
51
+ * Run script using the following command:
52
+
53
+ ```bash
54
+ python main.py
55
+ ```
56
+
57
+ * If this script is run for the **first time**. The following Output will be shown
58
+
59
+ ```bash
60
+
61
+ Config file not detected, creating templated config file: YourScriptPath/config.json
62
+ Config Initialization Unsuccessful!!
63
+
64
+ ```
65
+ * A templated config file would be generated on the same directory as that of your main script.
66
+
67
+ ```json
68
+ {
69
+ "MODEL_DIR": "YourScriptPath/models",
70
+ "REQUEST_DIR": "YourScriptPath/requests",
71
+ "SAVE_CONTEXT": true,
72
+ "TEMP_EXEC_DIR": "YourScriptPath",
73
+ "UPT_API_KEY": ""
74
+ }
75
+
76
+ ```
77
+
78
+ * Edit the JSON as per your requirements. The various keys represent:
79
+
80
+ * **TEMP_EXEC_DIR**: Directory on which you wan the AppEngine to run
81
+
82
+ * **REQUEST_DIR**: Files or Folders to be uploaded to AppEngine for using during the execution can be added under the specified **REQUEST_DIR**
83
+
84
+ * **MODEL_DIR**: Local model files/binaries to be uploaded to AppEngine for using during the execution can be added under the specified **MODEL_DIR**
85
+
86
+ * **SAVE_CONTEXT**: Retains context across multiple requests. Disable it using ```"SAVE_CONTEXT" : false```
87
+
88
+ * **UPT_API_KEY**: API Key token generated from the ModelCentral profile of the user.
89
+
90
+ * Once configured, run the following script once again to get:
91
+
92
+ ```bash
93
+ Config Initialization Successful!!
94
+ ```
95
+
96
+ ### EntryPoint.py
97
+
98
+ * In order to run your custom AppEngine, it is necessary to create a file named ```EntryPoint.py``` which is going to contain the inference logic.
99
+
100
+ This is an Example snippet of the `EntryPoint.py`:
101
+ ```python
102
+ import json
103
+ from UnityPredict.Platform import IPlatform, InferenceRequest, InferenceResponse, OutcomeValue, InferenceContextData
104
+ from typing import List, Dict, Optional
105
+ from collections import deque
106
+ import sys
107
+ import datetime
108
+
109
+
110
+
111
+ def run_local_engine(request: InferenceRequest, platform: IPlatform) -> InferenceResponse:
112
+
113
+
114
+
115
+ platform.logMsg("Running User Code...")
116
+ response = InferenceResponse()
117
+
118
+ context: Dict[str, str] = {}
119
+
120
+ try:
121
+ prompt = request.InputValues['InputMessage']
122
+
123
+
124
+ # Saved context across requests
125
+ # Use this variable to save new context in the dict format
126
+ # request.Context.StoredMeta is of the format: Dict[str, str]
127
+ context = request.Context.StoredMeta
128
+
129
+ currentExecTime = datetime.datetime.now()
130
+ currentExecTime = currentExecTime.strftime("%d-%m-%YT%H-%M-%S")
131
+ resp_message = "Echo message: {} Time:: {}".format(prompt, currentExecTime)
132
+
133
+
134
+ # platform.getRequestFile: Fetch Files specified under the "REQUEST_DIR" in config
135
+ with platform.getRequestFile("myDetails.txt", "r") as reqFile:
136
+
137
+ resp_message += "\n{}".format("\n".join(reqFile.readlines()))
138
+
139
+
140
+ # Fill context according to your needs
141
+ context[currentExecTime] = resp_message
142
+
143
+
144
+ # platform.saveRequestFile: Creates any file type Outputs
145
+ # These files would be present under TEMP_EXEC_DIR/execTmp/outputs_<RequestLaunchTimeStamp>__<RequestId>
146
+ # TEMP_EXEC_DIR: Configured under the config.json
147
+ # execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
148
+ with platform.saveRequestFile("final_resp_{}.txt".format(currentExecTime), "w+") as outFile:
149
+
150
+ outFile.write(resp_message)
151
+
152
+
153
+ cost = len(prompt)/1000 * 0.03 + len(resp_message)/1000 * 0.06
154
+ response.AdditionalInferenceCosts = cost
155
+ response.Outcomes['OutputMessage'] = [OutcomeValue(value=resp_message, probability=1.0)]
156
+
157
+ # Set the updated context back to the response
158
+ response.Context.StoredMeta = context
159
+ except Exception as e:
160
+ response.ErrorMessages = "Entrypoint Exception Occured: {}".format(str(e))
161
+
162
+ print("Finished Running User Code...")
163
+ return response
164
+
165
+
166
+ ```
167
+
168
+ * Some APIs for using the AppEngine environment
169
+ * **request.Context.StoredMeta**:
170
+ * Saved context across requests
171
+ * Use this variable to save new context in the dict format
172
+ * request.Context.StoredMeta is of the format: Dict[str, str]
173
+
174
+ * **platform.getRequestFile**:
175
+ * Fetch Files specified under the "**REQUEST_DIR**" in config
176
+
177
+ * **platform.saveRequestFile**:
178
+ * Creates any file type Outputs
179
+ * These files would be present under **TEMP_EXEC_DIR/execTmp/*outputs_RequestLaunchTimeStamp__RequestId***
180
+ * **TEMP_EXEC_DIR**: Configured under the config.json
181
+ * execTmp: Creates enviroment for the AppEngine under the specified TEMP_EXEC_DIR
182
+
183
+
184
+ * Go back to the `main.py` and add the following command to run your `EntryPoint.py`
185
+
186
+ ```python
187
+ if __name__ == "__main__":
188
+
189
+ # Previous Snippet for initialization
190
+ platformInit = UnityPredictHost()
191
+
192
+ configStat = platformInit.isConfigInitialized()
193
+
194
+ if not configStat:
195
+ print ("Config Initialization Unsuccessful!!")
196
+ sys.exit(0)
197
+
198
+
199
+ print ("Config Initialization Successful!!")
200
+
201
+ #### New Snippet to run EntryPoint.py via the AppEngine
202
+
203
+ request = Models.AppEngineRequest(RequestId=str(uuid.uuid4()))
204
+ request.EngineInputData = Models.EngineInputs(InputValues={"InputMessage": "Hi, this is the message to be echoed"}, DesiredOutcomes=[])
205
+
206
+ response : Models.UnityPredictEngineResponse = platformInit.run_engine(request=request)
207
+
208
+ # Print Outputs
209
+ if (response.EngineOutputs != None):
210
+ print ("Output: {}".format(response.EngineOutputs.toJSON()))
211
+
212
+ # Print Error Messages (if any)
213
+ print ("Error Messages: {}".format(response.ErrorMessages))
214
+
215
+ ```
216
+
217
+
218
+ ## Contributing
219
+
220
+ ## License
@@ -0,0 +1,12 @@
1
+ README.md
2
+ setup.py
3
+ unitypredict/Models.py
4
+ unitypredict/Platform.py
5
+ unitypredict/UnityPredictLocalHost.py
6
+ unitypredict/__init__.py
7
+ unitypredict/scripts.py
8
+ unitypredict.egg-info/PKG-INFO
9
+ unitypredict.egg-info/SOURCES.txt
10
+ unitypredict.egg-info/dependency_links.txt
11
+ unitypredict.egg-info/entry_points.txt
12
+ unitypredict.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ unitypredict = unitypredict.scripts:runcmd
@@ -0,0 +1 @@
1
+ unitypredict