对diagnose重构了一下

This commit is contained in:
pzc-x99 2025-03-01 00:23:43 +08:00
parent f56b66d8f1
commit fa00e1d19d
12 changed files with 342 additions and 186 deletions

View File

Before

Width:  |  Height:  |  Size: 928 KiB

After

Width:  |  Height:  |  Size: 928 KiB

View File

@ -1,9 +1,12 @@
from django.contrib import admin from django.contrib import admin
# Register your models here. # Register your models here.
from . models import Papers from . models import Papers, OpenAIDiagnose
@admin.register(Papers) @admin.register(Papers)
class PaperAdmin(admin.ModelAdmin): class PaperAdmin(admin.ModelAdmin):
list_display = ('id', 'uuid', 'status', 'created_at', 'updated_at') list_display = ('id', 'uuid', 'status', 'created_at', 'updated_at')
@admin.register(OpenAIDiagnose)
class OpenAIDiagnoseAdmin(admin.ModelAdmin):
list_display = ('id', 'uuid', 'status', 'diagnose_type', 'created_at', 'updated_at')

69
diagnose/db_views.py Normal file
View File

@ -0,0 +1,69 @@
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from authentication.authentication import CustomTokenAuthentication
import uuid
import os
from django.conf import settings
from django.http import JsonResponse
from rest_framework import status
from .models import OpenAIDiagnose
from .openai_dia import openai_diagnoser_asyna_wraper
from django.core.exceptions import ObjectDoesNotExist
import json
class MyProtectedUploadDiagnose(APIView):
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
def post(self, request):
user = request.user
uuid_str = str(uuid.uuid4())
save_file_path = os.path.join(settings.BASE_DIR, 'upload_file', user.username, uuid_str)
os.makedirs(os.path.dirname(save_file_path), exist_ok=True)
# 获取上传的文件
uploaded_file = request.FILES.get('file')
if not uploaded_file:
return JsonResponse({"error": "No file uploaded."}, status=status.HTTP_400_BAD_REQUEST)
# 保存文件
try:
with open(save_file_path, 'wb+') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
except:
return JsonResponse({"error": "Error saving file."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
obj = OpenAIDiagnose.objects.create(uuid=uuid_str, user=user, status='P')
obj.save()
user.subject_usage_count = user.subject_usage_count - 1
user.save()
openai_diagnoser_asyna_wraper.delay(uuid_str, user.username, "")
return JsonResponse({"message": "File uploaded successfully.", "uuid": uuid_str}, status=status.HTTP_200_OK)
class MyProtectedDiagnoseCheck(APIView):
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
def post(self, request):
user = request.user
# 处理 POST 请求,更新用户的联系信息
try:
data = json.loads(request.body)
uuid_str = data.get("uuid")
except json.JSONDecodeError:
return JsonResponse({"error": "Invalid JSON format"}, status=400)
try:
# print(uuid_str)
obj = OpenAIDiagnose.objects.get(uuid=uuid_str, user=user) # 只获取一个对象
if obj.status == 'D':
return JsonResponse({"status": "done"})
else:
return JsonResponse({"status": "processing"})
except ObjectDoesNotExist:
return JsonResponse({"error_code": "2004"}, status=404)

View File

@ -1,14 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
from openai import OpenAI
import markdown2
import pdfkit
from django.conf import settings from django.conf import settings
from django.http import JsonResponse, FileResponse from django.http import JsonResponse, FileResponse
from celery import shared_task
import uuid import uuid
from django.utils import timezone
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from authentication.authentication import CustomTokenAuthentication from authentication.authentication import CustomTokenAuthentication
@ -16,6 +11,8 @@ from django.core.exceptions import ObjectDoesNotExist
from .models import Papers from .models import Papers
from ec_user.models import SchoolInfo from ec_user.models import SchoolInfo
import json import json
from .openai_gen import paper_gen_async_wraper, convert_to_pdf
# ============== PYdoc =================== # ============== PYdoc ===================
# from docx import Document # from docx import Document
# import pypandoc # import pypandoc
@ -57,101 +54,6 @@ class DpArguments():
def generate_html_paper(md_result, file_path_name):
# 写到md中
md_file = open(f'{file_path_name}.md', 'w', encoding='utf-8')
md_file.write(md_result)
md_file.close()
# 从md中读出来再写到html中
md_read_file = open(f'{file_path_name}.md', 'r', encoding='utf-8')
md_text = md_read_file.read()
md_read_file.close()
html = markdown2.markdown(md_text)
html_write_file = open(f'{file_path_name}.html', 'w', encoding='utf-8')
html_write_file.write(
"""<head>
<meta charset="utf-8">
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
</head>"""+html)
html_write_file.close()
def convert_to_pdf(file_path_name):
# =============== pdfkit ================
# 从html中读出来再写到pdf中
f = open(f'{file_path_name}.html', 'r', encoding='utf-8')
content = f.read()
f.close()
config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)
pdfkit.from_string(content, f'{file_path_name}.pdf', configuration=config)
@shared_task
def async_wraper(file_path_name, uuid_str, subject, textbook_version, start_grade, \
start_semester, start_chapter, end_grade, end_semester, end_chapter, student):
# client = OpenAI(
# api_key = settings.OPAI_API_KEY,
# base_url = settings.OPAI_BASE_URL,
# )
# completion = client.chat.completions.create(
# model = "deepseek-r1-250120", # your model endpoint ID
# messages = [
# {"role": "system", "content": "你是教学助手"},
# # {"role": "user",
# # "content": f"请根据以下信息生成一份检测卷:学科为{subject},教材版本是{textbook_version},\
# # 检测范围从{start_grade}年级{start_semester}学期{start_chapter}章\
# # 到{end_grade}年级{end_semester}学期{end_chapter}章,学生年级为{student.get('grade')},\
# # 年龄为{student.get('age')},所在学校是{student.get('school')}。\
# # 根据答题所需时间一个半小时设置题量。题目有梯度。\
# # 试卷题目为{subject}{textbook_version}检测卷。只生成题目,不输出答案及说明等其他内容。"
# # },
# {"role": "user", "content": f"""请严格按照以下要求生成一份{subject}检测卷:
# 【试卷信息】
# 1. 标题:**{subject}{textbook_version}综合检测卷**
# 2. 检测范围:{start_grade}年级{start_semester}学期第{start_chapter}章 至
# {end_grade}年级{end_semester}学期第{end_chapter}章
# 3. 适用对象:{student.get('school')} {student.get('grade')}年级学生(年龄{student.get('age')}
# 【命题要求】
# 1. 题型结构:
# - 按难度梯度分为基础题60%、中档题30%、提高题10%
# - 根据学科特点设计合理的题型(如数学可设置选择题/填空题/计算题/应用题,语文可设置阅读理解/文言文/写作等)
# - 同一知识点不重复考查
# 2. 题量控制:
# - 总题数控制在18-22题以优秀学生完成时间约75分钟为标准
# - 选择题不超过5题填空题不超过6题
# - 需包含至少1道综合应用题理科或材料分析题文科
# 3. 内容要求:
# - 严格按照指定章节范围命题
# - 题目表述清晰无歧义,数字单位标注完整
# - 禁止出现需图片辅助的题目
# - 数学类题目需给出必要公式位置(如"提示可用公式____"
# 【输出格式】
# 仅输出以下内容:
# 1. 试卷标题(加粗居中)
# 2. 考试说明含总分值100分、考试时长、姓名班级填写处
# 3. 分模块的题目内容(标注题型、分值和题号)
# 4. "——以下为题目区域——" 分隔线
# 禁止包含:
# - 答案及解析
# - 评分标准
# - 额外说明文字
# - markdown格式及特殊符号"""}
# ],
# )
# generate_html_paper(completion.choices[0].message.content, file_path_name)
import time
time.sleep(30)
generate_html_paper(""" # Test md""", file_path_name)
try:
obj = Papers.objects.get(uuid=uuid_str) # 只获取一个对象
obj.status = 'D'
obj.updated_at = timezone.now()
obj.save()
except ObjectDoesNotExist:
print("warning: record not found")
class MyProtectedGeneratePaper(APIView): class MyProtectedGeneratePaper(APIView):
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证 authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
permission_classes = [IsAuthenticated] # 需要用户认证才能访问 permission_classes = [IsAuthenticated] # 需要用户认证才能访问
@ -197,7 +99,7 @@ class MyProtectedGeneratePaper(APIView):
obj.save() obj.save()
user.subject_usage_count = user.subject_usage_count - 1 user.subject_usage_count = user.subject_usage_count - 1
user.save() user.save()
async_wraper.delay(file_path_name, uuid_str, \ paper_gen_async_wraper.delay(file_path_name, uuid_str, \
dp_args.subject, dp_args.textbook_version, dp_args.start_grade, dp_args.start_semester, dp_args.start_chapter, \ dp_args.subject, dp_args.textbook_version, dp_args.start_grade, dp_args.start_semester, dp_args.start_chapter, \
dp_args.end_grade, dp_args.end_semester, dp_args.end_chapter, dp_args.student) dp_args.end_grade, dp_args.end_semester, dp_args.end_chapter, dp_args.student)
return JsonResponse({"status": "success", "uuid": uuid_str}) return JsonResponse({"status": "success", "uuid": uuid_str})

View File

@ -0,0 +1,28 @@
# Generated by Django 4.2.19 on 2025-02-28 15:39
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('diagnose', '0002_papers_created_at_papers_updated_at'),
]
operations = [
migrations.CreateModel(
name='OpenAIDiagnose',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.CharField(max_length=100)),
('status', models.CharField(choices=[('C', '任务创建'), ('P', '生成中'), ('D', '已完成')], default='C', max_length=1)),
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('diagnose_type', models.CharField(choices=[('M', '大模型试卷诊断'), ('S', '学校试卷诊断'), ('H', '作业诊断'), ('N', '课堂笔记诊断')], default='M', max_length=1)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -16,4 +16,27 @@ class Papers(models.Model):
updated_at = models.DateTimeField(auto_now=True,null=True, blank=True) # 更新时间 updated_at = models.DateTimeField(auto_now=True,null=True, blank=True) # 更新时间
def __str__(self): def __str__(self):
return self.user.username + '的试卷' return self.user.name + '的试卷'
class OpenAIDiagnose(models.Model):
STATUS_CHOICES = (
('C', '任务创建'),
('P', '生成中'),
('D', '已完成')
)
DIAGNOSE_TYPE = (
('M', '大模型试卷诊断'), # big model
('S', '学校试卷诊断'), # school
('H', '作业诊断'), # homework
('N', '课堂笔记诊断') # notebook
)
uuid = models.CharField(max_length=100) # 一次分析唯一标识符
# 定义一个与EcUser一对多关联的外键
user = models.ForeignKey(EcUser, on_delete=models.CASCADE) # 当EcUser被删除时关联的Papers也会被删除
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='C') # 默认值设置为'C'
created_at = models.DateTimeField(auto_now_add=True,null=True, blank=True) # 创建时间
updated_at = models.DateTimeField(auto_now=True,null=True, blank=True) # 更新时间
diagnose_type = models.CharField(max_length=1, choices=DIAGNOSE_TYPE, default='M') # 默认值设置为'M'
def __str__(self):
return self.user.name + '的诊断'

90
diagnose/openai_dia.py Normal file
View File

@ -0,0 +1,90 @@
import os
from openai import OpenAI
import base64
from PIL import Image
from celery import shared_task
from django.conf import settings
import markdown2
from django.utils import timezone
from .models import OpenAIDiagnose
from django.core.exceptions import ObjectDoesNotExist
def get_image_type(image_path):
with Image.open(image_path) as img:
return img.format # 返回图片的格式,例如 'PNG' 或 'JPEG'
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# 将图片转为Base64编码
def generate_html_paper(md_result, file_path_name):
# 写到md中
md_file = open(f'{file_path_name}.md', 'w', encoding='utf-8')
md_file.write(md_result)
md_file.close()
# 从md中读出来再写到html中
md_read_file = open(f'{file_path_name}.md', 'r', encoding='utf-8')
md_text = md_read_file.read()
md_read_file.close()
html = markdown2.markdown(md_text)
html_write_file = open(f'{file_path_name}.html', 'w', encoding='utf-8')
html_write_file.write(
"""<head>
<meta charset="utf-8">
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
</head>"""+html)
html_write_file.close()
@shared_task
def openai_diagnoser_asyna_wraper(uuid_str: str, username: str, diagnose_type: str):
client = OpenAI(
api_key = settings.OPAI_IMG_API_KEY,
base_url = settings.OPAI_IMG_BASE_URL
)
# 需要传给大模型的图片
# image_path = "ch.jpg"
image_path = os.path.join(settings.BASE_DIR, 'upload_file', username, uuid_str)
base64_image = encode_image(image_path)
image_type = get_image_type(image_path)
image_type = image_type.lower()
# print("===> image type:" + image_type)
# Image input:
response = client.chat.completions.create(
model="doubao-1-5-vision-pro-32k-250115",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "图中是几个题目,帮我分析一下,我是否做对了",
},
{
"type": "image_url",
"image_url": {
# 需要注意传入Base64编码前需要增加前缀 data:image/{图片格式};base64,{Base64编码}
# PNG图片"url": f"data:image/png;base64,{base64_image}"
# JEPG图片"url": f"data:image/jpeg;base64,{base64_image}"
# WEBP图片"url": f"data:image/webp;base64,{base64_image}"
"url": f"data:image/{image_type};base64,{base64_image}"
},
},
],
}
],
)
# print(response.choices[0].message.content)
generate_html_paper(response.choices[0].message.content, image_path)
try:
obj = OpenAIDiagnose.objects.get(uuid=uuid_str) # 只获取一个对象
obj.status = 'D'
obj.updated_at = timezone.now()
obj.save()
except ObjectDoesNotExist:
print("warning: record not found")

116
diagnose/openai_gen.py Normal file
View File

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
from openai import OpenAI
import markdown2
import pdfkit
from django.conf import settings
from celery import shared_task
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist
from .models import Papers
# ============== PYdoc ===================
# from docx import Document
# import pypandoc
# pypandoc.download_pandoc()
# ================ weasyprint ===========
# 库用不了
# from weasyprint import HTML
# HTML(string=html).write_pdf("output.pdf")
def generate_html_paper(md_result, file_path_name):
# 写到md中
md_file = open(f'{file_path_name}.md', 'w', encoding='utf-8')
md_file.write(md_result)
md_file.close()
# 从md中读出来再写到html中
md_read_file = open(f'{file_path_name}.md', 'r', encoding='utf-8')
md_text = md_read_file.read()
md_read_file.close()
html = markdown2.markdown(md_text)
html_write_file = open(f'{file_path_name}.html', 'w', encoding='utf-8')
html_write_file.write(
"""<head>
<meta charset="utf-8">
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
</head>"""+html)
html_write_file.close()
def convert_to_pdf(file_path_name):
# =============== pdfkit ================
# 从html中读出来再写到pdf中
f = open(f'{file_path_name}.html', 'r', encoding='utf-8')
content = f.read()
f.close()
config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)
pdfkit.from_string(content, f'{file_path_name}.pdf', configuration=config)
@shared_task
def paper_gen_async_wraper(file_path_name, uuid_str, subject, textbook_version, start_grade, \
start_semester, start_chapter, end_grade, end_semester, end_chapter, student):
# client = OpenAI(
# api_key = settings.OPAI_API_KEY,
# base_url = settings.OPAI_BASE_URL,
# )
# completion = client.chat.completions.create(
# model = "deepseek-r1-250120", # your model endpoint ID
# messages = [
# {"role": "system", "content": "你是教学助手"},
# # {"role": "user",
# # "content": f"请根据以下信息生成一份检测卷:学科为{subject},教材版本是{textbook_version},\
# # 检测范围从{start_grade}年级{start_semester}学期{start_chapter}章\
# # 到{end_grade}年级{end_semester}学期{end_chapter}章,学生年级为{student.get('grade')},\
# # 年龄为{student.get('age')},所在学校是{student.get('school')}。\
# # 根据答题所需时间一个半小时设置题量。题目有梯度。\
# # 试卷题目为{subject}{textbook_version}检测卷。只生成题目,不输出答案及说明等其他内容。"
# # },
# {"role": "user", "content": f"""请严格按照以下要求生成一份{subject}检测卷:
# 【试卷信息】
# 1. 标题:**{subject}{textbook_version}综合检测卷**
# 2. 检测范围:{start_grade}年级{start_semester}学期第{start_chapter}章 至
# {end_grade}年级{end_semester}学期第{end_chapter}章
# 3. 适用对象:{student.get('school')} {student.get('grade')}年级学生(年龄{student.get('age')}
# 【命题要求】
# 1. 题型结构:
# - 按难度梯度分为基础题60%、中档题30%、提高题10%
# - 根据学科特点设计合理的题型(如数学可设置选择题/填空题/计算题/应用题,语文可设置阅读理解/文言文/写作等)
# - 同一知识点不重复考查
# 2. 题量控制:
# - 总题数控制在18-22题以优秀学生完成时间约75分钟为标准
# - 选择题不超过5题填空题不超过6题
# - 需包含至少1道综合应用题理科或材料分析题文科
# 3. 内容要求:
# - 严格按照指定章节范围命题
# - 题目表述清晰无歧义,数字单位标注完整
# - 禁止出现需图片辅助的题目
# - 数学类题目需给出必要公式位置(如"提示可用公式____"
# 【输出格式】
# 仅输出以下内容:
# 1. 试卷标题(加粗居中)
# 2. 考试说明含总分值100分、考试时长、姓名班级填写处
# 3. 分模块的题目内容(标注题型、分值和题号)
# 4. "——以下为题目区域——" 分隔线
# 禁止包含:
# - 答案及解析
# - 评分标准
# - 额外说明文字
# - markdown格式及特殊符号"""}
# ],
# )
# generate_html_paper(completion.choices[0].message.content, file_path_name)
import time
time.sleep(30)
generate_html_paper(""" # Test md""", file_path_name)
try:
obj = Papers.objects.get(uuid=uuid_str) # 只获取一个对象
obj.status = 'D'
obj.updated_at = timezone.now()
obj.save()
except ObjectDoesNotExist:
print("warning: record not found")

View File

@ -1,43 +0,0 @@
import os
from openai import OpenAI
import base64
client = OpenAI(
api_key = 'd04d386a-7c67-4927-8251-171a236583a6',
base_url = "https://ark.cn-beijing.volces.com/api/v3",
)
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# 将图片转为Base64编码
# 需要传给大模型的图片
image_path = "ch.jpg"
base64_image = encode_image(image_path)
# Image input:
response = client.chat.completions.create(
model="doubao-1-5-vision-pro-32k-250115",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "图中是几个语文题目,帮我分析一下,我是否做对了",
},
{
"type": "image_url",
"image_url": {
# 需要注意传入Base64编码前需要增加前缀 data:image/{图片格式};base64,{Base64编码}
# PNG图片"url": f"data:image/png;base64,{base64_image}"
# JEPG图片"url": f"data:image/jpeg;base64,{base64_image}"
# WEBP图片"url": f"data:image/webp;base64,{base64_image}"
"url": f"data:image/jpg;base64,{base64_image}"
},
},
],
}
],
)
print(response.choices[0].message.content)

View File

@ -1,36 +0,0 @@
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from authentication.authentication import CustomTokenAuthentication
import uuid
import os
from django.conf import settings
from django.http import JsonResponse
from rest_framework import status
class MyProtectedUploadfile(APIView):
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
def post(self, request):
user = request.user
uuid_str = str(uuid.uuid4())
save_file_path = os.path.join(settings.BASE_DIR, 'upload_file', user.username, uuid_str)
os.makedirs(os.path.dirname(save_file_path), exist_ok=True)
# 获取上传的文件
uploaded_file = request.FILES.get('file')
if not uploaded_file:
return JsonResponse({"error": "No file uploaded."}, status=status.HTTP_400_BAD_REQUEST)
# 保存文件
try:
with open(save_file_path, 'wb+') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
except:
return JsonResponse({"error": "Error saving file."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return JsonResponse({"message": "File uploaded successfully."}, status=status.HTTP_200_OK)

View File

@ -1,11 +1,12 @@
from django.urls import path from django.urls import path
from .dp_views import MyProtectedGeneratePaper, MyProtectedGenerateCheck, MyProtectedDownloadPaper from .dp_views import MyProtectedGeneratePaper, MyProtectedGenerateCheck, MyProtectedDownloadPaper
from .upload_views import MyProtectedUploadfile from .db_views import MyProtectedUploadDiagnose, MyProtectedDiagnoseCheck
urlpatterns = [ urlpatterns = [
path('', MyProtectedGeneratePaper.as_view(), name='api_generate_paper'), path('', MyProtectedGeneratePaper.as_view(), name='api_generate_paper'),
path('check/', MyProtectedGenerateCheck.as_view(), name='api_generate_check'), path('check/', MyProtectedGenerateCheck.as_view(), name='api_generate_check'),
path('download/', MyProtectedDownloadPaper.as_view(), name='api_download_paper'), path('download/', MyProtectedDownloadPaper.as_view(), name='api_download_paper'),
path('upload/', MyProtectedUploadfile.as_view(), name='api_upload_file') path('upload/', MyProtectedUploadDiagnose.as_view(), name='api_upload_file'),
path('upload_diagnose_check/', MyProtectedDiagnoseCheck.as_view(), name='api_diagnose_file')
] ]

View File

@ -172,6 +172,9 @@ ERROR_CODE_MAP = {
OPAI_API_KEY = 'e119bd6c-a22a-404e-a002-6d72a2cea65d' OPAI_API_KEY = 'e119bd6c-a22a-404e-a002-6d72a2cea65d'
OPAI_BASE_URL = 'https://ark.cn-beijing.volces.com/api/v3' OPAI_BASE_URL = 'https://ark.cn-beijing.volces.com/api/v3'
OPAI_IMG_BASE_URL = 'https://ark.cn-beijing.volces.com/api/v3'
OPAI_IMG_API_KEY = 'd04d386a-7c67-4927-8251-171a236583a6'
WKHTMLTOPDF_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe' WKHTMLTOPDF_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
# settings.py # settings.py