fix(wechat/token/market): 修复微信对话时间、Token数据重置、技能市场复活、媒体内联
1. 微信Bot对话记录时间按北京时间渲染(ImBotHub/WechatHistory 的 formatTime 显式 +08:00 + Asia/Shanghai); 2. 新增 /app/api/chat/media/relay 媒体中转端点(白名单 agnES 域名, 经香港代理代取), 改写 _wechat_send_media 用平台中转地址,微信/iLink 可内联播放图片/视频; 3. 删除 014_clean_test_data.sql:该迁移每次重启重跑并 DELETE token_usage_logs/ messages/conversations/knowledge 等,导致 Token 驾驶舱数据每次重启被清空; 4. 002_init_data.sql 移除 market_apps 自动播种(原 WHERE COUNT=0 在用户删空后重启复活), 技能市场交由用户后台维护,重启不再复活。
This commit is contained in:
1 parent
da89a27bca
commit
82afe14a23
6 files changed
+85
-108
No files matched your search
@@ -3,7 +3,7 @@
|
||||
包含: Skill ID统一(MarketApp映射), 真实Skill执行, Agent工作流注入,
|
||||
多轮上下文保持, BM25 KB检索, Function Calling循环增强
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Response
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import and_, desc, asc, func
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -173,6 +173,40 @@ def _proxy_for_url(url: str) -> str | None:
|
||||
return _outbound_proxy()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 媒体中转(relay)端点:让微信/iLink 能内联渲染 AGNES 生成的图片/视频
|
||||
# 背景:AGNES 媒体 URL 位于境外(agnes-ai.com / agnes-ai.space),
|
||||
# iLink 服务器(中国大陆)直连常被墙/超时,导致微信里只看到"链接"无法内联播放。
|
||||
# 此端点由平台服务器(经香港代理可达 AGNES)代取媒体并以平台域名回传,
|
||||
# 微信即可内联显示。仅允许白名单域名,杜绝 SSRF。
|
||||
# ============================================================
|
||||
_MEDIA_RELAY_ALLOWED = ("agnes-ai.com", "agnes-ai.space", "qihuyun.com")
|
||||
|
||||
|
||||
@router.get("/media/relay")
|
||||
async def media_relay(url: str = Query(...)):
|
||||
"""中转 AGNES 媒体(图片/视频)到平台域名,供微信/iLink 内联渲染。
|
||||
|
||||
仅允许白名单域名;否则 400。返回的媒体流保持原 content-type。
|
||||
"""
|
||||
import urllib.parse as _up
|
||||
host = (_up.urlparse(url).hostname or "").lower()
|
||||
if not any(allowed in host for allowed in _MEDIA_RELAY_ALLOWED):
|
||||
raise HTTPException(status_code=400, detail="unsupported media host")
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=180, proxy=_proxy_for_url(url), trust_env=False) as client:
|
||||
r = await client.get(url)
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=r.status_code, detail="upstream error")
|
||||
content_type = r.headers.get("content-type", "application/octet-stream")
|
||||
data = await r.aread()
|
||||
return Response(content=data, media_type=content_type)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=502, detail=f"relay failed: {e}")
|
||||
|
||||
|
||||
async def _optimize_media_prompt(raw_prompt: str, media_type: str, db=None) -> str:
|
||||
"""使用平台文本模型对用户原始输入做「媒体提示词增强优化」。
|
||||
|
||||
|
||||
@@ -14,11 +14,13 @@ im_bot_user.py
|
||||
"""
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
from urllib.parse import quote as _quote
|
||||
|
||||
import requests
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
@@ -225,21 +227,31 @@ def _wechat_send_message(baseurl: str, bot_token: str, to_user_id: str, context_
|
||||
[{"type": 1, "text_item": {"text": text}}])
|
||||
|
||||
|
||||
def _platform_relay_url(raw_url: str) -> str:
|
||||
"""把 AGNES 等境外媒体 URL 改写为平台中转地址,使微信/iLink 可内联渲染。
|
||||
|
||||
iLink 服务器(中国大陆)直连境外 AGNES 常被墙/超时,微信里只能看到"链接"。
|
||||
改写为平台中转地址(平台服务器经香港代理可达 AGNES),微信即可内联显示图片/视频。
|
||||
"""
|
||||
access = os.environ.get("APP_ACCESS_URL", "http://210.16.161.218:12888").rstrip("/")
|
||||
return f"{access}/app/api/chat/media/relay?url={_quote(raw_url, safe='')}"
|
||||
|
||||
|
||||
def _wechat_send_media(baseurl: str, bot_token: str, to_user_id: str, context_token: str,
|
||||
media_type: str, url: str):
|
||||
"""发送媒体(图片/视频)并附带文本链接兜底,确保用户可在微信内直接查看。
|
||||
"""发送媒体(图片/视频)并在微信内联渲染。
|
||||
|
||||
iLink 消息 item_list:
|
||||
- type=2 图片:image_item: {url}
|
||||
- type=5 视频:video_item: {url}
|
||||
同时附带一条文本项(含直链),防止微信/iLink 不渲染外链时用户仍能复制查看。
|
||||
问题:AGNES 媒体 URL 位于境外,iLink(中国大陆服务器)直连常被墙/超时,
|
||||
微信里只能看到"链接"而无法内联播放。
|
||||
解决:改写为平台中转地址(经香港代理可达 AGNES),微信即可内联显示图片/视频。
|
||||
"""
|
||||
relay_url = _platform_relay_url(url)
|
||||
if media_type == "image":
|
||||
media_item = {"type": 2, "image_item": {"url": url}}
|
||||
caption = "🖼️ 图片已生成(若未直接显示,请点链接查看):" + url
|
||||
media_item = {"type": 2, "image_item": {"url": relay_url}}
|
||||
caption = "🖼️ 图片已生成(若未直接显示,请点此查看):" + relay_url
|
||||
else:
|
||||
media_item = {"type": 5, "video_item": {"url": url}}
|
||||
caption = "🎬 视频已生成(若未直接播放,请点链接查看):" + url
|
||||
media_item = {"type": 5, "video_item": {"url": relay_url}}
|
||||
caption = "🎬 视频已生成(若未直接播放,请点此查看):" + relay_url
|
||||
return _wechat_post_msg(baseurl, bot_token, to_user_id, context_token,
|
||||
[media_item, {"type": 1, "text_item": {"text": caption}}])
|
||||
|
||||
@@ -420,11 +432,12 @@ def _wechat_receiver_loop(account_id: int):
|
||||
media_type = reply.get("media_type") or "image"
|
||||
media_url = reply.get("url") or ""
|
||||
ok, ret, _ = _wechat_send_media(baseurl, bot_token, sender, ctx, media_type, media_url)
|
||||
# 对话历史里存可渲染的媒体标签(AI 聊天 WeXin Bot 窗与历史页均可显示)
|
||||
# 对话历史里存可渲染的媒体标签(经平台中转,AI 聊天 WeXin Bot 窗与历史页均可内联显示)
|
||||
relay_url = _platform_relay_url(media_url)
|
||||
reply_for_log = (
|
||||
f'<img src="{media_url}" alt="生成图片"/>'
|
||||
f'<img src="{relay_url}" alt="生成图片"/>'
|
||||
if media_type == "image"
|
||||
else f'<video src="{media_url}" controls></video>'
|
||||
else f'<video src="{relay_url}" controls></video>'
|
||||
)
|
||||
else:
|
||||
reply_text = reply if isinstance(reply, str) else str(reply)
|
||||
|
||||
Reference in new issue
Block a user