对diagnose重构了一下
This commit is contained in:
parent
f56b66d8f1
commit
fa00e1d19d
|
Before Width: | Height: | Size: 928 KiB After Width: | Height: | Size: 928 KiB |
@ -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
69
diagnose/db_views.py
Normal 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)
|
||||||
@ -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})
|
||||||
|
|||||||
28
diagnose/migrations/0003_openaidiagnose.py
Normal file
28
diagnose/migrations/0003_openaidiagnose.py
Normal 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)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -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
90
diagnose/openai_dia.py
Normal 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
116
diagnose/openai_gen.py
Normal 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")
|
||||||
@ -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)
|
|
||||||
@ -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)
|
|
||||||
@ -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')
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user