需求分析
作为合格的AI竞赛平台,EvalAI支持组织者创建比赛,比赛的定义标准已经在EvalAI-starters中进行声明,组织者只需要根据文档修改后上传即可,其提供了两种上传方式,一种为在github创建fork修改由服务器拉取,而另一种是运行run.sh后打包本地的修改后的配置文件为一个压缩文件,然后上传。 问:如何解析这个压缩文件?
问题分析
通过压缩文件创建比赛,那么我们需要提前定义好比赛的模型,并根据相应模型提供可用的配置信息,在压缩文件上传后我们需要对其解压后分析其中所需的文件是否存在,不存在则返回错误信息。
使用库包
处理逻辑
1. 基本模型定义
ChallengeConfiguration 提供user、challenge、zip_configuration等字段。 其中user关联用户模型,challenge关联比赛模型。
模型定义
@deconstructible
class RandomFileName(object):
def __init__(self, path):
self.path = path
def __call__(self, instance, filename):
extension = os.path.splitext(filename)[1]
path = self.path
if "id" in self.path and instance.pk:
path = self.path.format(id=instance.pk)
filename = "{}{}".format(uuid.uuid4(), extension)
filename = os.path.join(path, filename)
return filename
class ChallengeConfiguration(TimeStampedModel):
user = models.ForeignKey(User, on_delete=models.CASCADE)
challenge = models.OneToOneField(
Challenge, null=True, blank=True, on_delete=models.CASCADE
)
zip_configuration = models.FileField(
upload_to=RandomFileName("zip_configuration_files/challenge_zip")
)
...
序列化模型
ChallengeConfigSerializer 接收zip_configuration和user两个参数。
class ChallengeConfigSerializer(serializers.ModelSerializer):
"""
Serialize the ChallengeConfiguration Model.
"""
def __init__(self, *args, **kwargs):
super(ChallengeConfigSerializer, self).__init__(*args, **kwargs)
context = kwargs.get("context")
if context:
request = context.get("request")
kwargs["data"]["user"] = request.user.pk
class Meta:
model = ChallengeConfiguration
fields = ("zip_configuration", "user")
2. 开始处理上传压缩文件
上传的zip_configuration 字段的值表示上传文件。
流程:
- 创建临时文件夹
- 传入序列化模型获取文件保存地址
- 请求文件地址保存到唯一文件夹下
- 解压文件到同一文件夹下
- 开始解析内容
@api_view(["POST"])
...
def create_challenge_using_zip_file(request, challenge_host_team_pk):
...
BASE_LOCATION = tempfile.mkdtemp()
...
data = request.data.copy()
serializer = ChallengeConfigSerializer(data=data, context={"request": request})
if serializer.is_valid():
uploaded_zip_file = serializer.save()
uploaded_zip_file_path = serializer.data["zip_configuration"]
else:
response_data = serializer.errors
return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
try:
response = requests.get(uploaded_zip_file_path, stream=True)
unique_folder_name = get_unique_alpha_numeric_key(10)
CHALLENGE_ZIP_DOWNLOAD_LOCATION = os.path.join(
BASE_LOCATION, "{}.zip".format(unique_folder_name))
try:
if response and response.status_code == 200:
with open(CHALLENGE_ZIP_DOWNLOAD_LOCATION, "wb") as zip_file:
zip_file.write(response.content)
except IOError:
...
except requests.exceptions.RequestException:
...
try:
zip_ref = zipfile.ZipFile(CHALLENGE_ZIP_DOWNLOAD_LOCATION, "r")
zip_ref.extractll(os.path.join(BASE_LOCATION, unique_folder_name))
zip_ref.close()
except zipfile.BadZipfile:
...
...
for name in zip_ref.namelist():
if (name.endswith(".yaml") or name.endswith(".yml")) and (not name.startswith("__MACOSX")):
yaml_file = name
...
if os.path.isfile(evaluation_script_path):
with open(evaluation_script_path, "rb") as challenge_evaluation_script:
...
...
|