feat: AI routing DB-driven, payment gateway full integration, WeChat mini-program CI/CD
- AI routing rules now stored in system_configs DB table instead of hardcoded config - Multi-model support via name|model composite key for same-provider routing - UnifiedPayService with HMAC-SHA256 gateway integration (alipay/wechat) - Admin payment panel: list, stats, search, filter, refund - WeChat mini-program CI/CD via miniprogram-ci (v1.0.9) - Translation quota extended to LLM provider tier - SearchService with DB-driven provider config (bing/google_cse/searxng) - Footer cleanup across admin/workspace/uni-app - Private key excluded from git tracking
This commit is contained in:
@@ -41,6 +41,13 @@ class SearchService:
|
||||
return await searxng_search(provider.api_endpoint, query, limit)
|
||||
elif pt == "bing":
|
||||
return await bing_search(provider.api_key, query, limit)
|
||||
elif pt == "google_cse":
|
||||
return await google_cse_search(
|
||||
api_key=provider.api_key,
|
||||
cx=provider.extra_config.get("cx", "") if provider.extra_config else "",
|
||||
query=query,
|
||||
limit=limit,
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unknown provider type: {pt}")
|
||||
|
||||
@@ -100,3 +107,30 @@ async def bing_search(api_key: Optional[str], query: str, limit: int) -> List[Di
|
||||
break
|
||||
return results
|
||||
|
||||
|
||||
async def google_cse_search(api_key: Optional[str], cx: Optional[str], query: str, limit: int) -> List[Dict[str, str]]:
|
||||
if not api_key or not cx:
|
||||
raise ValueError("Google CSE API key or CX not configured")
|
||||
import httpx
|
||||
async with httpx.AsyncClient(timeout=15.0) as client:
|
||||
resp = await client.get(
|
||||
"https://www.googleapis.com/customsearch/v1",
|
||||
params={"key": api_key, "cx": cx, "q": query, "num": min(limit, 10), "lr": "lang_en"},
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
raise ValueError(f"Google CSE returned {resp.status_code}")
|
||||
data = resp.json()
|
||||
results = []
|
||||
for item in data.get("items", []):
|
||||
url = item.get("link", "")
|
||||
if any(d in url for d in IGNORE_DOMAINS):
|
||||
continue
|
||||
results.append({
|
||||
"title": (item.get("title") or url)[:100],
|
||||
"url": url.rstrip("/"),
|
||||
"snippet": (item.get("snippet") or "")[:200],
|
||||
})
|
||||
if len(results) >= limit:
|
||||
break
|
||||
return results
|
||||
|
||||
|
||||
Reference in New Issue
Block a user