diff --git a/saars/android-app/app/src/main/java/com/saars/chatplatform/presentation/agent/AgentChatActivity.java b/saars/android-app/app/src/main/java/com/saars/chatplatform/presentation/agent/AgentChatActivity.java index d485970..8879614 100644 --- a/saars/android-app/app/src/main/java/com/saars/chatplatform/presentation/agent/AgentChatActivity.java +++ b/saars/android-app/app/src/main/java/com/saars/chatplatform/presentation/agent/AgentChatActivity.java @@ -4,6 +4,8 @@ import android.os.Bundle; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; + +import org.json.JSONObject; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -97,18 +99,41 @@ public class AgentChatActivity extends AppCompatActivity { appendBotMessage(reply); scrollToBottom(); } else { - Toast.makeText(AgentChatActivity.this, "请求失败: " + response.message(), Toast.LENGTH_SHORT).show(); + String errMsg = getErrorMessage(response); + Toast.makeText(AgentChatActivity.this, errMsg, Toast.LENGTH_LONG).show(); } } @Override public void onFailure(Call call, Throwable t) { binding.btnSend.setEnabled(true); - Toast.makeText(AgentChatActivity.this, "请求失败: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + String msg = t.getMessage(); + if (msg == null || msg.isEmpty()) msg = "网络异常"; + Toast.makeText(AgentChatActivity.this, "知你客服暂不可用: " + msg, Toast.LENGTH_LONG).show(); } }); } + /** 从 502/503 等错误响应中解析后端返回的 error 文案 */ + private String getErrorMessage(Response response) { + try { + if (response.errorBody() != null) { + String body = response.errorBody().string(); + if (!body.isEmpty()) { + JSONObject jo = new JSONObject(body); + if (jo.has("error")) { + return jo.optString("error", "知你客服暂不可用,请稍后重试"); + } + } + } + } catch (Exception ignored) { } + int code = response.code(); + if (code == 502 || code == 503) { + return "知你客服暂不可用,请稍后重试"; + } + return "请求失败: " + response.message(); + } + private void appendUserMessage(String content) { ApiService.Message m = new ApiService.Message(); m.id = "local_u_" + System.currentTimeMillis(); diff --git a/saars/backend/app/api/agent_proxy.py b/saars/backend/app/api/agent_proxy.py index d970712..00c837d 100644 --- a/saars/backend/app/api/agent_proxy.py +++ b/saars/backend/app/api/agent_proxy.py @@ -30,5 +30,16 @@ def agent_chat(): try: reply = chat_with_agent(base_url, username, password, agent_id, message, user_id) return jsonify({"reply": reply or ""}) + except ValueError as e: + err = str(e) + if "401" in err or "登录失败" in err: + return jsonify({"error": err}), 503 + return jsonify({"error": err}), 502 except Exception as e: - return jsonify({"error": str(e)}), 502 + err = str(e) + # 任何包含 401/Unauthorized 的异常都视为平台认证失败,返回友好提示 + if "401" in err or "Unauthorized" in err: + return jsonify({ + "error": "知你客服平台登录失败(401),请确认 8037 服务已启动且 PLATFORM_USERNAME/PLATFORM_PASSWORD 正确" + }), 503 + return jsonify({"error": err}), 502 diff --git a/saars/backend/app/config.py b/saars/backend/app/config.py index 8677449..3d350d3 100644 --- a/saars/backend/app/config.py +++ b/saars/backend/app/config.py @@ -17,9 +17,9 @@ class Config: """Base config.""" SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-change-in-production") SQLALCHEMY_TRACK_MODIFICATIONS = False - # 知你客服 Agent 代理(方式一):低代码平台地址与对接账号(用户名 amind,密码 123456) + # 知你客服 Agent 代理:与 androidExampleDemo 一致,8037 使用 admin/123456 PLATFORM_BASE_URL = os.getenv("PLATFORM_BASE_URL", "http://101.43.95.130:8037") - PLATFORM_USERNAME = os.getenv("PLATFORM_USERNAME", "amind") + PLATFORM_USERNAME = os.getenv("PLATFORM_USERNAME", "admin") PLATFORM_PASSWORD = os.getenv("PLATFORM_PASSWORD", "123456") PLATFORM_AGENT_ID = os.getenv("PLATFORM_AGENT_ID", "7332bba7-f9e7-4e10-9af6-7a0509a3ef97") JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1) diff --git a/saars/backend/app/services/agent_proxy.py b/saars/backend/app/services/agent_proxy.py index 41e0195..84da686 100644 --- a/saars/backend/app/services/agent_proxy.py +++ b/saars/backend/app/services/agent_proxy.py @@ -21,12 +21,26 @@ def _get_platform_token(base_url, username, password): return _platform_token url = f"{base_url.rstrip('/')}/api/v1/auth/login" try: + # 8037 使用 form 登录;先 form,失败再试 JSON r = requests.post( url, data={"username": username, "password": password}, headers={"Content-Type": "application/x-www-form-urlencoded"}, timeout=10, ) + if r.status_code == 422: + logger.warning("平台登录 form 返回 422,尝试 JSON: %s", r.text[:200] if r.text else "") + r = requests.post( + url, + json={"username": username, "password": password}, + headers={"Content-Type": "application/json"}, + timeout=10, + ) + if r.status_code == 401: + logger.warning("平台登录仍 401,请检查 PLATFORM_USERNAME/PLATFORM_PASSWORD 及平台账号: %s", r.text[:200] if r.text else "") + raise ValueError( + "知你客服平台登录失败(401),请确认 8037 服务已启动且 PLATFORM_USERNAME/PLATFORM_PASSWORD 正确" + ) r.raise_for_status() data = r.json() token = data.get("access_token") @@ -35,6 +49,15 @@ def _get_platform_token(base_url, username, password): _platform_token = token _token_expires_at = time.time() + 3600 # 假设 1 小时有效 return token + except requests.exceptions.HTTPError as e: + if e.response is not None and e.response.status_code == 401: + raise ValueError( + "知你客服平台登录失败(401),请确认 8037 服务已启动且账号配置正确" + ) + logger.exception("平台登录失败: %s", e) + raise + except ValueError: + raise except Exception as e: logger.exception("平台登录失败: %s", e) raise diff --git a/saars/backend/scripts/check_platform_login.sh b/saars/backend/scripts/check_platform_login.sh new file mode 100644 index 0000000..4c602ca --- /dev/null +++ b/saars/backend/scripts/check_platform_login.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# 检查 8037 平台是否可访问,以及登录接口是否可用 +# 用法: bash scripts/check_platform_login.sh +# 或指定账号: PLATFORM_USERNAME=你的账号 PLATFORM_PASSWORD=你的密码 bash scripts/check_platform_login.sh + +BASE_URL="${PLATFORM_BASE_URL:-http://101.43.95.130:8037}" +USER="${PLATFORM_USERNAME:-admin}" +PASS="${PLATFORM_PASSWORD:-123456}" + +echo "=== 1. 检查 8037 是否可访问 ===" +echo "GET $BASE_URL" +if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$BASE_URL" | grep -qE '^[23]'; then + echo " 可访问" +else + echo " 无法访问或超时,请检查 8037 服务是否启动、防火墙/安全组是否放行" + exit 1 +fi + +echo "" +echo "=== 2. 尝试登录(先 form,再 JSON) ===" + +# 先试 form(8037 可能只接受 form) +echo "2a. POST form: username=$USER, password=***" +RESP=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/v1/auth/login" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "username=$USER&password=$PASS" \ + --connect-timeout 10) +HTTP_BODY=$(echo "$RESP" | head -n -1) +HTTP_CODE=$(echo "$RESP" | tail -n 1) + +if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "201" ]; then + echo " form 状态: $HTTP_CODE, 响应: $HTTP_BODY" + echo "2b. POST JSON: {\"username\":\"$USER\",\"password\":\"***\"}" + RESP=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"$USER\",\"password\":\"$PASS\"}" \ + --connect-timeout 10) + HTTP_BODY=$(echo "$RESP" | head -n -1) + HTTP_CODE=$(echo "$RESP" | tail -n 1) +fi + +if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then + echo " 状态: $HTTP_CODE 成功" + if echo "$HTTP_BODY" | grep -q "access_token"; then + echo " 响应含 access_token,登录正常" + else + echo " 响应无 access_token,内容: $HTTP_BODY" + fi +elif [ "$HTTP_CODE" = "401" ]; then + echo " 状态: 401 未授权" + echo " 响应: $HTTP_BODY" + echo " -> 请确认 8037 上账号 $USER 的密码是否正确" + exit 1 +elif [ "$HTTP_CODE" = "422" ]; then + echo " 状态: 422 参数错误" + echo " 响应: $HTTP_BODY" + echo " -> 8037 可能要求 form 或不同字段名,已尝试 form 与 JSON" + exit 1 +else + echo " 状态: $HTTP_CODE" + echo " 响应: $HTTP_BODY" + exit 1 +fi + +echo "" +echo "=== 3. 若上面都成功,SAARS 后端应能正常代理知你客服 ===" +echo " 重启后端: cd saars && docker compose restart backend" diff --git a/saars/docker-compose.yml b/saars/docker-compose.yml index c36e85c..e5c4373 100644 --- a/saars/docker-compose.yml +++ b/saars/docker-compose.yml @@ -10,9 +10,9 @@ services: PORT: "8052" DATABASE_URL: mysql+pymysql://root:!Rjb12191@gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com:24936/liaotian_db?charset=utf8mb4 REDIS_URL: redis://redis:6379/0 - # 知你客服 Agent 代理(方式一):平台账号 amind/123456;Agent ID 需在平台 Agent 管理中点「知你客服」复制 + # 知你客服 Agent 代理(与 androidExampleDemo 一致:admin/123456,8037 form 登录) PLATFORM_BASE_URL: http://101.43.95.130:8037 - PLATFORM_USERNAME: amind + PLATFORM_USERNAME: admin PLATFORM_PASSWORD: "123456" PLATFORM_AGENT_ID: "7332bba7-f9e7-4e10-9af6-7a0509a3ef97" depends_on: