| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import os
- import time
- import subprocess
- import sys
- import argparse
- import time
- from openai import OpenAI
- def fetch_generator(statement, model, maxtokens):
- APIKEY = os.environ.get('DEEPSEEK_API_KEY')
- if not APIKEY:
- raise Exception('需要设置 DEEPSEEK_API_KEY 环境变量')
- client = OpenAI(
- api_key=APIKEY,
- base_url='https://api.deepseek.com')
- start_time = time.time()
- msgs = [{ 'role': 'user', 'content':
- """
- 请根据以下信息学竞赛题目生成数据生成器。只输出 gen.py 代码。
- 要求:
- 1. 解析题目中的输入格式、数据范围和子任务划分
- 2. 创建 data/ 目录并生成所有 .in 文件
- 3. 数据严格符合题目约束
- 4. 使用合理的数据梯度,包含边界情况
- 5. 数据文件名一定为 'data{编号}.in',编号不含前导零
- 6. 没有子任务的,数据文件直接放在 data/ 下;有子任务的,为每个子任务创建 subtask{编号}/ 目录,把数据文件移动到对应的子任务目录中
- 7. 数据点在 10 到 20 个内
- 8. 务必确保你给出的数据是正确的!
- 输出只包含可以直接运行的 gen.py 的代码,无其他内容。
- 题目描述:""" + statement}]
- resp = client.chat.completions.create(
- model=model,
- messages=msgs,
- stream=True,
- temperature=0.0,
- max_tokens=maxtokens)
- response = ''
- for c in resp:
- d = c.choices[0].delta
- if hasattr(d, 'reasoning_content') and d.reasoning_content is not None:
- delta = d.reasoning_content
- elif hasattr(d, 'content') and d.content is not None:
- delta = d.content
- if response == '':
- delta = '\nThinking done\n' + delta
- response += d.content
- else:
- continue
-
- with open('stream', 'a') as f:
- f.write(delta)
- if hasattr(c, 'usage') and c.usage:
- tokens = c.usage
- if response.startswith('```python'):
- response = response[9:-3]
- return (response, tokens, time.time() - start_time)
- def execute(s):
- print('正在执行命令:', s)
- try:
- subprocess.run(['sh', '-c', s], check=True, timeout=20)
- except subprocess.CalledProcessError as e:
- raise Exception('命令执行错误')
- except subprocess.TimeoutExpired:
- raise Exception('命令执行超时(20s)')
- def generate_in():
- # 其实应该用个沙盒比较安全,但是我懒得写了。可以最后扔到容器里头跑。
- execute('python gen.py')
- def flatten_data():
- execute('find -type f | xargs -I {} mv -n {} . || true')
- execute('rmdir subtask* || true')
- def run_std():
- if not os.path.exists('../std.cpp'):
- raise Exception('未找到 std.cpp')
- execute('g++ ../std.cpp -o std -Wall -Wextra -O2 -std=c++14')
- for i in os.listdir():
- if not i.endswith('.in'):
- print(f'警告:未知文件 {i}')
- continue
- out = i[:-2] + 'ans'
- execute(f'./std < {i} > {out}')
- execute('rm std')
- def gen_problem_conf(time, mem):
- execute(f'python ../autoconf.py {time} {mem}')
- def compress_data():
- execute('zip ../data.zip -r .')
- def cleanup():
- os.chdir('..')
- execute('rm -r data/')
- def pretty_size(d):
- if d < 1024:
- return f'{d}'
- if d < 1048576:
- return f'{d/1024:.2f} KB'
- return f'{d/1048576:.2f} MB'
- if __name__ == '__main__':
- start_time = time.time()
- parser = argparse.ArgumentParser()
- parser.add_argument('statement', help='题面文件')
- parser.add_argument('--model', type=str, default='deepseek-v4-pro', help='使用的模型(默认为 deepseek-v4-pro,可以改为 deepseek-v4-flash)')
- parser.add_argument('--maxtokens', type=int, default=20000, help='token 上限(默认为 20000)')
- parser.add_argument('--time', type=int, default=1, help='时间限制(秒,默认为 1)')
- parser.add_argument('--mem', type=int, default=256, help='空间限制(MB,默认为 256)')
- parser.add_argument('--offline', help='不生成新的 gen.py', action='store_true')
- args = parser.parse_args()
- if os.path.exists('data'):
- print('正在清空已有的 data 目录')
- execute('rm -r data')
- if os.path.exists('data.zip'):
- print('删除已存在的 data.zip')
- execute('rm data.zip')
- tokens = 0
- with open(args.statement) as f:
- if not args.offline:
- print(f'正在请求 {args.model},token 上限为 {args.maxtokens} 个')
- resp, tokens, duration = fetch_generator(f.read(), args.model, args.maxtokens)
- with open('gen.py', 'w') as fw:
- fw.write(resp)
- print(f'--- tokens: {tokens}, time cost: {duration:.6f} seconds')
- else:
- if not os.path.exists('gen.py'):
- raise Exception('离线模式下必须提供已有的 gen.py')
- print('(离线模式)')
- generate_in()
- os.chdir('data')
- gen_problem_conf(args.time, args.mem)
- # run_std 需要一个扁平的目录,也就是所有文件放在 data/ 下,而 autoconf.py 不要求这么做
- flatten_data()
- run_std()
- compress_data()
- cleanup()
- prettysize = pretty_size(os.path.getsize('data.zip'))
- print(f'已生成 data.zip({prettysize}),耗时 {(time.time() - start_time):.2f} 秒,消耗 {tokens} 个 token')
|