Compare commits
2 Commits
8e79e78006
...
FEAT-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
362a47f88a | ||
|
|
c6b07ccb56 |
@@ -8,11 +8,15 @@ In kongruity, the artifacts become "sticky notes." A board full of them looks ch
|
|||||||
|
|
||||||
With a click, they are semantically evaluated, grouped into thematic clusters with descriptive headers, rankable and exportable to project planning and execution tools.
|
With a click, they are semantically evaluated, grouped into thematic clusters with descriptive headers, rankable and exportable to project planning and execution tools.
|
||||||
|
|
||||||
|
## Voyage AI voyage-3.5
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Clustering and evaluation: methodology
|
## Clustering and evaluation: methodology
|
||||||
|
|
||||||
Two models run in parallel, and neither sees the other's work. Anthropic's `claude-sonnet-5` (`backend/services/clustering.service.js`) reads the raw text of every note and groups them into labeled thematic clusters.
|
Two models run in parallel, and neither sees the other's work. Anthropic's `claude-sonnet-5` (`backend/services/clustering.service.js`) reads the raw text of every note and groups them into labeled thematic clusters.
|
||||||
|
|
||||||
At the same time, Voyage AI's voyage-3 model (`backend/services/embedding.service.js`) converts each note's text into a numeric representation of its semantic meaning aka vector.
|
At the same time, Voyage AI's voyage-3.5 model (`backend/services/embedding.service.js`) converts each note's text into a numeric representation of its semantic meaning aka vector.
|
||||||
|
|
||||||
Once the LLM returns, kongruity scores that grouping (`backend/services/validation.service.js`) using an established silhouette coefficient, with cosine distance rather than Euclidean as the proximity metric.
|
Once the LLM returns, kongruity scores that grouping (`backend/services/validation.service.js`) using an established silhouette coefficient, with cosine distance rather than Euclidean as the proximity metric.
|
||||||
|
|
||||||
|
|||||||
BIN
Voyage.jpg
Normal file
BIN
Voyage.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
@@ -27,7 +27,7 @@ export const embedNotes = async (notes) => {
|
|||||||
for await (const chunk of batches) {
|
for await (const chunk of batches) {
|
||||||
const response = await client.embed({
|
const response = await client.embed({
|
||||||
input: chunk.map((n) => n.text),
|
input: chunk.map((n) => n.text),
|
||||||
model: "voyage-3",
|
model: "voyage-3.5",
|
||||||
});
|
});
|
||||||
|
|
||||||
response.data.forEach((item, i) => {
|
response.data.forEach((item, i) => {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ const Stickies = () => {
|
|||||||
<div className="clusters-container">
|
<div className="clusters-container">
|
||||||
{score != null && (
|
{score != null && (
|
||||||
<div className="cohesion-score">
|
<div className="cohesion-score">
|
||||||
Cluster cohesion: {scoreLabel(score)}
|
Cluster cohesion: <strong>{scoreLabel(score)}</strong>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{rankedClusters.map((group, index) => (
|
{rankedClusters.map((group, index) => (
|
||||||
|
|||||||
@@ -1,100 +1,107 @@
|
|||||||
.stickies-grid {
|
.stickies-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stickies-container {
|
.stickies-container {
|
||||||
margin: 36px 0px 36px 0px;
|
margin: 36px 0px 36px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clusters-container {
|
.clusters-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
padding: 24px 0;
|
padding: 24px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-group {
|
.cluster-group {
|
||||||
border: 1px solid #6dd6f4;
|
border: 1px solid #6dd6f4;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-draggable {
|
.cluster-draggable {
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
|
transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-draggable:active {
|
.cluster-draggable:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-drag-over {
|
.cluster-drag-over {
|
||||||
border-color: #ffb7ce;
|
border-color: #ffb7ce;
|
||||||
box-shadow: 0 0 12px rgba(255, 183, 206, 0.4);
|
box-shadow: 0 0 12px rgba(255, 183, 206, 0.4);
|
||||||
transform: scale(1.01);
|
transform: scale(1.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-header {
|
.cluster-header {
|
||||||
display: flex;
|
position: relative;
|
||||||
align-items: center;
|
display: flex;
|
||||||
gap: 12px;
|
align-items: center;
|
||||||
margin-bottom: 16px;
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
min-height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-rank {
|
.cluster-rank {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #6dd6f4;
|
background: #6dd6f4;
|
||||||
color: #1a1a2e;
|
color: #1a1a2e;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-reorder-hint {
|
.cluster-reorder-hint {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-label {
|
.cluster-label {
|
||||||
margin: 0;
|
position: absolute;
|
||||||
font-size: 1.2em;
|
left: 50%;
|
||||||
font-weight: 600;
|
transform: translateX(-50%);
|
||||||
flex: 1;
|
max-width: 50%;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: 600;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-drag-handle {
|
.cluster-drag-handle {
|
||||||
font-size: 1.4em;
|
margin-left: auto;
|
||||||
color: #6dd6f4;
|
font-size: 1.4em;
|
||||||
opacity: 0.4;
|
color: #6dd6f4;
|
||||||
user-select: none;
|
opacity: 0.4;
|
||||||
transition: opacity 0.2s ease;
|
user-select: none;
|
||||||
flex-shrink: 0;
|
transition: opacity 0.2s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-draggable:hover .cluster-drag-handle {
|
.cluster-draggable:hover .cluster-drag-handle {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cohesion-score {
|
.cohesion-score {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
background: rgba(109, 214, 244, 0.1);
|
background: rgba(109, 214, 244, 0.1);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user