1+ /* eslint-disable @typescript-eslint/no-unsafe-call */
12/* eslint-disable @typescript-eslint/no-unsafe-member-access */
23/* eslint-disable @typescript-eslint/no-unsafe-assignment */
3- import { createEffect , createSignal , For , Show } from "solid-js" ;
4+ import { createEffect , createSignal , For , Show , useContext } from "solid-js" ;
45import { CopyButton } from "../../components/CopyButton" ;
56import { FaRegularCircleQuestion } from "solid-icons/fa" ;
67import { JsonInput , MultiStringInput , Select , Tooltip } from "shared/ui" ;
@@ -16,11 +17,16 @@ import {
1617} from "../../hooks/usePublicPageSettings" ;
1718import { createStore } from "solid-js/store" ;
1819import {
20+ $OpenApiTs ,
21+ CrawlRequest ,
1922 PriceToolCallOptions ,
2023 PublicPageTabMessage ,
2124 RelevanceToolCallOptions ,
2225} from "trieve-ts-sdk" ;
2326import FilterSidebarBuilder from "../../components/FilterSidebarBuilder" ;
27+ import { DatasetContext } from "../../contexts/DatasetContext" ;
28+ import { useTrieve } from "../../hooks/useTrieve" ;
29+ import { UserContext } from "../../contexts/UserContext" ;
2430
2531export const PublicPageSettingsPage = ( ) => {
2632 return (
@@ -42,6 +48,13 @@ export const PublicPageSettingsPage = () => {
4248 ) ;
4349} ;
4450
51+ export const defaultOpenGraphMetadata = {
52+ title : "Trieve AI Sitesearch" ,
53+ description :
54+ "Trieve AI Sitesearch is ChatGPT for your website and content. Replicate the experience of a human sales associate with AI." ,
55+ image : "" ,
56+ } ;
57+
4558export const defaultRelevanceToolCallOptions : RelevanceToolCallOptions = {
4659 userMessageTextPrefix :
4760 "Be extra picky and detailed. Thoroughly examine all details of the query and product." ,
@@ -95,6 +108,11 @@ const componentVersionOptions = [
95108] ;
96109
97110const PublicPageControls = ( ) => {
111+ const [ prospectiveCustomerUrl , setProspectiveCustomerUrl ] = createSignal ( "" ) ;
112+ const [ docColors , setDocColors ] = createSignal < string [ ] > ( [ ] ) ;
113+ const [ loadingDefaultConfig , setLoadingDefaultConfig ] = createSignal ( false ) ;
114+ const userContext = useContext ( UserContext ) ;
115+ const datasetContext = useContext ( DatasetContext ) ;
98116 const {
99117 extraParams,
100118 setExtraParams,
@@ -103,6 +121,138 @@ const PublicPageControls = () => {
103121 unpublishDataset,
104122 publicUrl,
105123 } = usePublicPage ( ) ;
124+ const trieve = useTrieve ( ) ;
125+
126+ const updateTrackingId = async ( newTrackingId : string ) => {
127+ const result = await trieve . fetch ( "/api/dataset" , "put" , {
128+ data : {
129+ dataset_id : datasetContext . datasetId ( ) ,
130+ new_tracking_id : newTrackingId ,
131+ } ,
132+ organizationId : userContext . selectedOrg ( ) . id ,
133+ } ) ;
134+ await userContext . invalidate ( ) ;
135+ return result ;
136+ } ;
137+
138+ const autoConfigure = async ( url : string ) => {
139+ setLoadingDefaultConfig ( true ) ;
140+ const domain = url . replace ( / ^ (?: h t t p s ? : \/ \/ ) ? (?: w w w \. ) ? / , "" ) . split ( "/" ) [ 0 ] ;
141+ const domainParts = domain . split ( "." ) ;
142+ const domainName = domainParts . slice ( 0 , - 1 ) . join ( "." ) ;
143+ void updateTrackingId ( domainName ) ;
144+
145+ const proxyUrl = `https://corsproxy.io/?url=${ encodeURIComponent ( url ) } ` ;
146+ const pageResponse = await fetch ( proxyUrl ) ;
147+ const pageText = await pageResponse . text ( ) ;
148+ const parser = new DOMParser ( ) ;
149+ const doc = parser . parseFromString ( pageText , "text/html" ) ;
150+
151+ const titleQuerysSelectors = [
152+ "title" ,
153+ "meta[property='og:title']" ,
154+ "meta[name='twitter:title']" ,
155+ ] ;
156+ const title = titleQuerysSelectors
157+ . map ( ( selector ) => doc . querySelector ( selector ) )
158+ . find ( ( title ) => title ?. getAttribute ( "content" ) || title ?. textContent ) ;
159+ const titleText = title ?. getAttribute ( "content" ) || title ?. textContent ;
160+ if ( titleText ) {
161+ setExtraParams ( "brandName" , titleText ) ;
162+ setExtraParams ( "forBrandName" , titleText ) ;
163+ setExtraParams ( "headingPrefix" , `Demo For` ) ;
164+ setExtraParams ( "openGraphMetadata" , "title" , titleText ) ;
165+ }
166+
167+ const faviconQuerySelectors = [
168+ "link[rel='shortcut icon']" ,
169+ "link[rel='icon']" ,
170+ "link[rel='apple-touch-icon']" ,
171+ ] ;
172+ const faviconHref = faviconQuerySelectors
173+ . map ( ( selector ) => doc . querySelector ( selector ) )
174+ . find ( ( link ) => link ?. getAttribute ( "href" ) )
175+ ?. getAttribute ( "href" ) ;
176+ if ( faviconHref ) {
177+ const url = new URL ( faviconHref , pageResponse . url ) ;
178+ const faviconUrl = url . href . replace ( / ^ \/ / , "" ) ;
179+ setExtraParams ( "navLogoImgSrcUrl" , faviconUrl ) ;
180+ setExtraParams ( "brandLogoImgSrcUrl" , faviconUrl ) ;
181+ }
182+
183+ const ogDescriptionQuerySelectors = [
184+ "meta[property='og:description']" ,
185+ "meta[name='twitter:description']" ,
186+ ] ;
187+ const ogDescription = ogDescriptionQuerySelectors
188+ . map ( ( selector ) => doc . querySelector ( selector ) )
189+ . find ( ( description ) => description ?. getAttribute ( "content" ) )
190+ ?. getAttribute ( "content" ) ;
191+ if ( ogDescription ) {
192+ setExtraParams ( "openGraphMetadata" , "description" , ogDescription ) ;
193+ }
194+
195+ const ogImageQuerySelectors = [
196+ "meta[property='og:image']" ,
197+ "meta[name='twitter:image']" ,
198+ ] ;
199+ const ogImage = ogImageQuerySelectors
200+ . map ( ( selector ) => doc . querySelector ( selector ) )
201+ . find ( ( image ) => image ?. getAttribute ( "content" ) )
202+ ?. getAttribute ( "content" ) ;
203+ if ( ogImage ) {
204+ setExtraParams ( "openGraphMetadata" , "image" , ogImage ) ;
205+ }
206+
207+ const hexColorRegex = / # ( [ 0 - 9 A - F a - f ] { 3 , 6 } ) / g;
208+ const hexColors = Array . from ( pageText . matchAll ( hexColorRegex ) ) . map (
209+ ( match ) => match [ 0 ] ,
210+ ) ;
211+ const uniqueColors = new Set ( hexColors ) ;
212+ const range = 64 ;
213+ const sortedColors = Array . from ( uniqueColors ) . sort ( ( a , b ) => {
214+ const [ ar , ag , ab ] = [
215+ Math . floor ( parseInt ( a . slice ( 1 , 3 ) , 16 ) / range ) ,
216+ Math . floor ( parseInt ( a . slice ( 3 , 5 ) , 16 ) / range ) ,
217+ Math . floor ( parseInt ( a . slice ( 5 , 7 ) , 16 ) / range ) ,
218+ ] ;
219+ const [ br , bg , bb ] = [
220+ Math . floor ( parseInt ( b . slice ( 1 , 3 ) , 16 ) / range ) ,
221+ Math . floor ( parseInt ( b . slice ( 3 , 5 ) , 16 ) / range ) ,
222+ Math . floor ( parseInt ( b . slice ( 5 , 7 ) , 16 ) / range ) ,
223+ ] ;
224+ return ar - br || ag - bg || ab - bb ;
225+ } ) ;
226+ setDocColors ( sortedColors ) ;
227+
228+ setLoadingDefaultConfig ( false ) ;
229+ } ;
230+
231+ createEffect ( ( ) => {
232+ void (
233+ trieve . fetch < "eject" > (
234+ `/api/crawl?limit=10&page=1` as keyof $OpenApiTs ,
235+ "get" ,
236+ {
237+ datasetId : datasetContext . datasetId ( ) ,
238+ } ,
239+ ) as Promise < CrawlRequest [ ] >
240+ ) . then ( ( result ) => {
241+ const lastUrl = result . length ? result [ 0 ] . url : "" ;
242+ setProspectiveCustomerUrl ( lastUrl ) ;
243+ } ) ;
244+
245+ const handleKeyDown = ( event : KeyboardEvent ) => {
246+ if ( ( event . ctrlKey || event . metaKey ) && event . key === "s" ) {
247+ event . preventDefault ( ) ;
248+ void publishDataset ( ) ;
249+ }
250+ } ;
251+ window . addEventListener ( "keydown" , handleKeyDown ) ;
252+ return ( ) => {
253+ window . removeEventListener ( "keydown" , handleKeyDown ) ;
254+ } ;
255+ } ) ;
106256
107257 return (
108258 < >
@@ -123,7 +273,26 @@ const PublicPageControls = () => {
123273 </ div >
124274 </ Show >
125275 < Show when = { isPublic ( ) } >
126- < div class = "mt-4 flex content-center items-center gap-1.5 gap-x-2.5" >
276+ < div class = "flex items-center space-x-2" >
277+ < input
278+ placeholder = "https://www.prospectivecustomer.com"
279+ value = { prospectiveCustomerUrl ( ) }
280+ onInput = { ( e ) => {
281+ setProspectiveCustomerUrl ( e . currentTarget . value ) ;
282+ } }
283+ class = "block w-full rounded border border-neutral-300 px-3 py-1.5 shadow-sm placeholder:text-neutral-400 focus:outline-magenta-500 sm:text-sm sm:leading-6"
284+ />
285+ < button
286+ onClick = { ( ) => {
287+ void autoConfigure ( prospectiveCustomerUrl ( ) ) ;
288+ } }
289+ disabled = { loadingDefaultConfig ( ) }
290+ class = "inline-flex w-[200px] justify-center rounded-md bg-magenta-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-magenta-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-magenta-900 disabled:animate-pulse"
291+ >
292+ { loadingDefaultConfig ( ) ? "Loading..." : "Auto Configure" }
293+ </ button >
294+ </ div >
295+ < div class = "mb-6 py-2 flex content-center items-center gap-1.5 gap-x-2.5" >
127296 < span class = "font-medium" > Published Url:</ span > { " " }
128297 < a class = "text-magenta-400" href = { publicUrl ( ) } target = "_blank" >
129298 { publicUrl ( ) }
@@ -179,7 +348,18 @@ const PublicPageControls = () => {
179348 options = { [ "light" , "dark" ] }
180349 />
181350 </ div >
182- < div class = "grow" >
351+ < div class = "grow max-w-[50%]" >
352+ < For each = { docColors ( ) } >
353+ { ( color ) => (
354+ < button
355+ class = "w-6 h-6 rounded-lg"
356+ style = { { "background-color" : color } }
357+ onClick = { ( ) => {
358+ setExtraParams ( "brandColor" , color ) ;
359+ } }
360+ />
361+ ) }
362+ </ For >
183363 < div class = "flex items-center gap-1" >
184364 < label class = "block" for = "" >
185365 Brand Color
@@ -1864,14 +2044,9 @@ const HtmlEditor = (props: {
18642044
18652045export const OgOptions = ( ) => {
18662046 const { extraParams, setExtraParams } = usePublicPage ( ) ;
1867- const [ defaultDetailOpen ] = createSignal (
1868- ! ! extraParams . openGraphMetadata ?. title ||
1869- ! ! extraParams . openGraphMetadata ?. image ||
1870- ! ! extraParams . openGraphMetadata ?. description ,
1871- ) ;
18722047
18732048 return (
1874- < details class = "my-4" open = { defaultDetailOpen ( ) } >
2049+ < details class = "my-4" >
18752050 < summary class = "cursor-pointer text-sm font-medium" > Open Graph</ summary >
18762051 < div class = "flex gap-4 pt-2" >
18772052 < div class = "grow" >
0 commit comments