使用更高效的api, 节约用时

This commit is contained in:
somunslotus 2024-06-27 14:24:38 +08:00
parent 16c1fb7b7b
commit 32be98f230
3 changed files with 194 additions and 2 deletions

View File

@ -12,6 +12,6 @@ RUN pip install httpx -i https://pypi.tuna.tsinghua.edu.cn/simple
ENV http_proxy=""
ENV https_proxy=""
COPY server.py /app/server.py
COPY aim_proxy.py /app/server.py
ENTRYPOINT ["python", "server.py"]

192
aim_proxy.py Normal file
View File

@ -0,0 +1,192 @@
from aim.storage.treeutils import decode_tree
from fastapi import FastAPI, HTTPException, Request
import httpx
import traceback
import uvicorn
import json
from typing import Iterator
import struct
from pydantic import BaseModel
from typing import List
from aim.sdk.repo import Repo
import os
import logging
import time
app = FastAPI()
# 设置日志格式
logging.basicConfig(level=logging.INFO)
@app.middleware("http")
async def log_request_time(request: Request, call_next):
start_time = time.time() # 记录请求开始时间
response = await call_next(request) # 处理请求
process_time = time.time() - start_time # 计算处理时间
logging.info(f"Request {request.method} {request.url} completed in {process_time:.4f} seconds")
return response # 返回响应
def is_running_in_kubernetes():
return 'KUBERNETES_SERVICE_HOST' in os.environ and 'KUBERNETES_SERVICE_PORT' in os.environ
if is_running_in_kubernetes():
print("Running in Kubernetes environment")
repo_path = 'aim://my-aim-server-service.aim:53800'
host = 'http://my-aim-ui-service.aim:43800'
else:
repo_path = 'aim://172.20.32.181:30058'
host = 'http://172.20.32.181:30059'
print("Not running in Kubernetes environment")
api_url = f'{host}/api/runs/search/run/'
delete_url = f'{host}/api/runs/delete-batch'
# 打开 Aim repository
repo = Repo(path=repo_path)
@app.get("/api/runs/search/run")
async def search_runs(query: str = None, offset: str = None, limit: int = 45):
try:
print("query is ", query)
print("offset is ", offset)
print("limit is ", limit)
query_url = f'{api_url}?q={query}&limit={limit}&offset={offset}'
print("query_url is ", query_url)
data = await fetch_run_data(query_url)
result = parse_run_data(data)
return result
except Exception as e:
print(f"An error occurred while searching runs: {str(e)}")
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
# 定义请求体模型
class RunDeleteRequest(BaseModel):
run_hashes: List[str]
@app.post("/api/runs/delete-batch/run")
async def delete_runs(request: RunDeleteRequest):
try:
if not request.run_hashes:
raise HTTPException(status_code=400, detail="run_hash is required")
async with httpx.AsyncClient() as client:
run_hashes = request.run_hashes
print("delete url is ", delete_url)
print("run_hashes is ", run_hashes)
response = await client.post(delete_url, json=run_hashes)
response.raise_for_status() # 如果响应状态码不是 200则引发异常
return {"message": "Runs deleted successfully"}
except httpx.HTTPStatusError as e:
print(f"HTTP error occurred: {e.response.status_code}")
print(e.response.text)
except Exception as e:
print(f"An error occurred: {str(e)}")
def decode_encoded_tree_stream(stream: Iterator[bytes], concat_chunks=False) -> bytes:
# TODO: handle case when chunk ends at the middle of key/value
# TODO: if remaining part of chunk cannot be unpacked, prepend to next one and try with new chunk
prev_chunk_tail = b''
if concat_chunks:
data = b''
for chunk in stream:
data += chunk
while data:
(key_size,), data_tail = struct.unpack('I', data[:4]), data[4:]
key, data_tail = data_tail[:key_size], data_tail[key_size:]
(value_size,), data_tail = struct.unpack('I', data_tail[:4]), data_tail[4:]
value, data_tail = data_tail[:value_size], data_tail[value_size:]
data = data_tail
yield key, value
else:
for chunk in stream:
data = prev_chunk_tail + chunk
prev_chunk_tail = b''
while data:
try:
(key_size,), data_tail = struct.unpack('I', data[:4]), data[4:]
key, data_tail = data_tail[:key_size], data_tail[key_size:]
(value_size,), data_tail = struct.unpack('I', data_tail[:4]), data_tail[4:]
value, data_tail = data_tail[:value_size], data_tail[value_size:]
data = data_tail
except Exception:
prev_chunk_tail = data
break
yield key, value
assert prev_chunk_tail == b''
async def fetch_run_data(api_url: str, query: str = '', limit: int = 45):
try:
params = {
'q': query,
'limit': limit
}
async with httpx.AsyncClient() as client:
response = await client.get(api_url, params=params)
response.raise_for_status() # 如果响应状态码不是 200则引发异常
decoded_response = decode_tree(decode_encoded_tree_stream(response.iter_bytes(chunk_size=512 * 1024)))
return decoded_response
except httpx.HTTPStatusError as e:
print(f"HTTP error occurred: {e.response.status_code}")
print(e.response.text)
except Exception as e:
print(f"An error occurred: {str(e)}")
def process_metrics(hash, data):
# 过滤掉名字以 __system 开头的 metric
filtered_metrics = [metric for metric in data['traces']['metric'] if not metric['name'].startswith('__system')]
# 给剩余的 metric 添加 last_value 键
for metric in filtered_metrics:
metric['last_value'] = metric['values']['last']
# 更新数据中的 metric 列表
data['traces']['metric'] = filtered_metrics
data['run_hash'] = hash
return data
def parse_run_data(decoded_response):
try:
if not decoded_response:
print("No data to parse")
return
result = []
for i, run in decoded_response.items():
print(f"Run {i}:")
if i.startswith('progress'):
continue
run = process_metrics(i, run)
print("data is ", json.dumps(run, indent=4))
result.append(run)
print("result is ", json.dumps(result, indent=4))
return result
except Exception as e:
print(f"An error occurred while parsing data: {str(e)}")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7123)

View File

@ -5,7 +5,7 @@ import random
# 循环运行30次
for i in range(30):
for i in range(80):
expriment_name="experiment-0000"
# experiment_id 为随机uuid字符串
experiment_id= str(uuid.uuid4())