amber-laravel/app/Http/Controllers/Api/ChatHistoryController.php

159 lines
4.7 KiB
PHP
Raw Normal View History

2024-07-24 17:16:41 +00:00
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
2024-07-24 18:53:47 +00:00
use App\LLM\Qwen;
2024-07-24 17:16:41 +00:00
use App\Models\Chat;
2024-07-24 18:53:47 +00:00
use App\Repositories\LLM\ChatEnum;
use App\Repositories\LLM\History;
use App\Repositories\LLM\HumanMessage;
2024-07-24 17:16:41 +00:00
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
2024-07-24 18:53:47 +00:00
use Illuminate\Support\Facades\Log;
2024-07-24 17:16:41 +00:00
use Illuminate\Support\Str;
class ChatHistoryController extends Controller
{
2024-07-24 18:53:47 +00:00
private string $stream_prefix_id = 'chat_stream_id:';
private string $stream_random_id_prefix = 'chat_stream_random_id:';
2024-07-24 17:16:41 +00:00
/**
* Display a listing of the resource.
*/
public function index(Chat $chat)
{
return $this->success(
2024-07-24 18:53:47 +00:00
$chat->histories()->latest()->get()
2024-07-24 17:16:41 +00:00
);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request, Chat $chat)
{
// 获取上一条记录
$last_history = $chat->histories()->orderBy('id', 'desc')->first();
// 如果存在
if ($last_history) {
// 如果上一条是 user
2024-07-24 18:53:47 +00:00
if ($last_history->role == ChatEnum::Human) {
2024-07-24 17:16:41 +00:00
// 不允许发送消息
return $this->badRequest('你已经回复过了,请等待 AI 响应。');
}
// 检查缓存是否存在
2024-07-24 18:53:47 +00:00
$last_stream_key = $this->stream_prefix_id.$chat->id;
2024-07-24 17:16:41 +00:00
// 如果存在
if (Cache::has($last_stream_key)) {
return $this->conflict('上一个流信息还没有获取,请等待一分钟后重试。');
}
}
$request->validate([
'message' => 'required',
]);
2024-07-24 18:53:47 +00:00
$history = $chat->histories()->create([
2024-07-24 17:16:41 +00:00
'content' => $request->input('message'),
2024-07-24 18:53:47 +00:00
'role' => ChatEnum::Human,
2024-07-24 17:16:41 +00:00
]);
2024-07-24 18:53:47 +00:00
// 随机生成一个 ID
2024-07-24 17:16:41 +00:00
$random_id = Str::random(20);
2024-07-24 18:53:47 +00:00
// 缓存 key
$history_stream_key = $this->stream_prefix_id.$chat->id;
Cache::put($history_stream_key, $random_id, 60);
Cache::put($this->stream_random_id_prefix.$random_id, $chat->id, 60);
2024-07-24 17:16:41 +00:00
return $this->success([
'stream_url' => route('chat-stream', $random_id),
]);
}
2024-07-24 18:53:47 +00:00
/**
* @throws \Exception
*/
2024-07-24 17:16:41 +00:00
public function stream(string $stream_id)
{
2024-07-24 18:53:47 +00:00
$cached = Cache::get($this->stream_random_id_prefix.$stream_id);
if (! $cached) {
return $this->badRequest('无效的流 ID。');
}
$chat = Chat::with('assistant.tools', 'assistant')->findOrFail($cached);
$histories = $chat->histories()->get();
// 如果为 0
if ($histories->count() == 0) {
return $this->badRequest('请先发送消息。');
}
$llm_histories = new History();
$llm_histories->setHistory($histories->toArray());
$llm = new Qwen();
$history = new History();
$tools = $chat->assistant->tools()->get();
$llm->setTools($tools);
$llm->setHistory($history);
$last_human_message = $histories[$histories->count() - 1];
$history->addMessage(new HumanMessage($last_human_message));
$stream = $llm->streamResponse();
$response = response()->stream(function () use (&$stream, &$chat) {
// 循环输出
foreach ($stream as $item) {
$data = [];
if ($item->role == ChatEnum::Tool) {
if ($item->processing) {
$data = [
'message' => '正在执行: '.$item->content,
];
} else {
$data = [
'message' => '结果: '.$item->content,
];
}
} elseif ($item->role == ChatEnum::AssistantChunk) {
$data = [
'message' => $item->getLastAppend(),
];
} elseif ($item->role == ChatEnum::Assistant) {
$chat->histories()->create([
'content' => $item->content,
'role' => ChatEnum::Assistant,
]);
Log::info('AI: '.$item->content);
}
echo 'data: '.json_encode($data, JSON_UNESCAPED_UNICODE)."\n\n";
ob_flush();
flush();
}
});
Cache::forget($this->stream_random_id_prefix.$stream_id);
Cache::forget($this->stream_prefix_id.$chat->id);
$response->headers->set('Content-Type', 'text/event-stream');
$response->headers->set('Cache-Control', 'no-cache');
$response->headers->set('Connection', 'keep-alive');
return $response;
2024-07-24 17:16:41 +00:00
}
}