From 1225b6cbf0a028b765a0ab6d784bcb80459a67bb Mon Sep 17 00:00:00 2001
From: yj <2077506045@qq.com>
Date: 星期三, 23 七月 2025 17:59:54 +0800
Subject: [PATCH] 功能更新

---
 .gitignore                        |    8 
 app/models/conversation.py        |   47 
 app/utils/logger.py               |    6 
 start.bat                         |   42 +
 config.production.json            |   30 
 logs/app.log                      |   13 
 requirements.txt                  |    2 
 app/services/ecloud_client.py     |  234 ++++++
 app/services/redis_queue.py       |   27 
 app/workers/message_worker.py     |   62 +
 main.py                           |   13 
 ecloud_dify.spec                  |  127 +++
 app/api/callback.py               |    4 
 install_service.bat               |  102 +++
 config.example.json               |   34 +
 CONFIG_GUIDE.md                   |  103 +++
 README.md                         |    7 
 uninstall_service.bat             |   61 +
 /dev/null                         |   16 
 startup.py                        |  139 ++++
 E云管家接口文档.txt                      |  176 +++++
 app/services/contact_sync.py      |  167 +++++
 DEPLOYMENT_WINDOWS.md             |  186 +++++
 config.py                         |  114 ++
 app/services/message_processor.py |  159 ++++
 25 files changed, 1,730 insertions(+), 149 deletions(-)

diff --git a/.gitignore b/.gitignore
index a878fc4..5b0371a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 
 # 蹇界暐鐗瑰畾鏂囦欢
 config.ini
+config.json
 secrets.json
 
 # 蹇界暐鏁翠釜鐩綍
@@ -25,4 +26,9 @@
 .idea/
 
 # 渚嬪锛氫笉蹇界暐 dist 鐩綍涓嬬殑 important.js
-!dist/important.js
\ No newline at end of file
+!dist/important.js
+
+# 鍚屾椂蹇界暐鎵�鏈� .pyc 鏂囦欢锛堝彲閫変絾鎺ㄨ崘锛�
+*.pyc
+*.pyo
+*.pyd
\ No newline at end of file
diff --git a/CONFIG_GUIDE.md b/CONFIG_GUIDE.md
new file mode 100644
index 0000000..e7d48d4
--- /dev/null
+++ b/CONFIG_GUIDE.md
@@ -0,0 +1,103 @@
+# 閰嶇疆鏂囦欢浣跨敤鎸囧崡
+
+## 姒傝堪
+
+椤圭洰宸蹭粠Python閰嶇疆鏂囦欢锛坈onfig.py锛夎浆鎹负JSON閰嶇疆鏂囦欢锛坈onfig.json锛夛紝杩欐牱鏇撮�傚悎鎵撳寘涓篹xe鏂囦欢銆�
+
+## 閰嶇疆鏂囦欢缁撴瀯
+
+### config.json
+```json
+{
+  "database": {
+    "url": "mysql+pymysql://root:password@host:port/database"
+  },
+  "redis": {
+    "url": "redis://localhost:6379/0"
+  },
+  "ecloud": {
+    "base_url": "http://125.122.152.142:9899",
+    "authorization": "your_authorization_token"
+  },
+  "dify": {
+    "base_url": "https://api.dify.ai/v1",
+    "api_key": "your_dify_api_key"
+  },
+  "server": {
+    "host": "0.0.0.0",
+    "port": 7979,
+    "debug": true
+  },
+  "logging": {
+    "level": "INFO",
+    "file": "logs/app.log"
+  },
+  "message_processing": {
+    "max_retry_count": 3,
+    "retry_delay": 5,
+    "queue_timeout": 300
+  }
+}
+```
+
+## 閰嶇疆椤硅鏄�
+
+### 鏁版嵁搴撻厤缃� (database)
+- `url`: 鏁版嵁搴撹繛鎺ュ瓧绗︿覆锛屾敮鎸丮ySQL
+
+### Redis閰嶇疆 (redis)
+- `url`: Redis杩炴帴瀛楃涓�
+
+### E浜戠瀹堕厤缃� (ecloud)
+- `base_url`: E浜戠瀹禔PI鍩虹URL
+- `authorization`: E浜戠瀹禔PI鎺堟潈浠ょ墝
+
+### DifyAI閰嶇疆 (dify)
+- `base_url`: DifyAI API鍩虹URL
+- `api_key`: DifyAI API瀵嗛挜
+
+### 鏈嶅姟鍣ㄩ厤缃� (server)
+- `host`: 鏈嶅姟鍣ㄧ洃鍚湴鍧�
+- `port`: 鏈嶅姟鍣ㄧ洃鍚鍙�
+- `debug`: 鏄惁鍚敤璋冭瘯妯″紡
+
+### 鏃ュ織閰嶇疆 (logging)
+- `level`: 鏃ュ織绾у埆 (DEBUG, INFO, WARNING, ERROR)
+- `file`: 鏃ュ織鏂囦欢璺緞
+
+### 娑堟伅澶勭悊閰嶇疆 (message_processing)
+- `max_retry_count`: 鏈�澶ч噸璇曟鏁�
+- `retry_delay`: 閲嶈瘯寤惰繜鏃堕棿锛堢锛�
+- `queue_timeout`: 闃熷垪瓒呮椂鏃堕棿锛堢锛�
+
+## 浣跨敤鏂规硶
+
+### 1. 淇敼閰嶇疆
+鐩存帴缂栬緫 `config.json` 鏂囦欢鍗冲彲锛屽簲鐢ㄤ細鑷姩鍔犺浇鏂伴厤缃��
+
+### 2. 閰嶇疆鏂囦欢浣嶇疆
+- 寮�鍙戠幆澧冿細椤圭洰鏍圭洰褰曚笅鐨� `config.json`
+- 鐢熶骇鐜锛歟xe鏂囦欢鍚岀洰褰曚笅鐨� `config.json`
+
+### 3. 閰嶇疆楠岃瘉
+濡傛灉閰嶇疆鏂囦欢涓嶅瓨鍦ㄦ垨鏍煎紡閿欒锛岀郴缁熶細浣跨敤榛樿閰嶇疆骞惰緭鍑洪敊璇俊鎭��
+
+## 鍏煎鎬�
+
+- 鍘熸湁鐨� `from config import settings` 瀵煎叆鏂瑰紡淇濇寔涓嶅彉
+- 鎵�鏈夐厤缃睘鎬х殑璁块棶鏂瑰紡淇濇寔涓嶅彉锛堝 `settings.database_url`锛�
+- 鍚戝悗鍏煎锛屼笉闇�瑕佷慨鏀圭幇鏈変唬鐮�
+
+## 鎵撳寘涓篹xe鐨勪紭鍔�
+
+1. **閰嶇疆澶栭儴鍖�**: 閰嶇疆鏂囦欢鐙珛浜巈xe鏂囦欢锛屼究浜庨儴缃叉椂淇敼
+2. **鏃犻渶閲嶆柊缂栬瘧**: 淇敼閰嶇疆涓嶉渶瑕侀噸鏂版墦鍖卐xe
+3. **鏄撲簬缁存姢**: JSON鏍煎紡鐩磋鏄撹锛屼究浜庤繍缁翠汉鍛橀厤缃�
+4. **鐗堟湰鎺у埗鍙嬪ソ**: 鍙互涓轰笉鍚岀幆澧冨噯澶囦笉鍚岀殑閰嶇疆鏂囦欢
+
+## 娉ㄦ剰浜嬮」
+
+1. 纭繚 `config.json` 鏂囦欢鏍煎紡姝g‘锛屽彲浠ヤ娇鐢↗SON楠岃瘉宸ュ叿妫�鏌�
+2. 鏁忔劅淇℃伅锛堝鏁版嵁搴撳瘑鐮併�丄PI瀵嗛挜锛夊簲濡ュ杽淇濈
+3. 鐢熶骇鐜寤鸿灏� `debug` 璁剧疆涓� `false`
+4. 鏃ュ織鏂囦欢璺緞纭繚搴旂敤鏈夊啓鍏ユ潈闄�
diff --git a/DEPLOYMENT_WINDOWS.md b/DEPLOYMENT_WINDOWS.md
new file mode 100644
index 0000000..797b74d
--- /dev/null
+++ b/DEPLOYMENT_WINDOWS.md
@@ -0,0 +1,186 @@
+# E浜戠瀹�-DifyAI瀵规帴鏈嶅姟 Windows閮ㄧ讲鎸囧崡
+
+## 姒傝堪
+
+鏈枃妗d粙缁嶅浣曞湪Windows鏈嶅姟鍣ㄤ笂閮ㄧ讲E浜戠瀹�-DifyAI瀵规帴鏈嶅姟鐨別xe鐗堟湰銆�
+
+## 绯荤粺瑕佹眰
+
+- Windows Server 2016 鎴栨洿楂樼増鏈�
+- Windows 10/11 (鐢ㄤ簬娴嬭瘯)
+- 鑷冲皯 2GB 鍙敤鍐呭瓨
+- 鑷冲皯 1GB 鍙敤纾佺洏绌洪棿
+- 缃戠粶杩炴帴锛堢敤浜庤闂暟鎹簱銆丷edis銆丒浜戠瀹跺拰DifyAI鏈嶅姟锛�
+
+## 閮ㄧ讲姝ラ
+
+### 1. 鍑嗗閮ㄧ讲鏂囦欢
+
+纭繚浠ヤ笅鏂囦欢瀛樺湪浜庨儴缃茬洰褰曚腑锛�
+- `ecloud_dify.exe` - 涓荤▼搴忔枃浠�
+- `config.production.json` - 鐢熶骇鐜閰嶇疆妯℃澘
+- `config.example.json` - 閰嶇疆绀轰緥鏂囦欢
+- `install_service.bat` - Windows鏈嶅姟瀹夎鑴氭湰
+- `uninstall_service.bat` - Windows鏈嶅姟鍗歌浇鑴氭湰
+- `start.bat` - 鐩存帴鍚姩鑴氭湰锛堥潪鏈嶅姟妯″紡锛�
+
+### 2. 閰嶇疆鏈嶅姟
+
+#### 2.1 鍒涘缓閰嶇疆鏂囦欢
+
+1. 澶嶅埗 `config.production.json` 涓� `config.json`
+2. 缂栬緫 `config.json` 鏂囦欢锛屼慨鏀逛互涓嬮厤缃細
+
+```json
+{
+  "database": {
+    "url": "mysql+pymysql://鐢ㄦ埛鍚�:瀵嗙爜@鏁版嵁搴撳湴鍧�:绔彛/鏁版嵁搴撳悕"
+  },
+  "redis": {
+    "url": "redis://Redis鍦板潃:绔彛/鏁版嵁搴撶紪鍙�"
+  },
+  "ecloud": {
+    "base_url": "E浜戠瀹禔PI鍦板潃",
+    "authorization": "E浜戠瀹舵巿鏉冧护鐗�"
+  },
+  "dify": {
+    "base_url": "DifyAI API鍦板潃",
+    "api_key": "DifyAI API瀵嗛挜"
+  },
+  "server": {
+    "host": "0.0.0.0",
+    "port": 7979,
+    "debug": false
+  }
+}
+```
+
+#### 2.2 閰嶇疆璇存槑
+
+- **database.url**: MySQL鏁版嵁搴撹繛鎺ュ瓧绗︿覆
+- **redis.url**: Redis鏈嶅姟鍣ㄨ繛鎺ュ瓧绗︿覆
+- **ecloud**: E浜戠瀹剁浉鍏抽厤缃�
+- **dify**: DifyAI鐩稿叧閰嶇疆
+- **server**: 鏈嶅姟鍣ㄧ洃鍚厤缃�
+
+### 3. 瀹夎鍜屽惎鍔ㄦ湇鍔�
+
+#### 鏂瑰紡涓�锛歐indows鏈嶅姟妯″紡锛堟帹鑽愶級
+
+1. **瀹夎鏈嶅姟**锛�
+   - 鍙抽敭鐐瑰嚮 `install_service.bat`
+   - 閫夋嫨"浠ョ鐞嗗憳韬唤杩愯"
+   - 鎸夌収鎻愮ず瀹屾垚瀹夎
+
+2. **绠$悊鏈嶅姟**锛�
+   ```cmd
+   # 鍚姩鏈嶅姟
+   sc start ECloudDifyService
+   
+   # 鍋滄鏈嶅姟
+   sc stop ECloudDifyService
+   
+   # 鏌ョ湅鏈嶅姟鐘舵��
+   sc query ECloudDifyService
+   
+   # 鍒犻櫎鏈嶅姟
+   sc delete ECloudDifyService
+   ```
+
+3. **鍗歌浇鏈嶅姟**锛�
+   - 鍙抽敭鐐瑰嚮 `uninstall_service.bat`
+   - 閫夋嫨"浠ョ鐞嗗憳韬唤杩愯"
+
+#### 鏂瑰紡浜岋細鐩存帴杩愯妯″紡
+
+1. 鍙屽嚮 `start.bat` 鍚姩鏈嶅姟
+2. 鎸� Ctrl+C 鍋滄鏈嶅姟
+
+### 4. 楠岃瘉閮ㄧ讲
+
+1. **妫�鏌ユ湇鍔$姸鎬�**锛�
+   - 璁块棶 `http://鏈嶅姟鍣↖P:7979/health`
+   - 搴旇杩斿洖鍋ュ悍妫�鏌ヤ俊鎭�
+
+2. **鏌ョ湅鏃ュ織**锛�
+   - 鏃ュ織鏂囦欢浣嶄簬 `logs/app.log`
+   - 妫�鏌ユ槸鍚︽湁閿欒淇℃伅
+
+3. **娴嬭瘯API**锛�
+   - 璁块棶 `http://鏈嶅姟鍣↖P:7979/`
+   - 搴旇杩斿洖鏈嶅姟淇℃伅
+
+## 闃茬伀澧欓厤缃�
+
+纭繚Windows闃茬伀澧欏厑璁哥鍙�7979鐨勫叆绔欒繛鎺ワ細
+
+```cmd
+# 娣诲姞闃茬伀澧欒鍒�
+netsh advfirewall firewall add rule name="ECloudDify Service" dir=in action=allow protocol=TCP localport=7979
+```
+
+## 鏁呴殰鎺掗櫎
+
+### 甯歌闂
+
+1. **鏈嶅姟鍚姩澶辫触**锛�
+   - 妫�鏌ラ厤缃枃浠舵牸寮忔槸鍚︽纭�
+   - 纭鏁版嵁搴撳拰Redis杩炴帴鏄惁姝e父
+   - 鏌ョ湅鏃ュ織鏂囦欢鑾峰彇璇︾粏閿欒淇℃伅
+
+2. **绔彛琚崰鐢�**锛�
+   - 淇敼閰嶇疆鏂囦欢涓殑绔彛鍙�
+   - 鎴栬�呭仠姝㈠崰鐢ㄧ鍙g殑鍏朵粬绋嬪簭
+
+3. **鏉冮檺闂**锛�
+   - 纭繚浠ョ鐞嗗憳韬唤杩愯瀹夎鑴氭湰
+   - 妫�鏌xe鏂囦欢鐨勬墽琛屾潈闄�
+
+4. **缃戠粶杩炴帴闂**锛�
+   - 妫�鏌ラ槻鐏璁剧疆
+   - 纭缃戠粶杩炴帴姝e父
+
+### 鏃ュ織鏌ョ湅
+
+鏃ュ織鏂囦欢浣嶇疆锛歚logs/app.log`
+
+甯哥敤鏃ュ織绾у埆锛�
+- INFO: 涓�鑸俊鎭�
+- WARNING: 璀﹀憡淇℃伅
+- ERROR: 閿欒淇℃伅
+
+## 鎬ц兘浼樺寲
+
+1. **鍐呭瓨浼樺寲**锛�
+   - 鐩戞帶鍐呭瓨浣跨敤鎯呭喌
+   - 蹇呰鏃惰皟鏁寸郴缁熷唴瀛樺垎閰�
+
+2. **缃戠粶浼樺寲**锛�
+   - 纭繚缃戠粶寤惰繜杈冧綆
+   - 浣跨敤楂橀�熺綉缁滆繛鎺�
+
+3. **鏁版嵁搴撲紭鍖�**锛�
+   - 浼樺寲鏁版嵁搴撹繛鎺ユ睜璁剧疆
+   - 瀹氭湡娓呯悊鏃ュ織鏁版嵁
+
+## 瀹夊叏寤鸿
+
+1. **閰嶇疆鏂囦欢瀹夊叏**锛�
+   - 淇濇姢閰嶇疆鏂囦欢涓殑鏁忔劅淇℃伅
+   - 璁剧疆閫傚綋鐨勬枃浠舵潈闄�
+
+2. **缃戠粶瀹夊叏**锛�
+   - 浣跨敤HTTPS锛堝鏋滄敮鎸侊級
+   - 闄愬埗璁块棶IP鑼冨洿
+
+3. **瀹氭湡鏇存柊**锛�
+   - 瀹氭湡鏇存柊鏈嶅姟鐗堟湰
+   - 鍏虫敞瀹夊叏琛ヤ竵
+
+## 鑱旂郴鏀寔
+
+濡傞亣鍒伴棶棰橈紝璇锋彁渚涗互涓嬩俊鎭細
+- 閿欒鏃ュ織鍐呭
+- 閰嶇疆鏂囦欢锛堥殣钘忔晱鎰熶俊鎭級
+- 绯荤粺鐜淇℃伅
+- 闂澶嶇幇姝ラ
diff --git "a/E\344\272\221\347\256\241\345\256\266\346\216\245\345\217\243\346\226\207\346\241\243.txt" "b/E\344\272\221\347\256\241\345\256\266\346\216\245\345\217\243\346\226\207\346\241\243.txt"
index eda63e0..a275d7f 100644
--- "a/E\344\272\221\347\256\241\345\256\266\346\216\245\345\217\243\346\226\207\346\241\243.txt"
+++ "b/E\344\272\221\347\256\241\345\256\266\346\216\245\345\217\243\346\226\207\346\241\243.txt"
@@ -16,7 +16,7 @@
 
 鍙傛暟鍚�	蹇呴��	绫诲瀷	璇存槑
 wId	鏄�	String	鐧诲綍瀹炰緥鏍囪瘑
-wcId	鏄�	String	濂藉弸寰俊id/缇d
+wcId	鏄�	String	濂藉弸寰俊id/缇d锛屽涓娇鐢ㄨ嫳鏂囬�楀彿鍒嗛殧
 
 璇锋眰鍙傛暟绀轰緥
 
@@ -167,4 +167,176 @@
     "message": "澶辫触",
     "code": "1001",
     "data": null
-} 
\ No newline at end of file
+} 
+
+
+
+# 鍒濆鍖栭�氳褰曞垪琛ㄦ帴鍙�
+
+绠�瑕佹弿杩帮細
+鍒濆鍖栭�氳褰曞垪琛�
+
+璇锋眰URL锛�
+http://鍩熷悕鍦板潃/initAddressList
+
+璇锋眰鏂瑰紡锛�
+POST
+
+璇锋眰澶碒eaders锛�
+Content-Type锛歛pplication/json
+Authorization锛歿Authorization}
+
+鍙傛暟锛�
+鍙傛暟鍚�	蹇呴��	绫诲瀷	璇存槑
+wId	鏄�	String	鐧诲綍瀹炰緥鏍囪瘑
+
+璇锋眰鍙傛暟绀轰緥
+{
+    "wId": "6a696578-16ea-4edc-ac8b-e609bca39c69"
+}
+
+鎴愬姛杩斿洖绀轰緥
+{
+    "message": "鎴愬姛",
+    "code": "1000",
+    "data": null
+}
+
+閿欒杩斿洖绀轰緥
+{
+    "message": "澶辫触",
+    "code": "1001",
+    "data": null
+}
+
+杩斿洖鏁版嵁锛�
+鍙傛暟鍚�	绫诲瀷	璇存槑
+code	string	1000鎴愬姛銆�1001澶辫触
+msg	string	鍙嶉淇℃伅
+data	JSONObject	鏃�
+
+
+
+# 鑾峰彇閫氳褰曞垪琛ㄦ帴鍙�
+绠�瑕佹弿杩帮細
+鑾峰彇閫氳褰曞垪琛�
+
+璇锋眰URL锛�
+http://鍩熷悕鍦板潃/getAddressList
+
+璇锋眰鏂瑰紡锛�
+POST
+
+璇锋眰澶碒eaders锛�
+Content-Type锛歛pplication/json
+Authorization锛歿Authorization}
+
+鍙傛暟锛�
+
+鍙傛暟鍚�	蹇呴��	绫诲瀷	璇存槑
+wId	鏄�	String	鐧诲綍瀹炰緥鏍囪瘑
+灏忔彁绀猴細
+鑾峰彇閫氳褰曞垪琛ㄤ箣鍓嶏紝蹇呴』璋冪敤鍒濆鍖栭�氳褰曞垪琛ㄦ帴鍙c��
+
+璇锋眰鍙傛暟绀轰緥
+{
+    "wId": "6a696578-16ea-4edc-ac8b-e609bca39c69"
+}
+
+鎴愬姛杩斿洖绀轰緥
+{
+    "code": "1000",
+    "message": "鑾峰彇閫氳褰曟垚鍔�",
+    "data": {
+        "chatrooms": [
+            ""
+        ],
+        "friends": [
+            ""
+        ],
+        "ghs": [
+            ""
+        ],
+        "others": [
+            ""
+        ]
+    }
+}
+
+閿欒杩斿洖绀轰緥
+{
+    "message": "澶辫触",
+    "code": "1001",
+    "data": null
+}
+
+杩斿洖鏁版嵁锛�
+
+鍙傛暟鍚�	绫诲瀷	璇存槑
+code	String	1000鎴愬姛
+1001澶辫触
+msg	String	鍙嶉淇℃伅
+data	JSONObject	
+chatrooms	JSONArray	缇ょ粍鍒楄〃
+friends	JSONArray	濂藉弸鍒楄〃
+ghs	JSONArray	鍏紬鍙峰垪琛�
+others	JSONArray	寰俊鍏朵粬鐩稿叧
+
+
+
+# 缇よ亰@鎺ュ彛
+璇锋眰URL锛�
+http://鍩熷悕鍦板潃/sendText
+
+璇锋眰鏂瑰紡锛�
+POST
+
+璇锋眰澶碒eaders锛�
+Content-Type锛歛pplication/json
+Authorization锛歿Authorization}
+
+鍙傛暟锛�
+鍙傛暟鍚�	蹇呴��	绫诲瀷	璇存槑
+wId	鏄�	string	鐧诲綍瀹炰緥鏍囪瘑
+wcId	鏄�	string	鎺ユ敹鏂圭兢id
+content	鏄�	string	鏂囨湰鍐呭娑堟伅锛園鐨勫井淇℃樀绉伴渶瑕佽嚜宸辨嫾鎺ワ紝蹇呴』鎷兼帴鑹剧壒绗﹀彿锛屼笉鐒朵笉鐢熸晥锛�
+at	鏄�	string	鑹剧壒鐨勫井淇d锛堝涓互閫楀彿鍒嗗紑锛�
+
+杩斿洖鏁版嵁锛�
+鍙傛暟鍚�	绫诲瀷	璇存槑
+code	string	1000鎴愬姛锛�1001澶辫触
+msg	string	鍙嶉淇℃伅
+data		
+data.type	int	绫诲瀷
+data.msgId	long	娑堟伅msgId
+data.newMsgId	long	娑堟伅newMsgId
+data.createTime	long	娑堟伅鍙戦�佹椂闂存埑
+data.wcId	string	娑堟伅鎺ユ敹鏂筰d
+
+璇锋眰鍙傛暟绀轰緥
+{
+ "wId": "0000016f-8911-484a-0001-db2943fc2786",
+ "wcId": "22270365143@chatroom",
+ "at": "wxid_lr6j4nononb921,wxid_i6qsbbjenjuj22",
+ "content": "@E浜慣eam_Mr Li@浣犲井绗戞椂鐪熺編 娴嬭瘯"
+}
+
+鎴愬姛杩斿洖绀轰緥
+{
+    "code": "1000",
+    "message": "澶勭悊鎴愬姛",
+    "data": {
+        "type": 1,
+        "msgId": 2562652205,
+        "newMsgId": 4482117376572170921,
+        "createTime": 1641457769,
+        "wcId": "22270365143@chatroom"
+    }
+}
+
+閿欒杩斿洖绀轰緥
+{
+    "message": "澶辫触",
+    "code": "1001",
+    "data": null
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 7d0aac0..9170a7a 100644
--- a/README.md
+++ b/README.md
@@ -143,13 +143,14 @@
 
 ### conversations锛堝璇濊褰曡〃锛�
 - `id`: 涓婚敭
-- `user_conversation_key`: 鐢ㄦ埛瀵硅瘽鍞竴閿�
 - `from_user`: 鍙戦�佺敤鎴峰井淇D
 - `conversation_id`: Dify瀵硅瘽ID
-- `user_question`: 鐢ㄦ埛鎻愰棶
-- `ai_answer`: AI鍥炵瓟
+- `group`: 缇ょ粍ID
+- `hour`: 灏忔椂鏍囪瘑(YYYYMMDD_HH)
+- `content`: 瀵硅瘽鍐呭(JSON鏍煎紡)
 - `is_processed`: 鏄惁宸插鐞�
 - `is_sent`: 鏄惁宸插彂閫�
+- 鍞竴鎬х害鏉�: (from_user, conversation_id, group, hour)
 
 ## 閰嶇疆璇存槑
 
diff --git a/app/api/callback.py b/app/api/callback.py
index 3975cc3..e4c4858 100644
--- a/app/api/callback.py
+++ b/app/api/callback.py
@@ -54,10 +54,13 @@
         # 灏嗘秷鎭姞鍏ラ槦鍒�
         success = message_processor.enqueue_callback_message(callback_dict)
 
+        logger.info(f"娑堟伅鍏ラ槦缁撴灉: success={success}")
+
         if success:
             # 鑾峰彇鍙戦�佺敤鎴稩D
             from_user = callback_dict.get("data", {}).get("fromUser")
             if from_user:
+                logger.info(f"鍚姩鐢ㄦ埛闃熷垪澶勭悊: from_user={from_user}")
                 # 鍚姩鐢ㄦ埛闃熷垪澶勭悊
                 message_worker.process_user_queue(from_user)
 
@@ -65,6 +68,7 @@
                 success=True, message="娑堟伅宸叉垚鍔熷姞鍏ュ鐞嗛槦鍒�", code=200
             )
         else:
+            logger.warning("娑堟伅澶勭悊澶辫触锛屾湭鑳藉姞鍏ラ槦鍒�")
             return CallbackResponse(success=False, message="娑堟伅澶勭悊澶辫触", code=400)
 
     except Exception as e:
diff --git a/app/models/conversation.py b/app/models/conversation.py
index f153429..eb646c5 100644
--- a/app/models/conversation.py
+++ b/app/models/conversation.py
@@ -1,38 +1,51 @@
 """
 瀵硅瘽璁板綍妯″瀷
 """
-from sqlalchemy import Column, String, Integer, DateTime, Text, Boolean
+
+from sqlalchemy import Column, String, Integer, DateTime, Text, Boolean, UniqueConstraint
 from sqlalchemy.sql import func
 from .database import Base
 
 
 class Conversation(Base):
     """瀵硅瘽璁板綍琛�"""
+
     __tablename__ = "conversations"
-    
+
     id = Column(Integer, primary_key=True, index=True, autoincrement=True)
-    user_conversation_key = Column(String(200), unique=True, index=True, nullable=False, 
-                                 comment="鐢ㄦ埛瀵硅瘽鍞竴閿�(fromUser+conversation_id)")
-    from_user = Column(String(100), index=True, nullable=False, comment="鍙戦�佺敤鎴峰井淇D")
+    from_user = Column(
+        String(100), index=True, nullable=False, comment="鍙戦�佺敤鎴峰井淇D"
+    )
     conversation_id = Column(String(100), nullable=False, comment="Dify瀵硅瘽ID")
-    
-    # 鐢ㄦ埛闂
-    user_question = Column(Text, nullable=False, comment="鐢ㄦ埛鎻愰棶鍐呭")
-    
-    # AI鍥炵瓟
-    ai_answer = Column(Text, nullable=True, comment="AI鍥炵瓟鍐呭")
-    
+    group = Column(String(100), nullable=False, comment="缇ょ粍ID")
+    hour = Column(String(20), nullable=False, comment="灏忔椂鏍囪瘑(YYYYMMDD_HH)")
+
+    # 瀵硅瘽鍐呭锛圝SON鏍煎紡锛�
+    content = Column(
+        Text,
+        nullable=True,
+        comment='瀵硅瘽鍐呭JSON鏍煎紡锛屽[{"user":"浣犲ソ","ai":"浣犲ソ鏈変粈涔堣兘甯姪浣犵殑"}]',
+    )
+
     # 娑堟伅鐘舵��
     is_processed = Column(Boolean, default=False, comment="鏄惁宸插鐞�")
     is_sent = Column(Boolean, default=False, comment="鏄惁宸插彂閫佸洖澶�")
-    
+
     # 鏃堕棿鎴�
     question_time = Column(DateTime, default=func.now(), comment="鎻愰棶鏃堕棿")
     answer_time = Column(DateTime, nullable=True, comment="鍥炵瓟鏃堕棿")
     sent_time = Column(DateTime, nullable=True, comment="鍙戦�佹椂闂�")
-    
+
     created_at = Column(DateTime, default=func.now(), comment="鍒涘缓鏃堕棿")
-    updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), comment="鏇存柊鏃堕棿")
-    
+    updated_at = Column(
+        DateTime, default=func.now(), onupdate=func.now(), comment="鏇存柊鏃堕棿"
+    )
+
+    # 娣诲姞鍥涘瓧娈电粍鍚堢殑鍞竴鎬х害鏉�
+    __table_args__ = (
+        UniqueConstraint('from_user', 'conversation_id', 'group', 'hour',
+                         name='uq_conversation_key'),
+    )
+
     def __repr__(self):
-        return f"<Conversation(from_user='{self.from_user}', conversation_id='{self.conversation_id}')>"
+        return f"<Conversation(from_user='{self.from_user}', conversation_id='{self.conversation_id}', group='{self.group}', hour='{self.hour}')>"
diff --git a/app/services/contact_sync.py b/app/services/contact_sync.py
new file mode 100644
index 0000000..42d4acd
--- /dev/null
+++ b/app/services/contact_sync.py
@@ -0,0 +1,167 @@
+"""
+鑱旂郴浜哄悓姝ユ湇鍔�
+"""
+
+from typing import List, Optional
+from loguru import logger
+from sqlalchemy.orm import Session
+from app.models.contact import Contact
+from app.models.database import get_db
+from app.services.ecloud_client import ecloud_client
+
+
+class ContactSyncService:
+    """鑱旂郴浜哄悓姝ユ湇鍔�"""
+
+    def __init__(self):
+        pass
+
+    def sync_contacts_on_startup(self, w_id: str) -> bool:
+        """
+        鍚姩鏃跺悓姝ヨ仈绯讳汉淇℃伅
+
+        Args:
+            w_id: 鐧诲綍瀹炰緥鏍囪瘑
+
+        Returns:
+            鍚屾鎴愬姛杩斿洖True锛屽け璐ヨ繑鍥濬alse
+        """
+        try:
+            logger.info(f"寮�濮嬪悓姝ヨ仈绯讳汉淇℃伅: wId={w_id}")
+
+            # 1. 鍒濆鍖栭�氳褰曞垪琛�
+            if not ecloud_client.init_address_list(w_id):
+                logger.error(f"鍒濆鍖栭�氳褰曞垪琛ㄥけ璐�: wId={w_id}")
+                return False
+
+            # 2. 鑾峰彇閫氳褰曞垪琛�
+            address_data = ecloud_client.get_address_list(w_id)
+            if not address_data:
+                logger.error(f"鑾峰彇閫氳褰曞垪琛ㄥけ璐�: wId={w_id}")
+                return False
+
+            # 3. 鑾峰彇濂藉弸鍒楄〃涓殑wcid
+            friends = address_data.get("friends", [])
+            if not friends:
+                logger.warning(f"濂藉弸鍒楄〃涓虹┖: wId={w_id}")
+                return True
+
+            logger.info(f"鑾峰彇鍒板ソ鍙嬪垪琛�: wId={w_id}, count={len(friends)}")
+
+            # 4. 鎵归噺鑾峰彇鑱旂郴浜鸿缁嗕俊鎭�
+            return self._batch_sync_contacts(w_id, friends)
+
+        except Exception as e:
+            logger.error(f"鍚屾鑱旂郴浜轰俊鎭紓甯�: wId={w_id}, error={str(e)}")
+            return False
+
+    def _batch_sync_contacts(self, w_id: str, wc_ids: List[str]) -> bool:
+        """
+        鎵归噺鍚屾鑱旂郴浜轰俊鎭�
+
+        Args:
+            w_id: 鐧诲綍瀹炰緥鏍囪瘑
+            wc_ids: 寰俊ID鍒楄〃
+
+        Returns:
+            鍚屾鎴愬姛杩斿洖True锛屽け璐ヨ繑鍥濬alse
+        """
+        try:
+            # 灏唚cid鍒楄〃鐢ㄩ�楀彿鎷兼帴
+            wc_ids_str = ",".join(wc_ids)
+            logger.info(f"寮�濮嬫壒閲忚幏鍙栬仈绯讳汉淇℃伅: wId={w_id}, wc_ids_count={len(wc_ids)}")
+
+            # 璋冪敤鑾峰彇鑱旂郴浜轰俊鎭帴鍙�
+            contact_info = ecloud_client.get_contact_info(w_id, wc_ids_str)
+            if not contact_info:
+                logger.error(f"鎵归噺鑾峰彇鑱旂郴浜轰俊鎭け璐�: wId={w_id}")
+                return False
+
+            # 濡傛灉杩斿洖鐨勬槸鍗曚釜鑱旂郴浜轰俊鎭紝杞崲涓哄垪琛�
+            if isinstance(contact_info, dict):
+                contact_list = [contact_info]
+            else:
+                contact_list = contact_info
+
+            logger.info(f"鑾峰彇鍒拌仈绯讳汉璇︾粏淇℃伅: count={len(contact_list)}")
+
+            # 淇濆瓨鍒版暟鎹簱
+            return self._save_contacts_to_db(contact_list)
+
+        except Exception as e:
+            logger.error(f"鎵归噺鍚屾鑱旂郴浜轰俊鎭紓甯�: wId={w_id}, error={str(e)}")
+            return False
+
+    def _save_contacts_to_db(self, contact_list: List[dict]) -> bool:
+        """
+        淇濆瓨鑱旂郴浜轰俊鎭埌鏁版嵁搴�
+
+        Args:
+            contact_list: 鑱旂郴浜轰俊鎭垪琛�
+
+        Returns:
+            淇濆瓨鎴愬姛杩斿洖True锛屽け璐ヨ繑鍥濬alse
+        """
+        try:
+            with next(get_db()) as db:
+                saved_count = 0
+                updated_count = 0
+
+                for contact_data in contact_list:
+                    wc_id = contact_data.get("userName") or contact_data.get("wcId")
+                    if not wc_id:
+                        logger.warning(f"鑱旂郴浜轰俊鎭己灏憌cId: {contact_data}")
+                        continue
+
+                    # 妫�鏌ユ槸鍚﹀凡瀛樺湪
+                    existing_contact = db.query(Contact).filter(Contact.wc_id == wc_id).first()
+
+                    if existing_contact:
+                        # 鏇存柊鐜版湁鑱旂郴浜轰俊鎭�
+                        existing_contact.user_name = contact_data.get("userName")
+                        existing_contact.nick_name = contact_data.get("nickName")
+                        existing_contact.remark = contact_data.get("remark")
+                        existing_contact.signature = contact_data.get("signature")
+                        existing_contact.sex = contact_data.get("sex")
+                        existing_contact.alias_name = contact_data.get("aliasName")
+                        existing_contact.country = contact_data.get("country")
+                        existing_contact.big_head = contact_data.get("bigHead")
+                        existing_contact.small_head = contact_data.get("smallHead")
+                        existing_contact.label_list = contact_data.get("labelList")
+                        existing_contact.v1 = contact_data.get("v1")
+                        updated_count += 1
+                        logger.debug(f"鏇存柊鑱旂郴浜轰俊鎭�: wc_id={wc_id}, nick_name={contact_data.get('nickName')}")
+                    else:
+                        # 鍒涘缓鏂拌仈绯讳汉璁板綍
+                        new_contact = Contact(
+                            wc_id=wc_id,
+                            user_name=contact_data.get("userName"),
+                            nick_name=contact_data.get("nickName"),
+                            remark=contact_data.get("remark"),
+                            signature=contact_data.get("signature"),
+                            sex=contact_data.get("sex"),
+                            alias_name=contact_data.get("aliasName"),
+                            country=contact_data.get("country"),
+                            big_head=contact_data.get("bigHead"),
+                            small_head=contact_data.get("smallHead"),
+                            label_list=contact_data.get("labelList"),
+                            v1=contact_data.get("v1"),
+                        )
+                        db.add(new_contact)
+                        saved_count += 1
+                        logger.debug(f"鏂板鑱旂郴浜轰俊鎭�: wc_id={wc_id}, nick_name={contact_data.get('nickName')}")
+
+                # 鎻愪氦浜嬪姟
+                db.commit()
+                logger.info(f"鑱旂郴浜轰俊鎭繚瀛樺畬鎴�: 鏂板={saved_count}, 鏇存柊={updated_count}")
+                return True
+
+        except Exception as e:
+            logger.error(f"淇濆瓨鑱旂郴浜轰俊鎭埌鏁版嵁搴撳紓甯�: error={str(e)}")
+            if 'db' in locals():
+                db.rollback()
+            return False
+
+
+# 鍏ㄥ眬鑱旂郴浜哄悓姝ユ湇鍔″疄渚�
+contact_sync_service = ContactSyncService()
diff --git a/app/services/ecloud_client.py b/app/services/ecloud_client.py
index 5a76116..42495c3 100644
--- a/app/services/ecloud_client.py
+++ b/app/services/ecloud_client.py
@@ -3,7 +3,7 @@
 """
 
 import requests
-from typing import Optional, Dict, Any
+from typing import Optional, Dict, Any, List
 from loguru import logger
 from config import settings
 
@@ -26,10 +26,12 @@
 
         Args:
             w_id: 鐧诲綍瀹炰緥鏍囪瘑
-            wc_id: 濂藉弸寰俊id/缇d
+            wc_id: 濂藉弸寰俊id/缇d锛屽涓娇鐢ㄨ嫳鏂囬�楀彿鍒嗛殧
 
         Returns:
-            鑱旂郴浜轰俊鎭瓧鍏革紝澶辫触杩斿洖None
+            鑱旂郴浜轰俊鎭瓧鍏告垨鍒楄〃锛屽け璐ヨ繑鍥濶one
+            - 鍗曚釜wcId鏃惰繑鍥炲瓧鍏�
+            - 澶氫釜wcId鏃惰繑鍥炲垪琛�
         """
         try:
             url = f"{self.base_url}/getContact"
@@ -45,8 +47,14 @@
             if result.get("code") == "1000":
                 contact_data = result.get("data", [])
                 if contact_data and len(contact_data) > 0:
-                    logger.info(f"鎴愬姛鑾峰彇鑱旂郴浜轰俊鎭�: wcId={wc_id}")
-                    return contact_data[0]  # 杩斿洖绗竴涓仈绯讳汉淇℃伅
+                    # 濡傛灉鏄崟涓獁cId锛岃繑鍥炵涓�涓仈绯讳汉淇℃伅
+                    if "," not in wc_id:
+                        logger.info(f"鎴愬姛鑾峰彇鑱旂郴浜轰俊鎭�: wcId={wc_id}")
+                        return contact_data[0]
+                    else:
+                        # 濡傛灉鏄涓獁cId锛岃繑鍥炲畬鏁村垪琛�
+                        logger.info(f"鎴愬姛鑾峰彇鎵归噺鑱旂郴浜轰俊鎭�: count={len(contact_data)}")
+                        return contact_data
                 else:
                     logger.warning(f"鑱旂郴浜轰俊鎭负绌�: wcId={wc_id}")
                     return None
@@ -63,7 +71,7 @@
             logger.error(f"鑾峰彇鑱旂郴浜轰俊鎭紓甯�: wcId={wc_id}, error={str(e)}")
             return None
 
-    def send_text_message(self, w_id: str, wc_id: str, content: str) -> bool:
+    def send_text_message(self, w_id: str, wc_id: str, content: str, max_retries: int = None) -> bool:
         """
         鍙戦�佹枃鏈秷鎭�
 
@@ -71,38 +79,55 @@
             w_id: 鐧诲綍瀹炰緥鏍囪瘑
             wc_id: 鎺ユ敹浜哄井淇d/缇d
             content: 鏂囨湰鍐呭娑堟伅
+            max_retries: 鏈�澶ч噸璇曟鏁�
 
         Returns:
             鍙戦�佹垚鍔熻繑鍥濼rue锛屽け璐ヨ繑鍥濬alse
         """
-        try:
-            url = f"{self.base_url}/sendText"
-            payload = {"wId": w_id, "wcId": wc_id, "content": content}
+        if max_retries is None:
+            from config import settings
+            max_retries = settings.max_retry_count
+            
+        retry_count = 0
+        while retry_count <= max_retries:
+            try:
+                url = f"{self.base_url}/sendText"
+                payload = {"wId": w_id, "wcId": wc_id, "content": content}
 
-            logger.info(
-                f"鍙戦�佹枃鏈秷鎭�: wId={w_id}, wcId={wc_id}, content_length={len(content)}"
-            )
-
-            response = self.session.post(url, json=payload, timeout=30)
-            response.raise_for_status()
-
-            result = response.json()
-
-            if result.get("code") == "1000":
-                logger.info(f"鏂囨湰娑堟伅鍙戦�佹垚鍔�: wcId={wc_id}")
-                return True
-            else:
-                logger.error(
-                    f"鏂囨湰娑堟伅鍙戦�佸け璐�: wcId={wc_id}, code={result.get('code')}, message={result.get('message')}"
+                logger.info(
+                    f"鍙戦�佹枃鏈秷鎭�: wId={w_id}, wcId={wc_id}, content_length={len(content)}, retry={retry_count}"
                 )
-                return False
 
-        except requests.exceptions.RequestException as e:
-            logger.error(f"鍙戦�佹枃鏈秷鎭綉缁滈敊璇�: wcId={wc_id}, error={str(e)}")
-            return False
-        except Exception as e:
-            logger.error(f"鍙戦�佹枃鏈秷鎭紓甯�: wcId={wc_id}, error={str(e)}")
-            return False
+                response = self.session.post(url, json=payload, timeout=30)
+                response.raise_for_status()
+
+                result = response.json()
+
+                if result.get("code") == "1000":
+                    logger.info(f"鏂囨湰娑堟伅鍙戦�佹垚鍔�: wcId={wc_id}")
+                    return True
+                else:
+                    logger.error(
+                        f"鏂囨湰娑堟伅鍙戦�佸け璐�: wcId={wc_id}, code={result.get('code')}, message={result.get('message')}"
+                    )
+
+            except requests.exceptions.RequestException as e:
+                logger.error(f"鍙戦�佹枃鏈秷鎭綉缁滈敊璇�: wcId={wc_id}, retry={retry_count}, error={str(e)}")
+            except Exception as e:
+                logger.error(f"鍙戦�佹枃鏈秷鎭紓甯�: wcId={wc_id}, retry={retry_count}, error={str(e)}")
+            
+            retry_count += 1
+            if retry_count <= max_retries:
+                from config import settings
+                wait_time = settings.retry_delay * retry_count
+                logger.info(f"绛夊緟閲嶈瘯: wcId={wc_id}, wait_time={wait_time}s")
+                import time
+                time.sleep(wait_time)
+
+        logger.error(
+            f"鏂囨湰娑堟伅鍙戦�佸け璐ワ紝宸茶揪鏈�澶ч噸璇曟鏁�: wcId={wc_id}, max_retries={max_retries}"
+        )
+        return False
 
     def send_group_message(self, w_id: str, group_id: str, content: str) -> bool:
         """
@@ -118,6 +143,153 @@
         """
         return self.send_text_message(w_id, group_id, content)
 
+    def init_address_list(self, w_id: str) -> bool:
+        """
+        鍒濆鍖栭�氳褰曞垪琛�
+
+        Args:
+            w_id: 鐧诲綍瀹炰緥鏍囪瘑
+
+        Returns:
+            鍒濆鍖栨垚鍔熻繑鍥濼rue锛屽け璐ヨ繑鍥濬alse
+        """
+        try:
+            url = f"{self.base_url}/initAddressList"
+            payload = {"wId": w_id}
+
+            logger.info(f"鍒濆鍖栭�氳褰曞垪琛�: wId={w_id}")
+
+            response = self.session.post(url, json=payload, timeout=30)
+            response.raise_for_status()
+
+            result = response.json()
+
+            if result.get("code") == "1000":
+                logger.info(f"鍒濆鍖栭�氳褰曞垪琛ㄦ垚鍔�: wId={w_id}")
+                return True
+            else:
+                logger.error(
+                    f"鍒濆鍖栭�氳褰曞垪琛ㄥけ璐�: wId={w_id}, code={result.get('code')}, message={result.get('message')}"
+                )
+                return False
+
+        except requests.exceptions.RequestException as e:
+            logger.error(f"鍒濆鍖栭�氳褰曞垪琛ㄧ綉缁滈敊璇�: wId={w_id}, error={str(e)}")
+            return False
+        except Exception as e:
+            logger.error(f"鍒濆鍖栭�氳褰曞垪琛ㄥ紓甯�: wId={w_id}, error={str(e)}")
+            return False
+
+    def get_address_list(self, w_id: str) -> Optional[Dict[str, Any]]:
+        """
+        鑾峰彇閫氳褰曞垪琛�
+
+        Args:
+            w_id: 鐧诲綍瀹炰緥鏍囪瘑
+
+        Returns:
+            閫氳褰曟暟鎹瓧鍏革紝澶辫触杩斿洖None
+            杩斿洖鏍煎紡: {
+                "chatrooms": [...],  # 缇ょ粍鍒楄〃
+                "friends": [...],    # 濂藉弸鍒楄〃
+                "ghs": [...],        # 鍏紬鍙峰垪琛�
+                "others": [...]      # 鍏朵粬
+            }
+        """
+        try:
+            url = f"{self.base_url}/getAddressList"
+            payload = {"wId": w_id}
+
+            logger.info(f"鑾峰彇閫氳褰曞垪琛�: wId={w_id}")
+
+            response = self.session.post(url, json=payload, timeout=30)
+            response.raise_for_status()
+
+            result = response.json()
+
+            if result.get("code") == "1000":
+                address_data = result.get("data", {})
+                logger.info(f"鎴愬姛鑾峰彇閫氳褰曞垪琛�: wId={w_id}, friends_count={len(address_data.get('friends', []))}")
+                return address_data
+            else:
+                logger.error(
+                    f"鑾峰彇閫氳褰曞垪琛ㄥけ璐�: wId={w_id}, code={result.get('code')}, message={result.get('message')}"
+                )
+                return None
+
+        except requests.exceptions.RequestException as e:
+            logger.error(f"鑾峰彇閫氳褰曞垪琛ㄧ綉缁滈敊璇�: wId={w_id}, error={str(e)}")
+            return None
+        except Exception as e:
+            logger.error(f"鑾峰彇閫氳褰曞垪琛ㄥ紓甯�: wId={w_id}, error={str(e)}")
+            return None
+
+    def send_group_at_message(self, w_id: str, wc_id: str, content: str, at_wc_ids: List[str], max_retries: int = None) -> bool:
+        """
+        鍙戦�佺兢鑱夽娑堟伅
+
+        Args:
+            w_id: 鐧诲綍瀹炰緥鏍囪瘑
+            wc_id: 鎺ユ敹鏂圭兢id
+            content: 鏂囨湰鍐呭娑堟伅锛園鐨勫井淇℃樀绉伴渶瑕佽嚜宸辨嫾鎺ワ紝蹇呴』鎷兼帴鑹剧壒绗﹀彿锛屼笉鐒朵笉鐢熸晥锛�
+            at_wc_ids: 鑹剧壒鐨勫井淇d鍒楄〃
+            max_retries: 鏈�澶ч噸璇曟鏁�
+
+        Returns:
+            鍙戦�佹垚鍔熻繑鍥濼rue锛屽け璐ヨ繑鍥濬alse
+        """
+        if max_retries is None:
+            from config import settings
+            max_retries = settings.max_retry_count
+
+        retry_count = 0
+        while retry_count <= max_retries:
+            try:
+                url = f"{self.base_url}/sendText"
+                # 灏哸t_wc_ids鍒楄〃鐢ㄩ�楀彿鎷兼帴
+                at_str = ",".join(at_wc_ids)
+                payload = {
+                    "wId": w_id,
+                    "wcId": wc_id,
+                    "content": content,
+                    "at": at_str
+                }
+
+                logger.info(
+                    f"鍙戦�佺兢鑱夽娑堟伅: wId={w_id}, wcId={wc_id}, at={at_str}, content_length={len(content)}, retry={retry_count}"
+                )
+
+                response = self.session.post(url, json=payload, timeout=30)
+                response.raise_for_status()
+
+                result = response.json()
+
+                if result.get("code") == "1000":
+                    logger.info(f"缇よ亰@娑堟伅鍙戦�佹垚鍔�: wcId={wc_id}, at={at_str}")
+                    return True
+                else:
+                    logger.error(
+                        f"缇よ亰@娑堟伅鍙戦�佸け璐�: wcId={wc_id}, at={at_str}, code={result.get('code')}, message={result.get('message')}"
+                    )
+
+            except requests.exceptions.RequestException as e:
+                logger.error(f"鍙戦�佺兢鑱夽娑堟伅缃戠粶閿欒: wcId={wc_id}, at={at_str}, retry={retry_count}, error={str(e)}")
+            except Exception as e:
+                logger.error(f"鍙戦�佺兢鑱夽娑堟伅寮傚父: wcId={wc_id}, at={at_str}, retry={retry_count}, error={str(e)}")
+
+            retry_count += 1
+            if retry_count <= max_retries:
+                from config import settings
+                wait_time = settings.retry_delay * retry_count
+                logger.info(f"绛夊緟閲嶈瘯: wcId={wc_id}, wait_time={wait_time}s")
+                import time
+                time.sleep(wait_time)
+
+        logger.error(
+            f"缇よ亰@娑堟伅鍙戦�佸け璐ワ紝宸茶揪鏈�澶ч噸璇曟鏁�: wcId={wc_id}, at={at_str}, max_retries={max_retries}"
+        )
+        return False
+
 
 # 鍏ㄥ眬E浜戠瀹跺鎴风瀹炰緥
 ecloud_client = ECloudClient()
diff --git a/app/services/message_processor.py b/app/services/message_processor.py
index 11308fc..12aaea2 100644
--- a/app/services/message_processor.py
+++ b/app/services/message_processor.py
@@ -3,7 +3,10 @@
 """
 
 import json
-from typing import Dict, Any, Optional
+import time
+import re
+from typing import Dict, Any, Optional, List, Tuple
+from datetime import datetime
 from sqlalchemy.orm import Session
 from loguru import logger
 
@@ -13,6 +16,7 @@
 from app.services.redis_queue import redis_queue
 from app.services.ecloud_client import ecloud_client
 from app.services.dify_client import dify_client
+from config import settings
 
 
 class MessageProcessor:
@@ -20,6 +24,51 @@
 
     def __init__(self):
         pass
+
+    def parse_at_mentions(self, ai_answer: str) -> Tuple[str, List[str]]:
+        """
+        瑙f瀽AI鍥炲涓殑@瀛楃锛屾彁鍙栧鏈嶅悕绉�
+
+        Args:
+            ai_answer: AI鍥炲鍐呭
+
+        Returns:
+            (澶勭悊鍚庣殑娑堟伅鍐呭, 闇�瑕丂鐨勫鏈峸cid鍒楄〃)
+        """
+        try:
+            # 鑾峰彇閰嶇疆鐨勫鏈嶅悕绉板垪琛�
+            customer_service_names = settings.customer_service_names
+
+            # 鏌ユ壘鎵�鏈堾瀛楃鍚庣殑瀹㈡湇鍚嶇О
+            at_pattern = r'@([^\s]+)'
+            matches = re.findall(at_pattern, ai_answer)
+
+            valid_at_names = []
+            at_wc_ids = []
+
+            for match in matches:
+                # 妫�鏌ユ槸鍚﹀湪閰嶇疆鐨勫鏈嶅悕绉板垪琛ㄤ腑
+                if match in customer_service_names:
+                    valid_at_names.append(match)
+                    logger.info(f"鍙戠幇鏈夋晥鐨凘瀹㈡湇鍚嶇О: {match}")
+
+            # 濡傛灉鏈夋湁鏁堢殑@瀹㈡湇鍚嶇О锛屾煡璇㈡暟鎹簱鑾峰彇wcid
+            if valid_at_names:
+                with next(get_db()) as db:
+                    for name in valid_at_names:
+                        # 鏍规嵁nick_name鏌ユ壘鑱旂郴浜�
+                        contact = db.query(Contact).filter(Contact.nick_name == name).first()
+                        if contact:
+                            at_wc_ids.append(contact.wc_id)
+                            logger.info(f"鎵惧埌瀹㈡湇鑱旂郴浜�: name={name}, wc_id={contact.wc_id}")
+                        else:
+                            logger.warning(f"鏈壘鍒板鏈嶈仈绯讳汉: name={name}")
+
+            return ai_answer, at_wc_ids
+
+        except Exception as e:
+            logger.error(f"瑙f瀽@瀛楃寮傚父: error={str(e)}")
+            return ai_answer, []
 
     def is_valid_group_message(self, callback_data: Dict[str, Any]) -> bool:
         """
@@ -151,17 +200,15 @@
 
             logger.info(f"寮�濮嬪鐞嗘秷鎭�: from_user={from_user}, from_group={from_group}")
 
-            # 鑾峰彇鏁版嵁搴撲細璇�
-            db = next(get_db())
-
-            try:
+            # 浣跨敤涓婁笅鏂囩鐞嗗櫒纭繚鏁版嵁搴撲細璇濇纭鐞�
+            with next(get_db()) as db:
                 # 3.1 纭繚鑱旂郴浜轰俊鎭瓨鍦�
                 if not self.ensure_contact_exists(from_group, w_id, db):
                     logger.error(f"鑱旂郴浜轰俊鎭鐞嗗け璐�: from_group={from_group}")
                     return False
 
-                # 3.2 鑾峰彇鐢ㄦ埛鐨刢onversation_id
-                conversation_id = redis_queue.get_conversation_id(from_user)
+                # 3.2 鑾峰彇鐢ㄦ埛鍦ㄥ綋鍓嶇兢缁勭殑conversation_id
+                conversation_id = redis_queue.get_conversation_id(from_user, from_group)
 
                 # 璋冪敤Dify鎺ュ彛鍙戦�佹秷鎭�
                 dify_response = dify_client.send_chat_message(
@@ -176,55 +223,112 @@
                 ai_answer = dify_response.get("answer", "")
                 new_conversation_id = dify_response.get("conversation_id", "")
 
-                # 鏇存柊Redis涓殑conversation_id
+                # 鏇存柊Redis涓殑conversation_id锛堝熀浜庣敤鎴�+缇ょ粍锛�
                 if new_conversation_id:
-                    redis_queue.set_conversation_id(from_user, new_conversation_id)
+                    redis_queue.set_conversation_id(from_user, new_conversation_id, from_group)
 
                 # 3.3 淇濆瓨瀵硅瘽璁板綍鍒版暟鎹簱
-                user_conversation_key = f"{from_user}_{new_conversation_id}"
+                # 鎸夌敤鎴枫�佺兢缁勫拰灏忔椂鍒嗙粍瀵硅瘽璁板綍
+                current_time = datetime.now()
+                hour_key = current_time.strftime("%Y%m%d_%H")
 
-                # 妫�鏌ユ槸鍚﹀凡瀛樺湪璁板綍
+                # 鏌ユ壘褰撳墠鐢ㄦ埛鍦ㄥ綋鍓嶇兢缁勫綋鍓嶅皬鏃剁殑瀵硅瘽璁板綍
                 existing_conversation = (
                     db.query(Conversation)
-                    .filter(Conversation.user_conversation_key == user_conversation_key)
+                    .filter(
+                        Conversation.from_user == from_user,
+                        Conversation.conversation_id == new_conversation_id,
+                        Conversation.group == from_group,
+                        Conversation.hour == hour_key
+                    )
                     .first()
                 )
 
                 if existing_conversation:
-                    # 鏇存柊鐜版湁璁板綍
-                    existing_conversation.user_question = content
-                    existing_conversation.ai_answer = ai_answer
-                    existing_conversation.is_processed = True
-                    logger.info(f"鏇存柊瀵硅瘽璁板綍: key={user_conversation_key}")
+                    # 鏇存柊鐜版湁璁板綍 - 浣跨敤JSON鏍煎紡杩藉姞瀵硅瘽鍐呭锛堝綋鍓嶇敤鎴峰湪褰撳墠缇ょ粍褰撳墠灏忔椂鐨勫璇濓級
+                    try:
+                        # 瑙f瀽鐜版湁鐨刢ontent JSON
+                        if existing_conversation.content:
+                            content_list = json.loads(existing_conversation.content)
+                        else:
+                            content_list = []
+
+                        # 杩藉姞鏂扮殑瀵硅瘽鍐呭
+                        content_list.append({
+                            "user": content,
+                            "ai": ai_answer
+                        })
+
+                        # 鏇存柊璁板綍
+                        existing_conversation.content = json.dumps(content_list, ensure_ascii=False)
+                        existing_conversation.is_processed = True
+                        logger.info(f"杩藉姞鍒板綋鍓嶇敤鎴风兢缁勫皬鏃跺璇濊褰�: user={from_user}, group={from_group}, hour={hour_key}, 瀵硅瘽杞={len(content_list)}")
+                    except json.JSONDecodeError as e:
+                        logger.error(f"瑙f瀽鐜版湁瀵硅瘽鍐呭JSON澶辫触: {str(e)}, 閲嶆柊鍒涘缓")
+                        # 濡傛灉JSON瑙f瀽澶辫触锛岄噸鏂板垱寤篶ontent
+                        content_list = [{"user": content, "ai": ai_answer}]
+                        existing_conversation.content = json.dumps(content_list, ensure_ascii=False)
+                        existing_conversation.is_processed = True
                 else:
-                    # 鍒涘缓鏂拌褰�
+                    # 鍒涘缓鏂拌褰� - 鏂扮殑鐢ㄦ埛缇ょ粍灏忔椂瀵硅瘽鎴栭娆″璇濓紝浣跨敤JSON鏍煎紡瀛樺偍瀵硅瘽鍐呭
+                    content_list = [{"user": content, "ai": ai_answer}]
                     new_conversation = Conversation(
-                        user_conversation_key=user_conversation_key,
                         from_user=from_user,
                         conversation_id=new_conversation_id,
-                        user_question=content,
-                        ai_answer=ai_answer,
+                        group=from_group,
+                        hour=hour_key,
+                        content=json.dumps(content_list, ensure_ascii=False),
                         is_processed=True,
                     )
                     db.add(new_conversation)
-                    logger.info(f"鍒涘缓瀵硅瘽璁板綍: key={user_conversation_key}")
+                    logger.info(f"鍒涘缓鏂扮殑鐢ㄦ埛缇ょ粍灏忔椂瀵硅瘽璁板綍: user={from_user}, group={from_group}, hour={hour_key}, 鍒濆瀵硅瘽杞=1")
 
                 db.commit()
 
                 # 鍙戦�丄I鍥炵瓟鍒扮兢鑱�
-                if ai_answer and ecloud_client.send_group_message(
-                    w_id, from_group, ai_answer
-                ):
+                success = False
+                if ai_answer:
+                    # 瑙f瀽AI鍥炲涓殑@瀛楃
+                    processed_answer, at_wc_ids = self.parse_at_mentions(ai_answer)
+
+                    # 鍙戦�佹秷鎭紝鏈�澶氶噸璇�3娆�
+                    for attempt in range(3):
+                        if at_wc_ids:
+                            # 濡傛灉鏈堾瀹㈡湇锛屼娇鐢ㄧ兢鑱夽鎺ュ彛
+                            logger.info(f"浣跨敤缇よ亰@鎺ュ彛鍙戦�佹秷鎭�: at_wc_ids={at_wc_ids}")
+                            if ecloud_client.send_group_at_message(
+                                w_id, from_group, processed_answer, at_wc_ids
+                            ):
+                                success = True
+                                break
+                        else:
+                            # 鏅�氱兢鑱婃秷鎭�
+                            logger.info("浣跨敤鏅�氱兢鑱婃帴鍙e彂閫佹秷鎭�")
+                            if ecloud_client.send_group_message(
+                                w_id, from_group, processed_answer
+                            ):
+                                success = True
+                                break
+
+                        logger.warning(f"鍙戦�丄I鍥炵瓟澶辫触锛屽皾璇曢噸璇� ({attempt + 1}/3): from_user={from_user}")
+                        if attempt < 2:  # 涓嶆槸鏈�鍚庝竴娆″皾璇曪紝绛夊緟涓�娈垫椂闂村啀閲嶈瘯
+                            time.sleep(2 ** attempt)  # 鎸囨暟閫�閬�
+                
+                if success:
                     # 鏇存柊鍙戦�佺姸鎬�
                     conversation = (
                         db.query(Conversation)
                         .filter(
-                            Conversation.user_conversation_key == user_conversation_key
+                            Conversation.from_user == from_user,
+                            Conversation.conversation_id == new_conversation_id,
+                            Conversation.group == from_group,
+                            Conversation.hour == hour_key
                         )
                         .first()
                     )
                     if conversation:
                         conversation.is_sent = True
+                        conversation.sent_time = current_time
                         db.commit()
 
                     logger.info(f"娑堟伅澶勭悊瀹屾垚: from_user={from_user}")
@@ -232,9 +336,6 @@
                 else:
                     logger.error(f"鍙戦�丄I鍥炵瓟澶辫触: from_user={from_user}")
                     return False
-
-            finally:
-                db.close()
 
         except Exception as e:
             logger.error(f"澶勭悊娑堟伅寮傚父: from_user={from_user}, error={str(e)}")
diff --git a/app/services/redis_queue.py b/app/services/redis_queue.py
index 792bcc5..54af4a4 100644
--- a/app/services/redis_queue.py
+++ b/app/services/redis_queue.py
@@ -26,9 +26,14 @@
         """鑾峰彇澶勭悊鐘舵�侀敭"""
         return f"{self.processing_prefix}{from_user}"
 
-    def get_conversation_key(self, from_user: str) -> str:
+    def get_conversation_key(self, from_user: str, group: str = None) -> str:
         """鑾峰彇鐢ㄦ埛瀵硅瘽ID閿�"""
-        return f"{self.conversation_prefix}{from_user}"
+        if group:
+            # 鍩轰簬鐢ㄦ埛+缇ょ粍鐢熸垚conversation_key锛岀‘淇濅笉鍚岀兢缁勭殑瀵硅瘽鐙珛
+            return f"{self.conversation_prefix}{from_user}:{group}"
+        else:
+            # 鍏煎鏃х増鏈紝浠呭熀浜庣敤鎴�
+            return f"{self.conversation_prefix}{from_user}"
 
     def enqueue_message(self, from_user: str, message_data: Dict[str, Any]) -> bool:
         """灏嗘秷鎭姞鍏ョ敤鎴烽槦鍒�"""
@@ -36,8 +41,8 @@
             queue_key = self.get_user_queue_key(from_user)
             message_json = json.dumps(message_data, ensure_ascii=False)
 
-            # 浣跨敤LPUSH灏嗘秷鎭姞鍏ラ槦鍒楀ご閮�
-            result = self.redis_client.lpush(queue_key, message_json)
+            # 浣跨敤RPUSH灏嗘秷鎭姞鍏ラ槦鍒楀熬閮紝纭繚FIFO椤哄簭
+            result = self.redis_client.rpush(queue_key, message_json)
 
             logger.info(f"娑堟伅宸插姞鍏ラ槦鍒�: user={from_user}, queue_length={result}, message={message_json}")
             return True
@@ -107,28 +112,28 @@
             logger.error(f"妫�鏌ュ鐞嗙姸鎬佸け璐�: user={from_user}, error={str(e)}")
             return False
 
-    def get_conversation_id(self, from_user: str) -> Optional[str]:
+    def get_conversation_id(self, from_user: str, group: str = None) -> Optional[str]:
         """鑾峰彇鐢ㄦ埛鐨勫璇滻D"""
         try:
-            conversation_key = self.get_conversation_key(from_user)
+            conversation_key = self.get_conversation_key(from_user, group)
             return self.redis_client.get(conversation_key)
         except Exception as e:
-            logger.error(f"鑾峰彇瀵硅瘽ID澶辫触: user={from_user}, error={str(e)}")
+            logger.error(f"鑾峰彇瀵硅瘽ID澶辫触: user={from_user}, group={group}, error={str(e)}")
             return None
 
     def set_conversation_id(
-        self, from_user: str, conversation_id: str, ttl: int = 86400
+        self, from_user: str, conversation_id: str, group: str = None, ttl: int = 86400
     ) -> bool:
         """璁剧疆鐢ㄦ埛鐨勫璇滻D"""
         try:
-            conversation_key = self.get_conversation_key(from_user)
+            conversation_key = self.get_conversation_key(from_user, group)
             self.redis_client.setex(conversation_key, ttl, conversation_id)
             logger.info(
-                f"璁剧疆瀵硅瘽ID: user={from_user}, conversation_id={conversation_id}"
+                f"璁剧疆瀵硅瘽ID: user={from_user}, group={group}, conversation_id={conversation_id}"
             )
             return True
         except Exception as e:
-            logger.error(f"璁剧疆瀵硅瘽ID澶辫触: user={from_user}, error={str(e)}")
+            logger.error(f"璁剧疆瀵硅瘽ID澶辫触: user={from_user}, group={group}, error={str(e)}")
             return False
 
     def get_queue_length(self, from_user: str) -> int:
diff --git a/app/utils/logger.py b/app/utils/logger.py
index 16ad222..ef16c81 100644
--- a/app/utils/logger.py
+++ b/app/utils/logger.py
@@ -28,11 +28,11 @@
         level=settings.log_level,
         format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
         rotation="1 day",
-        retention="30 days",
+        retention="7 days",
         compression="zip",
         encoding="utf-8"
     )
-    
+
     # 娣诲姞閿欒鏃ュ織鏂囦欢
     error_log_file = settings.log_file.replace('.log', '_error.log')
     logger.add(
@@ -40,7 +40,7 @@
         level="ERROR",
         format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
         rotation="1 day",
-        retention="30 days",
+        retention="7 days",
         compression="zip",
         encoding="utf-8"
     )
diff --git a/app/workers/message_worker.py b/app/workers/message_worker.py
index 21a28a3..bb06b8d 100644
--- a/app/workers/message_worker.py
+++ b/app/workers/message_worker.py
@@ -47,10 +47,34 @@
         """鐩戞帶闃熷垪锛屼负鏈夋秷鎭殑鐢ㄦ埛鍚姩澶勭悊绾跨▼"""
         while self.running:
             try:
-                # 杩欓噷鍙互瀹炵幇鏇村鏉傜殑闃熷垪鍙戠幇鏈哄埗
-                # 鐩墠绠�鍖栦负妫�鏌ュ凡鐭ョ殑娲昏穬鐢ㄦ埛
-                # 鍦ㄥ疄闄呭簲鐢ㄤ腑锛屽彲浠ラ�氳繃Redis鐨凷CAN鍛戒护鎵弿鎵�鏈夐槦鍒�
-
+                # 浣跨敤Redis鐨凷CAN鍛戒护鎵弿鎵�鏈夐槦鍒楅敭
+                cursor = 0
+                queue_keys = set()
+                
+                while self.running:
+                    cursor, keys = self._scan_queue_keys(cursor)
+                    queue_keys.update(keys)
+                    
+                    # 濡傛灉娓告爣涓�0锛岃〃绀烘壂鎻忓畬鎴�
+                    if cursor == 0:
+                        break
+                
+                # 涓烘瘡涓湁娑堟伅鐨勯槦鍒楀惎鍔ㄥ鐞嗙嚎绋�
+                for queue_key in queue_keys:
+                    if not self.running:
+                        break
+                    
+                    # 浠庨槦鍒楅敭涓彁鍙栫敤鎴稩D
+                    if queue_key.startswith(redis_queue.queue_prefix):
+                        from_user = queue_key[len(redis_queue.queue_prefix):]
+                        
+                        # 妫�鏌ラ槦鍒楁槸鍚︽湁娑堟伅
+                        queue_length = redis_queue.get_queue_length(from_user)
+                        if queue_length > 0:
+                            logger.info(f"鍙戠幇鐢ㄦ埛闃熷垪鏈夋秷鎭�: user={from_user}, length={queue_length}")
+                            # 鍚姩鐢ㄦ埛闃熷垪澶勭悊
+                            self.process_user_queue(from_user)
+                
                 # 娓呯悊宸插畬鎴愮殑绾跨▼
                 self._cleanup_finished_threads()
 
@@ -60,6 +84,29 @@
             except Exception as e:
                 logger.error(f"闃熷垪鐩戞帶寮傚父: {str(e)}")
                 time.sleep(10)
+    
+    def _scan_queue_keys(self, cursor: int = 0, count: int = 100) -> tuple:
+        """
+        鎵弿闃熷垪閿�
+        
+        Args:
+            cursor: 鎵弿娓告爣
+            count: 姣忔鎵弿鐨勯敭鏁伴噺
+            
+        Returns:
+            (鏂版父鏍�, 闃熷垪閿垪琛�)
+        """
+        try:
+            # 浣跨敤SCAN鍛戒护鎵弿鍖归厤妯″紡鐨勯敭
+            new_cursor, keys = redis_queue.redis_client.scan(
+                cursor=cursor,
+                match=f"{redis_queue.queue_prefix}*",
+                count=count
+            )
+            return new_cursor, keys
+        except Exception as e:
+            logger.error(f"鎵弿闃熷垪閿け璐�: {str(e)}")
+            return 0, []
 
     def _cleanup_finished_threads(self):
         """娓呯悊宸插畬鎴愮殑绾跨▼"""
@@ -102,6 +149,10 @@
         """
         try:
             logger.info(f"寮�濮嬪鐞嗙敤鎴锋秷鎭槦鍒�: {from_user}")
+            
+            # 鑾峰彇闃熷垪闀垮害
+            queue_length = redis_queue.get_queue_length(from_user)
+            logger.info(f"鐢ㄦ埛闃熷垪鍒濆闀垮害: {from_user}, length={queue_length}")
 
             while self.running:
                 # 妫�鏌ョ敤鎴锋槸鍚︽鍦ㄥ鐞嗕腑锛堥槻姝㈠苟鍙戯級
@@ -132,6 +183,9 @@
 
                     if success:
                         logger.info(f"娑堟伅澶勭悊鎴愬姛: {from_user}")
+                        # 鏇存柊闃熷垪闀垮害淇℃伅
+                        queue_length = redis_queue.get_queue_length(from_user)
+                        logger.info(f"鐢ㄦ埛闃熷垪鍓╀綑闀垮害: {from_user}, length={queue_length}")
                     else:
                         logger.error(f"娑堟伅澶勭悊澶辫触: {from_user}")
                         # 鍙互鑰冭檻灏嗗け璐ョ殑娑堟伅閲嶆柊鍏ラ槦鎴栬褰曞埌閿欒闃熷垪
diff --git a/config.example.json b/config.example.json
new file mode 100644
index 0000000..b2df84d
--- /dev/null
+++ b/config.example.json
@@ -0,0 +1,34 @@
+{
+  "database": {
+    "url": "mysql+pymysql://username:password@host:port/database_name"
+  },
+  "redis": {
+    "url": "redis://localhost:6379/0"
+  },
+  "ecloud": {
+    "base_url": "http://your-ecloud-server:port",
+    "authorization": "your_ecloud_authorization_token",
+    "w_id": "your_ecloud_w_id"
+  },
+  "dify": {
+    "base_url": "https://api.dify.ai/v1",
+    "api_key": "your_dify_api_key"
+  },
+  "server": {
+    "host": "0.0.0.0",
+    "port": 7979,
+    "debug": false
+  },
+  "logging": {
+    "level": "INFO",
+    "file": "logs/app.log"
+  },
+  "message_processing": {
+    "max_retry_count": 3,
+    "retry_delay": 5,
+    "queue_timeout": 300
+  },
+  "customer_service": {
+    "names": ["瀹㈡湇1", "瀹㈡湇2"]
+  }
+}
diff --git a/config.production.json b/config.production.json
new file mode 100644
index 0000000..efbd202
--- /dev/null
+++ b/config.production.json
@@ -0,0 +1,30 @@
+{
+  "database": {
+    "url": "mysql+pymysql://root:password@localhost:3306/ecloud_dify"
+  },
+  "redis": {
+    "url": "redis://localhost:6379/0"
+  },
+  "ecloud": {
+    "base_url": "http://125.122.152.142:9899",
+    "authorization": "your_ecloud_authorization_token"
+  },
+  "dify": {
+    "base_url": "https://api.dify.ai/v1",
+    "api_key": "your_dify_api_key"
+  },
+  "server": {
+    "host": "0.0.0.0",
+    "port": 7979,
+    "debug": false
+  },
+  "logging": {
+    "level": "INFO",
+    "file": "logs/app.log"
+  },
+  "message_processing": {
+    "max_retry_count": 3,
+    "retry_delay": 5,
+    "queue_timeout": 300
+  }
+}
diff --git a/config.py b/config.py
index ae16800..d7919aa 100644
--- a/config.py
+++ b/config.py
@@ -3,44 +3,104 @@
 """
 
 import os
-from typing import Optional
-from pydantic_settings import BaseSettings
+import json
 
 
-class Settings(BaseSettings):
+class Settings:
     """搴旂敤閰嶇疆"""
 
-    # 鏁版嵁搴撻厤缃�
-    database_url: str = "mysql+pymysql://root:TAI%402019%23Zjun@120.24.39.179:3306/ecloud_dify"
+    def __init__(self, config_file: str = "config.json"):
+        """鍒濆鍖栭厤缃紝浠嶫SON鏂囦欢鍔犺浇"""
+        self.config_file = config_file
+        self._load_config()
 
-    # Redis閰嶇疆
-    redis_url: str = "redis://localhost:6379/0"
+    def _load_config(self):
+        """浠嶫SON鏂囦欢鍔犺浇閰嶇疆"""
+        try:
+            if os.path.exists(self.config_file):
+                with open(self.config_file, 'r', encoding='utf-8') as f:
+                    config_data = json.load(f)
+                self._set_config_from_dict(config_data)
+            else:
+                # 濡傛灉閰嶇疆鏂囦欢涓嶅瓨鍦紝浣跨敤榛樿鍊�
+                self._set_default_config()
+        except Exception as e:
+            print(f"鍔犺浇閰嶇疆鏂囦欢澶辫触: {e}")
+            self._set_default_config()
 
-    # E浜戠瀹堕厤缃�
-    ecloud_base_url: str = "http://your-ecloud-domain.com"
-    ecloud_authorization: str = "your-authorization-token"
+    def _set_config_from_dict(self, config_data: dict):
+        """浠庡瓧鍏歌缃厤缃�"""
+        # 鏁版嵁搴撻厤缃�
+        self.database_url = config_data.get("database", {}).get("url", "mysql+pymysql://root:TAI%402019%23Zjun@120.24.39.179:3306/ecloud_dify")
 
-    # DifyAI閰嶇疆
-    dify_base_url: str = "https://api.dify.ai/v1"
-    dify_api_key: str = "your-dify-api-key"
+        # Redis閰嶇疆
+        self.redis_url = config_data.get("redis", {}).get("url", "redis://localhost:6379/0")
 
-    # 鏈嶅姟閰嶇疆
-    server_host: str = "0.0.0.0"
-    server_port: int = 8000
-    debug: bool = True
+        # E浜戠瀹堕厤缃�
+        ecloud_config = config_data.get("ecloud", {})
+        self.ecloud_base_url = ecloud_config.get("base_url", "http://125.122.152.142:9899")
+        self.ecloud_authorization = ecloud_config.get("authorization", "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxMzYxMTQ1MjE3NSIsInBhc3N3b3JkIjoiJDJhJDEwJEU3Ry5LOEJzekphM2JGQlh0SG8vOXVrUk1NalVweGVVemguUDRnMkJBdHN2YXpBb0JIQWJpIn0.Gd2vbeJjL5pUGFhUngWPLkDTLhD3GUaEPXOkdoTf4KRh9o2FtST1OZJxmZuGdUy7WIYlIPVueoVyIu5iHOyi8A")
+        self.ecloud_w_id = ecloud_config.get("w_id", "")
 
-    # 鏃ュ織閰嶇疆
-    log_level: str = "INFO"
-    log_file: str = "logs/app.log"
+        # DifyAI閰嶇疆
+        dify_config = config_data.get("dify", {})
+        self.dify_base_url = dify_config.get("base_url", "https://api.dify.ai/v1")
+        self.dify_api_key = dify_config.get("api_key", "app-OMnBr7zsf5UTV83Ey8QcSErA")
 
-    # 娑堟伅澶勭悊閰嶇疆
-    max_retry_count: int = 3
-    retry_delay: int = 5  # 绉�
-    queue_timeout: int = 300  # 绉�
+        # 鏈嶅姟閰嶇疆
+        server_config = config_data.get("server", {})
+        self.server_host = server_config.get("host", "0.0.0.0")
+        self.server_port = server_config.get("port", 7979)
+        self.debug = server_config.get("debug", True)
 
-    class Config:
-        env_file = ".env"
-        env_file_encoding = "utf-8"
+        # 鏃ュ織閰嶇疆
+        logging_config = config_data.get("logging", {})
+        self.log_level = logging_config.get("level", "INFO")
+        self.log_file = logging_config.get("file", "logs/app.log")
+
+        # 娑堟伅澶勭悊閰嶇疆
+        msg_config = config_data.get("message_processing", {})
+        self.max_retry_count = msg_config.get("max_retry_count", 3)
+        self.retry_delay = msg_config.get("retry_delay", 5)
+        self.queue_timeout = msg_config.get("queue_timeout", 300)
+
+        # 瀹㈡湇閰嶇疆
+        customer_service_config = config_data.get("customer_service", {})
+        self.customer_service_names = customer_service_config.get("names", ["瀹㈡湇1", "瀹㈡湇2"])
+
+    def _set_default_config(self):
+        """璁剧疆榛樿閰嶇疆"""
+        # 鏁版嵁搴撻厤缃�
+        self.database_url = "mysql+pymysql://root:TAI%402019%23Zjun@120.24.39.179:3306/ecloud_dify"
+
+        # Redis閰嶇疆
+        self.redis_url = "redis://localhost:6379/0"
+
+        # E浜戠瀹堕厤缃�
+        self.ecloud_base_url = "http://125.122.152.142:9899"
+        self.ecloud_authorization = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxMzYxMTQ1MjE3NSIsInBhc3N3b3JkIjoiJDJhJDEwJEU3Ry5LOEJzekphM2JGQlh0SG8vOXVrUk1NalVweGVVemguUDRnMkJBdHN2YXpBb0JIQWJpIn0.Gd2vbeJjL5pUGFhUngWPLkDTLhD3GUaEPXOkdoTf4KRh9o2FtST1OZJxmZuGdUy7WIYlIPVueoVyIu5iHOyi8A"
+        self.ecloud_w_id = ""
+
+        # DifyAI閰嶇疆
+        self.dify_base_url = "https://api.dify.ai/v1"
+        self.dify_api_key = "app-OMnBr7zsf5UTV83Ey8QcSErA"
+
+        # 鏈嶅姟閰嶇疆
+        self.server_host = "0.0.0.0"
+        self.server_port = 7979
+        self.debug = True
+
+        # 鏃ュ織閰嶇疆
+        self.log_level = "INFO"
+        self.log_file = "logs/app.log"
+
+        # 娑堟伅澶勭悊閰嶇疆
+        self.max_retry_count = 3
+        self.retry_delay = 5
+        self.queue_timeout = 300
+
+        # 瀹㈡湇閰嶇疆
+        self.customer_service_names = ["瀹㈡湇1", "瀹㈡湇2"]
 
 
 # 鍏ㄥ眬閰嶇疆瀹炰緥
diff --git a/ecloud_dify.spec b/ecloud_dify.spec
new file mode 100644
index 0000000..528fbd5
--- /dev/null
+++ b/ecloud_dify.spec
@@ -0,0 +1,127 @@
+# -*- mode: python ; coding: utf-8 -*-
+import os
+import sys
+from PyInstaller.utils.hooks import collect_data_files, collect_submodules
+
+# 鑾峰彇椤圭洰鏍圭洰褰�
+project_root = os.path.abspath('.')
+
+# 鏀堕泦鎵�鏈夋暟鎹枃浠�
+datas = []
+
+# 娣诲姞閰嶇疆鏂囦欢
+datas.append(('config.example.json', '.'))
+datas.append(('config.production.json', '.'))
+if os.path.exists('config.json'):
+    datas.append(('config.json', '.'))
+
+# 娣诲姞鏃ュ織鐩綍
+if os.path.exists('logs'):
+    datas.append(('logs', 'logs'))
+
+# 鏀堕泦FastAPI鍜屽叾浠栧寘鐨勬暟鎹枃浠�
+datas.extend(collect_data_files('fastapi'))
+datas.extend(collect_data_files('uvicorn'))
+datas.extend(collect_data_files('pydantic'))
+datas.extend(collect_data_files('sqlalchemy'))
+
+# 鏀堕泦闅愯棌瀵煎叆
+hiddenimports = []
+hiddenimports.extend(collect_submodules('uvicorn'))
+hiddenimports.extend(collect_submodules('fastapi'))
+hiddenimports.extend(collect_submodules('pydantic'))
+hiddenimports.extend(collect_submodules('sqlalchemy'))
+hiddenimports.extend(collect_submodules('pymysql'))
+hiddenimports.extend(collect_submodules('redis'))
+hiddenimports.extend(collect_submodules('celery'))
+hiddenimports.extend(collect_submodules('loguru'))
+hiddenimports.extend(collect_submodules('cryptography'))
+hiddenimports.extend(collect_submodules('requests'))
+hiddenimports.extend(collect_submodules('httpx'))
+
+# 娣诲姞鐗瑰畾鐨勯殣钘忓鍏�
+hiddenimports.extend([
+    'uvicorn.lifespan.on',
+    'uvicorn.lifespan.off',
+    'uvicorn.protocols.websockets.auto',
+    'uvicorn.protocols.websockets.websockets_impl',
+    'uvicorn.protocols.http.auto',
+    'uvicorn.protocols.http.h11_impl',
+    'uvicorn.protocols.http.httptools_impl',
+    'uvicorn.loops.auto',
+    'uvicorn.loops.asyncio',
+    'uvicorn.logging',
+    'pymysql.converters',
+    'pymysql.cursors',
+    'pymysql.connections',
+    'sqlalchemy.dialects.mysql.pymysql',
+    'sqlalchemy.pool',
+    'sqlalchemy.engine.default',
+    'app.api.callback',
+    'app.models.database',
+    'app.workers.message_worker',
+    'app.services.message_processor',
+    'app.services.dify_client',
+    'app.services.ecloud_client',
+    'app.services.redis_queue',
+    'app.utils.logger',
+])
+
+# 鎺掗櫎涓嶉渶瑕佺殑妯″潡
+excludes = [
+    'tkinter',
+    'matplotlib',
+    'numpy',
+    'pandas',
+    'scipy',
+    'PIL',
+    'IPython',
+    'jupyter',
+    'notebook',
+    'pytest',
+    'test',
+    'tests',
+]
+
+block_cipher = None
+
+a = Analysis(
+    ['startup.py'],
+    pathex=[project_root],
+    binaries=[],
+    datas=datas,
+    hiddenimports=hiddenimports,
+    hookspath=[],
+    hooksconfig={},
+    runtime_hooks=[],
+    excludes=excludes,
+    win_no_prefer_redirects=False,
+    win_private_assemblies=False,
+    cipher=block_cipher,
+    noarchive=False,
+)
+
+pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
+
+exe = EXE(
+    pyz,
+    a.scripts,
+    a.binaries,
+    a.zipfiles,
+    a.datas,
+    [],
+    name='ecloud_dify',
+    debug=False,
+    bootloader_ignore_signals=False,
+    strip=False,
+    upx=True,
+    upx_exclude=[],
+    runtime_tmpdir=None,
+    console=True,
+    disable_windowed_traceback=False,
+    argv_emulation=False,
+    target_arch=None,
+    codesign_identity=None,
+    entitlements_file=None,
+    icon=None,
+)
diff --git a/init.sql b/init.sql
deleted file mode 100644
index ae1312a..0000000
--- a/init.sql
+++ /dev/null
@@ -1,16 +0,0 @@
--- 鍒濆鍖栨暟鎹簱鑴氭湰
-
--- 鍒涘缓鏁版嵁搴擄紙濡傛灉涓嶅瓨鍦級
-CREATE DATABASE IF NOT EXISTS ecloud_dify CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- 浣跨敤鏁版嵁搴�
-USE ecloud_dify;
-
--- 鍒涘缓鐢ㄦ埛锛堝鏋滀笉瀛樺湪锛�
-CREATE USER IF NOT EXISTS 'ecloud'@'%' IDENTIFIED BY 'ecloud123';
-
--- 鎺堟潈
-GRANT ALL PRIVILEGES ON ecloud_dify.* TO 'ecloud'@'%';
-
--- 鍒锋柊鏉冮檺
-FLUSH PRIVILEGES;
diff --git a/install_service.bat b/install_service.bat
new file mode 100644
index 0000000..4c0b14f
--- /dev/null
+++ b/install_service.bat
@@ -0,0 +1,102 @@
+@echo off
+chcp 65001 >nul
+echo ========================================
+echo E浜戠瀹�-DifyAI瀵规帴鏈嶅姟 Windows鏈嶅姟瀹夎鑴氭湰
+echo ========================================
+echo.
+
+:: 妫�鏌ョ鐞嗗憳鏉冮檺
+net session >nul 2>&1
+if %errorLevel% == 0 (
+    echo 妫�娴嬪埌绠$悊鍛樻潈闄愶紝缁х画瀹夎...
+) else (
+    echo 閿欒锛氶渶瑕佺鐞嗗憳鏉冮檺鎵嶈兘瀹夎Windows鏈嶅姟
+    echo 璇峰彸閿偣鍑绘鑴氭湰锛岄�夋嫨"浠ョ鐞嗗憳韬唤杩愯"
+    pause
+    exit /b 1
+)
+
+:: 鑾峰彇褰撳墠鐩綍
+set "CURRENT_DIR=%~dp0"
+set "SERVICE_NAME=ECloudDifyService"
+set "SERVICE_DISPLAY_NAME=E浜戠瀹�-DifyAI瀵规帴鏈嶅姟"
+set "SERVICE_DESCRIPTION=灏咵浜戠瀹舵秷鎭浆鍙戝埌DifyAI骞惰繑鍥濧I鍥炵瓟鐨勬湇鍔�"
+set "EXE_PATH=%CURRENT_DIR%ecloud_dify.exe"
+
+echo 褰撳墠鐩綍: %CURRENT_DIR%
+echo 鏈嶅姟鍚嶇О: %SERVICE_NAME%
+echo 鍙墽琛屾枃浠�: %EXE_PATH%
+echo.
+
+:: 妫�鏌xe鏂囦欢鏄惁瀛樺湪
+if not exist "%EXE_PATH%" (
+    echo 閿欒锛氭壘涓嶅埌鍙墽琛屾枃浠� %EXE_PATH%
+    echo 璇风‘淇濆凡缁忓畬鎴愰」鐩墦鍖咃紝骞朵笖ecloud_dify.exe鏂囦欢瀛樺湪
+    pause
+    exit /b 1
+)
+
+:: 鍋滄骞跺垹闄ゅ凡瀛樺湪鐨勬湇鍔�
+echo 妫�鏌ユ槸鍚﹀瓨鍦ㄥ悓鍚嶆湇鍔�...
+sc query "%SERVICE_NAME%" >nul 2>&1
+if %errorLevel% == 0 (
+    echo 鍙戠幇宸插瓨鍦ㄧ殑鏈嶅姟锛屾鍦ㄥ仠姝㈠苟鍒犻櫎...
+    sc stop "%SERVICE_NAME%" >nul 2>&1
+    timeout /t 3 /nobreak >nul
+    sc delete "%SERVICE_NAME%" >nul 2>&1
+    if %errorLevel% == 0 (
+        echo 宸插垹闄ゆ棫鏈嶅姟
+    ) else (
+        echo 璀﹀憡锛氬垹闄ゆ棫鏈嶅姟澶辫触锛岀户缁畨瑁呮柊鏈嶅姟
+    )
+    echo.
+)
+
+:: 鍒涘缓Windows鏈嶅姟
+echo 姝e湪鍒涘缓Windows鏈嶅姟...
+sc create "%SERVICE_NAME%" binPath= "\"%EXE_PATH%\"" DisplayName= "%SERVICE_DISPLAY_NAME%" start= auto
+if %errorLevel% == 0 (
+    echo 鏈嶅姟鍒涘缓鎴愬姛
+) else (
+    echo 閿欒锛氭湇鍔″垱寤哄け璐�
+    pause
+    exit /b 1
+)
+
+:: 璁剧疆鏈嶅姟鎻忚堪
+sc description "%SERVICE_NAME%" "%SERVICE_DESCRIPTION%"
+
+:: 璁剧疆鏈嶅姟鎭㈠閫夐」锛堝け璐ユ椂鑷姩閲嶅惎锛�
+sc failure "%SERVICE_NAME%" reset= 86400 actions= restart/5000/restart/10000/restart/30000
+
+echo.
+echo 鏈嶅姟瀹夎瀹屾垚锛�
+echo.
+echo 鍙敤鐨勬搷浣滐細
+echo 1. 鍚姩鏈嶅姟: sc start %SERVICE_NAME%
+echo 2. 鍋滄鏈嶅姟: sc stop %SERVICE_NAME%
+echo 3. 鏌ョ湅鏈嶅姟鐘舵��: sc query %SERVICE_NAME%
+echo 4. 鍒犻櫎鏈嶅姟: sc delete %SERVICE_NAME%
+echo.
+echo 鎴栬�呬娇鐢╓indows鏈嶅姟绠$悊鍣� (services.msc) 杩涜绠$悊
+echo.
+
+:: 璇㈤棶鏄惁绔嬪嵆鍚姩鏈嶅姟
+set /p START_NOW="鏄惁绔嬪嵆鍚姩鏈嶅姟锛�(Y/N): "
+if /i "%START_NOW%"=="Y" (
+    echo 姝e湪鍚姩鏈嶅姟...
+    sc start "%SERVICE_NAME%"
+    if %errorLevel% == 0 (
+        echo 鏈嶅姟鍚姩鎴愬姛锛�
+        echo 鏈嶅姟灏嗗湪绔彛 7979 涓婅繍琛�
+        echo 鍙互閫氳繃 http://localhost:7979 璁块棶鏈嶅姟
+    ) else (
+        echo 鏈嶅姟鍚姩澶辫触锛岃妫�鏌ラ厤缃枃浠跺拰鏃ュ織
+    )
+) else (
+    echo 鏈嶅姟宸插畨瑁呬絾鏈惎鍔�
+    echo 鍙互绋嶅悗閫氳繃 sc start %SERVICE_NAME% 鍚姩鏈嶅姟
+)
+
+echo.
+pause
diff --git a/logs/app.log b/logs/app.log
index 6cbf9bc..fec3d52 100644
--- a/logs/app.log
+++ b/logs/app.log
@@ -1,4 +1,9 @@
-2025-07-22 14:23:00 | INFO | __main__:<module>:94 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-07-22 14:24:44 | INFO | __main__:<module>:94 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-07-22 14:25:57 | INFO | __main__:<module>:94 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-07-22 14:37:50 | INFO | __main__:<module>:94 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 14:46:37 | INFO | __main__:<module>:105 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 15:03:24 | INFO | __main__:<module>:105 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 16:48:21 | INFO | __main__:<module>:121 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 16:50:14 | INFO | __main__:<module>:121 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 16:55:09 | INFO | __main__:<module>:121 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 16:56:49 | INFO | __main__:<module>:121 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 17:19:58 | INFO | __main__:<module>:121 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 17:43:16 | INFO | __main__:<module>:105 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-07-23 17:44:16 | INFO | __main__:<module>:105 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
diff --git a/main.py b/main.py
index dd776b7..978923a 100644
--- a/main.py
+++ b/main.py
@@ -7,6 +7,7 @@
 from fastapi.middleware.cors import CORSMiddleware
 from contextlib import asynccontextmanager
 from loguru import logger
+import time
 from config import settings
 from app.api.callback import router as callback_router
 from app.models.database import create_tables
@@ -81,12 +82,22 @@
     }
 
 
+@app.get("/health")
+async def health_check():
+    """鍋ュ悍妫�鏌ユ帴鍙�"""
+    return {
+        "status": "healthy",
+        "message": "E浜戠瀹�-DifyAI瀵规帴鏈嶅姟杩愯姝e父",
+        "timestamp": int(time.time()),
+    }
+
+
 if __name__ == "__main__":
     # 閰嶇疆鏃ュ織
     logger.add(
         settings.log_file,
         rotation="1 day",
-        retention="30 days",
+        retention="7 days",
         level=settings.log_level,
         format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}",
     )
diff --git a/requirements.txt b/requirements.txt
index 6e0f4a5..56a01b2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,3 +11,5 @@
 cryptography==45.0.5
 pytest==8.4.1
 httpx==0.28.1
+pyinstaller==6.3.0
+pywin32==306
diff --git a/start.bat b/start.bat
new file mode 100644
index 0000000..cc26592
--- /dev/null
+++ b/start.bat
@@ -0,0 +1,42 @@
+@echo off
+chcp 65001 >nul
+echo ========================================
+echo E浜戠瀹�-DifyAI瀵规帴鏈嶅姟 鍚姩鑴氭湰
+echo ========================================
+echo.
+
+:: 鑾峰彇褰撳墠鐩綍
+set "CURRENT_DIR=%~dp0"
+set "EXE_PATH=%CURRENT_DIR%ecloud_dify.exe"
+
+echo 褰撳墠鐩綍: %CURRENT_DIR%
+echo 鍙墽琛屾枃浠�: %EXE_PATH%
+echo.
+
+:: 妫�鏌xe鏂囦欢鏄惁瀛樺湪
+if not exist "%EXE_PATH%" (
+    echo 閿欒锛氭壘涓嶅埌鍙墽琛屾枃浠� %EXE_PATH%
+    echo 璇风‘淇濆凡缁忓畬鎴愰」鐩墦鍖咃紝骞朵笖ecloud_dify.exe鏂囦欢瀛樺湪
+    pause
+    exit /b 1
+)
+
+:: 妫�鏌ラ厤缃枃浠�
+if not exist "%CURRENT_DIR%config.json" (
+    echo 璀﹀憡锛氭湭鎵惧埌config.json閰嶇疆鏂囦欢
+    echo 绋嬪簭灏嗕娇鐢ㄩ粯璁ら厤缃垨config.production.json妯℃澘
+    echo.
+)
+
+echo 姝e湪鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟...
+echo 鏈嶅姟灏嗗湪绔彛 7979 涓婅繍琛�
+echo 鍙互閫氳繃 http://localhost:7979 璁块棶鏈嶅姟
+echo 鎸� Ctrl+C 鍋滄鏈嶅姟
+echo.
+
+:: 鍚姩鏈嶅姟
+"%EXE_PATH%"
+
+echo.
+echo 鏈嶅姟宸插仠姝�
+pause
diff --git a/startup.py b/startup.py
new file mode 100644
index 0000000..dad9b0e
--- /dev/null
+++ b/startup.py
@@ -0,0 +1,139 @@
+"""
+鍚姩鑴氭湰 - 澶勭悊閰嶇疆鏂囦欢鍜岀洰褰曞垵濮嬪寲
+"""
+
+import os
+import sys
+import json
+import shutil
+from pathlib import Path
+
+
+def get_exe_dir():
+    """鑾峰彇exe鏂囦欢鎵�鍦ㄧ洰褰�"""
+    if getattr(sys, 'frozen', False):
+        # 濡傛灉鏄墦鍖呭悗鐨別xe鏂囦欢
+        return os.path.dirname(sys.executable)
+    else:
+        # 濡傛灉鏄紑鍙戠幆澧�
+        return os.path.dirname(os.path.abspath(__file__))
+
+
+def ensure_directories():
+    """纭繚蹇呰鐨勭洰褰曞瓨鍦�"""
+    exe_dir = get_exe_dir()
+    
+    # 鍒涘缓鏃ュ織鐩綍
+    logs_dir = os.path.join(exe_dir, 'logs')
+    if not os.path.exists(logs_dir):
+        os.makedirs(logs_dir)
+        print(f"鍒涘缓鏃ュ織鐩綍: {logs_dir}")
+    
+    return exe_dir
+
+
+def ensure_config_file():
+    """纭繚閰嶇疆鏂囦欢瀛樺湪"""
+    exe_dir = get_exe_dir()
+    config_file = os.path.join(exe_dir, 'config.json')
+    
+    if not os.path.exists(config_file):
+        # 濡傛灉config.json涓嶅瓨鍦紝灏濊瘯澶嶅埗鐢熶骇閰嶇疆妯℃澘
+        production_config = os.path.join(exe_dir, 'config.production.json')
+        example_config = os.path.join(exe_dir, 'config.example.json')
+        
+        if os.path.exists(production_config):
+            shutil.copy2(production_config, config_file)
+            print(f"澶嶅埗鐢熶骇閰嶇疆鏂囦欢: {production_config} -> {config_file}")
+        elif os.path.exists(example_config):
+            shutil.copy2(example_config, config_file)
+            print(f"澶嶅埗绀轰緥閰嶇疆鏂囦欢: {example_config} -> {config_file}")
+        else:
+            # 鍒涘缓榛樿閰嶇疆鏂囦欢
+            default_config = {
+                "database": {
+                    "url": "mysql+pymysql://root:password@localhost:3306/ecloud_dify"
+                },
+                "redis": {
+                    "url": "redis://localhost:6379/0"
+                },
+                "ecloud": {
+                    "base_url": "http://125.122.152.142:9899",
+                    "authorization": "your_ecloud_authorization_token",
+                    "w_id": "your_ecloud_w_id"
+                },
+                "dify": {
+                    "base_url": "https://api.dify.ai/v1",
+                    "api_key": "your_dify_api_key"
+                },
+                "server": {
+                    "host": "0.0.0.0",
+                    "port": 7979,
+                    "debug": False
+                },
+                "logging": {
+                    "level": "INFO",
+                    "file": "logs/app.log"
+                },
+                "message_processing": {
+                    "max_retry_count": 3,
+                    "retry_delay": 5,
+                    "queue_timeout": 300
+                },
+                "customer_service": {
+                    "names": ["瀹㈡湇1", "瀹㈡湇2"]
+                }
+            }
+            
+            with open(config_file, 'w', encoding='utf-8') as f:
+                json.dump(default_config, f, indent=2, ensure_ascii=False)
+            print(f"鍒涘缓榛樿閰嶇疆鏂囦欢: {config_file}")
+    
+    return config_file
+
+
+def setup_environment():
+    """璁剧疆杩愯鐜"""
+    exe_dir = ensure_directories()
+    config_file = ensure_config_file()
+    
+    # 璁剧疆宸ヤ綔鐩綍涓篹xe鎵�鍦ㄧ洰褰�
+    os.chdir(exe_dir)
+    print(f"璁剧疆宸ヤ綔鐩綍: {exe_dir}")
+    
+    return exe_dir, config_file
+
+
+if __name__ == "__main__":
+    setup_environment()
+    
+    # 瀵煎叆骞跺惎鍔ㄤ富搴旂敤
+    try:
+        from main import app
+        import uvicorn
+        from config import settings
+        from loguru import logger
+        
+        # 閰嶇疆鏃ュ織
+        logger.add(
+            settings.log_file,
+            rotation="1 day",
+            retention="7 days",
+            level=settings.log_level,
+            format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}",
+        )
+        
+        logger.info("鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟")
+        
+        # 鍚姩鏈嶅姟
+        uvicorn.run(
+            app,
+            host=settings.server_host,
+            port=settings.server_port,
+            log_level=settings.log_level.lower(),
+        )
+        
+    except Exception as e:
+        print(f"鍚姩澶辫触: {e}")
+        input("鎸変换鎰忛敭閫�鍑�...")
+        sys.exit(1)
diff --git a/uninstall_service.bat b/uninstall_service.bat
new file mode 100644
index 0000000..c361981
--- /dev/null
+++ b/uninstall_service.bat
@@ -0,0 +1,61 @@
+@echo off
+chcp 65001 >nul
+echo ========================================
+echo E浜戠瀹�-DifyAI瀵规帴鏈嶅姟 Windows鏈嶅姟鍗歌浇鑴氭湰
+echo ========================================
+echo.
+
+:: 妫�鏌ョ鐞嗗憳鏉冮檺
+net session >nul 2>&1
+if %errorLevel% == 0 (
+    echo 妫�娴嬪埌绠$悊鍛樻潈闄愶紝缁х画鍗歌浇...
+) else (
+    echo 閿欒锛氶渶瑕佺鐞嗗憳鏉冮檺鎵嶈兘鍗歌浇Windows鏈嶅姟
+    echo 璇峰彸閿偣鍑绘鑴氭湰锛岄�夋嫨"浠ョ鐞嗗憳韬唤杩愯"
+    pause
+    exit /b 1
+)
+
+set "SERVICE_NAME=ECloudDifyService"
+
+echo 鏈嶅姟鍚嶇О: %SERVICE_NAME%
+echo.
+
+:: 妫�鏌ユ湇鍔℃槸鍚﹀瓨鍦�
+echo 妫�鏌ユ湇鍔℃槸鍚﹀瓨鍦�...
+sc query "%SERVICE_NAME%" >nul 2>&1
+if %errorLevel% == 0 (
+    echo 鎵惧埌鏈嶅姟锛屾鍦ㄥ嵏杞�...
+    
+    :: 鍋滄鏈嶅姟
+    echo 姝e湪鍋滄鏈嶅姟...
+    sc stop "%SERVICE_NAME%" >nul 2>&1
+    if %errorLevel% == 0 (
+        echo 鏈嶅姟宸插仠姝�
+    ) else (
+        echo 鏈嶅姟鍙兘宸茬粡鍋滄鎴栧仠姝㈠け璐�
+    )
+    
+    :: 绛夊緟鏈嶅姟瀹屽叏鍋滄
+    echo 绛夊緟鏈嶅姟瀹屽叏鍋滄...
+    timeout /t 5 /nobreak >nul
+    
+    :: 鍒犻櫎鏈嶅姟
+    echo 姝e湪鍒犻櫎鏈嶅姟...
+    sc delete "%SERVICE_NAME%"
+    if %errorLevel% == 0 (
+        echo 鏈嶅姟鍒犻櫎鎴愬姛锛�
+    ) else (
+        echo 閿欒锛氭湇鍔″垹闄ゅけ璐�
+        pause
+        exit /b 1
+    )
+) else (
+    echo 鏈壘鍒版湇鍔� %SERVICE_NAME%
+    echo 鍙兘鏈嶅姟宸茬粡琚垹闄ゆ垨浠庢湭瀹夎
+)
+
+echo.
+echo 鏈嶅姟鍗歌浇瀹屾垚锛�
+echo.
+pause

--
Gitblit v1.9.1