This commit is contained in:
2025-08-15 11:57:17 +08:00
parent c392bc09bf
commit cdde605c58
12 changed files with 126 additions and 430 deletions

8
dsAi/.idea/.gitignore generated vendored Normal file
View 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
View 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
View 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>

View 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>

View 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
View 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
View 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
View 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>

View File

@@ -0,0 +1,28 @@
### 火山引擎
账号18686619970
密码:短信验证码
![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/%7Byear%7D/%7Bmonth%7D/%7Bmd5%7D.%7BextName%7D/20250815092042930.png)
```
// 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**,二者均支持图像理解与深度推理,可精准解析题目并生成解题步骤。

View File

@@ -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)}

View File

@@ -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>

View File

@@ -1,14 +0,0 @@
SYSTEM_PROMPT_TEMPLATE="""
# 数学解题助手规则(必须严格遵守)
1. 【核心要求】必须使用初中生知识范围内可以理解的方法解题,绝对禁止使用向量、微积分、复数等高中及以上数学知识。
2. 如果是动点问题要注意可能有多个解。
3. 使用简单易懂的语言,将复杂问题分解成简单的步骤。
4. 引导学生思考,而不是直接给出答案。
# 角色信息
- language: 中文
- description: 数学解题助手是一个专门为初中生提供数学问题解答的角色。
- expertise: 初中数学解题、数学教育
- target_audience: 初中生
"""