Skip to content

Commit 9d635c5

Browse files
committed
user image, single result
1 parent 3b318c6 commit 9d635c5

File tree

8 files changed

+57
-50
lines changed

8 files changed

+57
-50
lines changed

app/data_sources/mattermost.py

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import logging
2-
from datetime import datetime
3-
from urllib.parse import urlparse
42
from dataclasses import dataclass, asdict
5-
from typing import Dict, List, Optional
3+
from datetime import datetime
64
from functools import lru_cache
5+
from typing import Dict, List, Optional
6+
from urllib.parse import urlparse
77

88
from mattermostdriver import Driver
99

@@ -13,7 +13,6 @@
1313
from data_source_api.utils import parse_with_workers
1414
from indexing_queue import IndexingQueue
1515

16-
1716
logger = logging.getLogger(__name__)
1817

1918

@@ -23,136 +22,126 @@ class MattermostChannel:
2322
name: str
2423
team_id: str
2524

25+
2626
@dataclass
2727
class MattermostConfig:
2828
url: str
2929
token: str
3030
scheme: Optional[str] = "https"
3131
port: Optional[int] = 443
32-
32+
3333
def __post_init__(self):
3434
try:
3535
parsed_url = urlparse(self.url)
3636
except Exception as e:
3737
raise ValueError from e
38-
38+
3939
self.url = parsed_url.hostname
4040
self.port = parsed_url.port if parsed_url.port is not None else self.port
4141
self.scheme = parsed_url.scheme if parsed_url.scheme != "" else self.scheme
4242

43-
4443

4544
class MattermostDataSource(BaseDataSource):
4645
FEED_BATCH_SIZE = 500
4746

4847
@staticmethod
4948
def get_config_fields() -> List[ConfigField]:
5049
return [
51-
ConfigField(label="Mattermost Server", name="url", placeholder="https://mattermost.server.com", input_type=HTMLInputType.TEXT),
52-
ConfigField(label="Token", name="token", placeholder="paste-your-token-here", input_type=HTMLInputType.PASSWORD),
50+
ConfigField(label="Mattermost Server", name="url", placeholder="https://mattermost.server.com",
51+
input_type=HTMLInputType.TEXT),
52+
ConfigField(label="Access Token", name="token", placeholder="paste-your-access-token-here",
53+
input_type=HTMLInputType.PASSWORD),
5354
]
5455

55-
5656
@staticmethod
5757
def validate_config(config: Dict) -> None:
5858
try:
5959
parsed_config = MattermostConfig(**config)
60-
maattermost = Driver(options = asdict(parsed_config))
60+
maattermost = Driver(options=asdict(parsed_config))
6161
maattermost.login()
6262
except Exception as e:
6363
raise InvalidDataSourceConfig from e
6464

65-
6665
def __init__(self, *args, **kwargs):
6766
super().__init__(*args, **kwargs)
6867
mattermost_config = MattermostConfig(**self._config)
69-
self._mattermost = Driver(options = asdict(mattermost_config))
70-
71-
68+
self._mattermost = Driver(options=asdict(mattermost_config))
69+
7270
def _list_channels(self) -> List[MattermostChannel]:
7371
channels = self._mattermost.channels.client.get(f"/users/me/channels")
7472
return [MattermostChannel(id=channel["id"], name=channel["name"], team_id=channel["team_id"])
7573
for channel in channels]
7674

77-
7875
def _is_valid_message(self, message: Dict) -> bool:
79-
return message["type"] == ""
80-
81-
76+
return message["type"] == ""
77+
8278
def _is_valid_channel(self, channel: MattermostChannel) -> bool:
8379
return channel.team_id != ""
84-
85-
80+
8681
def _list_posts_in_channel(self, channel_id: str, page: int) -> Dict:
8782
endpoint = f"/channels/{channel_id}/posts"
8883
params = {
8984
"since": int(self._last_index_time.timestamp()) * 1000,
9085
"page": page
9186
}
92-
87+
9388
posts = self._mattermost.channels.client.get(endpoint, params=params)
9489
return posts
9590

96-
9791
def _feed_new_documents(self) -> None:
9892
self._mattermost.login()
9993
channels = self._list_channels()
100-
94+
10195
logger.info(f'Found {len(channels)} channels')
10296
parse_with_workers(self._parse_channel_worker, channels)
10397

104-
105-
def _parse_channel_worker(self, channels: List[MattermostChannel]):
98+
def _parse_channel_worker(self, channels: List[MattermostChannel]):
10699
for channel in channels:
107100
self._feed_channel(channel)
108101

109-
110102
def _get_mattermost_url(self):
111103
options = self._mattermost.options
112104
return f"{options['scheme']}://{options['url']}:{options['port']}"
113105

114-
115106
def _get_team_url(self, channel: MattermostChannel):
116107
url = self._get_mattermost_url()
117108
team = self._mattermost.teams.get_team(channel.team_id)
118109
return f"{url}/{team['name']}"
119-
120-
110+
121111
@lru_cache(maxsize=512)
122112
def _get_mattermost_user(self, user_id: str):
123113
return self._mattermost.users.get_user(user_id)["username"]
124-
125-
114+
126115
def _feed_channel(self, channel: MattermostChannel):
127116
if not self._is_valid_channel(channel):
128-
return
117+
return
129118
logger.info(f'Feeding channel {channel.name}')
130-
119+
131120
page = 0
132121
total_fed = 0
133-
122+
134123
parsed_posts = []
135-
124+
136125
team_url = self._get_team_url(channel)
137-
126+
138127
while True:
139128
posts = self._list_posts_in_channel(channel.id, page)
140129

141130
last_message: Optional[BasicDocument] = None
142-
131+
143132
posts["order"].reverse()
144133
for id in posts["order"]:
145134
post = posts["posts"][id]
146-
135+
147136
if not self._is_valid_message(post):
148137
if last_message is not None:
149138
parsed_posts.append(last_message)
150139
last_message = None
151140
continue
152-
141+
153142
author = self._get_mattermost_user(post["user_id"])
154143
content = post["message"]
155-
144+
156145
if last_message is not None:
157146
if last_message.author == author:
158147
last_message.content += f"\n{content}"
@@ -163,7 +152,7 @@ def _feed_channel(self, channel: MattermostChannel):
163152
total_fed += len(parsed_posts)
164153
IndexingQueue.get().feed(docs=parsed_posts)
165154
parsed_posts = []
166-
155+
167156
author_image_url = f"{self._get_mattermost_url()}/api/v4/users/{post['user_id']}/image?_=0"
168157
timestamp = datetime.fromtimestamp(post["update_at"] / 1000)
169158
last_message = BasicDocument(
@@ -178,18 +167,16 @@ def _feed_channel(self, channel: MattermostChannel):
178167
url=f"{team_url}/pl/{id}",
179168
type=DocumentType.MESSAGE
180169
)
181-
170+
182171
if last_message is not None:
183172
parsed_posts.append(last_message)
184173

185174
if posts["prev_post_id"] == "":
186175
break
187176
page += 1
188-
189177

190178
IndexingQueue.get().feed(docs=parsed_posts)
191179
total_fed += len(parsed_posts)
192180

193181
if len(parsed_posts) > 0:
194182
logger.info(f"Worker fed {total_fed} documents")
195-

app/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ google-auth-oauthlib
1919
oauth2client
2020
mammoth
2121
python-pptx
22-
alembic
22+
alembic
23+
mattermostdriver

app/search_logic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ def _assign_answer_sentence(candidate: Candidate, answer: str):
155155
def _find_answers_in_candidates(candidates: List[Candidate], query: str) -> List[Candidate]:
156156
contexts = [candidate.content for candidate in candidates]
157157
answers = qa_model(question=[query] * len(contexts), context=contexts)
158+
159+
if type(answers) == dict:
160+
answers = [answers]
161+
158162
for candidate, answer in zip(candidates, answers):
159163
_assign_answer_sentence(candidate, answer['answer'])
160164

ui/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"react": "^18.2.0",
1515
"react-dom": "^18.2.0",
1616
"react-icons": "^4.8.0",
17+
"react-image": "^4.1.0",
1718
"react-modal": "^3.16.1",
1819
"react-scripts": "5.0.1",
1920
"react-select": "^5.7.0",

ui/src/assets/images/user.webp

2.33 KB
Binary file not shown.

ui/src/components/data-source-panel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ export default class DataSourcePanel extends React.Component<DataSourcePanelProp
202202
<span>1. {'Go to your Mattermost -> top-right profile picture -> Profile'}</span>
203203
<span>2. {'Security -> Personal Access Tokens -> Create token -> Name it'}</span>
204204
<span>3. {"Copy the Access Token"}</span>
205-
<span className="text-violet-300/[.75] text-sm"> {"* Personal Access Tokens must be on"} - <a className="inline hover:underline text-violet-400/[.75]" target="_blank" href="https://developers.mattermost.com/integrate/reference/personal-access-token/">For more info</a></span>
205+
<span className="text-violet-300/[.75] text-sm"> {"* Personal Access Tokens must be on"} - <a className="inline hover:underline text-violet-400/[.75]" target="_blank" href="https://developers.mattermost.com/integrate/reference/personal-access-token/">Click for more info</a></span>
206206
</span>
207207
)
208208
}

ui/src/components/search-result.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11

22
import React from 'react';
3+
import {Img} from 'react-image'
34

45
import BlueFolder from '../assets/images/blue-folder.svg';
56
import GoogleDoc from '../assets/images/google-doc.svg';
67
import Docx from '../assets/images/docx.svg';
78
import Pptx from '../assets/images/pptx.svg';
9+
import DefaultUserImage from '../assets/images/user.webp';
810
import { DataSourceType } from '../data-source';
911

10-
1112
export interface TextPart {
1213
content: string
1314
bold: boolean
@@ -69,7 +70,9 @@ export const SearchResult = (props: SearchResultProps) => {
6970
{props.resultDetails.location} ·&thinsp;
7071
</span>
7172
<span className="flex flex-row items-center">
72-
<img alt="author" className="inline-block ml-2 mr-2 h-4 rounded-xl" src={props.resultDetails.author_image_data ? props.resultDetails.author_image_data : props.resultDetails.author_image_url}></img>
73+
74+
<Img alt="author" className="inline-block ml-2 mr-2 h-4 rounded-xl"
75+
src={[props.resultDetails.author_image_url, props.resultDetails.author_image_data, DefaultUserImage]}></Img>
7376
<span className='capitalize'>{props.resultDetails.author} ·</span>
7477
</span>
7578
<span>
@@ -151,7 +154,7 @@ function getBigIcon(props: SearchResultProps) {
151154
if (onTopImage !== "") {
152155
return (
153156
<div className="mt-2 mr-[10px] drop-shadow-[0_0_25px_rgba(212,179,255,0.15)]">
154-
<img height={"45px"} width={"45px"} className={containingClasses} alt="file-type" src={containingImage}></img>
157+
<Img height={"45px"} width={"45px"} className={containingClasses} alt="file-type" src={[containingImage, DefaultUserImage]}/>
155158
<img alt="file-type" className="company-logo rounded-full p-[3px] h-[24px] w-[24px] absolute -right-[5px] -bottom-[5px] bg-white" src={onTopImage}></img>
156159
</div>
157160
)

0 commit comments

Comments
 (0)