main: 用户管理和会话功能初始实现
- 添加用户管理功能的测试,包括创建、更新、停用、激活用户及用户登录 JWT 测试 - 提供用户管理相关的请求验证类与控制器 - 引入 CORS 配置信息,支持跨域请求 - 添加数据库播种器以便创建根用户 - 配置 API 默认使用 JWT 认证 - 添加聊天会话和消息的模型、迁移文件及关联功能
This commit is contained in:
132
app/Services/ChatService.php
Normal file
132
app/Services/ChatService.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\ChatSessionStatus;
|
||||
use App\Exceptions\ChatSessionStatusException;
|
||||
use App\Models\ChatSession;
|
||||
use App\Models\Message;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ChatService
|
||||
{
|
||||
public function createSession(string $name = null): ChatSession
|
||||
{
|
||||
return ChatSession::create([
|
||||
'session_id' => (string) Str::uuid(),
|
||||
'session_name' => $name,
|
||||
'status' => ChatSessionStatus::OPEN,
|
||||
'last_seq' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getSession(string $sessionId): ChatSession
|
||||
{
|
||||
return ChatSession::query()->whereKey($sessionId)->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $dto
|
||||
*/
|
||||
public function appendMessage(array $dto): Message
|
||||
{
|
||||
return DB::transaction(function () use ($dto) {
|
||||
/** @var ChatSession $session */
|
||||
$session = ChatSession::query()
|
||||
->whereKey($dto['session_id'])
|
||||
->lockForUpdate()
|
||||
->firstOrFail();
|
||||
|
||||
$this->ensureCanAppend($session, $dto['role'], $dto['type']);
|
||||
|
||||
$dedupeKey = $dto['dedupe_key'] ?? null;
|
||||
if ($dedupeKey) {
|
||||
$existing = Message::query()
|
||||
->where('session_id', $session->session_id)
|
||||
->where('dedupe_key', $dedupeKey)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
$newSeq = $session->last_seq + 1;
|
||||
|
||||
$message = new Message([
|
||||
'message_id' => (string) Str::uuid(),
|
||||
'session_id' => $session->session_id,
|
||||
'role' => $dto['role'],
|
||||
'type' => $dto['type'],
|
||||
'content' => $dto['content'] ?? null,
|
||||
'payload' => $dto['payload'] ?? null,
|
||||
'reply_to' => $dto['reply_to'] ?? null,
|
||||
'dedupe_key' => $dedupeKey,
|
||||
'seq' => $newSeq,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
try {
|
||||
$message->save();
|
||||
} catch (QueryException $e) {
|
||||
if ($this->isUniqueConstraint($e) && $dedupeKey) {
|
||||
$existing = Message::query()
|
||||
->where('session_id', $session->session_id)
|
||||
->where('dedupe_key', $dedupeKey)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$session->update([
|
||||
'last_seq' => $newSeq,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
return $message;
|
||||
});
|
||||
}
|
||||
|
||||
public function listMessagesBySeq(string $sessionId, int $afterSeq, int $limit = 50): Collection
|
||||
{
|
||||
$this->getSession($sessionId); // ensure exists
|
||||
|
||||
return Message::query()
|
||||
->where('session_id', $sessionId)
|
||||
->where('seq', '>', $afterSeq)
|
||||
->orderBy('seq')
|
||||
->limit($limit)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function ensureCanAppend(ChatSession $session, string $role, string $type): void
|
||||
{
|
||||
if ($session->status === ChatSessionStatus::CLOSED) {
|
||||
$allowed = $role === Message::ROLE_SYSTEM && in_array($type, ['run.status', 'error'], true);
|
||||
if (! $allowed) {
|
||||
throw new ChatSessionStatusException('Session is closed');
|
||||
}
|
||||
}
|
||||
|
||||
if ($session->status === ChatSessionStatus::LOCKED) {
|
||||
if ($role === Message::ROLE_USER && $type === 'user.prompt') {
|
||||
throw new ChatSessionStatusException('Session is locked');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function isUniqueConstraint(QueryException $e): bool
|
||||
{
|
||||
$sqlState = $e->getCode() ?: ($e->errorInfo[0] ?? null);
|
||||
|
||||
return $sqlState === '23505';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user