Skip to content

Commit f1b0059

Browse files
committed
fix: issue #10
1 parent 53cf22f commit f1b0059

File tree

19 files changed

+1230
-785
lines changed

19 files changed

+1230
-785
lines changed

backend/api/api_upload.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from typing import List, Optional
77

8-
from fastapi import APIRouter, File, Request, UploadFile
8+
from fastapi import APIRouter, File, Form, Request, UploadFile
99

1010
from model.upload import UploadFileRsp
1111
from service.upload_service import upload_file_svc
@@ -17,25 +17,25 @@
1717
@router.post("", response_model=UploadFileRsp)
1818
async def upload_file(
1919
request: Request,
20-
type: str = "cert",
21-
cert_type: str = "cert_file",
2220
task_id: Optional[str] = None,
23-
file: List[UploadFile] = File(..., description="The file(s) to upload"),
21+
file_type: Optional[str] = "dataset",
22+
cert_type: Optional[str] = "cert_file",
23+
files: List[UploadFile] = File(..., description="The file(s) to upload"),
2424
):
2525
"""
2626
Upload one or more files.
2727
2828
This endpoint handles file uploads and can be used for different purposes
29-
based on the 'type' parameter. For example, it can be used to upload
29+
based on the 'file_type' parameter. For example, it can be used to upload
3030
certificates or files related to a specific task.
3131
3232
Args:
33-
type (str): The type of upload (e.g., "cert"). Defaults to "cert".
34-
cert_type (str): The specific type of certificate. Defaults to "cert_file".
35-
task_id (str, optional): The ID of the task to associate the upload with. Defaults to None.
36-
file (List[UploadFile]): A list of files to be uploaded.
33+
file_type (str, optional): The type of upload (e.g., "cert", "dataset").
34+
cert_type (str, optional): The specific type of certificate. Only used for cert uploads.
35+
task_id (str, optional): The ID of the task to associate the upload with.
36+
files (List[UploadFile]): A list of files to be uploaded.
3737
3838
Returns:
3939
UploadFileRsp: A response object confirming the file upload.
4040
"""
41-
return await upload_file_svc(request, file, type, cert_type, task_id)
41+
return await upload_file_svc(request, task_id, file_type, cert_type, files)

backend/db/init_db.sql

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
SET NAMES utf8mb4;
2+
SET FOREIGN_KEY_CHECKS = 0;
3+
-- 确保数据库存在并使用该数据库
4+
CREATE DATABASE IF NOT EXISTS lmeterx;
5+
USE lmeterx;
6+
7+
-- ----------------------------
8+
-- Table structure for tasks
9+
-- ----------------------------
10+
DROP TABLE IF EXISTS `tasks`;
11+
CREATE TABLE `tasks` (
12+
`id` varchar(36) COLLATE utf8mb4_unicode_ci NOT NULL,
13+
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
14+
`status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'idle',
15+
`target_host` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
16+
`model` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
17+
`system_prompt` longtext COLLATE utf8mb4_unicode_ci,
18+
`user_prompt` longtext COLLATE utf8mb4_unicode_ci,
19+
`stream_mode` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'True',
20+
`concurrent_users` int(11) DEFAULT '1',
21+
`spawn_rate` int(11) DEFAULT '0',
22+
`duration` int(11) DEFAULT '60',
23+
`chat_type` int(11) DEFAULT '0',
24+
`log_file` longtext COLLATE utf8mb4_unicode_ci,
25+
`result_file` longtext COLLATE utf8mb4_unicode_ci,
26+
`cert_file` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
27+
`key_file` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
28+
`headers` json DEFAULT NULL,
29+
`error_message` text COLLATE utf8mb4_unicode_ci,
30+
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
31+
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
32+
`api_path` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'API路径',
33+
PRIMARY KEY (`id`),
34+
KEY `idx_status_created` (`status`,`created_at`),
35+
KEY `idx_updated_at` (`updated_at`),
36+
KEY `idx_name` (`name`),
37+
KEY `idx_status` (`status`),
38+
KEY `idx_created_at` (`created_at`)
39+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
40+
41+
-- ----------------------------
42+
-- Table structure for task_results
43+
-- ----------------------------
44+
DROP TABLE IF EXISTS `task_results`;
45+
CREATE TABLE `task_results` (
46+
`id` int(11) NOT NULL AUTO_INCREMENT,
47+
`task_id` varchar(36) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务ID',
48+
`metric_type` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '指标类型',
49+
`num_requests` int(11) DEFAULT '0' COMMENT '请求总数量',
50+
`num_failures` int(11) DEFAULT '0' COMMENT '请求失败数量',
51+
`avg_latency` float DEFAULT '0' COMMENT '请求平均响应时间',
52+
`min_latency` float DEFAULT '0' COMMENT '请求最小响应时间',
53+
`max_latency` float DEFAULT '0' COMMENT '请求最大响应时间',
54+
`median_latency` float DEFAULT '0' COMMENT '请求中位响应时间',
55+
`p90_latency` float DEFAULT '0' COMMENT '请求90%响应时间',
56+
`rps` float DEFAULT '0' COMMENT '每秒请求数',
57+
`avg_content_length` float DEFAULT '0' COMMENT '平均输出的字符长度',
58+
`completion_tps` float DEFAULT '0' COMMENT '每秒输出的token数量',
59+
`total_tps` float DEFAULT '0' COMMENT '每秒输入输出的总token数量',
60+
`avg_total_tokens_per_req` float DEFAULT '0' COMMENT '每个请求的平均输入输出的总token数量',
61+
`avg_completion_tokens_per_req` float DEFAULT '0' COMMENT '每个请求的平均输出token数量',
62+
`created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
63+
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
64+
PRIMARY KEY (`id`),
65+
KEY `idx_task_id` (`task_id`)
66+
) ENGINE=InnoDB AUTO_INCREMENT=262 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
67+
68+
-- 最后重新启用外键检查
69+
SET FOREIGN_KEY_CHECKS = 1;

backend/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ greenlet
1010
werkzeug
1111
python-multipart
1212
httpx
13+
python-magic

backend/service/task_service.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import json
7+
import os
78
import time
89
import uuid
910
from typing import Dict, List, Optional, Tuple, Union
@@ -61,13 +62,13 @@ def _normalize_file_path(file_path: str) -> str:
6162

6263
def _get_cert_config(body: TaskCreateReq) -> Tuple[str, str]:
6364
"""
64-
Get and normalize certificate configuration from the request body.
65+
Get certificate configuration from the request body.
6566
6667
Args:
6768
body: The task creation request body
6869
6970
Returns:
70-
A tuple of (cert_file, key_file) normalized paths
71+
A tuple of (cert_file, key_file) absolute paths
7172
"""
7273
cert_file = ""
7374
key_file = ""
@@ -83,10 +84,6 @@ def _get_cert_config(body: TaskCreateReq) -> Tuple[str, str]:
8384
cert_file = cert_config.get("cert_file", "")
8485
key_file = cert_config.get("key_file", "")
8586

86-
# Normalize paths
87-
cert_file = _normalize_file_path(cert_file)
88-
key_file = _normalize_file_path(key_file)
89-
9087
return cert_file, key_file
9188

9289

@@ -327,15 +324,8 @@ async def create_task_svc(request: Request, body: TaskCreateReq):
327324
}
328325
cookies_json = json.dumps(cookies)
329326

330-
# Normalize test_data path to ensure cross-service compatibility
327+
# Use test_data as provided (should be absolute path from upload service)
331328
test_data = body.test_data or ""
332-
if (
333-
test_data
334-
and not test_data.strip().lower() in ("", "default")
335-
and not test_data.strip().startswith("{")
336-
):
337-
# If test_data is a file path, convert it to relative path
338-
test_data = _normalize_file_path(test_data)
339329

340330
db = request.state.db
341331
try:
@@ -848,11 +838,25 @@ def _prepare_request_payload(body: TaskCreateReq) -> Dict:
848838
def _prepare_client_cert(body: TaskCreateReq):
849839
"""Prepare SSL certificate configuration for the HTTP client."""
850840
client_cert: Optional[Union[str, Tuple[str, str]]] = None
851-
if hasattr(body, "cert_config") and body.cert_config:
852-
if body.cert_config.cert_file and body.cert_config.key_file:
853-
client_cert = (body.cert_config.cert_file, body.cert_config.key_file)
854-
elif body.cert_config.cert_file:
855-
client_cert = body.cert_config.cert_file
841+
842+
# Get certificate configuration
843+
cert_file, key_file = _get_cert_config(body)
844+
845+
# Use absolute paths directly from upload service
846+
if cert_file or key_file:
847+
try:
848+
if cert_file and key_file:
849+
# Both cert and key files provided
850+
if os.path.exists(cert_file) and os.path.exists(key_file):
851+
client_cert = (cert_file, key_file)
852+
elif cert_file:
853+
# Only cert file provided (combined cert+key file)
854+
if os.path.exists(cert_file):
855+
client_cert = cert_file
856+
except Exception as e:
857+
logger.error(f"Error preparing certificate configuration: {e}")
858+
return None
859+
856860
return client_cert
857861

858862

@@ -1016,8 +1020,8 @@ async def _handle_streaming_response(response, full_url: str) -> Dict:
10161020
}
10171021

10181022
# For testing purposes, we limit the time and data we collect
1019-
max_chunks = 300 # max chunks to collect for testing
1020-
max_duration = 15 # max duration to wait for testing
1023+
max_chunks = 5000 # max chunks to collect for testing
1024+
max_duration = 60 # max duration to wait for testing
10211025

10221026
start_time = asyncio.get_event_loop().time()
10231027

0 commit comments

Comments
 (0)