| 99 | } |
| 100 | |
| 101 | func parseOpenSearchHits(b []byte) (types.RetrievalResult, error) { |
| 102 | var root struct { |
| 103 | Hits struct { |
| 104 | Hits []struct { |
| 105 | ID string `json:"_id"` |
| 106 | Index string `json:"_index"` |
| 107 | Score float64 `json:"_score"` |
| 108 | Source json.RawMessage `json:"_source"` |
| 109 | } `json:"hits"` |
| 110 | } `json:"hits"` |
| 111 | } |
| 112 | if err := json.Unmarshal(b, &root); err != nil { |
| 113 | return types.RetrievalResult{}, fmt.Errorf("opensearch decode: %w", err) |
| 114 | } |
| 115 | var out []types.RetrievalChunk |
| 116 | for _, h := range root.Hits.Hits { |
| 117 | var src map[string]any |
| 118 | if err := json.Unmarshal(h.Source, &src); err != nil { |
| 119 | continue |
| 120 | } |
| 121 | text := firstString(src, "text", "content", "body", "passage", "chunk") |
| 122 | if text == "" { |
| 123 | continue |
| 124 | } |
| 125 | srcPath := h.Index + "/" + h.ID |
| 126 | out = append(out, types.RetrievalChunk{ |
| 127 | Text: text, |
| 128 | Source: srcPath, |
| 129 | Score: h.Score, |
| 130 | }) |
| 131 | } |
| 132 | return types.RetrievalResult{Chunks: out}, nil |
| 133 | } |
| 134 | |
| 135 | func firstString(m map[string]any, keys ...string) string { |
| 136 | for _, k := range keys { |