diff --git a/app/api/__init__.py b/app/api/__init__.py
index 30df3db..8707704 100644
--- a/app/api/__init__.py
+++ b/app/api/__init__.py
@@ -1,13 +1,11 @@
from fastapi import APIRouter
from .chat import chat_router
-from .upload import upload_api_router
from .v1 import v1_router
api_router = APIRouter()
api_router.include_router(v1_router, prefix="/v1")
api_router.include_router(chat_router, prefix="")
-api_router.include_router(upload_api_router, prefix="")
__all__ = ["api_router"]
diff --git a/app/api/chat/ai/chat_service.py b/app/api/chat/ai/chat_service.py
index 48ee766..cfb95d5 100644
--- a/app/api/chat/ai/chat_service.py
+++ b/app/api/chat/ai/chat_service.py
@@ -1,4 +1,6 @@
import os, openai, aiomysql
+import random
+
from openai import OpenAI
from dotenv import load_dotenv
import redis.asyncio as redis
@@ -83,20 +85,73 @@ EXTRACT_PROMPT = """你是一名景区名称精准匹配助手。用户的问题
大慈阁"""
# 客流查询后回答的提示词
-ANSWER_PROMPT = """生成一份人性化的出行指南。输出结构要求如下,使用生活化语言表达,注意不可依据想象生成未经查询的客流数据:
- 首行为标题(如:**景区名称**游览建议,景区名称要显示正确、完整),
- **实时客流**(展示在园人数,=进入人数-离开人数,若为负取绝对值,超出最大承载量时不显示具体人数,仅显示舒适度等级;展示舒适度等级,进入和离开人数、瞬时承载量不展示,承载率仅以“舒适度等级”汉字形式体现,不展示百分比,并用简短1-2句话描述舒适度等级代表的游览体验,如游客较少,游览体验轻松。根据承载率范围输出等级,并用 HTML 字体颜色标签展示,舒适度等级:<30% 为舒适(绿色)(热门景点基本不排队,通道畅通,拍照无遮挡),30%-50% 为较舒适(蓝色)(热门景点排队 5-10 分钟,通道不挤,拍照等待短),50%-70% 为一般(黄色)(热门景点排队 15-30 分钟,部分通道挤,拍照需等),70%-90% 为较拥挤(橙色)**(热门景点排队 30-60 分钟,通道拥挤,拍照需错峰,座位紧张),>90% 为拥挤(红色)(热门景点排队超 60 分钟,通道拥堵,拍照困难,可能限流),如 舒适 较舒适 一般 较拥挤 拥挤,不要加括号或冗余说明,仅展示彩色词语),
-**周边停车指南**(展示停车场名称,距景区距离,步行所需时间,当前余位,收费标准;每项数据为一行,收费标准需提示“具体以现场公示为准”),
- **出行与游览建议**(是否前往:强烈推荐/推荐/谨慎考虑/暂缓前往,用生活化建议替代机械的等级描述,如:强烈推荐可表述为现在正是游览的好时机!馆内人少舒适,无需排队等候,可以随到随游,享受宁静的观展氛围;当较拥挤或拥挤时显示错峰建议:如当日16:00后或次日8:30前;交通方式:停车场充足时推荐自驾,紧张建议打车或备用停车场,已满建议使用公共交通如XX路公交;路线建议:当较拥挤或拥挤时则推荐反常规路线或人少区域;建议游览时长:较舒适多10%,一般多20%,较拥挤/拥挤多30%-50%;不要直接显示百分比,需提出具体时长,如1小时以上;替代方案:当较拥挤或拥挤时推荐1-2个周边承载率低的景区并说明优势),
-**温馨提示**(如安全提醒、天气影响等影响游客游览的内容),语言风格亲切如朋友交谈,用"您""记得""推荐"等暖心词汇,禁用机械术语,用**加粗**突出关键建议,加入表情符号增加亲和力,不展示原始字段数据,结尾不输出数据时间,仅加提示“动态信息请以现场为准,祝您旅途愉快!”。
-若未找到景区的信息时,生成景区通用游览建议,使用以下输出结构,
-首行为标题(如:**景区名称** 游览建议,景区名称要显示正确、完整),
-**实时客流**(仅显示提示“暂时无法获取实时客流数据,您仍可参考以下出行建议。”),
-**出行与游览建议**(交通方式:列出几种常规交通方式,并推荐大众选择较多的出行方式,简单描述优势和注意事项;
-游览路线:描述游览景区常规路线和游览重点,突出表现景区特色;
-游览时间:显示常规参观时间,旺季需多预留30%,不要直接显示百分比,需提出具体时长,如1小时以上;
-附近景区推荐:推荐1-2个周边景区并说明景区特点),
-**温馨提示**(如安全提醒、天气影响等影响游客游览的内容),语言风格亲切如朋友交谈,用"您""记得""推荐"等暖心词汇,禁用机械术语,用**加粗**突出关键建议,加入表情符号增加亲和力,不展示原始字段数据,结尾不输出数据时间,仅加提示“动态信息请以现场为准,祝您旅途愉快!”。"""
+ANSWER_PROMPT = """
+**景区游览指南生成要求**
+
+输入数据格式:
+- 用户问题:{msg}
+- 查询到的数据:{data}(包含景区名称、在园人数、最大承载量、进出人数等)
+- 输出语言:{language}
+
+输出要求:
+
+1. 标题格式:
+**完整景区名称**游览建议
+
+2. 实时客流展示:
+- 计算当前在园人数(进入人数-离开人数的绝对值)
+- 计算承载率(在园人数/最大承载量)
+- 按以下标准显示舒适度等级:
+ <30%:舒适
+ 30%-50%:较舒适
+ 50%-70%:一般
+ 70%-90%:较拥挤
+ >90%:拥挤
+- 附加简短体验描述(1-2句)
+
+3. 周边停车指南:
+- 停车场名称
+- 距离(米)
+- 步行时间(分钟)
+- 当前余位/总车位
+- 收费标准(注明"具体以现场公示为准")
+
+4. 出行与游览建议:
+- 推荐程度(强烈推荐/推荐/谨慎考虑/暂缓前往)
+- 具体建议(包含错峰时间、交通方式、路线建议)
+- 建议游览时长(根据舒适度调整)
+- 替代景区推荐(当拥挤时)
+
+5. 温馨提示:
+- 安全提醒
+- 天气影响
+- 其他注意事项
+
+6. 数据缺失时的通用建议:
+- 标题:**景区名称**游览建议
+- 实时客流提示
+- 常规交通建议
+- 游览路线说明
+- 附近景区推荐
+
+语言风格要求:
+- 使用生动形象的语言描述,适当添加emoji表情符号增强表现力
+- 采用"您""记得""推荐"等暖心词汇
+- 禁用专业术语
+- 使用**加粗**强调关键信息
+- 结尾提示:"动态信息请以现场为准,祝您旅途愉快!"
+
+数据要求:
+- 仅使用查询到的数据
+- 不虚构未提供的信息
+- 数字数据仅展示计算后的在园人数,不显示例如进入人数、离开人数、承载量和承载率等原始数据字段
+- 不输出数据更新时间
+- 标题字体大小为 18–20px,加粗显示
+- 正文内容字体大小为 15–16px
+- 行间距为 1.6–1.8 倍字体大小
+- 段落与模块之间上下边距应为10–16px
+- 不能使用小于 14px 的字体
+"""
async def classify(msg: str) -> str:
print(f"Starting classification for message: {msg}")
@@ -113,10 +168,24 @@ async def classify(msg: str) -> str:
raise
async def ai_chat_stream(inp: ChatIn, conversation_history: list) -> AsyncGenerator[str, None]:
- chat_prompt = (
- f"你是一个河北省保定市的旅游助手,为游客提供保定市文旅相关问答服务,包括但不限于行程规划、"
- f"景点推荐等,不提供其他任何非保定文旅相关信息。输出语言为:{inp.language}"
- )
+ chat_prompt = f"""
+ 你是一个专门服务河北省保定市旅游的AI助手,主要提供以下精准服务:
+ 1. 行程规划:根据游客的停留天数(1-7天)、预算范围(经济型/中档/豪华)、兴趣偏好(历史文化/自然风光/美食体验)提供定制化行程方案
+ 2. 景点推荐:详细介绍保定市3A级以上旅游景区(如白洋淀、野三坡、清西陵等)的开放时间、门票价格、最佳游览季节和交通方式
+ 3. 特色推荐:提供保定驴肉火烧、槐茂酱菜等地方特色美食的具体店铺地址和人均消费
+ 4. 实用信息:提供保定市区及周边县市的公共交通线路、出租车参考价格、天气情况等实用旅行信息
+
+ **服务要求**:
+ - 使用生动形象的语言描述,适当添加emoji表情符号增强表现力
+ - 采用Markdown语法组织内容,合理使用**加粗**、*斜体*等格式
+ - 分点说明时使用清晰的列表格式
+ - 重要信息使用高亮标记
+
+ **服务限制**:
+ - 地理范围:仅限保定市行政区划内(含下辖县市)的文旅信息
+ - 语言输出:严格使用用户指定的{inp.language}语言回复
+ - 问题边界:对非保定文旅相关问题统一回复"我是您的保定旅行助手,专注于解答有关保定市的旅行问题哦~"
+ """
messages = [{"role": "system", "content": chat_prompt}] + conversation_history
messages.append({"role": "user", "content": inp.message})
@@ -150,9 +219,12 @@ async def ai_chat_stream(inp: ChatIn, conversation_history: list) -> AsyncGenera
conversation_history.append({"role": "assistant", "content": full_response})
print("AI chat stream finished.")
+def get_formatted_prompt(user_language,msg,data):
+ # 使用format方法替换占位符
+ return ANSWER_PROMPT.format(language=user_language, msg=msg, data=data)
async def gen_markdown_stream(msg: str, data: str, language: str, conversation_history: list) -> AsyncGenerator[str, None]:
- prompt = f"""你是一位智能旅游助手,结合用户问题:{msg} 和查询内容:{data},"""+ANSWER_PROMPT + f"""输出语言为:{language}"""
+ prompt = get_formatted_prompt(language,msg,data) # 将变量替换到提示词中
messages = conversation_history + [{"role": "user", "content": prompt}]
@@ -235,8 +307,11 @@ async def query_flow(request: Request, spot: str) -> str:
print(f"No data found for spot: {spot}")
return f"**未找到景区【{spot}】的信息,请检查名称是否正确。\n\n(内容仅供参考)"
+ #随机生成剩余车位数量进行测试
+ car_num = random.randint(0, 100)
+ jl_num = random.randint(50, 200)
# 修改结果拼接部分,使用新的列名
- result = f"**{spot} 客流**\n\n进入人数: {row[0]}\n离开人数: {row[1]}\n\n景区瞬时承载量:{row[2]},暂无停车场数据(内容仅供参考)"
+ result = f"**{spot} 客流**\n\n进入人数: {row[0]}\n离开人数: {row[1]}\n\n景区瞬时承载量:{row[2]};停车场名称:临时地上停车场 ,距离:{jl_num}米,空余车位:{car_num},总车位:100,收费标准:30分钟内免费,超出后3元/小时。(内容仅供参考)"
# Step 3: 写入 Redis 缓存
print(f"Writing data to Redis cache for key: {cache_key}")
diff --git a/app/api/upload/__init__.py b/app/api/upload/__init__.py
deleted file mode 100644
index ffe587f..0000000
--- a/app/api/upload/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# app/api/v1/upload/__init__.py
-from fastapi import APIRouter
-from .upload import upload_api_router as upload_router
-
-upload_api_router = APIRouter()
-upload_api_router.include_router(upload_router, prefix='/upload')
\ No newline at end of file
diff --git a/app/api/v1/__init__.py b/app/api/v1/__init__.py
index f6d801b..bd414f3 100644
--- a/app/api/v1/__init__.py
+++ b/app/api/v1/__init__.py
@@ -10,7 +10,7 @@ from .menus import menus_router
from .roles import roles_router
from .users import users_router
from .quick_question import quick_question_router
-from app.api.upload import upload_api_router
+from .upload import upload_api_router
v1_router = APIRouter()
@@ -22,6 +22,6 @@ v1_router.include_router(apis_router, prefix="/api", dependencies=[DependPermiss
v1_router.include_router(depts_router, prefix="/dept", dependencies=[DependPermission])
v1_router.include_router(auditlog_router, prefix="/auditlog", dependencies=[DependPermission])
v1_router.include_router(quick_question_router, prefix="/question", dependencies=[DependPermission])
-v1_router.include_router(upload_api_router)
+v1_router.include_router(upload_api_router, prefix="/upload", dependencies=[DependPermission])
diff --git a/app/api/upload/upload/__init__.py b/app/api/v1/upload/__init__.py
similarity index 100%
rename from app/api/upload/upload/__init__.py
rename to app/api/v1/upload/__init__.py
diff --git a/app/api/upload/upload/upload.py b/app/api/v1/upload/upload.py
similarity index 100%
rename from app/api/upload/upload/upload.py
rename to app/api/v1/upload/upload.py
diff --git a/web/.env.development b/web/.env.development
index 2af1748..d4aa8df 100644
--- a/web/.env.development
+++ b/web/.env.development
@@ -5,4 +5,4 @@ VITE_PUBLIC_PATH = '/'
VITE_USE_PROXY = true
# base api
-VITE_BASE_API = 'http://localhost:8111/api/v1'
+VITE_BASE_API = '/api/v1'
diff --git a/web/build/constant.js b/web/build/constant.js
index cf58a73..31be433 100644
--- a/web/build/constant.js
+++ b/web/build/constant.js
@@ -17,7 +17,7 @@ export const PROXY_CONFIG = {
* @转发路径 http://localhost:9999/api/v1/user
*/
'/api/v1': {
- target: 'http://127.0.0.1:9999',
+ target: 'http://127.0.0.1:8111', // 修改为与.env.development中一致的端口
changeOrigin: true,
},
}
diff --git a/web/src/views/system/question/index.vue b/web/src/views/system/question/index.vue
index 3479dd7..69706d7 100644
--- a/web/src/views/system/question/index.vue
+++ b/web/src/views/system/question/index.vue
@@ -87,7 +87,6 @@
@@ -363,9 +365,8 @@ watch(
border: 1px solid #e5e7eb;
border-radius: 4px;
width: 100%;
- /* 增加最小高度和高度设置 */
min-height: 300px;
- height: 50vh; /* 使用视口高度单位,确保编辑器随页面大小调整 */
+ height: 50vh;
overflow: hidden;
}
\ No newline at end of file
diff --git a/web/vite.config.js b/web/vite.config.js
index 8133af2..9828e40 100644
--- a/web/vite.config.js
+++ b/web/vite.config.js
@@ -31,11 +31,6 @@ export default defineConfig(({ command, mode }) => {
proxy: VITE_USE_PROXY
? {
[VITE_BASE_API]: PROXY_CONFIG[VITE_BASE_API],
- // 添加对/api/upload路径的代理配置
- '/api/upload': {
- target: 'http://127.0.0.1:8111',
- changeOrigin: true,
- },
}
: undefined,
},