'commit'
This commit is contained in:
8
dsAi/.idea/.gitignore
generated
vendored
Normal file
8
dsAi/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
18
dsAi/.idea/compiler.xml
generated
Normal file
18
dsAi/.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="dsAi" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="dsAi" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
7
dsAi/.idea/encodings.xml
generated
Normal file
7
dsAi/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
6
dsAi/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
dsAi/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
6
dsAi/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
dsAi/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
25
dsAi/.idea/jarRepositories.xml
generated
Normal file
25
dsAi/.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="ali-maven" />
|
||||
<option name="name" value="ali-maven" />
|
||||
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
12
dsAi/.idea/misc.xml
generated
Normal file
12
dsAi/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
|
||||
</project>
|
6
dsAi/.idea/vcs.xml
generated
Normal file
6
dsAi/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
28
dsAi/src/main/java/com/dsideal/Ai/Util/JiMeng/Doc/文档.md
Normal file
28
dsAi/src/main/java/com/dsideal/Ai/Util/JiMeng/Doc/文档.md
Normal file
@@ -0,0 +1,28 @@
|
||||
### 火山引擎
|
||||
|
||||
账号:18686619970
|
||||
密码:短信验证码
|
||||
|
||||

|
||||
|
||||
```
|
||||
// API访问凭证
|
||||
protected static final String ak="AKLTZjVlOGU1NzA1YWZkNDExMzkzYzY5YTNlOTRmMTMxODg"; // Access Key
|
||||
protected static final String sk="WkdabU9UTXdNVEJpTmpWbE5HVTJZVGxtTnpWbU5XSTBaRGN5TW1NMk5tRQ=="; // Secret Key
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 使用内容
|
||||
|
||||
1. 即梦AI
|
||||
|
||||
https://www.volcengine.com/docs/85621/1544716
|
||||
|
||||
|
||||
|
||||
2. 视觉识别模型
|
||||
|
||||
开发拍照解题APP,推荐使用**doubao-seed-1-6-thinking(版本250715)** 或 **doubao-1-5-thinking-vision-pro(版本250428)**,二者均支持图像理解与深度推理,可精准解析题目并生成解题步骤。
|
||||
|
||||
|
@@ -37,7 +37,7 @@ async def get_tree_data(request: fastapi.Request):
|
||||
prerequisites = prerequisite_data
|
||||
else:
|
||||
# 转换为新格式
|
||||
prerequisites = [{{"id": str(id), "title": title}} for id, title in (prerequisite_data or [])] if prerequisite_data else None
|
||||
prerequisites = [{"id": str(id), "title": title} for id, title in (prerequisite_data or [])] if prerequisite_data else None
|
||||
|
||||
related_data = json.loads(row[5]) if row[5] else []
|
||||
# 转换相关知识格式
|
||||
@@ -46,9 +46,9 @@ async def get_tree_data(request: fastapi.Request):
|
||||
related = related_data
|
||||
else:
|
||||
# 转换为新格式
|
||||
related = [{{"id": str(id), "title": title}} for id, title in (related_data or [])] if related_data else None
|
||||
related = [{"id": str(id), "title": title} for id, title in (related_data or [])] if related_data else None
|
||||
|
||||
node = {{
|
||||
node = {
|
||||
"id": row[0],
|
||||
"title": row[1],
|
||||
"parent_id": row[2],
|
||||
@@ -56,7 +56,7 @@ async def get_tree_data(request: fastapi.Request):
|
||||
"prerequisite": prerequisites,
|
||||
"related": related,
|
||||
"children": []
|
||||
}}
|
||||
}
|
||||
nodes[row[0]] = node
|
||||
|
||||
# 构建树结构
|
||||
@@ -71,9 +71,9 @@ async def get_tree_data(request: fastapi.Request):
|
||||
nodes[parent_id]["children"] = []
|
||||
nodes[parent_id]["children"].append(node)
|
||||
|
||||
return {{"code": 0, "data": tree_data}}
|
||||
return {"code": 0, "data": tree_data}
|
||||
except Exception as e:
|
||||
return {{"code": 1, "msg": str(e)}}
|
||||
return {"code": 1, "msg": str(e)}
|
||||
|
||||
# 更新知识节点接口
|
||||
@router.post("/update-knowledge")
|
||||
@@ -96,7 +96,7 @@ async def update_knowledge(request: Request):
|
||||
WHERE id = $2
|
||||
""",
|
||||
json.dumps(
|
||||
[{{"id": p["id"], "title": p["title"]}} for p in knowledge],
|
||||
[{"id": p["id"], "title": p["title"]} for p in knowledge],
|
||||
ensure_ascii=False
|
||||
),
|
||||
node_id)
|
||||
@@ -107,11 +107,11 @@ async def update_knowledge(request: Request):
|
||||
WHERE id = $2
|
||||
""",
|
||||
json.dumps(
|
||||
[{{"id": p["id"], "title": p["title"]}} for p in knowledge],
|
||||
[{"id": p["id"], "title": p["title"]} for p in knowledge],
|
||||
ensure_ascii=False
|
||||
),
|
||||
node_id)
|
||||
|
||||
return {{"code": 0, "msg": "更新成功"}}
|
||||
return {"code": 0, "msg": "更新成功"}
|
||||
except Exception as e:
|
||||
return {{"code": 1, "msg": str(e)}}
|
||||
return {"code": 1, "msg": str(e)}
|
@@ -1,406 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>浮力AI助手</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f5f5f5;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.simulation-panel {
|
||||
flex: 0 0 60%;
|
||||
border: 1px solid #ddd;
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.simulation-panel iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
flex: 0 0 40%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ddd;
|
||||
background-color: white;
|
||||
box-shadow: -2px 0 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
max-width: 85%;
|
||||
padding: 10px 15px;
|
||||
border-radius: 18px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
background-color: #E3F2FD;
|
||||
margin-left: auto;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ai-message {
|
||||
background-color: #f1f1f1;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.chat-input textarea {
|
||||
flex: 1;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
resize: none;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.chat-input button {
|
||||
padding: 0 15px;
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.chat-input button:hover {
|
||||
background-color: #1976D2;
|
||||
}
|
||||
|
||||
.loading-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.loading-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #2196F3;
|
||||
margin: 0 4px;
|
||||
animation: pulse 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.loading-dot:nth-child(1) {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.loading-dot:nth-child(2) {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 80%, 100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
40% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 默认问题按钮样式 */
|
||||
.default-questions {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.question-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.default-question-btn {
|
||||
background-color: #E3F2FD;
|
||||
border: 1px solid #2196F3;
|
||||
border-radius: 16px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: #2196F3;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.default-question-btn:hover {
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="simulation-panel">
|
||||
<iframe src="deepseek_fulishiyanshi.html"></iframe>
|
||||
</div>
|
||||
<div class="chat-panel">
|
||||
<div class="chat-header">浮力AI助手</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
<div class="message ai-message">
|
||||
<div class="message-content">您好!我是浮力AI助手,可以帮助您理解浮力相关的物理知识。请随时提问,我会尽力为您解答。</div>
|
||||
</div>
|
||||
<div class="message ai-message default-questions">
|
||||
<p style="margin-bottom: 8px; font-weight: bold;">推荐问题:</p>
|
||||
<div class="question-buttons">
|
||||
<button class="default-question-btn">什么是浮力?</button>
|
||||
<button class="default-question-btn">浮力的计算公式是什么?</button>
|
||||
<button class="default-question-btn">物体的浮沉条件是什么?</button>
|
||||
<button class="default-question-btn">阿基米德原理的内容是什么?</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<textarea id="userInput" placeholder="请输入您的问题..."></textarea>
|
||||
<button id="sendBtn">发送</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const chatMessages = document.getElementById('chatMessages');
|
||||
const userInput = document.getElementById('userInput');
|
||||
const sendBtn = document.getElementById('sendBtn');
|
||||
let isLoading = false;
|
||||
|
||||
// 发送消息
|
||||
function sendMessage() {
|
||||
const message = userInput.value.trim();
|
||||
if (!message || isLoading) return;
|
||||
|
||||
// 添加用户消息
|
||||
addMessage(message, 'user');
|
||||
userInput.value = '';
|
||||
|
||||
// 显示加载中
|
||||
showLoading();
|
||||
|
||||
// 发送POST请求到/api/llm
|
||||
fetch('/api/llm', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ question: message })
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('HTTP error! status: ' + response.status);
|
||||
}
|
||||
|
||||
// 处理流式响应
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
let aiMessageElement = null;
|
||||
let aiMessageContentElement = null;
|
||||
|
||||
function processChunk({ done, value }) {
|
||||
if (done) {
|
||||
// 处理最后一块数据
|
||||
if (buffer) {
|
||||
handleSSEMessage(buffer, aiMessageElement, aiMessageContentElement);
|
||||
}
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
// 解码接收到的数据
|
||||
const chunk = decoder.decode(value, { stream: true });
|
||||
buffer += chunk;
|
||||
|
||||
// 按行分割数据
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop(); // 保存不完整的行
|
||||
|
||||
// 如果还没有创建AI消息元素,则创建
|
||||
if (!aiMessageElement) {
|
||||
aiMessageElement = document.createElement('div');
|
||||
aiMessageElement.className = 'message ai-message';
|
||||
aiMessageContentElement = document.createElement('div');
|
||||
aiMessageContentElement.className = 'message-content';
|
||||
aiMessageElement.appendChild(aiMessageContentElement);
|
||||
chatMessages.appendChild(aiMessageElement);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
// 处理每一行
|
||||
for (const line of lines) {
|
||||
if (line.trim()) {
|
||||
handleSSEMessage(line, aiMessageElement, aiMessageContentElement);
|
||||
}
|
||||
}
|
||||
|
||||
// 继续读取
|
||||
return reader.read().then(processChunk);
|
||||
}
|
||||
|
||||
// 开始读取响应体
|
||||
return reader.read().then(processChunk);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('发送请求失败:', error);
|
||||
hideLoading();
|
||||
addMessage('抱歉,请求失败: ' + error.message, 'ai');
|
||||
});
|
||||
}
|
||||
|
||||
// 处理SSE消息
|
||||
function handleSSEMessage(line, aiMessageElement, aiMessageContentElement) {
|
||||
// 检查是否是SSE格式 (以'data: '开头)
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = line.substring(6).trim();
|
||||
|
||||
// 检查是否是结束信号
|
||||
if (data === 'DONE') {
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 解析JSON
|
||||
const jsonData = JSON.parse(data);
|
||||
// 提取content字段
|
||||
if (jsonData.content) {
|
||||
aiMessageContentElement.textContent += jsonData.content;
|
||||
scrollToBottom();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析JSON失败:', error, '数据:', data);
|
||||
// 如果解析失败,尝试直接添加文本
|
||||
aiMessageContentElement.textContent += data;
|
||||
scrollToBottom();
|
||||
}
|
||||
} else if (line) {
|
||||
// 如果不是标准SSE格式,尝试直接解析
|
||||
try {
|
||||
const jsonData = JSON.parse(line);
|
||||
if (jsonData.content) {
|
||||
aiMessageContentElement.textContent += jsonData.content;
|
||||
scrollToBottom();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析非标准SSE数据失败:', error, '数据:', line);
|
||||
// 如果解析失败,直接添加文本
|
||||
aiMessageContentElement.textContent += line;
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加消息到聊天框
|
||||
function addMessage(message, sender) {
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.className = `message ${sender}-message`;
|
||||
|
||||
const contentElement = document.createElement('div');
|
||||
contentElement.className = 'message-content';
|
||||
contentElement.textContent = message;
|
||||
|
||||
messageElement.appendChild(contentElement);
|
||||
chatMessages.appendChild(messageElement);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
// 显示加载中
|
||||
function showLoading() {
|
||||
if (isLoading) return;
|
||||
isLoading = true;
|
||||
|
||||
const loadingElement = document.createElement('div');
|
||||
loadingElement.className = 'loading-indicator';
|
||||
loadingElement.id = 'loading-indicator';
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const dot = document.createElement('div');
|
||||
dot.className = 'loading-dot';
|
||||
loadingElement.appendChild(dot);
|
||||
}
|
||||
|
||||
chatMessages.appendChild(loadingElement);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
// 隐藏加载中
|
||||
function hideLoading() {
|
||||
if (!isLoading) return;
|
||||
isLoading = false;
|
||||
|
||||
const loadingElement = document.getElementById('loading-indicator');
|
||||
if (loadingElement) {
|
||||
loadingElement.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
function scrollToBottom() {
|
||||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||
}
|
||||
|
||||
// 发送按钮点击事件
|
||||
sendBtn.addEventListener('click', sendMessage);
|
||||
|
||||
// 输入框回车事件
|
||||
userInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
// 绑定默认问题按钮事件
|
||||
document.querySelectorAll('.default-question-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const question = this.textContent;
|
||||
userInput.value = question;
|
||||
sendMessage();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,14 +0,0 @@
|
||||
SYSTEM_PROMPT_TEMPLATE="""
|
||||
# 数学解题助手规则(必须严格遵守)
|
||||
|
||||
1. 【核心要求】必须使用初中生知识范围内可以理解的方法解题,绝对禁止使用向量、微积分、复数等高中及以上数学知识。
|
||||
2. 如果是动点问题要注意可能有多个解。
|
||||
3. 使用简单易懂的语言,将复杂问题分解成简单的步骤。
|
||||
4. 引导学生思考,而不是直接给出答案。
|
||||
|
||||
# 角色信息
|
||||
- language: 中文
|
||||
- description: 数学解题助手是一个专门为初中生提供数学问题解答的角色。
|
||||
- expertise: 初中数学解题、数学教育
|
||||
- target_audience: 初中生
|
||||
"""
|
Reference in New Issue
Block a user