7 Commits
master ... dev

Author SHA1 Message Date
雷雨
7ebd1b105b feat:提交预订会议室 2025-12-03 16:29:45 +08:00
雷雨
f6720ed11a feat:查询已预订会议提交 2025-12-02 11:33:34 +08:00
雷雨
8dd675638a feat:查询可用会议室接口更改 2025-12-02 11:15:19 +08:00
雷雨
e8f95dff59 feat:查询会议室流程打通 2025-12-02 10:41:29 +08:00
雷雨
eec994ca84 feat:预订会议室节点-增加识别查询空闲会议室以及触发预订会议室的功能 2025-11-15 11:25:31 +08:00
雷雨
ed9e3adce3 feat:移除多余依赖 2025-11-13 16:10:47 +08:00
雷雨
02b56ac1ea feat:整改会议预订助手-接入langgrah,增加意图识别 2025-11-13 16:07:45 +08:00
17 changed files with 590 additions and 24 deletions

12
.env
View File

@@ -1,19 +1,19 @@
#api key
MODEL_API_KEY=sk-7391d759f1e4488f82c2d278b977c359
MODEL_API_KEY=sk-trjqfqhisfwuooakphcqbacotdrfqxnohmmtxzakfpjpinrq
#模型地址
MODEL_BASE_URL=http://10.254.23.128:31205/v1
MODEL_BASE_URL=https://api.siliconflow.cn/v1
#模型名称
MODEL_NAME=deepseek_70B
MODEL_NAME=Qwen/Qwen3-Next-80B-A3B-Instruct
#模型活跃度
MODEL_TEMPERATURE=0.1
MODEL_TEMPERATURE=0.5
#放行host地址
DJANGO_ALLOWED_HOSTS=192.168.237.130,127.0.0.1,10.212.26.130,192.168.31.115
#是否开启debug模式
DJANGO_DEBUG_ENABLE=True
DJANGO_LOG_LEVEL=INFO
DEFAULT_AUTH_URL = 'https://oa-pre.cyj.cn/iuap-api-auth'
DEFAULT_GATEWAY_URL = 'https://oa-pre.cyj.cn/iuap-api-gateway '
DEFAULT_AUTH_URL = 'https://fmis-pre.cyj.cn/iuap-api-auth'
DEFAULT_GATEWAY_URL = 'https://fmis-pre.cyj.cn/iuap-api-gateway'
TEMP_TENANT_ID = 'pr3rl2oj'
#APPKEY = 'e5d615eb169944abb3a1db5bd699ca65'
#APPSECRET = '84bb250c995c6161a97aebc2296abe558f6551ac'

96
prompt_template.yaml Normal file
View File

@@ -0,0 +1,96 @@
template:
#意图识别节点-系统提示词
intent_recognition: |
# 角色与目标
你是一个专业的意图识别模块,是会议室预订智能体的核心决策中枢。你的唯一职责是根据用户的当前提问和聊天历史,准确判断用户的核心意图,并将其映射到指定的下游处理节点。
# 上下文信息
你将作为 Langgraph 工作流中的一个节点存在。你的输出(一个 JSON 对象)将直接用于决定下一步应该调用哪个功能节点(如预订会议室、查询预订等)。你的判断必须精准、高效。
<节点名称> 必须是且仅是以下四个选项之一:
pre_book_meeting - 当用户明确表示要预订/预约会议室时
cancel_meeting - 当用户明确表示要取消已预订的会议室时
query_meeting - 当用户查询已预订的会议室信息时
unknown - 当意图不明确或超出上述三种情况时
# 输入信息
当前时间:<current_time>{current_time}</current_time>
用户输入信息:<user_input>{user_input}</user_input>
history【历史对话消息】:<history>{history}</history>
# 输出信息
<意图摘要> 是对该意图的简短描述不超过50字符
你必须严格遵守以下 JSON 格式进行输出,不包含任何其他解释性文字或代码块标记:
{{"node": "<节点名称>", "summary": "<意图摘要>"}}
result_summary: |
你是一个会议预订智能体的自然语言生成模块用户的请求已经由系统模块处理并调用了相应的API。请阅读API返回的结构化结果数据并将其用自然语言进行解释和总结后呈现给用户。你的任务是根据API返回的内容输出清晰、准确、友好的反馈信息。
用户操作可能包括查询空闲会议室、预订会议室、取消预订、查询已预订会议等
#你需要完成的任务:
准确解析API返回的数据结构。
识别结果是否成功是否有“error”字段或status不为200等
如果结果成功,请用自然、简洁的方式向用户说明具体信息。
如果结果中出现错误,请以友好、易于理解的方式提示错误信息,并可提供适当建议。
处理结果信息时尽量“结构化解析”,避免遗漏关键信息(如时间、会议室名称、人数等)
使用口语化中文,避免生硬术语。
解析结果展示时候尽量以MD格式展示。
#用户数据:
{user_operation}
<data>{data}</data>
结果展示示例:
1.空闲会议室查询示例:
```
1.会议室名称: <name>
会议室Id: <id>
容量: <capacity>
```
book_meeting: |
你是一个会议室预订智能体负责识别用户意图并根据提供的信息自动构造相应的JSON查询或预订指令。
当前时间:<current_time>{current_time}</current_time>
**核心指令**
- 严格遵守上述信息检查和响应规则。
- 优先处理时间合法性特别是24:00:00的转换。
- 会议室Id必须是长度大于15位的数字编号可以通过会议室名称匹配上下文获取禁止使用默认值。
- 所有JSON输出必须严格遵循提供的模板格式不得添加任何额外字段或说明文字。
- 禁止对查询结果做任何假设,直接按规则执行。
处理流程如下:
当用户表达预订意向时:
1. **信息检查与提取**
* 严格检查用户的表达中是否包含以下信息,仅作判断和提取:
* `会议室Id` (必需,注意:[1]会议室编号是长度大于15位的数字编号不要混淆会议室名称和编号[2]可以根据会议室名称去上下文中去匹配会议室Id禁止使用默认的)
* `具体时间段` (必需,至少包含开始时间或结束时间中的一个)
* `参会人数` (非必需若用户未指明则默认为20)
* `会议主题` (非必需,若会议主题不存在则用"默认主题")
2. **时间处理规则**
* 如果会议具体的开始和结束时间都没有,则按规则 (4) 提示用户确认会议具体时间。
* 如果只有开始时间则结束时间按照时长2小时自动补齐。补齐时需特别注意24点的合法性例如`2025-05-23 24:00:00` 不合法,必须转换成 `2025-05-24 00:00:00`。
* 如果只有结束时间则开始时间按照提前2小时自动补齐。补齐时同样需处理跨日的情况例如结束时间为 `2025-05-24 01:00:00`,补齐的开始时间应为 `2025-05-23 23:00:00`。
* 时间标准格式为 `YYYY-MM-DD HH:MM:SS`。
* 用户用户只说了上午则默认为上午9-11点下午则默认为下午15-17点。
3. **响应规则**
* (1) **无时间信息**如果用户表达中完全没有提及任何具体的开始或结束时间无法根据上下文推断则按照规则构造并返回如下JSON提示用户输入
```json
{{
"node":"END",
"message":"请输入会议的具体开始-结束时间"
}}
```
* (2) **无会议室ID但有时间段**:如果用户未明确指定`会议室Id`无论是通过ID还是名称但`具体时间段`至少存在一个根据规则2补齐完整后则构造JSON直接查询会议室信息。`start_time`和`end_time`不能为空,`Region`可能是城市、区域、学校、酒店等的名称,注意从上下文中识别并提取。`capacity`参会人数未指明则默认20。禁止假设查询失败按如下方式填充构造json查询体返回给用户:
```json
{{
"node":"query_avali_room",
"start_time":"",
"end_time":"",
"Region":"",
"capacity":""
}}
```
* (3) **信息完整且确认预定**:若用户确认预定且提供了信息完整的`会议室Id`长度大于15位的数字编号并且`具体时间段`存在一个根据规则2补齐完整后则直接构造标准JSON执行预定操作。参会人数未指明则默认20会议主题不存在则用"默认主题"。按如下方式填充构造json返回
```json
{{
"room_id":"",
"capacity":20,
"subject":"会议主题",
"start_time":"2025-06-04 09:30:10",
"end_time":"2025-06-04 11:30:10",
"node":"book_meeting"
}}
```
4 .用户历史消息对话如下:
<history>{history}</history>

View File

@@ -4,4 +4,6 @@ python-decouple==3.8
APScheduler==3.11.0
pydantic-ai==0.3.6
gunicorn==23.0.0
redis==6.2.0
redis==6.2.0
langgraph
langchain-openai

View File

View File

@@ -0,0 +1,19 @@
from datetime import datetime
from django.db import models
from django.db.models import Q, CheckConstraint
'''
会话表
'''
class Conversation(models.Model):
id = models.CharField(max_length=100, primary_key=True)
create_time = models.DateTimeField(default=datetime.now())
content = models.TextField(null=False)
user_id = models.CharField(max_length=100, null=False)
cvs_id = models.CharField(max_length=100, null=False)
role = models.CharField(max_length=100, null=False)
meta = models.TextField(null=True)
class Meta:
db_table = 'db_conversation'

View File

@@ -0,0 +1,77 @@
import time
import threading
class Snowflake:
def __init__(self, worker_id, datacenter_id):
# 初始化起始时间2020-01-01
self.epoch = 1577836800000
# 结构配置
self.worker_id_bits = 5
self.datacenter_id_bits = 5
self.sequence_bits = 12
# 最大值计算
self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
# 移位偏移量
self.worker_id_shift = self.sequence_bits
self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
self.timestamp_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
# 序列号掩码
self.sequence_mask = -1 ^ (-1 << self.sequence_bits)
# 参数校验
if worker_id > self.max_worker_id or worker_id < 0:
raise ValueError(f"Worker ID需在0~{self.max_worker_id}之间")
if datacenter_id > self.max_datacenter_id or datacenter_id < 0:
raise ValueError(f"Datacenter ID需在0~{self.max_datacenter_id}之间")
self.worker_id = worker_id
self.datacenter_id = datacenter_id
self.sequence = 0
self.last_timestamp = -1
self.lock = threading.Lock()
def _current_time(self):
"""获取当前毫秒时间戳"""
return int(time.time() * 1000)
def _wait_next_millis(self, last_timestamp):
"""等待至下一毫秒"""
timestamp = self._current_time()
while timestamp <= last_timestamp:
time.sleep(0.001)
timestamp = self._current_time()
return timestamp
def generate_id(self):
with self.lock:
timestamp = self._current_time()
# 时钟回拨检测
if timestamp < self.last_timestamp:
raise ValueError(f"时钟回拨异常!时间差:{self.last_timestamp - timestamp}ms")
# 同一毫秒序列号递增
if timestamp == self.last_timestamp:
self.sequence = (self.sequence + 1) & self.sequence_mask
if self.sequence == 0:
timestamp = self._wait_next_millis(self.last_timestamp)
else:
self.sequence = 0
self.last_timestamp = timestamp
return ((timestamp - self.epoch) << self.timestamp_shift) | \
(self.datacenter_id << self.datacenter_id_shift) | \
(self.worker_id << self.worker_id_shift) | \
self.sequence
id_generator = Snowflake(worker_id=1, datacenter_id=1)
def next_id():
return id_generator.generate_id()

View File

View File

@@ -0,0 +1,268 @@
import orjson
from decouple import config
from datetime import datetime
from langchain_openai import ChatOpenAI
from typing import TypedDict, Annotated, List, Optional, Union
import logging, json
from yj_room_agent.db import snow_id, db_main
from yj_room_agent.template import template
from yj_room_agent.tools import json_tools, getinfo, params_filter
from langgraph.graph import StateGraph, END, START
from langgraph.checkpoint.memory import MemorySaver
from yj_room_agent.temp_history import msg_history
DEFAULT_QUERY_SIZE = config('DEFAULT_QUERY_SIZE', cast=int, default=30)
room_llm = ChatOpenAI(
model=config('MODEL_NAME', default=''),
base_url=config('MODEL_BASE_URL', default=''),
temperature=config('MODEL_TEMPERATURE', default=0.5, cast=float),
max_tokens=8000,
max_retries=2,
api_key=config('MODEL_API_KEY', default='empty'),
)
logger = logging.getLogger('django')
def parse_time(time_str: str) -> int:
try:
timestamp = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S").timestamp()
return int(timestamp * 1000)
except Exception as ee:
print("解析时间错误:" + str(ee.with_traceback()))
return int(datetime.now().timestamp() * 1000)
class RoomChatAgentState(TypedDict):
user_query: str
conversation_id: str
user_id: str
params: dict
history: Optional[list]
# 用户意图
user_intention: Optional[dict]
user_intention_error: Optional[str]
# 上一个执行节点
last_node: Optional[str]
result_summary: Optional[str]
result_error: Optional[str]
# data_数据
query_meeting_data: Optional[dict | str]
pre_book_meeting_data: Optional[dict | str]
book_meeting_data: Optional[dict | str]
cancel_meeting_data: Optional[dict | str]
avli_room_data: Optional[dict | str | list]
'''
用户意图识别节点
'''
def intent_recognition_node(state: RoomChatAgentState) -> dict:
logger.info(
f"user:{state.get('user_id', '1')} ---------------进入 intent_recognition_node(意图识别) 节点---------------")
user_query = state.get('user_query', '')
history = state.get('history', [])
user_id = state.get('user_id', '')
msg_history.add_msg(state.get('conversation_id', ''), 'user', user_query)
xx_template = template.get_base_template()
sys_template = xx_template['template']['intent_recognition']
sys_template = sys_template.format(history=history, user_input=user_query,
current_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
resp = room_llm.invoke(sys_template).text()
logger.info(f"user:{user_id} intent_recognition_node(意图识别) 节点返回结果:{resp}")
resp = json_tools.extract_nested_json(resp)
result = orjson.loads(resp)
if result is None or type(result) is not dict:
logger.error(f"user:{user_id} intent_recognition_node(意图识别) 节点返回结果:{resp} 解析失败")
return {'user_intention': None,
'user_intention_error': f"user:{user_id} intent_recognition_node(意图识别) 节点返回结果:{resp} 解析失败"}
return {'user_intention': result}
def intent_recognition_node_handler(state: RoomChatAgentState) -> str:
user_intention = state.get('user_intention', {})
conversation_id = state.get('conversation_id', '')
if user_intention is None:
msg_history.add_msg(conversation_id, 'assistant', '识别用户意图识别失败')
return END
node = user_intention.get('node', '')
if node == '' or node == 'unknown':
logger.error(f"user:{state.get('user_id', '1')} 未知意图:{user_intention}")
msg_history.add_msg(conversation_id, 'assistant', user_intention.get('summary', ''))
return END
return node
# 预约会议,需要判断历史消息或者用户输入,判断是否有会议室号,如果有,则预约会议,如果没有,触发查询空闲会议室
def pre_book_meeting_node(state: RoomChatAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 pre_book_meeting_node(预约会议) 节点-")
user_query = state.get('user_query', '')
history = state.get('history', [])
user_id = state.get('user_id', '')
xx_template = template.get_base_template()
sys_template = xx_template['template']['book_meeting']
sys_template = sys_template.format(history=history, current_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
resp = room_llm.invoke(
[{'role': 'system', 'content': sys_template}, {'role': 'user', 'content': user_query}]).text()
resp = json_tools.extract_nested_json(resp)
result = orjson.loads(resp)
logger.info(f"user:{user_id} book_meeting_node(预约会议) 节点返回结果:{resp}")
return {'pre_book_meeting_data': result}
def pre_book_meeting_node_handler(state: RoomChatAgentState) -> str:
user_intention = state.get('pre_book_meeting_data', {})
if user_intention is None:
return END
node = user_intention.get('node', '')
if node == 'END':
logger.error(f"user:{state.get('user_id', '1')} 提取预约会议数据失败:{user_intention}")
msg_history.add_msg(state.get('conversation_id', ''), 'assistant', user_intention.get('message', ''))
return END
return node
# 查询空闲会议室,需要判断历史消息或者用户输入,查询空闲会议室,返回结果
def query_avliable_meeting_room_node(state: RoomChatAgentState) -> dict:
param = state.get('params', {})
pre_data = state.get('pre_book_meeting_data', {})
param['startTimeStr'] = pre_data.get('start_time', '')
param['endTimeStr'] = pre_data.get('end_time', '')
param['pageNum'] = 1
param['pageSize'] = DEFAULT_QUERY_SIZE
content = getinfo.query_avali_meetinroom(param)
list = content['data'].get('list', [])
result = params_filter.filter_meetingroom(list)
logger.info(" filter data: {0}".format(result))
result = params_filter.filter_params(result, "query_meeting_room")
logger.debug("query_room_info result => {0}".format(result))
# 字典中只要key存在哪怕对应的value是'',也能取出来空字符串 data.get('capacity', 0)可能是空字符串
capacity = pre_data.get('capacity', 0)
capacity_limit = int(capacity) if capacity not in [None, ''] else 0
logger.info("capacity limit {0} {1}".format(capacity_limit, type(capacity_limit)))
new_list = []
if pre_data.get('Region') and pre_data.get('Region') != 'None':
region = pre_data.get('Region')
for b in result:
logger.info("b.capacity {0} {1}".format(b.get('capacity', 0), type(b.get('capacity', 0))))
if ((region in b.get('name', 'default') or region in b.get('typeName', 'default')) and b.get('capacity',
0) >= capacity_limit):
new_list.append(b)
else:
for b in result:
if b.get('capacity', 0) >= capacity_limit:
new_list.append(b)
return {'avli_room_data': new_list, 'last_node': 'query_avali_room'}
def book_meeting_node(state: RoomChatAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 book_meeting_node(预订会议) 节点-")
data = state.get('pre_book_meeting_data', {})
params = state.get('params', {})
result=None
try:
new_data = {
"subject": data.get('subject', '系统默认主题'),
"meetingRoomId": data["room_id"],
"meetingRoomName": "会议室名称",
"meetingDateTimeStamp": parse_time(data["start_time"]),
"startDateTimeStamp": parse_time(data["start_time"]),
"endDateTimeStamp": parse_time(data["end_time"]),
"meetingPersonYhtUserIds": [
],
"meetingPersonAmount": data.get('capacity', 0),
"remindArray": [
15
],
"content": "会议内容",
"isSendMail": True,
"isSendMsg": True
}
result=getinfo.book_meeting(params, new_data)
data = result.get('data', {})
start_time = data.get('startTime', None)
end_time = data.get('endTime', None)
del data['startDateTime']
del data['endDateTime']
del data['meetingDateTime']
if start_time:
st = params_filter.parse_timestamp_to_str(start_time)
data['startTime'] = st
if end_time:
end = params_filter.parse_timestamp_to_str(end_time)
data['endTime'] = end
result['data'] = data
except Exception as e:
logger.error(f"user:{state.get('user_id', '1')} 预订会议失败:{e}")
result={"code":"500","message":f"预订会议失败,原因:{e}"}
return {'last_node': 'book_meeting', 'book_meeting_data': result}
# 取消会议室,需要判断历史消息或者用户输入,判断是否有会议室号,如果有,则取消会议,如果没有,触发查询已预订会议
def cancel_meeting_node(state: RoomChatAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 cancel_meeting_node(取消会议) 节点-")
return {}
# 查询已预订会议,需要判断历史消息或者用户输入,查询已预订会议,返回结果
def query_meeting_node(state: RoomChatAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 query_meeting_node(查询已预订会议) 节点-")
param = state.get('params', {})
# 示例数据,后面替换用友查询接口数据
meeting_room = getinfo.query_meetingbooking_info(param)
result = params_filter.filter_state(meeting_room)
return {'query_meeting_data': result, 'last_node': 'query_meeting'}
# 结果汇总节点,根据上一个节点的返回结果,生成结果汇总模板,返回结果,结束会话
def _result_summary_node(state: RoomChatAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 _result_summary_node(结果汇总) 节点-")
last_node = state.get('last_node', '')
node_msg = ''
data = None
if last_node == 'book_meeting':
node_msg = '用户调用APi预订会议数据如下:'
data = state.get('book_meeting_data', None)
if last_node == 'cancel_meeting':
node_msg = '用户调用APi取消会议结果如下:'
data = state.get('cancel_meeting_data', None)
if last_node == 'query_meeting':
node_msg = '用户调用APi查询已预订会议结果如下:'
data = state.get('query_meeting_data', None)
if last_node == 'query_avali_room':
node_msg = '用户调用APi查询空闲会议室结果如下:'
data = state.get('avli_room_data', None)
template_msg = template.get_base_template()
result_summary = template_msg['template']['result_summary']
result_summary = result_summary.format(user_operation=node_msg, data=data)
logger.info(f"大模型汇总结果模板:{result_summary}")
resp = room_llm.invoke(result_summary).text()
msg_history.add_msg(state.get('conversation_id', ''), 'assistant', resp)
return {'result_summary': resp}
workflow = StateGraph(RoomChatAgentState)
workflow.add_node("_intent_recognition", intent_recognition_node)
workflow.add_node("pre_book_meeting", pre_book_meeting_node)
workflow.add_node("book_meeting", book_meeting_node)
workflow.add_node("query_avali_room", query_avliable_meeting_room_node)
workflow.add_node("cancel_meeting", cancel_meeting_node)
workflow.add_node("query_meeting", query_meeting_node)
workflow.add_node("_result_summary", _result_summary_node)
workflow.add_edge(START, "_intent_recognition")
workflow.add_conditional_edges('_intent_recognition', intent_recognition_node_handler,
[END, 'pre_book_meeting', 'cancel_meeting', 'query_meeting'])
workflow.add_conditional_edges("pre_book_meeting", pre_book_meeting_node_handler,
[END, 'book_meeting', 'query_avali_room'])
workflow.add_edge("_result_summary", END)
workflow.add_edge("cancel_meeting", END)
workflow.add_edge("query_meeting", '_result_summary')
workflow.add_edge("book_meeting", '_result_summary')
workflow.add_edge("query_avali_room", '_result_summary')
memory = MemorySaver()
room_chat_agent = workflow.compile(checkpointer=memory)

View File

View File

@@ -0,0 +1,20 @@
'''
仅用于测试验证使用,后期历史消息还是在数据库中保存
'''
cache = {}
def add_msg(conversation_id, role, msg):
if conversation_id not in cache:
ms = {'role': role, 'content': msg}
cache[conversation_id] = [ms]
else:
cache[conversation_id].append({'role': role, 'content': msg})
print(cache[conversation_id])
def get_msg(conversation_id):
if conversation_id in cache:
return cache[conversation_id]
else:
return []

View File

View File

@@ -0,0 +1,15 @@
import yaml
base_template = None
def load():
with open('./prompt_template.yaml', 'r', encoding='utf-8') as f:
global base_template
base_template = yaml.load(f, Loader=yaml.SafeLoader)
def get_base_template():
if not base_template:
load()
return base_template

View File

@@ -210,6 +210,8 @@ def query_meetingroom(params: dict):
logger.info("request url => {0}".format(request_url))
if not params.get("pageSize", None):
params['pageSize'] = page_size
token=get_access_token(tenant_id)
params['access_token'] = token
logger.debug("query_meetingroom params => {0}".format(params))
respones = requests.get(url=request_url, params=params,
headers=header,verify=False)
@@ -237,6 +239,8 @@ def query_avali_meetinroom(params: dict):
logger.info("request url => {0}".format(request_url))
if not params.get("pageSize", None):
params['pageSize'] = page_size
acc_token=get_access_token(tenant_id)
params['access_token'] = acc_token
logger.debug("query_avali_meetingroom params => {0}".format(params))
respones = requests.get(url=request_url, params=params,
headers=header, verify=False)
@@ -266,6 +270,8 @@ def query_meetingbooking_info(params: dict):
logger.info("request url => {0}".format(request_url))
if not params.get("pageSize",None):
params['pageSize'] = page_size
ac=get_access_token(tenant_id)
params['access_token'] = ac
logger.info("now page size => {0}".format(params['pageSize']))
logger.debug("query_meetingbooking_info params => {0}".format(params))
respones = requests.get(url=request_url, params=params,
@@ -296,6 +302,8 @@ def book_meeting(params: dict, data: dict):
request_url = gateway_url + BOOKMEETING
logger.debug("request url => {0}".format(request_url))
logger.debug("book_meeting params => {0}".format(params))
acc=get_access_token(tenant_id)
params['access_token'] = acc
respones = requests.post(url=request_url, params=params,
headers=header, data=json.dumps(data),verify=False)
logger.info("book meeting respones => {0}".format(respones.text))

View File

@@ -0,0 +1,31 @@
import orjson
import logging
logger = logging.getLogger('django')
def extract_nested_json(text):
stack = []
start_index = -1
results = []
if not text:
logger.warning("extract_nested_json: text is empty")
for i, char in enumerate(text):
if char in '{[':
if not stack: # 记录起始位置
start_index = i
stack.append(char)
elif char in '}]':
if stack and ((char == '}' and stack[-1] == '{') or (char == ']' and stack[-1] == '[')):
stack.pop()
if not stack: # 栈空时截取完整JSON
json_str = text[start_index:i + 1]
try:
orjson.loads(json_str) # 验证有效性
results.append(json_str)
except:
pass
else:
stack = [] # 括号不匹配则重置
if len(results) > 0 and results[0]:
return results[0]
return None

View File

@@ -35,7 +35,7 @@ def filter_params(data, endpoint_name):
'''
def filter_state(content: dict):
filtered_data = []
for room in content['data']:
for room in content.get('data',[]):
filtered_meetings = [meeting for meeting in room['meetingDTOList'] if meeting['state'] in [0, 1]]
if filtered_meetings: # 只保留有会议的会议室

View File

@@ -16,18 +16,19 @@ 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),
path('test/', views.hello, name='hello'),
path('book_room/', views.room_chat, name='room_chat'),
path('book_room_2/', views.room_chat_2, name='room_chat_2'),
path('getMeetingType/', views.query_meeting_type),
path('getMeeting/', views.query_meeting),
path('getMeetingBookingDetails/', views.query_meetingooking_info),
path('bookMeeting/', views.book_meeting),
path('cancelMeeting/', views.cancel_meeting),
path('editMeeting/',views.edit_meeting),
path('editMeeting/', views.edit_meeting),
path('yj-agent-api/tianyi_chatbot', views.tian_yi_chat_bot, name='tianyi_chatbot'),
]

View File

@@ -5,10 +5,14 @@ from django.views.decorators.http import require_POST
import json
import requests
from .tools import getinfo
from .tianyi_ai import knowledge_chat
from .tianyi_ai import knowledge_chat
from yj_room_agent.graph.room_meeting_graph_agent import RoomChatAgentState, room_chat_agent
import uuid
from yj_room_agent.temp_history import msg_history
def hello(request):
return JsonResponse({'msg': 'ok'})
def query_meeting_type(request):
"""
query_params:
@@ -31,11 +35,12 @@ def query_meeting_type(request):
result = getinfo.query_meetingroom_type(params)
content = json.loads(json.dumps(result))
print("room type :",content)
print("room type :", content)
return JsonResponse(content)
except Exception as ex:
return JsonResponse(str(ex))
def query_meeting(request):
"""
query_params:
@@ -60,7 +65,7 @@ def query_meeting(request):
result = getinfo.query_meetingroom(params)
content = json.loads(json.dumps(result))
print("content :",content)
print("content :", content)
return JsonResponse(content)
except Exception as ex:
return JsonResponse(str(ex))
@@ -93,16 +98,15 @@ def query_meetingooking_info(request):
params['access_token'] = access_token
print("params is -----", params)
result = getinfo.query_meetingbooking_info(params)
print("params is -----",params)
print("params is -----", params)
result = params_filter.filter_state(result)
content = json.loads(json.dumps(result))
print("content is ------------------ :",content)
print("content is ------------------ :", content)
return JsonResponse(content)
except Exception as ex:
return JsonResponse(str(ex))
def book_meeting(request):
"""
data{
@@ -130,7 +134,7 @@ def book_meeting(request):
params = request.GET.dict()
yht_token = ((request.META.get('HTTP_YHT_ACCESS_TOKEN', None))
or request.headers.get('yht_access_token', None))
or request.headers.get('yht_access_token', None))
print("yht is {0}".format(yht_token))
if yht_token:
params['yht_access_token'] = yht_token
@@ -152,6 +156,7 @@ def book_meeting(request):
except Exception as ex:
return JsonResponse(str(ex))
def edit_meeting(request):
"""
:params:
@@ -175,7 +180,7 @@ def edit_meeting(request):
params = request.GET.dict()
yht_token = ((request.META.get('HTTP_YHT_ACCESS_TOKEN', None))
or request.headers.get('yht_access_token', None))
or request.headers.get('yht_access_token', None))
print("yht is {0}".format(yht_token))
if yht_token:
params['yht_access_token'] = yht_token
@@ -189,7 +194,7 @@ def edit_meeting(request):
access_token = getinfo.get_access_token(tenant_id)
params['access_token'] = access_token
result = getinfo.edit_meeting_info(params,data)
result = getinfo.edit_meeting_info(params, data)
content = json.loads(json.dumps(result))
print("content :", content)
return JsonResponse(content)
@@ -227,7 +232,6 @@ def cancel_meeting(request):
return JsonResponse(str(ex))
@require_POST
def room_chat(request):
params = request.GET.dict()
@@ -244,13 +248,38 @@ def room_chat(request):
return JsonResponse(resp)
@require_POST
def room_chat_2(request):
params = request.GET.dict()
yht_token = ((request.META.get('HTTP_YHT_ACCESS_TOKEN', None))
or request.headers.get('yht_access_token', None))
if yht_token:
params['yht_access_token'] = yht_token
if not yht_token:
ckk = request.COOKIES
params['yht_access_token'] = ckk.get('yht_access_token', None)
body = json.loads(request.body)
history = msg_history.get_msg(conversation_id=body['covers_id'])
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
state: RoomChatAgentState = {
'params': params,
'user_query': body['user_query'],
'user_id': body['user_id'],
'history': history,
'conversation_id': body['covers_id'],
}
resp = room_chat_agent.invoke(state,config=config)
return JsonResponse(resp)
@require_POST
def tian_yi_chat_bot(request):
data = json.loads(request.body)
user_query = data.get('user_query')
session_id = data.get('session_id')
if not user_query:
return JsonResponse(data={'message':'user_query 不能为空'},status=400)
return JsonResponse(data={'message': 'user_query 不能为空'}, status=400)
if not session_id:
return JsonResponse(data={'message': 'session_id 不能为空'},status=400)
return StreamingHttpResponse(knowledge_chat.do_chat_with_bot(user_query,session_id),content_type='text/html; charset=utf-8')
return JsonResponse(data={'message': 'session_id 不能为空'}, status=400)
return StreamingHttpResponse(knowledge_chat.do_chat_with_bot(user_query, session_id),
content_type='text/html; charset=utf-8')