Spaces:
Sleeping
Sleeping
Add echo streaming endpoint
Browse files
server.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
|
4 |
import os
|
5 |
import re
|
|
|
6 |
import asyncio
|
7 |
import json
|
8 |
import traceback
|
@@ -24,6 +25,9 @@ from aiohttp.web_response import Response
|
|
24 |
curl -X POST http://0.0.0.0:10000/chat/ -H "api_key: hello" -d '{"k": 5, "timeout": 3, "roles": ["user"], "messages": ["hello world"]}'
|
25 |
|
26 |
curl -X POST http://0.0.0.0:10000/chat/ -H "api_key: hey-michal" -d '{"k": 5, "timeout": 3, "roles": ["user"], "messages": ["on what exact date did the 21st century begin?"]}'
|
|
|
|
|
|
|
27 |
```
|
28 |
|
29 |
TROUBLESHOOT
|
@@ -31,11 +35,17 @@ check if port is open
|
|
31 |
```
|
32 |
sudo ufw allow 10000/tcp
|
33 |
sudo ufw allow 10000/tcp
|
34 |
-
```
|
35 |
# run
|
36 |
```
|
37 |
EXPECTED_ACCESS_KEY="hey-michal" pm2 start app.py --interpreter python3 --name app -- --neuron.model_id mock --wallet.name sn1 --wallet.hotkey v1 --netuid 1 --neuron.tasks math --neuron.task_p 1 --neuron.device cpu
|
38 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
"""
|
40 |
|
41 |
EXPECTED_ACCESS_KEY = os.environ.get('EXPECTED_ACCESS_KEY')
|
@@ -210,6 +220,62 @@ async def chat(request: web.Request) -> Response:
|
|
210 |
|
211 |
|
212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
|
214 |
class ValidatorApplication(web.Application):
|
215 |
def __init__(self, *a, **kw):
|
@@ -218,7 +284,10 @@ class ValidatorApplication(web.Application):
|
|
218 |
|
219 |
|
220 |
validator_app = ValidatorApplication()
|
221 |
-
validator_app.add_routes([
|
|
|
|
|
|
|
222 |
|
223 |
bt.logging.info("Starting validator application.")
|
224 |
bt.logging.info(validator_app)
|
|
|
3 |
|
4 |
import os
|
5 |
import re
|
6 |
+
import time
|
7 |
import asyncio
|
8 |
import json
|
9 |
import traceback
|
|
|
25 |
curl -X POST http://0.0.0.0:10000/chat/ -H "api_key: hello" -d '{"k": 5, "timeout": 3, "roles": ["user"], "messages": ["hello world"]}'
|
26 |
|
27 |
curl -X POST http://0.0.0.0:10000/chat/ -H "api_key: hey-michal" -d '{"k": 5, "timeout": 3, "roles": ["user"], "messages": ["on what exact date did the 21st century begin?"]}'
|
28 |
+
|
29 |
+
# stream
|
30 |
+
curl --no-buffer -X POST http://129.146.127.82:10000/echo/ -H "api_key: hey-michal" -d '{"k": 3, "timeout": 0.2, "roles": ["user"], "messages": ["i need to tell you something important but first"]}'
|
31 |
```
|
32 |
|
33 |
TROUBLESHOOT
|
|
|
35 |
```
|
36 |
sudo ufw allow 10000/tcp
|
37 |
sudo ufw allow 10000/tcp
|
38 |
+
```
|
39 |
# run
|
40 |
```
|
41 |
EXPECTED_ACCESS_KEY="hey-michal" pm2 start app.py --interpreter python3 --name app -- --neuron.model_id mock --wallet.name sn1 --wallet.hotkey v1 --netuid 1 --neuron.tasks math --neuron.task_p 1 --neuron.device cpu
|
42 |
```
|
43 |
+
|
44 |
+
basic testing
|
45 |
+
```
|
46 |
+
EXPECTED_ACCESS_KEY="hey-michal" python app.py --neuron.model_id mock --wallet.name sn1 --wallet.hotkey v1 --netuid 1 --neuron.tasks math --neuron.task_p 1 --neuron.device cpu
|
47 |
+
```
|
48 |
+
add --mock to test the echo stream
|
49 |
"""
|
50 |
|
51 |
EXPECTED_ACCESS_KEY = os.environ.get('EXPECTED_ACCESS_KEY')
|
|
|
220 |
|
221 |
|
222 |
|
223 |
+
async def echo_stream(request):
|
224 |
+
|
225 |
+
bt.logging.info(f'echo_stream()')
|
226 |
+
# Check access key
|
227 |
+
access_key = request.headers.get("api_key")
|
228 |
+
if EXPECTED_ACCESS_KEY is not None and access_key != EXPECTED_ACCESS_KEY:
|
229 |
+
bt.logging.error(f'Invalid access key: {access_key}')
|
230 |
+
return Response(status=401, reason="Invalid access key")
|
231 |
+
|
232 |
+
try:
|
233 |
+
request_data = await request.json()
|
234 |
+
except ValueError:
|
235 |
+
bt.logging.error(f'Invalid request data: {request_data}')
|
236 |
+
return Response(status=400)
|
237 |
+
|
238 |
+
bt.logging.info(f'Request data: {request_data}')
|
239 |
+
k = request_data.get('k', 1)
|
240 |
+
exclude = request_data.get('exclude', [])
|
241 |
+
timeout = request_data.get('timeout', 0.2)
|
242 |
+
message = '\n\n'.join(request_data['messages'])
|
243 |
+
|
244 |
+
# Create a StreamResponse
|
245 |
+
response = web.StreamResponse(status=200, reason='OK', headers={'Content-Type': 'text/plain'})
|
246 |
+
await response.prepare(request)
|
247 |
+
|
248 |
+
completion = ''
|
249 |
+
# Echo the message k times with a timeout between each chunk
|
250 |
+
for _ in range(k):
|
251 |
+
for word in message.split():
|
252 |
+
chunk = f'{word} '
|
253 |
+
await response.write(chunk.encode('utf-8'))
|
254 |
+
completion += chunk
|
255 |
+
time.sleep(timeout)
|
256 |
+
bt.logging.info(f"Echoed: {chunk}")
|
257 |
+
|
258 |
+
completion = completion.strip()
|
259 |
+
|
260 |
+
# Prepare final JSON chunk
|
261 |
+
json_chunk = json.dumps({
|
262 |
+
"uids": [0],
|
263 |
+
"completion": completion,
|
264 |
+
"completions": [completion.strip()],
|
265 |
+
"timings": [0],
|
266 |
+
"status_messages": ['Went well!'],
|
267 |
+
"status_codes": [200],
|
268 |
+
"completion_is_valid": [True],
|
269 |
+
"task_name": 'echo',
|
270 |
+
"ensemble_result": {}
|
271 |
+
})
|
272 |
+
|
273 |
+
# Send the final JSON as part of the stream
|
274 |
+
await response.write(f"\n\nJSON_RESPONSE_BEGIN:\n{json_chunk}".encode('utf-8'))
|
275 |
+
|
276 |
+
# Finalize the response
|
277 |
+
await response.write_eof()
|
278 |
+
return response
|
279 |
|
280 |
class ValidatorApplication(web.Application):
|
281 |
def __init__(self, *a, **kw):
|
|
|
284 |
|
285 |
|
286 |
validator_app = ValidatorApplication()
|
287 |
+
validator_app.add_routes([
|
288 |
+
web.post('/chat/', chat),
|
289 |
+
web.post('/echo/', echo_stream)
|
290 |
+
])
|
291 |
|
292 |
bt.logging.info("Starting validator application.")
|
293 |
bt.logging.info(validator_app)
|