mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat: add IsLark field to FeishuConfig to switch between Feishu and Lark domains (#1753)
* feat(feishu): add Lark (international) support via IsLark config field Add IsLark field to FeishuConfig to switch between Feishu and Lark domains. Also fix domain inconsistency where WS client defaulted to LarkBaseUrl while HTTP client used FeishuBaseUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update documentation and web UI for Lark support Add is_lark field to config example, feishu docs, i18n translations, and web frontend form. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,7 +122,8 @@
|
||||
"verification_token": "",
|
||||
"allow_from": [],
|
||||
"reasoning_channel_id": "",
|
||||
"random_reaction_emoji": []
|
||||
"random_reaction_emoji": [],
|
||||
"is_lark": false
|
||||
},
|
||||
"dingtalk": {
|
||||
"enabled": false,
|
||||
|
||||
@@ -13,25 +13,27 @@
|
||||
"app_secret": "xxx",
|
||||
"encrypt_key": "",
|
||||
"verification_token": "",
|
||||
"allow_from": []
|
||||
"allow_from": [],
|
||||
"is_lark": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
| ------------------ | ------ | ---- | -------------------------------- |
|
||||
| enabled | bool | 是 | 是否启用飞书频道 |
|
||||
| app_id | string | 是 | 飞书应用的 App ID(以cli\_开头) |
|
||||
| app_secret | string | 是 | 飞书应用的 App Secret |
|
||||
| encrypt_key | string | 否 | 事件回调加密密钥 |
|
||||
| verification_token | string | 否 | 用于Webhook事件验证的Token |
|
||||
| allow_from | array | 否 | 用户ID白名单,空表示所有用户 |
|
||||
| random_reaction_emoji | array | 否 | 随机添加的表情列表,空则使用默认 "Pin" |
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
| --------------------- | ------ | ---- | ------------------------------------------------------------------------------------------------ |
|
||||
| enabled | bool | 是 | 是否启用飞书频道 |
|
||||
| app_id | string | 是 | 飞书应用的 App ID(以cli\_开头) |
|
||||
| app_secret | string | 是 | 飞书应用的 App Secret |
|
||||
| encrypt_key | string | 否 | 事件回调加密密钥 |
|
||||
| verification_token | string | 否 | 用于Webhook事件验证的Token |
|
||||
| allow_from | array | 否 | 用户ID白名单,空表示所有用户 |
|
||||
| random_reaction_emoji | array | 否 | 随机添加的表情列表,空则使用默认 "Pin" |
|
||||
| is_lark | bool | 否 | 是否使用 Lark 国际版域名(`open.larksuite.com`),默认为 `false`(使用飞书域名 `open.feishu.cn`) |
|
||||
|
||||
## 设置流程
|
||||
|
||||
1. 前往 [飞书开放平台](https://open.feishu.cn/)创建应用程序
|
||||
1. 前往 [飞书开放平台](https://open.feishu.cn/)(国际版用户请前往 [Lark 开放平台](https://open.larksuite.com/))创建应用程序
|
||||
2. 获取 App ID 和 App Secret
|
||||
3. 配置事件订阅和Webhook URL
|
||||
4. 设置加密(可选,生产环境建议启用)
|
||||
|
||||
@@ -54,11 +54,15 @@ func NewFeishuChannel(cfg config.FeishuConfig, bus *bus.MessageBus) (*FeishuChan
|
||||
)
|
||||
|
||||
tc := newTokenCache()
|
||||
opts := []lark.ClientOptionFunc{lark.WithTokenCache(tc)}
|
||||
if cfg.IsLark {
|
||||
opts = append(opts, lark.WithOpenBaseUrl(lark.LarkBaseUrl))
|
||||
}
|
||||
ch := &FeishuChannel{
|
||||
BaseChannel: base,
|
||||
config: cfg,
|
||||
tokenCache: tc,
|
||||
client: lark.NewClient(cfg.AppID, cfg.AppSecret, lark.WithTokenCache(tc)),
|
||||
client: lark.NewClient(cfg.AppID, cfg.AppSecret, opts...),
|
||||
}
|
||||
ch.SetOwner(ch)
|
||||
return ch, nil
|
||||
@@ -83,10 +87,15 @@ func (c *FeishuChannel) Start(ctx context.Context) error {
|
||||
|
||||
c.mu.Lock()
|
||||
c.cancel = cancel
|
||||
domain := lark.FeishuBaseUrl
|
||||
if c.config.IsLark {
|
||||
domain = lark.LarkBaseUrl
|
||||
}
|
||||
c.wsClient = larkws.NewClient(
|
||||
c.config.AppID,
|
||||
c.config.AppSecret,
|
||||
larkws.WithEventHandler(dispatcher),
|
||||
larkws.WithDomain(domain),
|
||||
)
|
||||
wsClient := c.wsClient
|
||||
c.mu.Unlock()
|
||||
|
||||
@@ -325,6 +325,7 @@ type FeishuConfig struct {
|
||||
Placeholder PlaceholderConfig `json:"placeholder,omitempty"`
|
||||
ReasoningChannelID string `json:"reasoning_channel_id" env:"PICOCLAW_CHANNELS_FEISHU_REASONING_CHANNEL_ID"`
|
||||
RandomReactionEmoji FlexibleStringSlice `json:"random_reaction_emoji" env:"PICOCLAW_CHANNELS_FEISHU_RANDOM_REACTION_EMOJI"`
|
||||
IsLark bool `json:"is_lark" env:"PICOCLAW_CHANNELS_FEISHU_IS_LARK"`
|
||||
}
|
||||
|
||||
type DiscordConfig struct {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"
|
||||
|
||||
import type { ChannelConfig } from "@/api/channels"
|
||||
import { maskedSecretPlaceholder } from "@/components/secret-placeholder"
|
||||
import { Field, KeyInput } from "@/components/shared-form"
|
||||
import { Field, KeyInput, SwitchCardField } from "@/components/shared-form"
|
||||
import { Input } from "@/components/ui/input"
|
||||
|
||||
interface FeishuFormProps {
|
||||
@@ -16,6 +16,10 @@ function asString(value: unknown): string {
|
||||
return typeof value === "string" ? value : ""
|
||||
}
|
||||
|
||||
function asBool(value: unknown): boolean {
|
||||
return typeof value === "boolean" ? value : false
|
||||
}
|
||||
|
||||
function asStringArray(value: unknown): string[] {
|
||||
if (!Array.isArray(value)) return []
|
||||
return value.filter((item): item is string => typeof item === "string")
|
||||
@@ -98,6 +102,12 @@ export function FeishuForm({
|
||||
)}
|
||||
/>
|
||||
</Field>
|
||||
<SwitchCardField
|
||||
label={t("channels.field.isLark")}
|
||||
hint={t("channels.form.desc.isLark")}
|
||||
checked={asBool(config.is_lark)}
|
||||
onCheckedChange={(checked) => onChange("is_lark", checked)}
|
||||
/>
|
||||
<Field
|
||||
label={t("channels.field.allowFrom")}
|
||||
hint={t("channels.form.desc.allowFrom")}
|
||||
|
||||
@@ -259,6 +259,7 @@
|
||||
"placeholderText": "Placeholder Text",
|
||||
"groupTriggerMentionOnly": "Group Mention Only",
|
||||
"groupTriggerPrefixes": "Group Trigger Prefixes",
|
||||
"isLark": "Lark (International)",
|
||||
"allowFrom": "Allow From",
|
||||
"allowFromPlaceholder": "e.g. 123456, 789012",
|
||||
"allowOrigins": "Allow Origins",
|
||||
@@ -290,6 +291,7 @@
|
||||
"placeholderEnabled": "Enable temporary placeholder messages before the final reply is sent.",
|
||||
"groupTriggerMentionOnly": "In group chats, respond only when the bot is mentioned.",
|
||||
"groupTriggerPrefixes": "Custom group-chat trigger prefixes, separated by commas.",
|
||||
"isLark": "Use Lark international domain (open.larksuite.com) instead of Feishu domain (open.feishu.cn).",
|
||||
"allowFrom": "Allowed user or group IDs, separated by commas.",
|
||||
"allowOrigins": "Allowed origin domains, separated by commas.",
|
||||
"wsUrl": "WebSocket service URL.",
|
||||
|
||||
@@ -259,6 +259,7 @@
|
||||
"placeholderText": "占位文案",
|
||||
"groupTriggerMentionOnly": "群聊仅提及时响应",
|
||||
"groupTriggerPrefixes": "群聊触发前缀",
|
||||
"isLark": "Lark(国际版)",
|
||||
"allowFrom": "允许来源",
|
||||
"allowFromPlaceholder": "例如 123456, 789012",
|
||||
"allowOrigins": "允许来源域名",
|
||||
@@ -290,6 +291,7 @@
|
||||
"placeholderEnabled": "在最终回复发送前,先发送临时占位消息。",
|
||||
"groupTriggerMentionOnly": "在群聊中仅当提及机器人时才响应。",
|
||||
"groupTriggerPrefixes": "群聊触发前缀,多个值用逗号分隔。",
|
||||
"isLark": "使用 Lark 国际版域名(open.larksuite.com)替代飞书域名(open.feishu.cn)。",
|
||||
"allowFrom": "允许访问的用户或群组 ID,多个值用逗号分隔。",
|
||||
"allowOrigins": "允许访问的来源域名,多个值用逗号分隔。",
|
||||
"wsUrl": "WebSocket 服务地址。",
|
||||
|
||||
Reference in New Issue
Block a user