c6206787da
项目结构: - backend/ Python FastAPI 后端 - uni-app/ uni-app跨端前端 - docs/ 设计文档 - docker-compose.yml Docker编排 - nginx/scripts/systemd 运维配置 已完成功能: - 用户认证 (JWT) - 智能翻译 + 回复建议 - 营销素材生成 - 客户管理 + 沉默检测 - 报价单管理 - 产品库管理 - 汇率换算 - 推送通知 (uni-push) - WhatsApp Webhook框架 - Celery定时任务
56 lines
2.7 KiB
Python
56 lines
2.7 KiB
Python
from typing import Dict, Any, Optional
|
|
import json, httpx
|
|
from app.ai.base import AIProvider
|
|
|
|
|
|
class LocalProvider(AIProvider):
|
|
def __init__(self, model_url: str = "http://localhost:8001", model_name: str = "gemma-3-8b"):
|
|
self.model_url = model_url.rstrip("/")
|
|
self.model_name = model_name
|
|
self._name = f"local-{model_name}"
|
|
|
|
async def translate(self, text: str, source_lang: Optional[str], target_lang: str, context: Optional[str] = None) -> Dict[str, Any]:
|
|
prompt = f"Translate{ f' from {source_lang}' if source_lang else ''} to {target_lang}:\n{text}\n\nTranslation:"
|
|
result = await self._generate(prompt)
|
|
return {"translated_text": result, "provider": self.name, "cost": 0.0}
|
|
|
|
async def reply(self, inquiry: str, context: Optional[Dict[str, Any]] = None, tone: str = "professional") -> Dict[str, Any]:
|
|
ctx = ""
|
|
if context:
|
|
ctx = "\n".join(f"{k}: {v}" for k, v in context.items() if v)
|
|
prompt = f"{ctx}\nCustomer: {inquiry}\n\nWrite a {tone} reply:"
|
|
result = await self._generate(prompt)
|
|
return {"reply": result, "provider": self.name, "cost": 0.0}
|
|
|
|
async def generate_marketing(self, product_info: Dict[str, Any], target: str, style: str = "professional", language: str = "en") -> Dict[str, Any]:
|
|
info = json.dumps(product_info, ensure_ascii=False)
|
|
prompt = f"Product: {info}\nTarget: {target}\nStyle: {style}\nLanguage: {language}\n\nMarketing copy:"
|
|
result = await self._generate(prompt, max_tokens=800)
|
|
return {"content": result, "provider": self.name, "cost": 0.0}
|
|
|
|
async def extract_info(self, text: str, schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
prompt = f"Extract JSON from text matching schema:\nSchema: {json.dumps(schema)}\n\nText: {text}\n\nJSON:"
|
|
result = await self._generate(prompt, max_tokens=500)
|
|
try:
|
|
return {"data": json.loads(result), "confidence": 0.7, "provider": self.name, "cost": 0.0}
|
|
except json.JSONDecodeError:
|
|
return {"data": {}, "confidence": 0.0, "provider": self.name, "cost": 0.0, "error": "parse_failed"}
|
|
|
|
async def _generate(self, prompt: str, max_tokens: int = 500) -> str:
|
|
async with httpx.AsyncClient() as client:
|
|
resp = await client.post(
|
|
f"{self.model_url}/v1/completions",
|
|
json={"model": self.model_name, "prompt": prompt, "max_tokens": max_tokens, "temperature": 0.7, "stream": False},
|
|
timeout=60,
|
|
)
|
|
resp.raise_for_status()
|
|
return resp.json()["choices"][0]["text"].strip()
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return self._name
|
|
|
|
@property
|
|
def cost_per_1k_tokens(self) -> float:
|
|
return 0.0
|