Browse Source

聊天接口传入外部账号时自动创建客户账号

master
pyx 11 hours ago
parent
commit
b11d3f7ad7
  1. 29
      src/main/java/com/wok/supportbot/controller/AiController.java
  2. 64
      src/main/java/com/wok/supportbot/service/CustomerAccountService.java

29
src/main/java/com/wok/supportbot/controller/AiController.java

@ -72,7 +72,7 @@ public class AiController {
*/
@GetMapping("/assistant_app/chat/sync")
public String doChatWithAssistantAppSync(String message, String chatId, Long roleId, String accountId, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
return assistantApp.doChat(message, chatId, resolveSystemPrompt(scope, systemPrompt));
@ -88,7 +88,7 @@ public class AiController {
*/
@GetMapping(value = "/assistant_app/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> doChatWithLoveAppSSE(String message, String chatId, Long roleId, String accountId, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
return assistantApp.doChatByStream(message, chatId, resolveSystemPrompt(scope, systemPrompt));
@ -104,7 +104,7 @@ public class AiController {
*/
@GetMapping(value = "/assistant_app/chat/server_sent_event")
public Flux<ServerSentEvent<String>> doChatWithAssistantAppServerSentEvent(String message, String chatId, Long roleId, String accountId, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
return assistantApp.doChatByStream(message, chatId, resolveSystemPrompt(scope, systemPrompt))
@ -123,7 +123,7 @@ public class AiController {
*/
@GetMapping(value = "/assistant_app/chat/sse_emitter")
public SseEmitter doChatWithAssistantAppServerSseEmitter(String message, String chatId, Long roleId, String accountId, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
// 创建一个超时时间较长的 SseEmitter
@ -155,7 +155,7 @@ public class AiController {
*/
@GetMapping("/assistant_app/chat/rag/sync")
public String doChatWithRagSync(String message, String chatId, String rewriteStrategy, Long roleId, String accountId, Long categoryId, String categoryIds, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
String sys = resolveSystemPrompt(scope, systemPrompt);
@ -182,7 +182,7 @@ public class AiController {
*/
@GetMapping(value = "/assistant_app/chat/rag/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> doChatWithRagSSE(String message, String chatId, String rewriteStrategy, Long roleId, String accountId, Long categoryId, String categoryIds, String systemPrompt) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
bindConversation(chatId, context);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
String sys = resolveSystemPrompt(scope, systemPrompt);
@ -202,7 +202,7 @@ public class AiController {
@GetMapping("/assistant_app/rag/sources")
public Map<String, Object> getRagSources(String message, String chatId, String rewriteStrategy,
Long roleId, String accountId, Long categoryId, String categoryIds) {
AccountRoleContext context = resolveAccountRole(toLong(accountId), roleId);
AccountRoleContext context = resolveAccountRole(accountId, roleId);
RoleScope scope = customerServiceRoleService.getRoleScope(context.roleId());
if (message == null || message.isBlank() || isKbDenied(scope) || shouldBypassKnowledgeRetrieval(message)) {
return Map.of("success", true, "data", List.of());
@ -264,8 +264,8 @@ public class AiController {
}
/** 命中角色时用角色人设,否则用客户端兜底人设。 */
private AccountRoleContext resolveAccountRole(Long accountId, Long fallbackRoleId) {
AccountScope accountScope = customerAccountService.getAccountScope(accountId);
private AccountRoleContext resolveAccountRole(String accountId, Long fallbackRoleId) {
AccountScope accountScope = customerAccountService.getOrCreateAccountScope(accountId, fallbackRoleId);
Long effectiveRoleId = accountScope.hasAccount() && accountScope.roleId() != null
? accountScope.roleId()
: fallbackRoleId;
@ -316,15 +316,4 @@ public class AiController {
private record AccountRoleContext(Long accountId, Long roleId) {
}
/** 将字符串 accountId 安全转为 Long,非数字字符串返回 null */
private static Long toLong(String value) {
if (value == null || value.isBlank()) {
return null;
}
try {
return Long.valueOf(value.trim());
} catch (NumberFormatException e) {
return null;
}
}
}

64
src/main/java/com/wok/supportbot/service/CustomerAccountService.java

@ -1,6 +1,7 @@
package com.wok.supportbot.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -102,10 +103,73 @@ public class CustomerAccountService {
return new AccountScope(true, ((Number) row.get("id")).longValue(), Objects.toString(row.get("name"), ""), roleId);
}
@Transactional(rollbackFor = Exception.class)
public AccountScope getOrCreateAccountScope(String accountId, Long fallbackRoleId) {
if (accountId == null || accountId.trim().isEmpty()) {
return AccountScope.empty();
}
String accountKey = accountId.trim();
Long numericAccountId = toLong(accountKey);
AccountScope scope = getAccountScope(numericAccountId);
if (scope.hasAccount()) {
return scope;
}
scope = getAccountScopeByKey(accountKey);
if (scope.hasAccount()) {
return scope;
}
Long roleId = normalizeRoleId(fallbackRoleId);
try {
jdbcTemplate.update("""
INSERT INTO customer_account (account_key, name, description, role_id, enabled, is_delete)
VALUES (?, ?, ?, ?, true, false)
ON CONFLICT (account_key)
DO UPDATE SET enabled = true,
is_delete = false,
role_id = COALESCE(customer_account.role_id, EXCLUDED.role_id),
update_time = CURRENT_TIMESTAMP
""",
accountKey, accountKey, "Auto-created from external chat accountId", roleId);
} catch (DuplicateKeyException ignored) {
// Another request may have created the same account; read it below.
}
return getAccountScopeByKey(accountKey);
}
private AccountScope getAccountScopeByKey(String accountKey) {
if (accountKey == null || accountKey.trim().isEmpty()) {
return AccountScope.empty();
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList("""
SELECT id, name, role_id
FROM customer_account
WHERE account_key = ? AND is_delete = false AND enabled = true
""", accountKey.trim());
if (rows.isEmpty()) {
return AccountScope.empty();
}
Map<String, Object> row = rows.get(0);
Long roleId = row.get("role_id") == null ? null : ((Number) row.get("role_id")).longValue();
return new AccountScope(true, ((Number) row.get("id")).longValue(), Objects.toString(row.get("name"), ""), roleId);
}
private Long normalizeRoleId(Long roleId) {
return roleId != null && roleId > 0 ? roleId : null;
}
private static Long toLong(String value) {
if (value == null || value.isBlank()) {
return null;
}
try {
return Long.valueOf(value.trim());
} catch (NumberFormatException e) {
return null;
}
}
public record AccountScope(boolean present, Long accountId, String name, Long roleId) {
public static AccountScope empty() {

Loading…
Cancel
Save