python django orm websocket html 实现deepseek持续聊天对话页面
最终效果:
技术栈:
python django orm websocket html
项目结构:
这里只展示关键代码:
@File: consumers.py
# -*- coding:utf-8 -*-
# @Author: 喵酱
# @time: 2025 - 03 -02
# @File: consumers.py
# desc:
import json
from asgiref.sync import sync_to_async
from .models import Message, Conversation
from channels.generic.websocket import AsyncWebsocketConsumer
import requestsclass ChatConsumer(AsyncWebsocketConsumer):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.message_history = {} # 用于缓存历史消息async def connect(self):print("WebSocket scope:", self.scope)self.conversation_id = self.scope['url_route']['kwargs']['conversation_id']self.room_group_name = f'chat_{self.conversation_id}'# 初始化历史消息缓存self.message_history[self.conversation_id] = await self.load_message_history()# 加入房间组await self.channel_layer.group_add(self.room_group_name,self.channel_name)await self.accept()async def disconnect(self, close_code):# 离开房间组print(f"WebSocket disconnected with code: {close_code}")if hasattr(self, 'channel_layer') and self.channel_layer:await self.channel_layer.group_discard(self.room_group_name,self.channel_name)async def receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json['message']print(f"服务端接收到消息: {message}")# 保存用户消息到数据库await self.save_message_to_db(message, role='user')# 将用户消息添加到历史消息缓存self.message_history[self.conversation_id].append({"role": "user", "content": message})# 调用对话接口处理消息processed_message = await self.call_dialogue_service(message)# 将 AI 回复添加到历史消息缓存self.message_history[self.conversation_id].append({"role": "assistant", "content": processed_message})# 保存 AI 回复到数据库await self.save_message_to_db(processed_message, role='assistant')# 发送处理后的消息到房间组await self.channel_layer.group_send(self.room_group_name,{'type': 'chat_message','message': processed_message,'role': 'assistant' # 角色为 assistant})@sync_to_asyncdef save_message_to_db(self, message, role):# 保存消息到数据库conversation = Conversation.objects.get(id=self.conversation_id)Message.objects.create(conversation=conversation, role=role, content=message)@sync_to_asyncdef load_message_history(self):# 从数据库加载历史消息conversation = Conversation.objects.get(id=self.conversation_id)messages = conversation.messages.all().order_by('created_at')return [{"role": msg.role, "content": msg.content} for msg in messages]async def call_dialogue_service(self, message):# DeepSeek API 的 URL 和 API KeyDEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"DEEPSEEK_API_KEY = "sk-8b7c9285aac14885a60d610e7fdcedda"# 获取当前对话的历史消息message_history = self.message_history[self.conversation_id]# 构造请求数据,包含历史消息和当前消息data = {"model": "deepseek-chat","messages": message_history, # 包含历史消息和当前消息"max_tokens": 300 # 根据需要调整}print("发送请求到 DeepSeek API")# 发送请求到 DeepSeek APItry:response = requests.post(DEEPSEEK_API_URL,headers={"Authorization": f"Bearer {DEEPSEEK_API_KEY}","Content-Type": "application/json"},json=data)response.raise_for_status() # 检查请求是否成功response_data = response.json()ai_response = response_data['choices'][0]['message']['content']print("发送请求到 DeepSeek API,发送成功")except requests.exceptions.RequestException as e:# 如果 API 调用失败,返回错误信息ai_response = f"Error: {str(e)}"print("发送请求到 DeepSeek API,发送失败")return ai_responseasync def chat_message(self, event):print(f"服务端发送消息: {event['message']}")message = event['message']role = event.get('role', 'assistant') # 默认角色为 assistant# 发送消息到 WebSocketawait self.send(text_data=json.dumps({'message': message,'role': role}))
# views.py
# views.py
from django.http import JsonResponse
from django.shortcuts import render# Create your views here.
import requestsfrom .forms import UploadFileFormfrom django.shortcuts import render, redirect, get_object_or_404
from .models import Conversation, Message
import markdown
import yaml
import json
import os
from django.conf import settings
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exemptDEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
DEEPSEEK_API_KEY = "sk-8b"# MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
MAX_FILE_SIZE = 100 * 1024 * 1024 # 100MBdef index(request):return render(request, 'index.html')def business_test(request):return render(request, 'business_test.html')def api_test(request):return render(request, 'api_test.html')
def data_generator(request):return render(request, 'data_generator.html')def test_report(request):return render(request, 'test_report.html')def chat(request, conversation_id=None):# 确保会话已初始化if not request.session.session_key:request.session.create()session_id = request.session.session_key# 获取历史对话列表history_conversations = Conversation.objects.filter(session_id=session_id).order_by('-created_at')# 获取当前对话if conversation_id:current_conversation = get_object_or_404(Conversation, id=conversation_id, session_id=session_id)else:# 如果没有传递 conversation_id,则使用最近的对话或创建一个新对话current_conversation = history_conversations.first()if not current_conversation:current_conversation = Conversation.objects.create(session_id=session_id, title="New Conversation")if request.method == 'POST':user_input = request.POST.get('user_input')files = request.FILES.getlist('file') # 获取上传的文件列表# 检查文件大小for file in files:if file.size > MAX_FILE_SIZE:return JsonResponse({'error': f'文件 {file.name} 大小超过 50MB 限制'}, status=400)# 保存用户输入if user_input:print(f"用户输入:{user_input}")Message.objects.create(conversation=current_conversation, role='user', content=user_input)# 处理上传的文件file_contents = []for file in files:# 保存文件到本地file_path = os.path.join(settings.MEDIA_ROOT, file.name)with open(file_path, 'wb+') as destination:for chunk in file.chunks():destination.write(chunk)# 读取文件内容file_content = file.read().decode('utf-8')file_contents.append(f"文件: {file.name}\n内容:\n{file_content}")# 将文件内容与用户输入合并full_input = user_input if user_input else ""if file_contents:full_input += "\n\n上传的文件内容:\n" + "\n".join(file_contents)# 调用 DeepSeek APItry:response = requests.post(DEEPSEEK_API_URL,headers={"Authorization": f"Bearer {DEEPSEEK_API_KEY}","Content-Type": "application/json"},json={"model": "deepseek-chat","messages": [{"role": "user", "content": full_input}],"max_tokens": 150 # 根据需要调整})response.raise_for_status() # 检查请求是否成功response_data = response.json()ai_response = response_data['choices'][0]['message']['content']except requests.exceptions.RequestException as e:# 如果 API 调用失败,返回错误信息ai_response = f"Error: {str(e)}"# 保存 AI 回答Message.objects.create(conversation=current_conversation, role='assistant', content=ai_response)# 通过 WebSocket 发送消息到前端channel_layer = get_channel_layer()async_to_sync(channel_layer.group_send)(f'chat_{current_conversation.id}',{'type': 'chat_message','message': ai_response,'role': 'assistant'})# 获取当前对话的所有消息messages = current_conversation.messages.all().order_by('created_at')return render(request, 'chat.html', {'current_conversation': current_conversation,'history_conversations': history_conversations,'messages': messages})
def new_conversation(request):# 确保会话已初始化if not request.session.session_key:request.session.create()session_id = request.session.session_key# 创建新对话new_conversation = Conversation.objects.create(session_id=session_id, title="New Conversation")return redirect('chat_with_id', conversation_id=new_conversation.id) # 使用 chat_with_id
models.py
from django.db import modelsclass Conversation(models.Model):session_id = models.CharField(max_length=255)title = models.CharField(max_length=255, default="New Conversation")created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)def __str__(self):return self.titleclass Message(models.Model):conversation = models.ForeignKey(Conversation, related_name='messages', on_delete=models.CASCADE)role = models.CharField(max_length=10, choices=[('user', 'User'), ('assistant', 'Assistant')])content = models.TextField()created_at = models.DateTimeField(auto_now_add=True)def __str__(self):return f"{self.role}: {self.content}"
routing.py
# @File: routing.py
# desc:
from django.urls import re_path
from . import consumers# 定义 WebSocket 路由
websocket_urlpatterns = [re_path(r'ws_chat/(?P<conversation_id>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
@File: urls.py
# @File: urls.py
# desc:
from django.urls import path, include
from . import views
from django.conf import settings
from django.conf.urls.static import static
from .routing import websocket_urlpatterns # 导入 WebSocket 路由urlpatterns = [path('chat/', views.chat, name='chat'), # 用于没有 conversation_id 的情况path('chat/<int:conversation_id>/', views.chat, name='chat_with_id'), # 用于有 conversation_id 的情况path('ws/chat/<int:conversation_id>/', views.chat, name='chat_with_id'), # 用于有 conversation_id 的情况path('ws_chat/', include(websocket_urlpatterns)), # 这个是关键配置path('new-conversation/', views.new_conversation, name='new_conversation'),path('upload/', views.upload_file, name='upload'),path('autocomplete/', views.autocomplete, name='autocomplete'),path('generate-business-test/', views.generate_business_test, name='generate_business_test'),path('generate-api-test/', views.generate_api_test, name='generate_api_test'),path('', views.index, name='index'), # 首页] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# ASGI配置文件 # asgi.py
# ASGI配置文件
# asgi.pyimport os
import django
from django.core.asgi import get_asgi_application# 设置 DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'deepseek_project.settings')# 初始化 Django
django.setup()# 导入其他模块
from channels.routing import ProtocolTypeRouter, URLRouter
from deepseek_app.routing import websocket_urlpatterns# 获取 Django 的 ASGI 应用
django_asgi_app = get_asgi_application()# 配置 ProtocolTypeRouter
application = ProtocolTypeRouter({"http": django_asgi_app, # 处理 HTTP 请求# "http": get_asgi_application(), # 处理 HTTP 请求"websocket": URLRouter(websocket_urlpatterns # 处理 WebSocket 请求),
})
settings.py
from pathlib import Path
import os
import pymysql
pymysql.install_as_MySQLdb()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-ge1ljrz+2^1-f4(y)+!a0n#!(4e)+^z4fx$2$2v7=uf+e$^a&5'# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = TrueALLOWED_HOSTS = ['*']# Application definitionINSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','channels', # 添加 channels'deepseek_app',]ASGI_APPLICATION = 'deepseek_project.asgi.application'MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware','django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 配置静态文件存储
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
ROOT_URLCONF = 'deepseek_project.urls'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]WSGI_APPLICATION = 'deepseek_project.wsgi.application'# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
# }DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', # 使用 MySQL'NAME': 'ds11111','USER': 'root','PASSWORD': '121111','HOST': '11.11.21.11', # 或者是你 MySQL 的主机地址'PORT': '3306',}
}# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validatorsAUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
]# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/LANGUAGE_CODE = 'en-us'TIME_ZONE = 'UTC'USE_I18N = TrueUSE_TZ = True# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-fieldDEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')CORS_ALLOWED_ORIGINS = ["http://127.0.0.1:8000","http://localhost:8000",
]#
# CHANNEL_LAYERS = {
# "default": {
# "BACKEND": "channels_redis.core.RedisChannelLayer",
# "CONFIG": {
# "hosts": [("11.11.21.11", 6379)],
# "channel_capacity": {
# "http.request": 200,
# "http.response!*": 200,
# "websocket.send!*": 200,
# },
# },
# },
# }CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer",},
}
wsgi.py
import osfrom django.core.wsgi import get_wsgi_applicationos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'deepseek_project.settings')application = get_wsgi_application()
前端代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>AI对话</title><!-- 加载 static 标签库 -->{% load static %}<!-- Bootstrap CSS (本地文件) --><link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"><!-- Font Awesome (本地文件) --><link href="{% static 'css/all.min.css' %}" rel="stylesheet"><style>/* 自定义样式 */body {display: flex;height: 100vh;background-color: #f8f9fa;margin: 0;}.sidebar {width: 250px;background-color: #2c3e50;color: white;padding: 20px;overflow-y: auto;}.main-content {flex: 1;display: flex;flex-direction: column;background-color: #fff;}.chat-history {flex: 1;overflow-y: auto;padding: 20px;scroll-behavior: smooth; /* 平滑滚动 */}.chat-input {padding: 20px;background-color: #fff;border-top: 1px solid #ddd;}.message {margin-bottom: 15px;}.message.user {text-align: right;}.message.assistant {text-align: left;}.message .card {max-width: 70%;display: inline-block;}.message.user .card {background-color: #007bff;color: white;}.message.assistant .card {background-color: #f1f1f1;color: black;}.loading {display: none;text-align: center;margin: 10px 0;}.loading .spinner-border {width: 1.5rem;height: 1.5rem;}.file-preview {margin-bottom: 10px;}.file-info {padding: 5px;border: 1px solid #ddd;border-radius: 5px;background-color: #f9f9f9;}</style>
</head>
<body><!-- 侧边栏 --><div class="sidebar d-none d-md-block"><h2>Conversations</h2><ul class="list-unstyled">{% for conversation in history_conversations %}<li class="mb-2"><a href="{% url 'chat_with_id' conversation.id %}" class="text-white text-decoration-none"><i class="fas fa-comment-dots me-2"></i>{{ conversation.title }}</a></li>{% endfor %}</ul><button class="btn btn-primary w-100" onclick="location.href='{% url 'new_conversation' %}'"><i class="fas fa-plus me-2"></i>新建对话</button></div><!-- 主内容区 --><div class="main-content"><!-- 对话历史 --><div class="chat-history" id="chat-history"><h2>{{ current_conversation.title }}</h2>{% for message in messages %}<div class="message {% if message.role == 'user' %}user{% else %}assistant{% endif %}"><div class="card"><div class="card-body"><p class="card-text">{{ message.content }}</p><small class="text-muted">{{ message.created_at|date:"Y-m-d H:i:s" }}</small></div></div></div>{% endfor %}</div><!-- 加载动画 --><div class="loading" id="loading"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div><!-- 输入框 --><div class="chat-input"><form method="post" class="d-flex flex-column" id="chat-form" enctype="multipart/form-data">{% csrf_token %}<!-- 文件上传 --><div class="file-upload mb-2"><input type="file" class="form-control" id="file-input" name="file" multipleaccept=".txt,.pdf,.docx,.xmind,.jpg,.jpeg,.png,.gif"></div><!-- 文件预览 --><div class="file-preview" id="file-preview"></div><!-- 文本输入 --><div class="d-flex"><textarea name="user_input" class="form-control me-2" placeholder="输入你的内容..." rows="1" id="user-input"></textarea><button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane me-2"></i>提交</button></div></form></div></div><!-- Bootstrap JS (本地文件) --><script src="{% static 'js/bootstrap.bundle.min.js' %}"></script><!-- jQuery (本地文件) --><script src="{% static 'js/jquery-3.6.0.min.js' %}"></script><!-- WebSocket 支持 --><script>// 获取当前对话 IDconst conversationId = '{{ current_conversation.id }}';let chatSocket; // 将 chatSocket 定义在全局作用域if (!conversationId) {console.error('Conversation ID is missing');} else {// 创建 WebSocket 连接const websocketUrl = 'ws://' + window.location.host + '/ws_chat/' + conversationId + '/';console.log('Attempting to establish WebSocket connection to:', websocketUrl);chatSocket = new WebSocket(websocketUrl);// WebSocket 连接成功chatSocket.onopen = function (e) {console.log('WebSocket connection opened successfully');};// 处理接收到的消息chatSocket.onmessage = function (e) {console.log('Received message from server:', e.data);const data = JSON.parse(e.data);const chatHistory = document.getElementById('chat-history');// 添加新消息到对话历史const messageHtml = `<div class="message ${data.role}"><div class="card"><div class="card-body"><p class="card-text">${data.message}</p><small class="text-muted">${new Date().toLocaleString()}</small></div></div></div>`;chatHistory.innerHTML += messageHtml;// 滚动到底部chatHistory.scrollTop = chatHistory.scrollHeight;// 隐藏加载动画$('#loading').hide();};// 处理 WebSocket 关闭事件chatSocket.onclose = function (e) {console.error('WebSocket connection closed:', e);alert('WebSocket 连接已关闭,请刷新页面重试。');};// 处理 WebSocket 错误事件chatSocket.onerror = function (e) {console.error('WebSocket error:', e);alert('WebSocket 连接出错,请检查网络或刷新页面。');};}// 文件选择事件$('#file-input').on('change', function () {console.log('File input changed');const filePreview = $('#file-preview');filePreview.empty(); // 清空之前的预览const files = this.files;for (let i = 0; i < files.length; i++) {const file = files[i];const fileInfo = `<div class="file-info mb-2"><span>${file.name}</span><small class="text-muted">(${(file.size / 1024).toFixed(2)} KB)</small></div>`;filePreview.append(fileInfo);}});// 发送消息时显示加载动画$(document).ready(function () {$('#chat-form').on('submit', function (e) {e.preventDefault();console.log('Form submitted');const userInput = $('#user-input').val().trim();const fileInput = $('#file-input')[0].files;if (!userInput && fileInput.length === 0) {console.log('No input or file selected');alert('请输入内容或选择文件');return;}$('#loading').show(); // 显示加载动画// 手动将用户的消息添加到聊天记录中const chatHistory = document.getElementById('chat-history');const messageHtml = `<div class="message user"><div class="card"><div class="card-body"><p class="card-text">${userInput}</p><small class="text-muted">${new Date().toLocaleString()}</small></div></div></div>`;chatHistory.innerHTML += messageHtml;// 滚动到底部chatHistory.scrollTop = chatHistory.scrollHeight;// 如果有文件上传,使用 FormData 发送if (fileInput.length > 0) {console.log('File upload detected, using AJAX');const formData = new FormData();formData.append('user_input', userInput);for (let i = 0; i < fileInput.length; i++) {formData.append('file', fileInput[i]);}// 使用 AJAX 发送文件$.ajax({url: '{% url "chat_with_id" current_conversation.id %}',method: 'POST',data: formData,processData: false,contentType: false,headers: {'X-CSRFToken': '{{ csrf_token }}'},success: function (response) {console.log('File upload successful:', response);$('#loading').hide();location.reload(); // 刷新页面以显示新消息},error: function (xhr, status, error) {console.error('File upload failed:', error);$('#loading').hide();alert('文件上传失败,请重试。');}});} else {console.log('Sending message via WebSocket:', userInput);if (chatSocket.readyState !== WebSocket.OPEN) {console.error('WebSocket is not open, readyState:', chatSocket.readyState);alert('WebSocket 连接未准备好,请稍后重试。');return;}// 发送消息chatSocket.send(JSON.stringify({'message': userInput}));console.log('Message sent via WebSocket:', userInput);$('#user-input').val(''); // 清空输入框}});
});</script>
</body>
</html>
相关文章:
python django orm websocket html 实现deepseek持续聊天对话页面
最终效果: 技术栈: python django orm websocket html 项目结构: 这里只展示关键代码: File: consumers.py # -*- coding:utf-8 -*- # Author: 喵酱 # time: 2025 - 03 -02 # File: consumers.py # desc: import json from asg…...
大白话html语义化标签优势与应用场景
大白话html语义化标签优势与应用场景 大白话解释 语义化标签就是那些名字能让人一看就大概知道它是用来做什么的标签。以前我们经常用<div>来做各种布局,但是<div>本身没有什么实际的含义,就像一个没有名字的盒子。而语义化标签就像是有名…...
考研英语语法全攻略:从基础到长难句剖析
引言 在考研英语的备考之旅中,语法犹如一座灯塔,为我们在浩瀚的英语知识海洋中指引方向。无论是阅读理解中复杂长难句的解读,还是写作时准确流畅表达的需求,扎实的语法基础都起着至关重要的作用。本文将结合有道考研语法基础入门课的相关内容,为大家全面梳理考研英语语法…...
Vue3 生命周期
回顾Vue2的生命周期 创建(创建前,创建完毕)beforeCreate、created挂载(挂载前,挂载完毕)beforeMount、mounted更新(更新前,更新完毕)beforeUpdate、updated销毁…...
hbase-05 namespace、数据的确界TTL
要点 掌握HBase的命名空间namespace概念 掌握HBase数据版本确界 掌握HBase数据TTL 1. HBase的namespace 1.1 namespace基本介绍 在HBase中,namespace命名空间指对一组表的逻辑分组,类似RDBMS中的database,方便对表在业务上划分。Apache…...
线程的常见使用方法
Java中的线程并不是真正意义的线程,我们使用的是Thread类来表示线程,而这个类是 JVM 用来管理线程的一个类,也就是说,每个线程都有一个唯一的 Thread对象 与之关联 每一个执行流都需要有一个对象来进行描述,那么一个Thread对象就是用来表述一个线程执行流的,JVM会将这些对象统…...
架构师面试(十一):消息收发
问题 IM 是互联网中非常典型的独立的系统,麻雀虽小但五脏俱全,非常值得深入研究和探讨,继上次IM相关题目之后,我们继续讨论IM相关话题。 关于IM系统【消息收发模型】的相关描述,下面说法错误的有哪几项? …...
MoonSharp 文档一
目录 1.Getting Started 步骤1:在 IDE 中引入 MoonSharp 步骤2:引入命名空间 步骤3:调用脚本 步骤4:运行代码 2.Keeping a Script around 步骤1:复现前教程所有操作 步骤2:改为创建Script对象 步骤…...
【linux网络编程】端口
一、端口(Port)概述 在计算机网络中,端口(Port) 是用来标识不同进程或服务的逻辑通信端点。它类似于一座大楼的房间号,帮助操作系统和网络协议区分不同的应用程序,以便正确地传输数据。 1. 端口…...
Vulnhub-Node
目录标题 一、靶机搭建二、信息收集靶机信息扫ip扫开放端口和版本服务信息指纹探测目录扫描 三、Web渗透信息收集zip爆破ssh连接 四、提权内核版本提权 利用信息收集拿到路径得到账户密码,下载备份文件,base64解密后,利用fcrackzip爆破zip压缩…...
RK3568平台(camera篇)camera3_profiles_rk3588.xml解析
camera3_profiles_rk3588.xml 是一个与 Android 相机 HAL(硬件抽象层)相关的配置文件,通常用于定义 Rockchip RK3588 平台上的相机设备及其功能。该文件基于 Android 的 Camera3 HAL 框架,用于描述相机的配置、流配置、分辨率、帧率、格式等信息。 以下是对 camera3_profi…...
高阶哈希算法
SHA-256简介 SHA-256 是 **SHA-2(Secure Hash Algorithm 2)**家族中的一种哈希算法,由美国国家安全局设计,并于 2001 年发布。它能够将任意长度的数据映射为一个固定长度256 位,即 32 字节的哈希值,通常以…...
Spark数据倾斜深度解析与实战解决方案
Spark数据倾斜深度解析与实战解决方案 一、数据倾斜的本质与影响 数据倾斜是分布式计算中因数据分布不均导致的性能瓶颈现象。当某些Key对应的数据量远超其他Key时,这些"热点Key"所在的Task会消耗80%以上的计算时间,成为整个作业的木桶短板。具体表现为: Task执…...
Kubernetes滚动更新实践
前言 在我之前的项目中,对微服务升级采用的做法是删除整个namespace, 再重新应用所有yaml。 这种方式简单粗暴,但是不可避免的导致服务中断,影响了用户体验 为了解决更新服务导致的服务中断问题, Kubernetes提供了一种…...
Broken pipe
比较常见的一个问题。 但是并不是每个人都能说清楚。 首先注意下写法: Broken pipe # B大写 p小写 主要是grep的时候别写错了 常见的原因 1、客户端关闭连接。 在服务器端处理请求的过程中,客户端突然关闭了连接,例如浏览器关闭、网络断开…...
doris:ClickHouse
Doris JDBC Catalog 支持通过标准 JDBC 接口连接 ClickHouse 数据库。本文档介绍如何配置 ClickHouse 数据库连接。 使用须知 要连接到 ClickHouse 数据库,您需要 ClickHouse 23.x 或更高版本 (低于此版本未经充分测试)。 ClickHouse 数据库的 JDBC 驱动程序&a…...
前K个高频单词
692. 前K个高频单词 - 力扣(LeetCode) 题目描述: 给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。 返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序…...
恢复IDEA的Load Maven Changes按钮
写代码的时候不知道点到什么东西了,pom文件上的这个弹窗就是不出来了,重启IDEA,reset windos都没用,网上搜也没收到解决方案 然后开打开其他项目窗口时,看到那个的功能名叫 Hide This Notification 于是跑到Setting里…...
【五.LangChain技术与应用】【31.LangChain ReAct Agent:反应式智能代理的实现】
一、ReAct Agent是啥?为什么说它比「普通AI」聪明? 想象一下,你让ChatGPT查快递物流,它可能直接编个假单号糊弄你。但换成ReAct Agent,它会先推理(Reasoning)需要调用哪个接口,再行动(Action)查询真实数据——这就是ReAct的核心:让AI学会「动脑子」再动手。 举个真…...
Leetcode 62: 不同路径
Leetcode 62: 不同路径 问题描述: 一个机器人位于一个 (m \times n) 网格的左上角(起始点位于 ((0, 0)))。 机器人每次只能向下或向右移动一步。网格的右下角为终点(位于 ((m-1, n-1)))。 计算机器人从左上角到右下角…...
计算机毕业设计SpringBoot+Vue.js火锅店管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Docker Desktop 4.38 安装与配置全流程指南(Windows平台)
一、软件定位与特性 Docker Desktop 是容器化应用开发与部署的一体化工具,支持在本地环境创建、管理和运行Docker容器。4.38版本新增GPU加速支持、WSL 2性能优化和Kubernetes 1.28集群管理功能,适用于微服务开发、CI/CD流水线搭建等场景。 二、安装环境…...
算法系列之广度优先搜索解决妖怪和尚过河问题
在算法学习中,广度优先搜索(BFS)是一种常用的图搜索算法,适用于解决最短路径问题、状态转换问题等。本文将介绍如何利用广度优先搜索解决经典的“妖怪和尚过河问题”。 问题描述 有三个妖怪和三个和尚需要过河。他们只有一条小船…...
【技术白皮书】内功心法 | 第一部分 | IP协议的目的与工作原理(IP地址)
目录 IP协议的介绍IP协议的目的与工作原理IP协议处理过程与信件传递的相似IP协议处理过程与信件传递的区别IP协议中的概念IP数据包IP地址IP地址组成IP地址分类和组成A、B、C三类地址的格式设计特殊类型的IP地址与传统通信地址进行类比IP地址的表示五类IP地址的地址范围IP地址的…...
【Linux】外接硬盘管理
查看外接硬盘信息 连接外接硬盘后,使用以下命令识别设备: lsblk:列出块设备及其挂载点 lsblk示例输出可能显示设备名称如 /dev/sdb。 通过 lsblk -f 可同时显示文件系统类型和 UUID。 fdisk -l:列出所有磁盘的分区信息ÿ…...
【Hadoop】详解Zookeeper选主流程
1. ZooKeeper 的工作原理 Zookeeper 的核心是Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。 为了保证事务的顺序一致性,Zookeeper采用了递增的事务id号(zxid)来标识事务。所有…...
C语言-语法
数据类型 字符串 C中字符串拼接不用+号,直接使用空格。 char* str = "hello" "world"; 换行链接,加上\就不会报错 char* longStr = "00000000000000000000000000000\ 00000000000000000000000000000"; typedef C 语言提供了 typedef …...
Flink Forward Asia 2024 大会 内容整理
一、Flink 2.0:十年磨一剑,开启流计算新纪元 作为 Flink 诞生十周年的重磅更新,Flink 2.0 被定位为“面向未来十年的流计算引擎”,核心目标是解决云原生、AI 融合、存算效率等新时代挑战。以下是它的几大杀手锏: 1. …...
golang进阶知识专项-理解值传递
在 Go 语言中,所有函数的参数传递都是值传递(Pass by Value)。当你将一个变量作为参数传递给函数时,实际上传递的是该变量的副本,而不是变量本身。理解这一点对于避免常见的编程错误至关重要。根据不同的类型ÿ…...
2020年联考《申论》第三题(河北县级卷)
材料: 总面积不过八平方米的店铺,摆满货品之后,两人在店内走动都有些困难,但这家小店在当地却是小有名气的老字号。69岁的店主老林是资深木雕艺人,更被称为“最后的手工酸枝筷子传人”。手工木筷取材自缅甸坤甸木、老挝…...
Kali WebDAV 客户端工具——Cadaver 与 Davtest
1. 工具简介 在 WebDAV 服务器管理和安全测试过程中,Cadaver 和 Davtest 是两款常用的命令行工具。 Cadaver 是一个 Unix/Linux 命令行 WebDAV 客户端,主要用于远程文件管理,支持文件上传、下载、移动、复制、删除等操作。Davtest 则是一款…...
八点八数字科技:开启数字人应用的无限可能
在数字科技飞速发展的时代,八点八数字科技凭借卓越实力,成为行业的领军者。自 2014 年成立,公司汇聚近百位顶尖人才,手握 30 新型发明专利与 80 软件著作权,完成数千万融资,实力备受认可。其自主研发的全…...
Vue 使用 vue-router 时,多级嵌套路由缓存问题处理
Vue 使用 vue-router 时,多级嵌套路由缓存问题处理 对于三级菜单(或多级嵌套路由),vue 都是 通过 keep-alive 组件来实现路由组件的缓存。 有时候三级或者多级路由时,会出现失效情况。以下是三级菜单缓存的例子。 最…...
《实战AI智能体》Deepseek可以做什么?自然语言理解与分析
在人工智能技术快速迭代的今天,Deepseek凭借其先进的自然语言处理能力,正在重塑人机交互的边界。本文将从技术实现维度,深入解析该平台在自然语言理解、知识推理与文本分类三大核心领域的技术突破与应用实践。 一、深度语义理解引擎 Deepseek构建了多层级的语义解析架构,实…...
虚拟主机认证功能
一.认证功能 类型: 1.基于客户端地址的认证 2.基于用户的认证 1.基于客户端地址的认证 nginx是一款模块化软件,功能都是基于模块实现的。 如上图所示,访问认证是使用的这个access_module模块。 这个模块也给我们提供了一些指令…...
BGP协议深度解析:从背景到术语的全面梳理
引言 在复杂的网络架构中,不同自治系统(AS)之间的路由交互至关重要。BGP(Border Gateway Protocol,边界网关协议)作为自治系统间的动态路由协议,承担着跨 AS 路由传递的关键任务。本文将深入探讨…...
初步认识线程
概念 一个线程就是一个 "执行流",每一个线程之间都可以按照顺序执行自己的代码,多个线程之间可以 "同步" 执行多份代码 比如说,原本一个人做的事情,现在交给三个人一起做,那么这三个人就是线程 使用原因 那么为什么要有线程呢?我们直接使用进程不可以…...
【从零开始学习计算机科学】数字逻辑(一)绪论
【从零开始学习计算机科学】数字逻辑(一)绪论 概论信息与数字数字系统中常用的概念数字信号的描述方法概论 从数字(集成)电路的出现到计算机到网络到今天的移动互联网,数字电路是所有现代信息技术的基础。那么数字电路的基础又是什么呢?就是数字逻辑。所有数字系统都是基…...
Tomcat与Jetty的选择
Tomcat与Jetty的对比分析,分核心区别、性能表现及选型建议三部分: 一、核心区别对比 对比维度TomcatJetty架构设计多层级容器结构(Server→Service→Engine等),复杂度高基于Handler链的轻量级设计,扩展性强…...
用AI学编程2——python学习1
一个py文件,学会所有python所有语法和特性,给出注释,给出这样的文件 Python 学习整合文件 """ Python 学习整合文件 包含 Python 的基础语法、数据结构、函数定义、面向对象编程、异常处理、文件操作、高级特性等内容 每个部…...
【教程】宝塔提示请不要将网站根目录设置到以下关键目录中
【教程】宝塔提示请不要将网站根目录设置到以下关键目录中 【教程】宝塔提示请不要将网站根目录设置到以下关键目录中更换目录解决问题 先在宝塔下载一个 【教程】宝塔提示请不要将网站根目录设置到以下关键目录中更换目录解决问题_起尔网【教程】宝塔提示请不要将网站根目录设…...
html常用的文本标签以及属性
HTML标签 HTML通过一系列的标签(也成为元素),来定义文本,图像,链接等等,HTML标签是由尖括号包围的关键字。 标签通常成对出现,包括开始标签和结束标签(也成为双标签)&a…...
城市霓虹灯夜景拍照后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色教程 在城市霓虹灯夜景拍摄中,由于现场光线复杂等因素,照片可能无法完全呈现出当时的视觉感受。通过 Lr 调色,可以弥补拍摄时的不足。例如,运用基本调整面板中的曝光、对比度、阴影等工具,可以处理出画面的整体明暗…...
c#面试题整理
1.如何保持数据库的完整性,一致性 最好的方法:数据库约束(check,unique,主键,外键,默认,非空) 其次是:用触发器 最后:才是自己些业务逻辑,这个效率低 2.事…...
数据库基础以及基本建库建表的简单操作
文章目录 一、数据库是啥1.1、数据库的概念1.1、关系型数据库、非关系型数据库1.1、数据库服务器,数据库与表之间的关系 二、为啥要使用数据库2.1:传统数据文件存储2.2:数据库存储数据2.3、结论 三、使用数据库了会咋样四、应该咋用数据库&am…...
基于spring boot使用@Sl4j的日志功能,注解引入后爆红未生效
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 问题描述问题分析解决方案 📃文章…...
《深度剖析架构蒸馏与逻辑蒸馏:探寻知识迁移的差异化路径》
在人工智能模型优化的前沿领域,架构蒸馏与逻辑蒸馏作为知识蒸馏的关键分支,正引领着模型小型化与高效化的变革浪潮。随着深度学习模型规模与复杂度的不断攀升,如何在资源受限的情况下,实现模型性能的最大化,成为了学术…...
使用OpenCV来获取视频的帧率
在OpenCV中,获取视频的帧率(FPS, Frames Per Second)是一个常见的操作,尤其是在处理视频流或进行视频分析时。帧率表示每秒钟视频中的帧数,这个参数对于视频播放速度和时间计算非常重要。 以下是如何使用OpenCV来获取…...
计算机视觉|3D卷积网络VoxelNet:点云检测的革新力量
一、引言 在科技快速发展的背景下,3D 目标检测技术在自动驾驶和机器人领域中具有重要作用。 在自动驾驶领域,车辆需实时、准确感知周围环境中的目标物体,如行人、车辆、交通标志和障碍物等。只有精确检测这些目标的位置、姿态和类别&#x…...
vue-cli3+vue2+elementUI+avue升级到vite+vue3+elementPlus+avue总结
上一个新公司接手了一个vue-cli3vue2vue-router3.0elementUI2.15avue2.6的后台管理项目,因为vue2在2023年底已经不更新维护了,elementUI也只支持到vue2,然后总结了一下vue3的优势,最后批准升级成为了vitevue3vue-router4.5element…...