feat: AI assistant phase 2 - configurable prompt, action operations, FAQ matching, NVIDIA provider

- Admin-configurable AI prompt/quick questions from system_configs DB
- GET /api/v1/ai/quick-questions endpoint for fetching quick questions
- Local FAQ matching for instant responses (avoid AI calls for common Qs)
- AI action extraction: "add customer" intent detected, structured data returned
- Frontend action confirmation card with editable fields, calls customer API on confirm
- NVIDIA provider (stepfun-ai/step-3.5-flash) for faster chat vs deepseek-v4-flash
- Fixed httpx client timeout preventing backend hangs
- Added log_usage calls for auth events (register/login/guest/wechat)
- Admin tabs (users/stats/logs/config) fully functional with real backend
- AiAssistant component added to all tabbar pages
This commit is contained in:
TradeMate Dev
2026-05-20 09:39:22 +08:00
parent 4755cc75ba
commit f8a23855d2
20 changed files with 744 additions and 5 deletions
+15 -1
View File
@@ -1,6 +1,6 @@
from typing import Dict, Any, Optional, List
from app.ai.base import AIProvider
from app.ai.providers import OpenAIProvider, ClaudeProvider, DeepLProvider, LocalProvider, SparkProvider, SensenovaProvider, OpencodeGoProvider
from app.ai.providers import OpenAIProvider, ClaudeProvider, DeepLProvider, LocalProvider, SparkProvider, SensenovaProvider, OpencodeGoProvider, NvidiaProvider
from app.config import settings
from app.ai.trade_corpus import TradeCorpus
import logging
@@ -45,6 +45,17 @@ class AIRouter:
except Exception as e:
logger.warning(f"OpencodeGo init failed: {e}")
if settings.NVIDIA_API_KEY:
try:
self.providers["nvidia"] = NvidiaProvider(
api_key=settings.NVIDIA_API_KEY,
model=settings.NVIDIA_MODEL,
base_url=settings.NVIDIA_BASE_URL,
)
logger.info("Nvidia provider ready")
except Exception as e:
logger.warning(f"Nvidia init failed: {e}")
if settings.ANTHROPIC_API_KEY:
try:
self.providers["anthropic"] = ClaudeProvider(api_key=settings.ANTHROPIC_API_KEY)
@@ -132,6 +143,9 @@ class AIRouter:
async def extract(self, text: str, schema: Dict[str, Any]) -> Dict[str, Any]:
return await self.execute("extract", "extract_info", text, schema)
async def chat(self, message: str, history: list = None, system_prompt: str = None) -> Dict[str, Any]:
return await self.execute("chat", "chat", message, history, system_prompt)
_router_instance = None