UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

281 lines (259 loc) โ€ข 7.44 kB
import qs from 'query-string'; import urlJoin from 'url-join'; import { BRANDING_EMAIL, BRANDING_NAME, SOCIAL_URL } from '@/const/branding'; import { DEFAULT_LANG } from '@/const/locale'; import { OFFICIAL_SITE, OFFICIAL_URL } from '@/const/url'; import { Locales } from '@/locales/resources'; import { getCanonicalUrl } from '@/server/utils/url'; import pkg from '../../package.json'; const LAST_MODIFIED = new Date().toISOString(); export const AUTHOR_LIST = { arvinxx: { avatar: 'https://avatars.githubusercontent.com/u/28616219?v=4', desc: 'Founder, Design Engineer', name: 'Arvin Xu', url: 'https://github.com/arvinxx', }, canisminor: { avatar: 'https://avatars.githubusercontent.com/u/17870709?v=4', desc: 'Founder, Design Engineer', name: 'CanisMinor', url: 'https://github.com/arvinxx', }, lobehub: { avatar: 'https://avatars.githubusercontent.com/u/131470832?v=4', desc: 'Official Account', name: 'LobeHub', url: 'https://github.com/lobehub', }, }; export class Ld { generate({ image = '/og/cover.png', article, url, title, description, date, locale = DEFAULT_LANG, webpage = { enable: true, }, }: { article?: { author: string[]; enable?: boolean; identifier: string; tags?: string[]; }; date?: string; description: string; image?: string; locale?: Locales; title: string; url: string; webpage?: { enable?: boolean; search?: string; }; }) { return { '@context': 'https://schema.org', '@graph': [ this.genWebSite(), article?.enable && this.genArticle({ ...article, date, description, locale, title, url }), webpage?.enable && this.genWebPage({ ...webpage, date, description, image, locale, title, url, }), image && this.genImageObject({ image, url }), this.genOrganization(), ].filter(Boolean), }; } genOrganization() { return { '@id': this.getId(OFFICIAL_URL, '#organization'), '@type': 'Organization', 'alternateName': 'LobeChat', 'contactPoint': { '@type': 'ContactPoint', 'contactType': 'customer support', 'email': BRANDING_EMAIL.support, }, 'description': 'We are a group of e/acc design-engineers, hoping to provide modern design components and tools for AIGC, and creating a technology-driven forum, fostering knowledge interaction and the exchange of ideas that may culminate in mutual inspiration and collaborative innovation.', 'email': BRANDING_EMAIL.business, 'founders': [this.getAuthors(['arvinxx']), this.getAuthors(['canisminor'])], 'image': urlJoin(OFFICIAL_SITE, '/icon-512x512.png'), 'logo': { '@type': 'ImageObject', 'height': 512, 'url': urlJoin(OFFICIAL_SITE, '/icon-512x512.png'), 'width': 512, }, 'name': 'LobeHub', 'sameAs': [SOCIAL_URL.x, SOCIAL_URL.github, SOCIAL_URL.medium, SOCIAL_URL.youtube], 'url': OFFICIAL_SITE, }; } getAuthors(ids: string[] = []) { const defaultAuthor = { '@id': this.getId(OFFICIAL_URL, '#organization'), '@type': 'Organization', }; if (!ids || ids.length === 0) return defaultAuthor; if (ids.length === 1 && ids[0] === 'lobehub') return defaultAuthor; const personId = ids.find((id) => id !== 'lobehub'); if (!personId) return defaultAuthor; const person = (AUTHOR_LIST as any)?.[personId]; if (!person) return defaultAuthor; return { '@type': 'Person', 'name': person.name, 'url': person.url, }; } genWebPage({ date, image, search, description, title, locale = DEFAULT_LANG, url, }: { breadcrumbs?: { title: string; url: string }[]; date?: string; description: string; image?: string; locale?: Locales; search?: string; title: string; url: string; }) { const fixedUrl = getCanonicalUrl(url); const dateCreated = date ? new Date(date).toISOString() : LAST_MODIFIED; const dateModified = date ? new Date(date).toISOString() : LAST_MODIFIED; const baseInfo: any = { '@id': fixedUrl, '@type': 'WebPage', 'about': { '@id': this.getId(OFFICIAL_URL, '#organization'), }, 'breadcrumbs': { '@id': this.getId(fixedUrl, '#breadcrumb'), }, 'dateModified': dateModified, 'datePublished': dateCreated, 'description': description, 'image': { '@id': this.getId(fixedUrl, '#primaryimage'), }, 'inLanguage': locale, 'isPartOf': { '@id': this.getId(OFFICIAL_URL, '#website'), }, 'name': this.fixTitle(title), 'primaryImageOfPage': { '@id': this.getId(fixedUrl, '#primaryimage'), }, 'thumbnailUrl': image, }; if (search) baseInfo.potentialAction = { '@type': 'SearchAction', 'query-input': 'required name=search_term_string', 'target': qs.stringifyUrl({ query: { q: '{search_term_string}' }, url: getCanonicalUrl(search), }), }; return baseInfo; } genImageObject({ image, url }: { image: string; url: string }) { const fixedUrl = getCanonicalUrl(url); return { '@id': this.getId(fixedUrl, '#primaryimage'), '@type': 'ImageObject', 'contentUrl': image, 'inLanguage': DEFAULT_LANG, 'url': image, }; } genWebSite() { const baseInfo: any = { '@id': this.getId(OFFICIAL_URL, '#website'), '@type': 'WebSite', 'description': pkg.description, 'inLanguage': DEFAULT_LANG, 'name': BRANDING_NAME, 'publisher': { '@id': this.getId(OFFICIAL_URL, '#organization'), }, 'url': OFFICIAL_URL, }; return baseInfo; } genArticle({ description, title, url, author, date, locale = DEFAULT_LANG, tags, identifier, }: { author: string[]; date?: string; description: string; identifier: string; locale: Locales; tags?: string[]; title: string; url: string; }) { const fixedUrl = getCanonicalUrl(url); const dateCreated = date ? new Date(date).toISOString() : LAST_MODIFIED; const dateModified = date ? new Date(date).toISOString() : LAST_MODIFIED; const baseInfo: any = { '@type': 'Article', 'author': this.getAuthors(author), 'creator': author, 'dateCreated': dateCreated, 'dateModified': dateModified, 'datePublished': dateCreated, 'description': description, 'headline': this.fixTitle(title), 'identifier': identifier, 'image': { '@id': this.getId(fixedUrl, '#primaryimage'), }, 'inLanguage': locale, 'keywords': tags?.join(' ') || 'LobeHub LobeChat', 'mainEntityOfPage': fixedUrl, 'name': title, 'publisher': { '@id': this.getId(OFFICIAL_URL, '#organization'), }, 'url': fixedUrl, }; return { ...baseInfo, }; } private getId(url: string, id: string) { return [url, id].join('/'); } private fixTitle(title: string) { return title.includes(BRANDING_NAME) ? title : `${title} ยท ${BRANDING_NAME}`; } } export const ldModule = new Ld();