Merge PR #1327
This commit is contained in:
commit
89237781c0
4 changed files with 182 additions and 6 deletions
|
|
@ -62,6 +62,61 @@ func extractJSONStringField(content, field string) string {
|
|||
// Format: {"image_key": "img_xxx"}
|
||||
func extractImageKey(content string) string { return extractJSONStringField(content, "image_key") }
|
||||
|
||||
// extractPostImageKeys extracts all image_key values from a Feishu post (rich text) message.
|
||||
// Post content format: {"title":"...","content":[[{"tag":"img","image_key":"..."},...],...]}.
|
||||
func extractPostImageKeys(rawContent string) []string {
|
||||
var post struct {
|
||||
Content [][]struct {
|
||||
Tag string `json:"tag"`
|
||||
ImageKey string `json:"image_key"`
|
||||
} `json:"content"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(rawContent), &post); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for _, paragraph := range post.Content {
|
||||
for _, elem := range paragraph {
|
||||
if elem.Tag == "img" && elem.ImageKey != "" {
|
||||
keys = append(keys, elem.ImageKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// extractPostText extracts plain text from a Feishu post (rich text) message.
|
||||
// Returns title and text elements joined by newlines. Falls back to rawContent on parse error.
|
||||
func extractPostText(rawContent string) string {
|
||||
var post struct {
|
||||
Title string `json:"title"`
|
||||
Content [][]struct {
|
||||
Tag string `json:"tag"`
|
||||
Text string `json:"text"`
|
||||
} `json:"content"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(rawContent), &post); err != nil {
|
||||
return rawContent
|
||||
}
|
||||
|
||||
var parts []string
|
||||
if post.Title != "" {
|
||||
parts = append(parts, post.Title)
|
||||
}
|
||||
for _, paragraph := range post.Content {
|
||||
for _, elem := range paragraph {
|
||||
if elem.Tag == "text" && elem.Text != "" {
|
||||
parts = append(parts, elem.Text)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(parts, "\n")
|
||||
}
|
||||
|
||||
// extractFileKey extracts the file_key from a Feishu file/audio message content JSON.
|
||||
// Format: {"file_key": "file_xxx", "file_name": "...", ...}
|
||||
func extractFileKey(content string) string { return extractJSONStringField(content, "file_key") }
|
||||
|
|
|
|||
|
|
@ -134,6 +134,93 @@ func TestExtractFileKey(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestExtractPostImageKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawContent string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "text and image",
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_v3_abc","width":100,"height":100}],[{"tag":"text","text":"hello","style":[]}]]}`,
|
||||
want: []string{"img_v3_abc"},
|
||||
},
|
||||
{
|
||||
name: "multiple images",
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_1","width":100,"height":100},{"tag":"img","image_key":"img_2","width":100,"height":100}]]}`,
|
||||
want: []string{"img_1", "img_2"},
|
||||
},
|
||||
{
|
||||
name: "no images",
|
||||
rawContent: `{"title":"","content":[[{"tag":"text","text":"hello","style":[]}]]}`,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid JSON",
|
||||
rawContent: `not json`,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "empty content",
|
||||
rawContent: `{"title":"","content":[]}`,
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := extractPostImageKeys(tt.rawContent)
|
||||
if len(got) != len(tt.want) {
|
||||
t.Errorf("extractPostImageKeys() = %v, want %v", got, tt.want)
|
||||
return
|
||||
}
|
||||
for i := range got {
|
||||
if got[i] != tt.want[i] {
|
||||
t.Errorf("extractPostImageKeys()[%d] = %q, want %q", i, got[i], tt.want[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractPostText(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawContent string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "text and image",
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_v3_abc","width":100,"height":100}],[{"tag":"text","text":"图里有啥","style":[]}]]}`,
|
||||
want: "图里有啥",
|
||||
},
|
||||
{
|
||||
name: "with title",
|
||||
rawContent: `{"title":"My Post","content":[[{"tag":"text","text":"body text","style":[]}]]}`,
|
||||
want: "My Post\nbody text",
|
||||
},
|
||||
{
|
||||
name: "only images returns empty",
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_v3_abc","width":100,"height":100}]]}`,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "invalid JSON returns raw",
|
||||
rawContent: `not json`,
|
||||
want: "not json",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := extractPostText(tt.rawContent)
|
||||
if got != tt.want {
|
||||
t.Errorf("extractPostText(%q) = %q, want %q", tt.rawContent, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractFileName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
|
|
@ -504,8 +504,8 @@ func extractContent(messageType, rawContent string) string {
|
|||
return rawContent
|
||||
|
||||
case larkim.MsgTypePost:
|
||||
// Pass raw JSON to LLM — structured rich text is more informative than flattened plain text
|
||||
return rawContent
|
||||
// Extract plain text from post; images are handled separately via downloadInboundMedia.
|
||||
return extractPostText(rawContent)
|
||||
|
||||
case larkim.MsgTypeImage:
|
||||
// Image messages don't have text content
|
||||
|
|
@ -544,6 +544,14 @@ func (c *FeishuChannel) downloadInboundMedia(
|
|||
refs = append(refs, ref)
|
||||
}
|
||||
|
||||
case larkim.MsgTypePost:
|
||||
for _, imageKey := range extractPostImageKeys(rawContent) {
|
||||
ref := c.downloadResource(ctx, messageID, imageKey, "image", ".jpg", store, scope)
|
||||
if ref != "" {
|
||||
refs = append(refs, ref)
|
||||
}
|
||||
}
|
||||
|
||||
case larkim.MsgTypeFile, larkim.MsgTypeAudio, larkim.MsgTypeMedia:
|
||||
fileKey := extractFileKey(rawContent)
|
||||
if fileKey == "" {
|
||||
|
|
@ -670,7 +678,7 @@ func appendMediaTags(content, messageType string, mediaRefs []string) string {
|
|||
|
||||
var tag string
|
||||
switch messageType {
|
||||
case larkim.MsgTypeImage:
|
||||
case larkim.MsgTypeImage, larkim.MsgTypePost:
|
||||
tag = "[image: photo]"
|
||||
case larkim.MsgTypeAudio:
|
||||
tag = "[audio]"
|
||||
|
|
|
|||
|
|
@ -28,10 +28,22 @@ func TestExtractContent(t *testing.T) {
|
|||
want: "not json",
|
||||
},
|
||||
{
|
||||
name: "post message returns raw JSON",
|
||||
name: "post message extracts text",
|
||||
messageType: "post",
|
||||
rawContent: `{"title": "test post"}`,
|
||||
want: `{"title": "test post"}`,
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_v3_xxx","width":100,"height":100}],[{"tag":"text","text":"图里有啥","style":[]}]]}`,
|
||||
want: "图里有啥",
|
||||
},
|
||||
{
|
||||
name: "post message with title",
|
||||
messageType: "post",
|
||||
rawContent: `{"title":"test post","content":[[{"tag":"text","text":"hello","style":[]}]]}`,
|
||||
want: "test post\nhello",
|
||||
},
|
||||
{
|
||||
name: "post message only images returns empty",
|
||||
messageType: "post",
|
||||
rawContent: `{"title":"","content":[[{"tag":"img","image_key":"img_v3_xxx","width":100,"height":100}]]}`,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "image message returns empty",
|
||||
|
|
@ -144,6 +156,20 @@ func TestAppendMediaTags(t *testing.T) {
|
|||
mediaRefs: []string{"ref1"},
|
||||
want: "report.pdf [file]",
|
||||
},
|
||||
{
|
||||
name: "post with image refs",
|
||||
content: "图里有啥",
|
||||
messageType: "post",
|
||||
mediaRefs: []string{"ref1"},
|
||||
want: "图里有啥 [image: photo]",
|
||||
},
|
||||
{
|
||||
name: "post empty content with image refs",
|
||||
content: "",
|
||||
messageType: "post",
|
||||
mediaRefs: []string{"ref1"},
|
||||
want: "[image: photo]",
|
||||
},
|
||||
{
|
||||
name: "unknown type",
|
||||
content: "something",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue