Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion astrbot/core/platform/sources/webchat/webchat_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,12 @@ async def get_reply_parts(

async def convert_message(self, data: tuple) -> AstrBotMessage:
username, cid, payload = data
sender_id = str(payload.get("sender_id") or username)
sender_name = str(payload.get("sender_name") or username)

abm = AstrBotMessage()
abm.self_id = "webchat"
abm.sender = MessageMember(username, username)
abm.sender = MessageMember(sender_id, sender_name)

abm.type = MessageType.FRIEND_MESSAGE

Expand Down
15 changes: 15 additions & 0 deletions astrbot/dashboard/routes/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,19 @@ async def chat(self, post_data: dict | None = None):
enable_streaming = post_data.get("enable_streaming", True)
platform_history_id = post_data.get("_platform_history_id") or "webchat"
thread_selected_text = post_data.get("_thread_selected_text")
use_internal_sender = request.path.startswith("/api/v1/") and bool(
g.get("api_key_id", None)
)
sender_id = (
str(post_data.get("_sender_id") or username)
if use_internal_sender
else username
)
sender_name = (
str(post_data.get("_sender_name") or username)
if use_internal_sender
else username
)

if not session_id:
return Response().error("session_id is empty").__dict__
Expand Down Expand Up @@ -1012,6 +1025,8 @@ def build_attachment_saved_event(part: dict | None) -> str | None:
"message_id": message_id,
"llm_checkpoint_id": llm_checkpoint_id,
"thread_selected_text": thread_selected_text,
"sender_id": sender_id,
"sender_name": sender_name,
},
),
)
Expand Down
35 changes: 27 additions & 8 deletions astrbot/dashboard/routes/open_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ def _resolve_open_username(
return None, "username is empty"
return username, None

@staticmethod
def _build_openapi_sender_id(api_key_id: str | None, username: str) -> str:
key_id = str(api_key_id or "unknown").strip() or "unknown"
return f"openapi:{key_id}:{username}"

def _get_chat_config_list(self) -> list[dict]:
conf_list = self.core_lifecycle.astrbot_config_mgr.get_conf_list()

Expand Down Expand Up @@ -170,6 +175,11 @@ async def chat_send(self):

original_username = g.get("username", "guest")
g.username = effective_username
post_data["_sender_id"] = self._build_openapi_sender_id(
g.get("api_key_id", None),
effective_username,
)
post_data["_sender_name"] = effective_username
if config_id:
umo = f"webchat:FriendMessage:webchat!{effective_username}!{session_id}"
try:
Expand Down Expand Up @@ -213,10 +223,12 @@ def _extract_ws_api_key() -> str | None:
return auth_header.removeprefix("ApiKey ").strip()
return None

async def _authenticate_chat_ws_api_key(self) -> tuple[bool, str | None]:
async def _authenticate_chat_ws_api_key(
self,
) -> tuple[bool, str | None, str | None]:
raw_key = self._extract_ws_api_key()
if not raw_key:
return False, "Missing API key"
return False, "Missing API key", None

key_hash = hashlib.pbkdf2_hmac(
"sha256",
Expand All @@ -226,18 +238,18 @@ async def _authenticate_chat_ws_api_key(self) -> tuple[bool, str | None]:
).hex()
api_key = await self.db.get_active_api_key_by_hash(key_hash)
if not api_key:
return False, "Invalid API key"
return False, "Invalid API key", None

if isinstance(api_key.scopes, list):
scopes = api_key.scopes
else:
scopes = list(ALL_OPEN_API_SCOPES)

if "*" not in scopes and "chat" not in scopes:
return False, "Insufficient API key scope"
return False, "Insufficient API key scope", None

await self.db.touch_api_key(api_key.key_id)
return True, None
return True, None, api_key.key_id

async def _send_chat_ws_error(self, message: str, code: str) -> None:
await websocket.send_json(
Expand Down Expand Up @@ -277,7 +289,11 @@ async def _update_session_config_route(
return f"Failed to update chat config route: {e}"
return None

async def _handle_chat_ws_send(self, post_data: dict) -> None:
async def _handle_chat_ws_send(
self,
post_data: dict,
api_key_id: str | None,
) -> None:
effective_username, username_err = self._resolve_open_username(
post_data.get("username")
)
Expand Down Expand Up @@ -331,6 +347,7 @@ async def _handle_chat_ws_send(self, post_data: dict) -> None:
selected_provider = post_data.get("selected_provider")
selected_model = post_data.get("selected_model")
enable_streaming = post_data.get("enable_streaming", True)
sender_id = self._build_openapi_sender_id(api_key_id, effective_username)

back_queue = webchat_queue_mgr.get_or_create_back_queue(message_id, session_id)
try:
Expand All @@ -345,6 +362,8 @@ async def _handle_chat_ws_send(self, post_data: dict) -> None:
"selected_model": selected_model,
"enable_streaming": enable_streaming,
"message_id": message_id,
"sender_id": sender_id,
"sender_name": effective_username,
},
)
)
Expand Down Expand Up @@ -493,7 +512,7 @@ async def _handle_chat_ws_send(self, post_data: dict) -> None:
webchat_queue_mgr.remove_back_queue(message_id)

async def chat_ws(self) -> None:
authed, auth_err = await self._authenticate_chat_ws_api_key()
authed, auth_err, api_key_id = await self._authenticate_chat_ws_api_key()
if not authed:
await self._send_chat_ws_error(auth_err or "Unauthorized", "UNAUTHORIZED")
await websocket.close(1008, auth_err or "Unauthorized")
Expand All @@ -520,7 +539,7 @@ async def chat_ws(self) -> None:
)
continue

await self._handle_chat_ws_send(message)
await self._handle_chat_ws_send(message, api_key_id)
except Exception as e:
logger.debug("Open API WS connection closed: %s", e)

Expand Down
Loading
Loading