langroid 0.32.0__py3-none-any.whl → 0.32.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. langroid/agent/base.py +3 -1
  2. langroid/language_models/openai_gpt.py +16 -1
  3. {langroid-0.32.0.dist-info → langroid-0.32.2.dist-info}/METADATA +2 -2
  4. {langroid-0.32.0.dist-info → langroid-0.32.2.dist-info}/RECORD +7 -41
  5. pyproject.toml +1 -1
  6. langroid/agent/.chainlit/config.toml +0 -121
  7. langroid/agent/.chainlit/translations/bn.json +0 -231
  8. langroid/agent/.chainlit/translations/en-US.json +0 -229
  9. langroid/agent/.chainlit/translations/gu.json +0 -231
  10. langroid/agent/.chainlit/translations/he-IL.json +0 -231
  11. langroid/agent/.chainlit/translations/hi.json +0 -231
  12. langroid/agent/.chainlit/translations/kn.json +0 -231
  13. langroid/agent/.chainlit/translations/ml.json +0 -231
  14. langroid/agent/.chainlit/translations/mr.json +0 -231
  15. langroid/agent/.chainlit/translations/ta.json +0 -231
  16. langroid/agent/.chainlit/translations/te.json +0 -231
  17. langroid/agent/.chainlit/translations/zh-CN.json +0 -229
  18. langroid/agent/helpers.py +0 -0
  19. langroid/agent/junk +0 -13
  20. langroid/agent/structured_message.py +0 -9
  21. langroid/agent/typed_task.py +0 -19
  22. langroid/agent_config.py +0 -0
  23. langroid/embedding_models/clustering.py +0 -189
  24. langroid/experimental/team-save.py +0 -391
  25. langroid/language_models/.chainlit/config.toml +0 -121
  26. langroid/language_models/.chainlit/translations/en-US.json +0 -231
  27. langroid/parsing/code-parsing.md +0 -86
  28. langroid/parsing/config.py +0 -0
  29. langroid/parsing/image_text.py +0 -32
  30. langroid/parsing/url_loader_cookies.py +0 -73
  31. langroid/prompts/chat-gpt4-system-prompt.md +0 -68
  32. langroid/utils/.chainlit/config.toml +0 -121
  33. langroid/utils/.chainlit/translations/en-US.json +0 -231
  34. langroid/utils/docker.py +0 -37
  35. langroid/utils/llms/__init__.py +0 -0
  36. langroid/utils/llms/strings.py +0 -8
  37. langroid/utils/web/__init__.py +0 -0
  38. langroid/utils/web/login.py +0 -83
  39. langroid/vector_store/qdrant_cloud.py +0 -6
  40. {langroid-0.32.0.dist-info → langroid-0.32.2.dist-info}/LICENSE +0 -0
  41. {langroid-0.32.0.dist-info → langroid-0.32.2.dist-info}/WHEEL +0 -0
@@ -1,189 +0,0 @@
1
- import logging
2
- from collections import Counter
3
- from typing import Callable, List, Tuple
4
-
5
- import faiss
6
- import numpy as np
7
- from sklearn.cluster import DBSCAN
8
- from sklearn.neighbors import NearestNeighbors
9
- from sklearn.preprocessing import StandardScaler
10
-
11
- from langroid.mytypes import Document
12
-
13
- logging.getLogger("faiss").setLevel(logging.ERROR)
14
- logging.getLogger("faiss-cpu").setLevel(logging.ERROR)
15
-
16
-
17
- def find_optimal_clusters(X: np.ndarray, max_clusters: int, threshold=0.1) -> int:
18
- """
19
- Find the optimal number of clusters for FAISS K-means using the Elbow Method.
20
-
21
- Args:
22
- X (np.ndarray): A 2D NumPy array of data points.
23
- max_clusters (int): The maximum number of clusters to try.
24
- threshold (float): Threshold for the rate of change in inertia values.
25
- Defaults to 0.1.
26
-
27
- Returns:
28
- int: The optimal number of clusters.
29
- """
30
- inertias = []
31
- max_clusters = min(max_clusters, X.shape[0])
32
- cluster_range = range(1, max_clusters + 1)
33
-
34
- for nclusters in cluster_range:
35
- kmeans = faiss.Kmeans(X.shape[1], nclusters, niter=20, verbose=False)
36
- kmeans.train(X)
37
- centroids = kmeans.centroids
38
- distances = np.sum(np.square(X[:, None] - centroids), axis=-1)
39
- inertia = np.sum(np.min(distances, axis=-1))
40
- inertias.append(inertia)
41
-
42
- # Calculate the rate of change in inertia values
43
- rate_of_change = [
44
- abs((inertias[i + 1] - inertias[i]) / inertias[i])
45
- for i in range(len(inertias) - 1)
46
- ]
47
-
48
- # Find the optimal number of clusters based on the rate of change threshold
49
- optimal_clusters = 1
50
- for i, roc in enumerate(rate_of_change):
51
- if roc < threshold:
52
- optimal_clusters = i + 1
53
- break
54
-
55
- return optimal_clusters
56
-
57
-
58
- def densest_clusters(
59
- embeddings: List[np.ndarray], k: int = 5
60
- ) -> List[Tuple[np.ndarray, int]]:
61
- """
62
- Find the top k densest clusters in the given list of embeddings using FAISS K-means.
63
- See here:
64
- 'https://github.com/facebookresearch/faiss/wiki/Faiss-building-blocks%3A-clustering%
65
- 2C-PCA%2C-quantization'
66
-
67
- Args:
68
- embeddings (List[np.ndarray]): A list of embedding vectors.
69
- k (int, optional): The number of densest clusters to find. Defaults to 5.
70
-
71
- Returns:
72
- List[Tuple[np.ndarray, int]]: A list of representative vectors and their indices
73
- from the k densest clusters.
74
- """
75
- # Convert the list of embeddings to a NumPy array
76
- X = np.vstack(embeddings)
77
-
78
- # FAISS K-means clustering
79
- ncentroids = find_optimal_clusters(X, max_clusters=2 * k, threshold=0.1)
80
- k = min(k, ncentroids)
81
- niter = 20
82
- verbose = True
83
- d = X.shape[1]
84
- kmeans = faiss.Kmeans(d, k, niter=niter, verbose=verbose)
85
- kmeans.train(X)
86
-
87
- # Get the cluster centroids
88
- centroids = kmeans.centroids
89
-
90
- # Find the nearest neighbors of the centroids in the original embeddings
91
- nbrs = NearestNeighbors(n_neighbors=1, algorithm="auto").fit(X)
92
- distances, indices = nbrs.kneighbors(centroids)
93
-
94
- # Sort the centroids by their nearest neighbor distances
95
- sorted_centroids_indices = np.argsort(distances, axis=0).flatten()
96
-
97
- # Select the top k densest clusters
98
- densest_clusters_indices = sorted_centroids_indices[:k]
99
-
100
- # Get the representative vectors and their indices from the densest clusters
101
- representative_vectors = [
102
- (idx, embeddings[idx]) for idx in densest_clusters_indices
103
- ]
104
-
105
- return representative_vectors
106
-
107
-
108
- def densest_clusters_DBSCAN(
109
- embeddings: np.ndarray, k: int = 10
110
- ) -> List[Tuple[int, np.ndarray]]:
111
- """
112
- Find the representative vector and corresponding index from each of the k densest
113
- clusters in the given embeddings.
114
-
115
- Args:
116
- embeddings (np.ndarray): A NumPy array of shape (n, d), where n is the number
117
- of embedding vectors and d is their dimensionality.
118
- k (int): Number of densest clusters to find.
119
-
120
- Returns:
121
- List[Tuple[int, np.ndarray]]: A list of tuples containing the index and
122
- representative vector for each of the k densest
123
- clusters.
124
- """
125
-
126
- # Normalize the embeddings if necessary
127
- scaler = StandardScaler()
128
- embeddings_normalized = scaler.fit_transform(embeddings)
129
-
130
- # Choose a clustering algorithm (DBSCAN in this case)
131
- # Tune eps and min_samples for your use case
132
- dbscan = DBSCAN(eps=4, min_samples=5)
133
-
134
- # Apply the clustering algorithm
135
- cluster_labels = dbscan.fit_predict(embeddings_normalized)
136
-
137
- # Compute the densities of the clusters
138
- cluster_density = Counter(cluster_labels)
139
-
140
- # Sort clusters by their density
141
- sorted_clusters = sorted(cluster_density.items(), key=lambda x: x[1], reverse=True)
142
-
143
- # Select top-k densest clusters
144
- top_k_clusters = sorted_clusters[:k]
145
-
146
- # Find a representative vector for each cluster
147
- representatives = []
148
- for cluster_id, _ in top_k_clusters:
149
- if cluster_id == -1:
150
- continue # Skip the noise cluster (label -1)
151
- indices = np.where(cluster_labels == cluster_id)[0]
152
- centroid = embeddings[indices].mean(axis=0)
153
- closest_index = indices[
154
- np.argmin(np.linalg.norm(embeddings[indices] - centroid, axis=1))
155
- ]
156
- representatives.append((closest_index, embeddings[closest_index]))
157
-
158
- return representatives
159
-
160
-
161
- def densest_doc_clusters(
162
- docs: List[Document], k: int, embedding_fn: Callable[[str], np.ndarray]
163
- ) -> List[Document]:
164
- """
165
- Find the documents corresponding to the representative vectors of the k densest
166
- clusters in the given list of documents.
167
-
168
- Args:
169
- docs (List[Document]): A list of Document instances, each containing a "content"
170
- field to be embedded and a "metadata" field.
171
- k (int): Number of densest clusters to find.
172
- embedding_fn (Callable[[str], np.ndarray]): A function that maps a string to an
173
- embedding vector.
174
-
175
- Returns:
176
- List[Document]: A list of Document instances corresponding to the representative
177
- vectors of the k densest clusters.
178
- """
179
-
180
- # Extract embeddings from the documents
181
- embeddings = np.array(embedding_fn([doc.content for doc in docs]))
182
-
183
- # Find the densest clusters and their representative indices
184
- representative_indices_and_vectors = densest_clusters(embeddings, k)
185
-
186
- # Extract the corresponding documents
187
- representative_docs = [docs[i] for i, _ in representative_indices_and_vectors]
188
-
189
- return representative_docs
@@ -1,391 +0,0 @@
1
- import logging
2
- from abc import ABC, abstractmethod
3
- from typing import Callable, Dict, List, Optional, Union
4
-
5
- import langroid as lr
6
- from langroid.language_models.mock_lm import MockLMConfig
7
-
8
- # Fix logging level type
9
- logging.basicConfig(level=logging.WARNING)
10
- logger = logging.getLogger(__name__)
11
-
12
-
13
- def sum_fn(s: str) -> str:
14
- """Dummy response for MockLM"""
15
- nums = [
16
- int(subpart)
17
- for part in s.split()
18
- for subpart in part.split(",")
19
- if subpart.isdigit()
20
- ]
21
- return str(sum(nums) + 1)
22
-
23
-
24
- def user_message(msg: Union[str, lr.ChatDocument]) -> lr.ChatDocument:
25
- """Create a user-role msg from a string or ChatDocument"""
26
- if isinstance(msg, lr.ChatDocument):
27
- return msg
28
- return lr.ChatDocument(
29
- content=msg,
30
- metadata=lr.ChatDocMetaData(
31
- sender=lr.Entity.USER,
32
- sender_name="user",
33
- ),
34
- )
35
-
36
-
37
- class InputContext:
38
- """Context for a Component to respond to"""
39
-
40
- def __init__(self) -> None:
41
- self.messages: List[lr.ChatDocument] = []
42
-
43
- def add(
44
- self, results: Union[str, List[str], lr.ChatDocument, List[lr.ChatDocument]]
45
- ) -> None:
46
- """
47
- Add messages to the input messages list
48
- """
49
- msgs: List[lr.ChatDocument] = []
50
- if isinstance(results, str):
51
- msgs = [user_message(results)]
52
- elif isinstance(results, lr.ChatDocument):
53
- msgs = [results]
54
- elif isinstance(results, list):
55
- if len(results) == 0:
56
- return
57
- if isinstance(results[0], str):
58
- msgs = [user_message(r) for r in results]
59
- else:
60
- msgs = [r for r in results if isinstance(r, lr.ChatDocument)]
61
- self.messages.extend(msgs)
62
-
63
- def clear(self) -> None:
64
- self.messages.clear()
65
-
66
- def get_context(self) -> lr.ChatDocument:
67
- """Construct a user-role ChatDocument from the input messages"""
68
- if len(self.messages) == 0:
69
- return lr.ChatDocument(content="", metadata={"sender": lr.Entity.USER})
70
- content = "\n".join(
71
- f"{msg.metadata.sender_name}: {msg.content}" for msg in self.messages
72
- )
73
- return lr.ChatDocument(content=content, metadata={"sender": lr.Entity.USER})
74
-
75
-
76
- class Scheduler(ABC):
77
- """Schedule the Components of a Team"""
78
-
79
- def __init__(self) -> None:
80
- self.init_state()
81
-
82
- def init_state(self) -> None:
83
- self.stepped = False
84
- self.responders: List[str] = []
85
- self.responder_counts: Dict[str, int] = {}
86
- self.current_result: List[lr.ChatDocument] = []
87
-
88
- @abstractmethod
89
- def step(self) -> None:
90
- pass
91
-
92
- @abstractmethod
93
- def done(self) -> bool:
94
- pass
95
-
96
- @abstractmethod
97
- def result(self) -> List[lr.ChatDocument]:
98
- pass
99
-
100
- def run(self) -> List[lr.ChatDocument]:
101
- self.init_state()
102
- while not self.done():
103
- self.step()
104
- return self.result()
105
-
106
-
107
- class Component(ABC):
108
- """A component of a Team"""
109
-
110
- def __init__(self) -> None:
111
- self.input = InputContext()
112
- self._listeners: List["Component"] = []
113
- self.name: str = ""
114
-
115
- @abstractmethod
116
- def run(self) -> List[lr.ChatDocument]:
117
- pass
118
-
119
- def listen(self, component: Union["Component", List["Component"]]) -> None:
120
- if isinstance(component, list):
121
- for comp in component:
122
- comp.listeners.append(self)
123
- else:
124
- component.listeners.append(self)
125
-
126
- @property
127
- def listeners(self) -> List["Component"]:
128
- return self._listeners
129
-
130
- def _notify(self, results: List[lr.ChatDocument]) -> None:
131
- logger.warning(f"{self.name} Notifying listeners...")
132
- for listener in self.listeners:
133
- logger.warning(f"--> Listener {listener.name} notified")
134
- listener.input.add(results)
135
-
136
-
137
- class SimpleScheduler(Scheduler):
138
- def __init__(
139
- self,
140
- components: List[Component],
141
- ) -> None:
142
- super().__init__()
143
- self.components = components # Get components from team
144
- self.stepped: bool = False
145
-
146
- def step(self) -> None:
147
- results = []
148
- for comp in self.components:
149
- result = comp.run()
150
- if result:
151
- results.extend(result)
152
- self.current_result = results
153
- self.stepped = True
154
-
155
- def done(self) -> bool:
156
- """done after 1 step, i.e. all components have responded"""
157
- return self.stepped
158
-
159
- def result(self) -> List[lr.ChatDocument]:
160
- return self.current_result
161
-
162
-
163
- class OrElseScheduler(Scheduler):
164
- """
165
- Implements "OrElse scheduling", i.e. if the components are A, B, C, then
166
- in each step, it will try for a valid response from A OrElse B OrElse C,
167
- i.e. the first component that gives a valid response is chosen.
168
- In the next step, it will start from the next component in the list,
169
- cycling back to the first component after the last component.
170
- (There may be a better name than OrElseScheduler though.)
171
- """
172
-
173
- def __init__(
174
- self,
175
- components: List[Component],
176
- ) -> None:
177
- super().__init__()
178
- self.components = components
179
- self.team: Optional[Team] = None
180
- self.current_index: int = 0
181
-
182
- def init_state(self) -> None:
183
- super().init_state()
184
- self.current_index = 0
185
-
186
- def is_valid(self, result: Optional[List[lr.ChatDocument]]) -> bool:
187
- return result is not None and len(result) > 0
188
-
189
- def step(self) -> None:
190
- start_index = self.current_index
191
- n = len(self.components)
192
-
193
- for i in range(n):
194
- idx = (start_index + i) % n
195
- comp = self.components[idx]
196
- result = comp.run()
197
- if self.is_valid(result):
198
- self.responders.append(comp.name)
199
- self.responder_counts[comp.name] = (
200
- self.responder_counts.get(comp.name, 0) + 1
201
- )
202
- self.current_result = result
203
- # cycle to next component
204
- self.current_index = (idx + 1) % n
205
- return
206
-
207
- def done(self) -> bool:
208
- if self.team is None:
209
- return False
210
- return self.team.done(self)
211
-
212
- def result(self) -> List[lr.ChatDocument]:
213
- return self.current_result
214
-
215
-
216
- class Team(Component):
217
- def __init__(
218
- self,
219
- name: str,
220
- done_condition: Optional[Callable[["Team", Scheduler], bool]] = None,
221
- ) -> None:
222
- super().__init__()
223
- self.name = name
224
- self.components: List[Component] = []
225
- self.scheduler: Optional[Scheduler] = None
226
- self.done_condition = done_condition or Team.default_done_condition
227
-
228
- def set_done_condition(
229
- self, done_condition: Callable[["Team", Scheduler], bool]
230
- ) -> None:
231
- self.done_condition = done_condition
232
-
233
- def done(self, scheduler: Scheduler) -> bool:
234
- return self.done_condition(self, scheduler)
235
-
236
- def default_done_condition(self, scheduler: Scheduler) -> bool:
237
- # Default condition, can be overridden
238
- return False
239
-
240
- def add_scheduler(self, scheduler_class: type) -> None:
241
- self.scheduler = scheduler_class(self.components)
242
- if hasattr(self.scheduler, "team"):
243
- setattr(self.scheduler, "team", self)
244
-
245
- def add(self, component: Union[Component, List[Component]]) -> None:
246
- if isinstance(component, list):
247
- self.components.extend(component)
248
- else:
249
- self.components.append(component)
250
-
251
- def reset(self) -> None:
252
- self.input.clear()
253
- if self.scheduler is not None:
254
- self.scheduler.init_state()
255
-
256
- def run(self, input: str | lr.ChatDocument | None = None) -> List[lr.ChatDocument]:
257
- if input is not None:
258
- self.input.add(input)
259
- if self.scheduler is None:
260
- raise ValueError(
261
- f"Team '{self.name}' has no scheduler. Call add_scheduler() first."
262
- )
263
- input_str = self.input.get_context().content
264
- logger.warning(f"Running team {self.name}... on input = {input_str}")
265
- # push the input of self to each component that's a listener of self.
266
- n_pushed = 0
267
- for comp in self.components:
268
-
269
- if comp in self.listeners:
270
- comp.input.add(self.input.messages)
271
- n_pushed += 1
272
- if len(self.input.messages) > 0 and n_pushed == 0:
273
- logger.warning(
274
- """
275
- Warning: Team inputs not pushed to any components!
276
- You may not be able to run any components unless they have their
277
- own inputs. Make sure to set up component to listen to parent team
278
- if needed.
279
- """
280
- )
281
- # clear own input since we've pushed it to internal components
282
- self.input.clear()
283
-
284
- result = self.scheduler.run()
285
- if len(result) > 0:
286
- self._notify(result)
287
- result_value = result[0].content if len(result) > 0 else "null"
288
- logger.warning(f"Team {self.name} done: {result_value}")
289
- return result
290
-
291
-
292
- class DummyAgent:
293
- def __init__(self, name: str) -> None:
294
- self.name = name
295
-
296
- def process(self, data: str) -> str:
297
- return f"{self.name} processed: {data}"
298
-
299
-
300
- class TaskComponent(Component):
301
- def __init__(self, task: lr.Task) -> None:
302
- super().__init__()
303
- self.task = task
304
- self.name = task.agent.config.name
305
-
306
- def run(self, input: str | lr.ChatDocument | None = None) -> List[lr.ChatDocument]:
307
- if input is not None:
308
- self.input.add(input)
309
- input_msg = self.input.get_context()
310
- if input_msg.content == "":
311
- return []
312
- logger.warning(f"Running task {self.name} on input = {input_msg.content}")
313
- result = self.task.run(input_msg)
314
- result_value = result.content if result else "null"
315
- logger.warning(f"Task {self.name} done: {result_value}")
316
- result_list = [result] if result else []
317
- if len(result_list) > 0:
318
- self._notify(result_list)
319
- self.input.clear() # clear own input since we just consumed it!
320
- return result_list
321
-
322
-
323
- def make_task(name: str, sys: str = "") -> TaskComponent:
324
- llm_config = MockLMConfig(response_fn=sum_fn)
325
- agent = lr.ChatAgent(
326
- lr.ChatAgentConfig(
327
- llm=llm_config,
328
- name=name,
329
- )
330
- )
331
- # set as single_round since there are no Tools
332
- task = lr.Task(agent, interactive=False, single_round=True)
333
- return TaskComponent(task)
334
-
335
-
336
- if __name__ == "__main__":
337
- # Create agents, tasks
338
- t1 = make_task("a1")
339
- t2 = make_task("a2")
340
- t3 = make_task("a3")
341
-
342
- # done conditions for each time
343
- def team1_done_condition(team: Team, scheduler: Scheduler) -> bool:
344
- return (
345
- scheduler.responder_counts.get("a1", 0) >= 2
346
- and scheduler.responder_counts.get("a2", 0) >= 2
347
- )
348
-
349
- def team2_done_condition(team: Team, scheduler: Scheduler) -> bool:
350
- return "a3" in scheduler.responders
351
-
352
- def general_team_done_condition(team: Team, scheduler: Scheduler) -> bool:
353
- # Example: all components have responded at least once
354
- return len(set(scheduler.responders)) == len(team.components)
355
-
356
- # Create teams
357
- team1 = Team("T1", done_condition=team1_done_condition)
358
- team2 = Team("T2", done_condition=team2_done_condition)
359
-
360
- team = Team("Team", done_condition=general_team_done_condition)
361
-
362
- team1.add_scheduler(OrElseScheduler)
363
- team2.add_scheduler(OrElseScheduler)
364
- team.add_scheduler(OrElseScheduler)
365
-
366
- team.add([team1, team2])
367
-
368
- # Build hierarchy
369
- team1.add([t1, t2])
370
- team2.add(t3)
371
-
372
- # Set up listening
373
- # team2.listen(team1) # listens to team1 final result
374
- team1.listen(team)
375
- t1.listen(team1)
376
- t2.listen(t1)
377
- t1.listen(t2)
378
- # TODO should we forbid listening to a component OUTSIDE the team?
379
-
380
- # t3 listens to its parent team2 =>
381
- # any input to team2 gets pushed to t3 when t3 runs
382
- team2.listen([t1, t2])
383
- t3.listen(team2)
384
-
385
- # TODO - we should either define which component of a team gets the teams inputs,
386
- # or explicitly add messages to a specific component of the team
387
-
388
- print("Running top-level team...")
389
- result = team.run("1")
390
-
391
- ##########
@@ -1,121 +0,0 @@
1
- [project]
2
- # Whether to enable telemetry (default: true). No personal data is collected.
3
- enable_telemetry = true
4
-
5
-
6
- # List of environment variables to be provided by each user to use the app.
7
- user_env = []
8
-
9
- # Duration (in seconds) during which the session is saved when the connection is lost
10
- session_timeout = 3600
11
-
12
- # Enable third parties caching (e.g LangChain cache)
13
- cache = false
14
-
15
- # Authorized origins
16
- allow_origins = ["*"]
17
-
18
- # Follow symlink for asset mount (see https://github.com/Chainlit/chainlit/issues/317)
19
- # follow_symlink = false
20
-
21
- [features]
22
- # Show the prompt playground
23
- prompt_playground = true
24
-
25
- # Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript)
26
- unsafe_allow_html = false
27
-
28
- # Process and display mathematical expressions. This can clash with "$" characters in messages.
29
- latex = false
30
-
31
- # Automatically tag threads with the current chat profile (if a chat profile is used)
32
- auto_tag_thread = true
33
-
34
- # Authorize users to spontaneously upload files with messages
35
- [features.spontaneous_file_upload]
36
- enabled = true
37
- accept = ["*/*"]
38
- max_files = 20
39
- max_size_mb = 500
40
-
41
- [features.audio]
42
- # Threshold for audio recording
43
- min_decibels = -45
44
- # Delay for the user to start speaking in MS
45
- initial_silence_timeout = 3000
46
- # Delay for the user to continue speaking in MS. If the user stops speaking for this duration, the recording will stop.
47
- silence_timeout = 1500
48
- # Above this duration (MS), the recording will forcefully stop.
49
- max_duration = 15000
50
- # Duration of the audio chunks in MS
51
- chunk_duration = 1000
52
- # Sample rate of the audio
53
- sample_rate = 44100
54
-
55
- [UI]
56
- # Name of the app and chatbot.
57
- name = "Chatbot"
58
-
59
- # Show the readme while the thread is empty.
60
- show_readme_as_default = true
61
-
62
- # Description of the app and chatbot. This is used for HTML tags.
63
- # description = ""
64
-
65
- # Large size content are by default collapsed for a cleaner ui
66
- default_collapse_content = true
67
-
68
- # The default value for the expand messages settings.
69
- default_expand_messages = false
70
-
71
- # Hide the chain of thought details from the user in the UI.
72
- hide_cot = false
73
-
74
- # Link to your github repo. This will add a github button in the UI's header.
75
- # github = ""
76
-
77
- # Specify a CSS file that can be used to customize the user interface.
78
- # The CSS file can be served from the public directory or via an external link.
79
- # custom_css = "/public/test.css"
80
-
81
- # Specify a Javascript file that can be used to customize the user interface.
82
- # The Javascript file can be served from the public directory.
83
- # custom_js = "/public/test.js"
84
-
85
- # Specify a custom font url.
86
- # custom_font = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap"
87
-
88
- # Specify a custom meta image url.
89
- # custom_meta_image_url = "https://chainlit-cloud.s3.eu-west-3.amazonaws.com/logo/chainlit_banner.png"
90
-
91
- # Specify a custom build directory for the frontend.
92
- # This can be used to customize the frontend code.
93
- # Be careful: If this is a relative path, it should not start with a slash.
94
- # custom_build = "./public/build"
95
-
96
- [UI.theme]
97
- #layout = "wide"
98
- #font_family = "Inter, sans-serif"
99
- # Override default MUI light theme. (Check theme.ts)
100
- [UI.theme.light]
101
- #background = "#FAFAFA"
102
- #paper = "#FFFFFF"
103
-
104
- [UI.theme.light.primary]
105
- #main = "#F80061"
106
- #dark = "#980039"
107
- #light = "#FFE7EB"
108
-
109
- # Override default MUI dark theme. (Check theme.ts)
110
- [UI.theme.dark]
111
- #background = "#FAFAFA"
112
- #paper = "#FFFFFF"
113
-
114
- [UI.theme.dark.primary]
115
- #main = "#F80061"
116
- #dark = "#980039"
117
- #light = "#FFE7EB"
118
-
119
-
120
- [meta]
121
- generated_by = "1.1.202"