Files
aiagent/backend/app/services/suyao_app_service.py
renjianbo beff3fac8d fix: delete agent 500 error + dynamic personality + deployment guide
- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions,
  schedules, executions, team_members) and unbind goals/tasks before delete
- Remove hardcoded personality templates in Android, replace with dynamic
  system prompt generation from name + description
- Set promptSectionsEnabled=false to bypass PromptComposer for personality
- Add Tencent Cloud Linux deployment guide (Docker Compose)
- Accumulated backend service updates, frontend UI fixes, Android app changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-29 01:17:21 +08:00

121 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""苏瑶飞书应用 API 服务 — 通过苏瑶应用发送消息到用户"""
from __future__ import annotations
import json
import logging
import time
from typing import Optional
import httpx
from app.core.config import settings
logger = logging.getLogger(__name__)
# Token 缓存tenant_access_token 有效期 2 小时,提前 5 分钟刷新)
_token_cache: dict = {"token": None, "expires_at": 0}
def _get_tenant_access_token() -> Optional[str]:
"""获取苏瑶应用的 tenant_access_token带缓存"""
now = time.time()
if _token_cache["token"] and now < _token_cache["expires_at"] - 300:
return _token_cache["token"]
app_id = settings.SUYAO_APP_ID
app_secret = settings.SUYAO_APP_SECRET
if not app_id or not app_secret:
logger.warning("苏瑶应用未配置SUYAO_APP_ID / SUYAO_APP_SECRET")
return None
try:
with httpx.Client(timeout=10) as client:
resp = client.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": app_id, "app_secret": app_secret},
)
result = resp.json()
if resp.is_success and result.get("code") == 0:
token = result["tenant_access_token"]
expire = result.get("expire", 7200)
_token_cache["token"] = token
_token_cache["expires_at"] = now + expire
logger.info("苏瑶 tenant_access_token 获取成功")
return token
else:
logger.warning("苏瑶 token 获取失败: %s", result)
return None
except Exception as e:
logger.warning("苏瑶 token 获取异常: %s", e)
return None
def send_message_to_user(
open_id: str,
title: str,
content: str,
status: str = "info",
detail_link: Optional[str] = None,
execution_log_id: Optional[str] = None,
agent_name: Optional[str] = None,
) -> bool:
"""通过苏瑶应用向用户发送消息卡片。"""
from app.services.feishu_card_builder import build_reply_card
token = _get_tenant_access_token()
if not token:
return False
card = build_reply_card(
title=title, content=content,
execution_log_id=execution_log_id, agent_name=agent_name,
status=status, detail_link=detail_link,
include_feedback=bool(execution_log_id),
)
try:
with httpx.Client(timeout=10) as client:
resp = client.post(
"https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
headers={"Authorization": f"Bearer {token}"},
json={
"receive_id": open_id,
"msg_type": "interactive",
"content": json.dumps(card, ensure_ascii=False),
},
)
result = resp.json()
if resp.is_success and result.get("code") == 0:
logger.info("苏瑶消息发送成功: open_id=%s title=%s", open_id[:20], title)
return True
else:
logger.warning("苏瑶消息发送失败: code=%s msg=%s", result.get("code"), result.get("msg"))
return False
except Exception as e:
logger.warning("苏瑶消息发送异常: %s", e)
return False
def send_plain_text(open_id: str, text: str) -> bool:
"""通过苏瑶应用向用户发送纯文本消息。"""
token = _get_tenant_access_token()
if not token:
return False
try:
with httpx.Client(timeout=10) as client:
resp = client.post(
"https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
headers={"Authorization": f"Bearer {token}"},
json={
"receive_id": open_id,
"msg_type": "text",
"content": json.dumps({"text": text}, ensure_ascii=False),
},
)
result = resp.json()
return resp.is_success and result.get("code") == 0
except Exception as e:
logger.warning("苏瑶文本消息发送异常: %s", e)
return False