Merge branch 'dev2' into dev

# Conflicts:
#	yj_room_agent/settings.py
#	yj_room_agent/urls.py
#	yj_room_agent/views.py
This commit is contained in:
yujj128
2025-06-05 11:48:27 +08:00
7 changed files with 432 additions and 6 deletions

3
.env Normal file
View File

@@ -0,0 +1,3 @@
MODEL_API_KEY=sk-9nng4v6qsdiw42r6d3re4nym15hiti29
MODEL_BASE_URL=https://gateout.yced.com.cn/v1
MODEL_NAME=deepseek

View File

@@ -1,3 +1,3 @@
Django==5.2.1
Django==2.32.3
dotenv==0.9.9
requests==2.32.3
python-decouple==3.8

View File

@@ -0,0 +1,177 @@
from threading import Lock
from datetime import datetime
import requests, json
from .openai_client import call_openai_api
from decouple import config
import threading, re
MODEL_NAME = config('MODEL_NAME', default="")
BASE_URL = config('MODEL_BASE_URL', default="")
def is_json(myjson):
try:
json_object = json.loads(myjson)
return True
except ValueError:
return False
def query_room_info() -> str:
resp = requests.get('http://127.0.0.1:8000/myapi/room/')
return resp.text
def book_room(data: dict) -> str:
resp = requests.post('http://127.0.0.1:8000/myapi/room/', data)
return resp.text
def check_and_process_think(content: str) -> str:
filtered_text = re.sub(r"<think\b[^>]*>.*?</think>", '', content, flags=re.DOTALL)
return filtered_text
def build_prompt():
"""构建增强提示词"""
# 获取可用会议室信息
room_info = query_room_info()
for_mart_str = '''
{
"room_id":"11", //会议室ID
"capacity":20,
"start_time":"2025-06-04 09:30:10",
"end_time":"2025-06-04 12:30:10",
"user_confirm":1 //用户是否确认
}
'''
time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 增强提示词模板
template = f"""你是一个专业的OA会议预订助手请根据以下信息提供服务
现在时间是 :{time_now}
可用会议室信息:
{room_info}
请按以下步骤处理:
1. 解析用户预订需求(时间、人数、设备要求等)
2. 根据可用会议室列表推荐合适选项,推荐选项时不需要提取用户预订信息,待用户确认是再提取。按照正常自然语言对话返回
3. 如果用户确定要预订某间会议室,而不是在询问合适会议室时,请帮根据上下文我提取用户预订信息,预订时间等信息并返回结果请只返回json格式得预订信息且不需要包含多余的描述内容以及<think>标签等,输出结果示例如下:
{for_mart_str}
4. 当用户再次发起预订会议室时,不要直接提取用户的预订信息而是请重新查看现有会议室的最新情况,基于用户需求给用户推荐合理的会议室,推荐选项时不需要提取用户预订信息不要返回json数据,待用户确认是再提取。按照正常自然语言对话返回
5. 如果用户需要解析调用预订会议室返回的结果,请解析用户提供的相应结果信息,并给予自然语言反馈,不需要返回json数据
6. 用户其他需求,请按照自然语言对话返回
"""
return template
class DialogManager:
def __init__(self):
self.dialogs = {}
self.lock = Lock()
def get_history(self, session_id: str) -> list:
return self.dialogs.get(session_id, [])
def add_message(self, session_id, role, content):
with self.lock:
if session_id not in self.dialogs:
self.dialogs[session_id] = []
# 自动维护对话历史
self.dialogs[session_id].append({
"role": role,
"timestamp": datetime.now().isoformat(),
"content": content
})
# 上下文压缩(超长对话处理)
if len(self.dialogs[session_id]) > 50:
self.compress_context(session_id)
def compress_context(self, session_id):
"""对话历史压缩算法"""
history = self.dialogs[session_id]
# 保留最近3条完整记录
recent = history[-5:]
# 摘要生成中间对话内容
summary = self.generate_summary(history[3:-3])
# 重组会话历史
self.dialogs[session_id] = [
{"role": "system", "content": f"对话摘要:{summary}"},
*recent
]
def generate_summary(self, messages):
"""生成对话摘要(调用本地模型)"""
text = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
headers = {}
messages = [
{"role": "system",
"content": "你现在是一个对话总结助手,基于用户与模型智能体的对话,生成对话总结摘要,要求简明且保留关键信息"},
{"role": "user", "content": f"请生成以下对话的简明摘要(保留关键信息):\n\n{text}"}
]
payload = {
"model": MODEL_NAME,
"messages": messages,
}
headers["Authorization"] = f"Bearer {config('MODEL_API_KEY')}"
response = requests.post(f"{BASE_URL}/chat/completions", data=json.dumps(payload, ensure_ascii=False),
timeout=1000, headers=headers, verify=False)
response.raise_for_status()
print(response.text)
return response.json().get("response", "摘要生成失败")
dialog_manager = DialogManager()
def add_message_async(manager: DialogManager, session_id: str, role: str, content: str):
thread = threading.Thread(target=manager.add_message, args=(session_id, role, content))
thread.start()
def process_chat(user_id: str, user_input: str):
history = []
query_history = dialog_manager.get_history(user_id)
history.extend(query_history)
prompt = ''
if history is None or len(history) == 0:
prompt = build_prompt()
add_message_async(dialog_manager, user_id, 'system', prompt)
add_message_async(dialog_manager, user_id, 'user', user_input)
resp = call_openai_api(model=MODEL_NAME, system_prompt=prompt, user_query=user_input,
api_key=config('MODEL_API_KEY'),
history=history)
content = resp["choices"][0]["message"]["content"]
reasoning_content = resp["choices"][0]["message"]["reasoning_content"]
print(content)
new_content = check_and_process_think(content=content)
if 'json' in new_content or is_json(new_content):
new_content = new_content.replace("json", '')
new_content = new_content.replace("`", '')
data = json.loads(new_content)
# 触发预订函数------
result = book_room(data=data)
print(result)
book_promot = f'''
系统调用API预订该会议室的结果如下:
{result}
请帮用户解析预订会议室的结果,并根据结果给予用户相应自然语言反馈
'''
new_history = []
query_history = dialog_manager.get_history(user_id)
new_history.extend(query_history)
resp = call_openai_api(model=MODEL_NAME, user_query=book_promot,
api_key=config('MODEL_API_KEY'),
history=new_history,
system_prompt='',
)
content = resp["choices"][0]["message"]["content"]
add_message_async(dialog_manager, user_id, 'assistant', content)
return {'response': resp}
else:
add_message_async(dialog_manager, user_id, 'assistant', content)
if reasoning_content:
add_message_async(dialog_manager, user_id, 'assistant', reasoning_content)
return {'response': resp}

File diff suppressed because one or more lines are too long

View File

@@ -12,19 +12,20 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
from pathlib import Path
from decouple import config
# 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/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-i(fm5c2v*=vgfwmgdl^qi7iezv(xfwovbqu=+^=vm72e$gnx&l'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["10.212.26.178",'127.0.0.1']
ALLOWED_HOSTS = ["192.168.237.130", '127.0.0.1','10.212.27.4']
# Application definition
@@ -42,7 +43,7 @@ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

View File

@@ -16,7 +16,7 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path
from yj_room_agent import views
from yj_room_agent import views
urlpatterns = [
path('admin/', admin.site.urls),

View File

@@ -1,4 +1,8 @@
import json
from django.http import StreamingHttpResponse, JsonResponse, FileResponse
from yj_room_agent.LLM.ai_service import process_chat
from django.views.decorators.http import require_POST
import json
from django.http import StreamingHttpResponse, JsonResponse, FileResponse, HttpResponseNotAllowed
import requests