116 lines
3.8 KiB
Go
116 lines
3.8 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/andydixon/relata/internal/api"
|
|
"github.com/andydixon/relata/internal/relationships"
|
|
)
|
|
|
|
// publicBase carries what every public page needs.
|
|
//
|
|
// It deliberately does not embed `base`: the shared page context reads the
|
|
// pending-review count from the database, and a page served to an anonymous
|
|
// visitor must touch no workspace data at all.
|
|
type publicBase struct {
|
|
Title string
|
|
Version string
|
|
SignedIn bool
|
|
OAuthEnabled bool
|
|
LocalEnabled bool
|
|
ProviderName string
|
|
RequestID string
|
|
}
|
|
|
|
func (h *Handlers) newPublicBase(r *http.Request, title string) publicBase {
|
|
return publicBase{
|
|
Title: title,
|
|
Version: h.d.Version,
|
|
SignedIn: api.PrincipalFrom(r.Context()) != nil,
|
|
OAuthEnabled: h.oauthEnabled(),
|
|
LocalEnabled: h.localLoginEnabled(),
|
|
ProviderName: h.providerName(),
|
|
}
|
|
}
|
|
|
|
// LandingPage is the only dual-purpose route.
|
|
//
|
|
// Signed in, it is the dashboard. Signed out, it is a description of what
|
|
// Relata does — served rather than redirected, so the front page of the site is
|
|
// not a login form.
|
|
func (h *Handlers) LandingPage(w http.ResponseWriter, r *http.Request) {
|
|
if api.PrincipalFrom(r.Context()) != nil {
|
|
h.Dashboard(w, r)
|
|
return
|
|
}
|
|
|
|
data := struct {
|
|
publicBase
|
|
Weights []publicWeightRow
|
|
}{
|
|
publicBase: h.newPublicBase(r, "Relata — a self-organising semantic document database"),
|
|
Weights: publicWeightRows(),
|
|
}
|
|
h.d.Renderer.RenderPublic(w, r, "public_landing.html", http.StatusOK, data)
|
|
}
|
|
|
|
// HowItWorksPage explains the pipeline and the scoring, without any data.
|
|
func (h *Handlers) HowItWorksPage(w http.ResponseWriter, r *http.Request) {
|
|
data := struct {
|
|
publicBase
|
|
Weights []publicWeightRow
|
|
}{
|
|
publicBase: h.newPublicBase(r, "How Relata works"),
|
|
Weights: publicWeightRows(),
|
|
}
|
|
h.d.Renderer.RenderPublic(w, r, "public_how.html", http.StatusOK, data)
|
|
}
|
|
|
|
// PublicAPIPage describes the API and how to authenticate against it.
|
|
func (h *Handlers) PublicAPIPage(w http.ResponseWriter, r *http.Request) {
|
|
data := struct {
|
|
publicBase
|
|
CallbackURL string
|
|
}{
|
|
publicBase: h.newPublicBase(r, "The Relata API"),
|
|
CallbackURL: h.callbackURL(),
|
|
}
|
|
h.d.Renderer.RenderPublic(w, r, "public_api.html", http.StatusOK, data)
|
|
}
|
|
|
|
// publicWeightRow is one signal weight, shown publicly because the scoring model is
|
|
// part of what the product claims rather than something to be discovered.
|
|
type publicWeightRow struct {
|
|
Signal string
|
|
Weight float64
|
|
Means string
|
|
}
|
|
|
|
func publicWeightRows() []publicWeightRow {
|
|
explain := map[string]string{
|
|
"content_hash_match": "Byte-identical content.",
|
|
"semantic_similarity": "How alike the wording is, rebased so that ordinary similarity counts for little.",
|
|
"shared_entity": "An exact entity match, discounted by how common that entity is.",
|
|
"claim_support": "Two statements agree about the same subject.",
|
|
"claim_contradiction": "Two statements disagree about the same subject.",
|
|
"model_classification": "A language model's opinion. One signal, weighted below the storage " +
|
|
"threshold, so it can never create a relationship on its own.",
|
|
"shared_concept": "Overlapping concept vocabulary.",
|
|
"alias_entity": "A match through an alias a person confirmed. Unconfirmed candidates count for nothing.",
|
|
"temporal_proximity": "Created close together in time.",
|
|
"shared_metadata": "Matching metadata you supplied.",
|
|
"user_confirmation": "A person confirmed it. This dominates everything else.",
|
|
"user_rejection": "A person rejected it. This drives the score to zero.",
|
|
}
|
|
|
|
rows := make([]publicWeightRow, 0, len(relationships.Weights))
|
|
for _, sig := range relationships.WeightOrder() {
|
|
rows = append(rows, publicWeightRow{
|
|
Signal: string(sig),
|
|
Weight: relationships.Weights[sig],
|
|
Means: explain[string(sig)],
|
|
})
|
|
}
|
|
return rows
|
|
}
|