875 lines
29 KiB
PHP
875 lines
29 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Http\Requests\AIChatRequest;
|
||
use App\Http\Requests\AITaskRequest;
|
||
use App\Models\AIConversation;
|
||
use App\Models\AIMessage;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
class AIAssistantController extends Controller
|
||
{
|
||
/**
|
||
* AI服务
|
||
*/
|
||
protected $aiService;
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public function __construct()
|
||
{
|
||
$this->aiService = new \App\Services\AIService();
|
||
}
|
||
|
||
/**
|
||
* AI对话
|
||
*/
|
||
public function chat(AIChatRequest $request)
|
||
{
|
||
try {
|
||
$message = $request->input('message');
|
||
$conversationId = $request->input('conversation_id');
|
||
$context = $request->input('context', []);
|
||
|
||
// 获取或创建对话
|
||
if ($conversationId) {
|
||
$conversation = AIConversation::where('id', $conversationId)
|
||
->where('user_id', auth()->id())
|
||
->firstOrFail();
|
||
} else {
|
||
$conversation = AIConversation::create([
|
||
'user_id' => auth()->id(),
|
||
'title' => substr($message, 0, 50) . '...',
|
||
'model' => $this->config['model'],
|
||
'status' => 'active',
|
||
]);
|
||
}
|
||
|
||
// 添加上下文到消息
|
||
$messages = $this->buildMessages($message, $context, $conversation);
|
||
|
||
// 调用AI API
|
||
$response = $this->callAIAPI($messages);
|
||
|
||
if (!$response['success']) {
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => 'AI服务暂时不可用: ' . $response['error']
|
||
], 500);
|
||
}
|
||
|
||
$aiResponse = $response['data'];
|
||
|
||
// 保存消息记录
|
||
$userMessage = AIMessage::create([
|
||
'conversation_id' => $conversation->id,
|
||
'role' => 'user',
|
||
'content' => $message,
|
||
'tokens' => $this->estimateTokens($message),
|
||
]);
|
||
|
||
$aiMessage = AIMessage::create([
|
||
'conversation_id' => $conversation->id,
|
||
'role' => 'assistant',
|
||
'content' => $aiResponse,
|
||
'tokens' => $this->estimateTokens($aiResponse),
|
||
]);
|
||
|
||
// 更新对话统计
|
||
$conversation->increment('message_count', 2);
|
||
$conversation->increment('total_tokens', $userMessage->tokens + $aiMessage->tokens);
|
||
$conversation->last_message_at = now();
|
||
$conversation->save();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'conversation_id' => $conversation->id,
|
||
'response' => $aiResponse,
|
||
'message_id' => $aiMessage->id,
|
||
'tokens_used' => $userMessage->tokens + $aiMessage->tokens,
|
||
],
|
||
'message' => 'success'
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('AI对话失败: ' . $e->getMessage());
|
||
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => 'AI对话失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 构建消息数组
|
||
*/
|
||
private function buildMessages(string $message, array $context, AIConversation $conversation): array
|
||
{
|
||
$messages = [];
|
||
|
||
// 系统提示词
|
||
$systemPrompt = $this->getSystemPrompt($context);
|
||
$messages[] = ['role' => 'system', 'content' => $systemPrompt];
|
||
|
||
// 添加上下文消息
|
||
if (!empty($context)) {
|
||
foreach ($context as $ctx) {
|
||
if (isset($ctx['role']) && isset($ctx['content'])) {
|
||
$messages[] = ['role' => $ctx['role'], 'content' => $ctx['content']];
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加历史消息(最近10条)
|
||
$historyMessages = AIMessage::where('conversation_id', $conversation->id)
|
||
->orderBy('created_at', 'desc')
|
||
->limit(10)
|
||
->get()
|
||
->reverse();
|
||
|
||
foreach ($historyMessages as $history) {
|
||
$messages[] = ['role' => $history->role, 'content' => $history->content];
|
||
}
|
||
|
||
// 添加当前消息
|
||
$messages[] = ['role' => 'user', 'content' => $message];
|
||
|
||
return $messages;
|
||
}
|
||
|
||
/**
|
||
* 获取系统提示词
|
||
*/
|
||
private function getSystemPrompt(array $context): string
|
||
{
|
||
$basePrompt = "你是一个专业的ERP系统AI助手,专门帮助用户处理企业资源管理相关的问题。";
|
||
|
||
// 根据上下文添加特定提示
|
||
if (isset($context['module'])) {
|
||
switch ($context['module']) {
|
||
case 'goods':
|
||
$basePrompt .= "你现在正在处理商品管理模块的问题。";
|
||
break;
|
||
case 'orders':
|
||
$basePrompt .= "你现在正在处理订单管理模块的问题。";
|
||
break;
|
||
case 'purchase':
|
||
$basePrompt .= "你现在正在处理采购管理模块的问题。";
|
||
break;
|
||
case 'inventory':
|
||
$basePrompt .= "你现在正在处理库存管理模块的问题。";
|
||
break;
|
||
case 'finance':
|
||
$basePrompt .= "你现在正在处理财务管理模块的问题。";
|
||
break;
|
||
}
|
||
}
|
||
|
||
$basePrompt .= "\n\n请用专业、准确、简洁的语言回答用户的问题。如果涉及具体操作,请提供清晰的步骤说明。";
|
||
|
||
return $basePrompt;
|
||
}
|
||
|
||
/**
|
||
* 调用AI API
|
||
*/
|
||
private function callAIAPI(array $messages): array
|
||
{
|
||
try {
|
||
// 这里使用模拟响应,实际项目中需要配置真实的API密钥
|
||
$apiKey = config('services.ai.api_key', '');
|
||
|
||
if (empty($apiKey)) {
|
||
// 模拟AI响应(开发环境)
|
||
return $this->mockAIResponse($messages);
|
||
}
|
||
|
||
$response = Http::withHeaders([
|
||
'Authorization' => 'Bearer ' . $apiKey,
|
||
'Content-Type' => 'application/json',
|
||
])->timeout(30)->post($this->config['api_url'], [
|
||
'model' => $this->config['model'],
|
||
'messages' => $messages,
|
||
'max_tokens' => $this->config['max_tokens'],
|
||
'temperature' => $this->config['temperature'],
|
||
]);
|
||
|
||
if ($response->successful()) {
|
||
$data = $response->json();
|
||
$content = $data['choices'][0]['message']['content'] ?? '';
|
||
$tokens = $data['usage']['total_tokens'] ?? 0;
|
||
|
||
return [
|
||
'success' => true,
|
||
'data' => $content,
|
||
'tokens' => $tokens,
|
||
];
|
||
} else {
|
||
Log::error('AI API调用失败: ' . $response->body());
|
||
return [
|
||
'success' => false,
|
||
'error' => 'API调用失败: ' . $response->status(),
|
||
];
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::error('AI API异常: ' . $e->getMessage());
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 模拟AI响应(开发环境使用)
|
||
*/
|
||
private function mockAIResponse(array $messages): array
|
||
{
|
||
$lastMessage = end($messages);
|
||
$userMessage = $lastMessage['content'] ?? '';
|
||
|
||
// 根据用户消息生成模拟响应
|
||
$responses = [
|
||
'商品' => "关于商品管理,我可以帮你:\n1. 查询商品信息\n2. 添加新商品\n3. 更新商品库存\n4. 设置商品价格\n5. 管理商品分类\n\n请告诉我具体需要什么帮助?",
|
||
'订单' => "关于订单管理,我可以帮你:\n1. 查看订单状态\n2. 处理新订单\n3. 发货操作\n4. 订单统计\n5. 退款处理\n\n请提供订单号或具体问题。",
|
||
'采购' => "关于采购管理,我可以帮你:\n1. 创建采购单\n2. 供应商管理\n3. 采购审批流程\n4. 收货入库\n5. 采购统计\n\n请告诉我你的具体需求。",
|
||
'库存' => "关于库存管理,我可以帮你:\n1. 库存查询\n2. 库存预警\n3. 盘点管理\n4. 出入库记录\n5. 库存调拨\n\n请提供仓库或商品信息。",
|
||
'财务' => "关于财务管理,我可以帮你:\n1. 收支记录\n2. 财务报表\n3. 发票管理\n4. 对账处理\n5. 预算控制\n\n请告诉我具体财务问题。",
|
||
'default' => "我是ERP系统AI助手,可以帮你处理:\n• 商品管理\n• 订单处理\n• 采购管理\n• 库存控制\n• 财务统计\n• 系统操作指导\n\n请详细描述你的问题,我会尽力提供帮助。"
|
||
];
|
||
|
||
$response = $responses['default'];
|
||
foreach ($responses as $key => $value) {
|
||
if (strpos($userMessage, $key) !== false) {
|
||
$response = $value;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 添加个性化问候
|
||
if (strpos(strtolower($userMessage), '你好') !== false ||
|
||
strpos(strtolower($userMessage), 'hi') !== false ||
|
||
strpos(strtolower($userMessage), 'hello') !== false) {
|
||
$response = "你好!我是ERP系统AI助手。我可以帮你处理企业资源管理的各种问题,包括商品、订单、采购、库存、财务等模块的操作和咨询。有什么可以帮你的吗?";
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'data' => $response,
|
||
'tokens' => $this->estimateTokens($response),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 执行AI任务
|
||
*/
|
||
public function executeTask(AITaskRequest $request)
|
||
{
|
||
try {
|
||
$task = $request->input('task');
|
||
$parameters = $request->input('parameters', []);
|
||
|
||
// 根据任务类型处理
|
||
$result = $this->processTask($task, $parameters);
|
||
|
||
// 记录任务执行
|
||
\App\Models\OperationLog::log([
|
||
'module' => 'AI助手',
|
||
'action' => '执行任务',
|
||
'method' => 'POST',
|
||
'path' => 'api/ai/tasks/execute',
|
||
'request_data' => ['task' => $task, 'parameters' => $parameters],
|
||
'response_data' => $result,
|
||
'remark' => 'AI任务执行',
|
||
]);
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $result,
|
||
'message' => '任务执行成功'
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('AI任务执行失败: ' . $e->getMessage());
|
||
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '任务执行失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理具体任务
|
||
*/
|
||
private function processTask(string $task, array $parameters): array
|
||
{
|
||
switch ($task) {
|
||
case 'data_analysis':
|
||
return $this->analyzeData($parameters);
|
||
case 'report_generation':
|
||
return $this->generateReport($parameters);
|
||
case 'prediction':
|
||
return $this->makePrediction($parameters);
|
||
case 'recommendation':
|
||
return $this->provideRecommendation($parameters);
|
||
case 'document_summary':
|
||
return $this->summarizeDocument($parameters);
|
||
default:
|
||
return [
|
||
'success' => false,
|
||
'error' => '不支持的任务类型',
|
||
'task' => $task,
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 数据分析
|
||
*/
|
||
private function analyzeData(array $parameters): array
|
||
{
|
||
$type = $parameters['type'] ?? 'sales';
|
||
$period = $parameters['period'] ?? 'month';
|
||
|
||
// 模拟数据分析结果
|
||
$analysis = [
|
||
'type' => $type,
|
||
'period' => $period,
|
||
'summary' => "根据{$period}数据,发现以下趋势:",
|
||
'insights' => [
|
||
'销售额增长15%',
|
||
'最畅销商品:商品A',
|
||
'客户复购率:45%',
|
||
'库存周转率:2.5次',
|
||
],
|
||
'recommendations' => [
|
||
'增加商品A的库存',
|
||
'优化营销策略提高复购率',
|
||
'关注库存周转率提升',
|
||
],
|
||
];
|
||
|
||
return [
|
||
'success' => true,
|
||
'analysis' => $analysis,
|
||
'generated_at' => now()->toDateTimeString(),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 生成报告
|
||
*/
|
||
private function generateReport(array $parameters): array
|
||
{
|
||
$reportType = $parameters['report_type'] ?? 'sales';
|
||
$startDate = $parameters['start_date'] ?? now()->subMonth()->toDateString();
|
||
$endDate = $parameters['end_date'] ?? now()->toDateString();
|
||
|
||
// 模拟报告生成
|
||
$report = [
|
||
'type' => $reportType,
|
||
'period' => $startDate . ' 至 ' . $endDate,
|
||
'title' => ucfirst($reportType) . '分析报告',
|
||
'sections' => [
|
||
'executive_summary' => '报告摘要内容...',
|
||
'data_analysis' => '数据分析内容...',
|
||
'key_findings' => '主要发现...',
|
||
'recommendations' => '建议措施...',
|
||
],
|
||
'metrics' => [
|
||
'total_sales' => '¥125,000',
|
||
'order_count' => 156,
|
||
'average_order_value' => '¥801',
|
||
'growth_rate' => '15%',
|
||
],
|
||
];
|
||
|
||
return [
|
||
'success' => true,
|
||
'report' => $report,
|
||
'download_url' => '/api/reports/download/' . uniqid(),
|
||
'generated_at' => now()->toDateTimeString(),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 预测分析
|
||
*/
|
||
private function makePrediction(array $parameters): array
|
||
{
|
||
$target = $parameters['target'] ?? 'sales';
|
||
$periods = $parameters['periods'] ?? 3;
|
||
|
||
// 模拟预测结果
|
||
$predictions = [];
|
||
$current = 100000; // 基准值
|
||
|
||
for ($i = 1; $i <= $periods; $i++) {
|
||
$growth = rand(5, 15) / 100; // 5-15%增长
|
||
$predicted = $current * (1 + $growth);
|
||
|
||
$predictions[] = [
|
||
'period' => "第{$i}期",
|
||
'value' => number_format($predicted, 2),
|
||
'growth' => number_format($growth * 100, 1) . '%',
|
||
'confidence' => rand(70, 95) . '%',
|
||
];
|
||
|
||
$current = $predicted;
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'target' => $target,
|
||
'predictions' => $predictions,
|
||
'notes' => '基于历史数据的趋势预测,实际结果可能因市场变化而有所不同。',
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 提供建议
|
||
*/
|
||
private function provideRecommendation(array $parameters): array
|
||
{
|
||
$area = $parameters['area'] ?? 'inventory';
|
||
|
||
$recommendations = [
|
||
'inventory' => [
|
||
'优化库存水平,减少积压',
|
||
'建立安全库存机制',
|
||
'实施ABC分类管理',
|
||
'定期盘点,确保账实相符',
|
||
],
|
||
'sales' => [
|
||
'加强客户关系管理',
|
||
'优化产品定价策略',
|
||
'拓展销售渠道',
|
||
'提升客户服务质量',
|
||
],
|
||
'purchase' => [
|
||
'建立供应商评估体系',
|
||
'优化采购审批流程',
|
||
'实施集中采购降低成本',
|
||
'加强采购合同管理',
|
||
],
|
||
'finance' => [
|
||
'加强现金流管理',
|
||
'优化成本控制',
|
||
'完善财务报告体系',
|
||
'加强预算执行监控',
|
||
],
|
||
];
|
||
|
||
$areaRecommendations = $recommendations[$area] ?? $recommendations['inventory'];
|
||
|
||
return [
|
||
'success' => true,
|
||
'area' => $area,
|
||
'recommendations' => $areaRecommendations,
|
||
'priority' => '根据当前业务状况,建议优先实施前两项。',
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 文档摘要
|
||
*/
|
||
private function summarizeDocument(array $parameters): array
|
||
{
|
||
$content = $parameters['content'] ?? '';
|
||
$maxLength = $parameters['max_length'] ?? 200;
|
||
|
||
if (empty($content)) {
|
||
return [
|
||
'success' => false,
|
||
'error' => '文档内容不能为空',
|
||
];
|
||
}
|
||
|
||
// 简单摘要算法(实际应使用AI)
|
||
$sentences = preg_split('/[。!?.!?]/', $content);
|
||
$sentences = array_filter($sentences, function($sentence) {
|
||
return strlen(trim($sentence)) > 10;
|
||
});
|
||
|
||
$summary = '';
|
||
$count = 0;
|
||
|
||
foreach ($sentences as $sentence) {
|
||
if (strlen($summary) + strlen($sentence) < $maxLength) {
|
||
$summary .= trim($sentence) . '。';
|
||
$count++;
|
||
}
|
||
|
||
if ($count >= 3) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (empty($summary)) {
|
||
$summary = substr($content, 0, $maxLength) . '...';
|
||
}
|
||
|
||
$keywords = $this->extractKeywords($content);
|
||
|
||
return [
|
||
'success' => true,
|
||
'original_length' => strlen($content),
|
||
'summary_length' => strlen($summary),
|
||
'summary' => $summary,
|
||
'keywords' => $keywords,
|
||
'compression_rate' => round((1 - strlen($summary) / strlen($content)) * 100, 1) . '%',
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 提取关键词
|
||
*/
|
||
private function extractKeywords(string $content): array
|
||
{
|
||
// 简单关键词提取(实际应使用更复杂的算法)
|
||
$words = preg_split('/\s+/', $content);
|
||
$wordCount = array_count_values($words);
|
||
arsort($wordCount);
|
||
|
||
$keywords = array_slice(array_keys($wordCount), 0, 10);
|
||
|
||
// 过滤常见词
|
||
$commonWords = ['的', '了', '在', '是', '和', '与', '或', '等', '这个', '那个'];
|
||
$keywords = array_diff($keywords, $commonWords);
|
||
|
||
return array_values($keywords);
|
||
}
|
||
|
||
/**
|
||
* 估算Token数量
|
||
*/
|
||
private function estimateTokens(string $text): int
|
||
{
|
||
// 简单估算:英文约4字符=1token,中文约1.5字符=1token
|
||
$chineseChars = preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $text);
|
||
$otherChars = strlen($text) - $chineseChars * 3; // 中文字符占3字节
|
||
|
||
$tokens = ceil($chineseChars / 1.5 + $otherChars / 4);
|
||
|
||
return max(1, $tokens);
|
||
}
|
||
|
||
/**
|
||
* 获取对话列表
|
||
*/
|
||
public function getConversations(Request $request)
|
||
{
|
||
$query = AIConversation::where('user_id', auth()->id())
|
||
->orderBy('last_message_at', 'desc');
|
||
|
||
if ($request->filled('status')) {
|
||
$query->where('status', $request->status);
|
||
}
|
||
|
||
if ($request->filled('keyword')) {
|
||
$keyword = $request->keyword;
|
||
$query->where(function ($q) use ($keyword) {
|
||
$q->where('title', 'like', "%{$keyword}%")
|
||
->orWhereHas('messages', function ($q) use ($keyword) {
|
||
$q->where('content', 'like', "%{$keyword}%");
|
||
});
|
||
});
|
||
}
|
||
|
||
$perPage = $request->input('limit', 20);
|
||
$conversations = $query->paginate($perPage);
|
||
|
||
// 加载最后一条消息
|
||
$conversations->load(['lastMessage']);
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'list' => $conversations->items(),
|
||
'total' => $conversations->total(),
|
||
'current_page' => $conversations->currentPage(),
|
||
'last_page' => $conversations->lastPage(),
|
||
],
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取对话详情
|
||
*/
|
||
public function getConversation(string $id)
|
||
{
|
||
$conversation = AIConversation::with(['messages' => function ($query) {
|
||
$query->orderBy('created_at', 'asc');
|
||
}])->where('id', $id)
|
||
->where('user_id', auth()->id())
|
||
->firstOrFail();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $conversation,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 删除对话
|
||
*/
|
||
public function deleteConversation(string $id)
|
||
{
|
||
$conversation = AIConversation::where('id', $id)
|
||
->where('user_id', auth()->id())
|
||
->firstOrFail();
|
||
|
||
try {
|
||
// 删除相关消息
|
||
AIMessage::where('conversation_id', $id)->delete();
|
||
|
||
// 删除对话
|
||
$conversation->delete();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'message' => '对话删除成功'
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('删除对话失败: ' . $e->getMessage());
|
||
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '删除失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清空对话消息
|
||
*/
|
||
public function clearConversation(string $id)
|
||
{
|
||
$conversation = AIConversation::where('id', $id)
|
||
->where('user_id', auth()->id())
|
||
->firstOrFail();
|
||
|
||
try {
|
||
// 删除所有消息
|
||
AIMessage::where('conversation_id', $id)->delete();
|
||
|
||
// 重置对话统计
|
||
$conversation->update([
|
||
'message_count' => 0,
|
||
'total_tokens' => 0,
|
||
'last_message_at' => null,
|
||
]);
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'message' => '对话消息已清空'
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('清空对话失败: ' . $e->getMessage());
|
||
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '清空失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取AI能力列表
|
||
*/
|
||
public function getCapabilities()
|
||
{
|
||
$capabilities = [
|
||
'chat' => [
|
||
'name' => '智能对话',
|
||
'description' => '回答ERP系统相关问题,提供操作指导',
|
||
'examples' => [
|
||
'如何创建采购单?',
|
||
'查看商品库存',
|
||
'订单处理流程',
|
||
],
|
||
],
|
||
'data_analysis' => [
|
||
'name' => '数据分析',
|
||
'description' => '分析销售、库存、财务等数据',
|
||
'examples' => [
|
||
'分析本月销售趋势',
|
||
'库存周转率分析',
|
||
'客户购买行为分析',
|
||
],
|
||
],
|
||
'report_generation' => [
|
||
'name' => '报告生成',
|
||
'description' => '自动生成各类业务报告',
|
||
'examples' => [
|
||
'生成销售日报',
|
||
'制作库存月报',
|
||
'财务季度分析报告',
|
||
],
|
||
],
|
||
'prediction' => [
|
||
'name' => '趋势预测',
|
||
'description' => '基于历史数据预测未来趋势',
|
||
'examples' => [
|
||
'预测下月销售额',
|
||
'库存需求预测',
|
||
'客户增长预测',
|
||
],
|
||
],
|
||
'recommendation' => [
|
||
'name' => '智能建议',
|
||
'description' => '提供业务优化建议',
|
||
'examples' => [
|
||
'库存优化建议',
|
||
'销售策略建议',
|
||
'成本控制建议',
|
||
],
|
||
],
|
||
'document_summary' => [
|
||
'name' => '文档摘要',
|
||
'description' => '自动提取文档关键信息',
|
||
'examples' => [
|
||
'合同摘要',
|
||
'会议纪要整理',
|
||
'报告要点提取',
|
||
],
|
||
],
|
||
];
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $capabilities,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取使用统计
|
||
*/
|
||
public function getUsageStatistics(Request $request)
|
||
{
|
||
$userId = auth()->id();
|
||
|
||
// 今日使用统计
|
||
$todayStart = now()->startOfDay();
|
||
$todayEnd = now()->endOfDay();
|
||
|
||
$todayConversations = AIConversation::where('user_id', $userId)
|
||
->whereBetween('created_at', [$todayStart, $todayEnd])
|
||
->count();
|
||
|
||
$todayMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->whereBetween('created_at', [$todayStart, $todayEnd])
|
||
->count();
|
||
|
||
$todayTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->whereBetween('created_at', [$todayStart, $todayEnd])
|
||
->sum('tokens');
|
||
|
||
// 月度统计
|
||
$monthStart = now()->startOfMonth();
|
||
$monthEnd = now()->endOfMonth();
|
||
|
||
$monthConversations = AIConversation::where('user_id', $userId)
|
||
->whereBetween('created_at', [$monthStart, $monthEnd])
|
||
->count();
|
||
|
||
$monthMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->whereBetween('created_at', [$monthStart, $monthEnd])
|
||
->count();
|
||
|
||
$monthTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->whereBetween('created_at', [$monthStart, $monthEnd])
|
||
->sum('tokens');
|
||
|
||
// 总体统计
|
||
$totalConversations = AIConversation::where('user_id', $userId)->count();
|
||
$totalMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->count();
|
||
$totalTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) {
|
||
$query->where('user_id', $userId);
|
||
})->sum('tokens');
|
||
|
||
$statistics = [
|
||
'today' => [
|
||
'conversations' => $todayConversations,
|
||
'messages' => $todayMessages,
|
||
'tokens' => $todayTokens,
|
||
],
|
||
'month' => [
|
||
'conversations' => $monthConversations,
|
||
'messages' => $monthMessages,
|
||
'tokens' => $monthTokens,
|
||
],
|
||
'total' => [
|
||
'conversations' => $totalConversations,
|
||
'messages' => $totalMessages,
|
||
'tokens' => $totalTokens,
|
||
],
|
||
];
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $statistics,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 测试AI连接
|
||
*/
|
||
public function testConnection()
|
||
{
|
||
try {
|
||
$testMessage = '你好,请回复"AI服务正常"以确认连接成功。';
|
||
$messages = [
|
||
['role' => 'system', 'content' => '你是一个测试助手,只需要按照要求回复。'],
|
||
['role' => 'user', 'content' => $testMessage],
|
||
];
|
||
|
||
$response = $this->callAIAPI($messages);
|
||
|
||
if ($response['success']) {
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'status' => 'connected',
|
||
'response' => $response['data'],
|
||
'response_time' => '正常',
|
||
],
|
||
'message' => 'AI服务连接正常'
|
||
]);
|
||
} else {
|
||
return response()->json([
|
||
'code' => 503,
|
||
'data' => [
|
||
'status' => 'disconnected',
|
||
'error' => $response['error'],
|
||
],
|
||
'message' => 'AI服务连接失败'
|
||
], 503);
|
||
}
|
||
} catch (\Exception $e) {
|
||
return response()->json([
|
||
'code' => 500,
|
||
'data' => [
|
||
'status' => 'error',
|
||
'error' => $e->getMessage(),
|
||
],
|
||
'message' => '测试过程中发生错误'
|
||
], 500);
|
||
}
|
||
}
|
||
} |