Files
Jyotisha/frontend/src/lib/legal-documents.ts
T
Jesse_ChenandClaude Opus 5.5 12e315a9bb feat(reply-quality): 👎 keeps a snapshot of the turn; admin 对话质量记录
A 👎 now saves, server side, the rated turn plus the context window the
model read for it (reconstructed from the stored session with the same
consultationHistoryWindow the consult route uses), model and run facts.
👍 is only counted. Switching to 👍 or clearing deletes the snapshot.
Bodies are blanked after 90 days; the row cascades on session delete
and on account deletion.

- Optional 不满意原因 panel under the answer after a 👎 (five reasons,
  200-char note, "会把这一轮对话发给我们排查").
- Admin 对话质量记录: 👍/👎 stats by day and model, list without text,
  audited snapshot open, 处理状态 + note (support.quality.read/write).
- Privacy draft: what a 👎 keeps, why, 90 days, deletion.
- Migration 20260930050000 is add-only; set_reply_rating() replaced with
  the same signature.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-30 09:42:11 +08:00

212 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { LEGAL_ENTITY } from "./legal-entity";
/**
* 用户协议与隐私政策正文(2026-09-30 初稿,待律师审定)。
*
* 律师定稿后只替换这一个文件的正文,并把 `legal-entity.ts` 的
* `legalDocumentsVersion` 改成正式版本号、`legalDocumentsDraft` 改为 false。
* 凡是写作时无法从代码或配置核实的事实,都用 【待确认:…】 标出,定稿前逐条确认。
*/
export type LegalDocumentId = "terms" | "privacy";
export type LegalSection = Readonly<{
id: string;
title: string;
/** 每一项是一个段落;以「· 」开头的项渲染为列表项。 */
paragraphs: readonly string[];
}>;
export type LegalDocument = Readonly<{
id: LegalDocumentId;
title: string;
summary: string;
sections: readonly LegalSection[];
}>;
const WE = LEGAL_ENTITY.operatorName;
const EMAIL = LEGAL_ENTITY.contactEmail;
const ADDRESS = LEGAL_ENTITY.address;
const PRODUCT = "Jyotisha";
export const TERMS: LegalDocument = {
id: "terms",
title: "用户协议",
summary: `本协议是你与${WE}(以下称「我们」)之间关于使用 ${PRODUCT} 网站及相关服务(以下称「本服务」)的约定。请在注册或登录前仔细阅读;勾选同意并继续使用,即表示你接受本协议。`,
sections: [
{
id: "service",
title: "一、本服务是什么",
paragraphs: [
`${PRODUCT} 是一个基于印度占星(Jyotisha)计算的对话与报告服务:你提供出生日期、时间与地点,我们计算星盘、分盘、大运等数据,并由人工智能模型据此生成对话回答、个人报告与出生时间校正建议。`,
"本服务的回答与报告由人工智能生成,内容基于占星计算与模型推断,仅供文化娱乐与自我参考,不构成医疗、心理、法律、投资、财务或安全方面的专业意见,也不对任何具体事件作出确定性的预测或保证。",
"涉及健康、法律、投资、人身安全等事项,请以专业人士的意见为准;如你正处于危机之中,请立即联系当地紧急服务或专业机构。",
],
},
{
id: "account",
title: "二、账号",
paragraphs: [
"你可以使用邮箱验证码注册和登录,也可以为账号设置密码。请妥善保管邮箱与密码,不要把账号转借他人使用;通过你的账号进行的操作视为你本人的操作。",
"本服务不面向 14 周岁以下的未成年人。14 周岁以上、未满 18 周岁的未成年人,应在监护人同意与指导下使用。",
"你可以在账户菜单中申请注销账号。注销申请提交后有 7 天冷静期,期间重新登录即可撤销;冷静期满后,你的对话、星盘档案、报告与出生时间校正记录以及账号本身将被删除,账号内剩余的点数同时作废且不可恢复。法律法规要求保留的订单与点数流水将以去除个人身份信息的方式保留;你提交过的反馈与投诉会保留处理记录,但删除你填写的联系方式。",
],
},
{
id: "credits",
title: "三、点数、会员与退款",
paragraphs: [
"部分功能(例如对话回答、个人报告、出生时间校正)会消耗账号点数,具体消耗以使用前页面显示为准。点数可通过兑换码、活动赠送或在线支付获得【待确认:在线支付是否在正式站开放及具体支付方式】。",
"若因系统故障导致回答未能生成,本次扣除的点数会自动退回;被内容安全规则拦截、未发送给模型的提问不扣点数。",
"已购买的点数或会员原则上不支持转让。退款按照页面公示的规则与法律法规处理,你可以通过账户菜单中的「反馈与投诉」或本协议末尾的联系方式提出退款申请【待确认:退款规则与处理时限】。",
],
},
{
id: "conduct",
title: "四、使用规范",
paragraphs: [
"使用本服务时,你不得:",
"· 发布或诱导生成违反法律法规、危害国家安全、破坏民族团结、宣扬暴力恐怖、色情低俗、赌博、封建迷信诈骗等内容;",
"· 冒用他人身份,或在未取得本人同意的情况下录入、查询他人的出生资料等个人信息;",
"· 利用本服务从事欺诈、骚扰、侵犯他人合法权益,或以占星结果对他人作出歧视性决定;",
"· 以自动化方式大量抓取、攻击、干扰本服务,或绕过点数、限流与安全措施。",
"我们会对提问与模型回答进行内容安全检查。命中规则的提问不会发送给模型,命中规则的回答会被替换为说明并退回点数。对于违反本协议的行为,我们可以视情况采取提醒、限制功能、暂停或终止服务等措施。",
],
},
{
id: "content",
title: "五、内容与知识产权",
paragraphs: [
"你输入的内容归你所有。为向你提供服务,你授权我们在提供、维护与改进本服务的必要范围内处理这些内容;我们不会把你的对话内容公开展示给其他用户。",
"本服务的界面、程序、文案、图形与品牌标识的相关权利归我们或相关权利人所有。你可以个人保存、导出和分享自己的报告,但不得将本服务本身用于未经授权的商业转售。",
],
},
{
id: "liability",
title: "六、服务变更与责任限制",
paragraphs: [
"我们会尽力保证服务稳定,但可能因系统维护、第三方服务故障、网络或不可抗力等原因出现中断或错误。我们会在合理范围内提前通知计划内的维护。",
"在法律允许的范围内,对于因依赖人工智能生成内容作出的决定所产生的损失,以及非因我们过错造成的服务中断,我们不承担责任;因我们的故意或重大过失造成的损失,依法承担相应责任。",
],
},
{
id: "changes",
title: "七、协议变更、适用法律与争议解决",
paragraphs: [
"本协议更新时,我们会在登录页与账户菜单中提示;重大变更会在你下次登录时请你重新确认。你继续使用本服务即表示接受更新后的协议。",
"本协议适用中华人民共和国法律(不含港澳台地区法律)。因本协议产生的争议,双方应协商解决;协商不成的,提交【待确认:管辖法院,如「我们所在地有管辖权的人民法院」】诉讼解决。",
],
},
{
id: "contact",
title: "八、联系我们",
paragraphs: [
`运营主体:${WE}`,
`联系地址:${ADDRESS}`,
`联系邮箱:${EMAIL}`,
"你也可以通过账户菜单中的「反馈与投诉」提交问题、举报内容或提出退款申请。",
],
},
],
};
export const PRIVACY: LegalDocument = {
id: "privacy",
title: "隐私政策",
summary: `${WE}(以下称「我们」)重视你的个人信息。本政策说明 ${PRODUCT} 收集哪些信息、为什么收集、交给谁处理、保存多久,以及你享有的权利。出生日期、时间与地点属于你的个人信息,我们仅在提供服务所必需的范围内处理。`,
sections: [
{
id: "collect",
title: "一、我们收集哪些信息",
paragraphs: [
"· 账号信息:邮箱地址;如你设置了密码,我们只保存经过加密处理的密码摘要,不保存明文。",
"· 出生资料:你本人以及你添加到「星盘档案」的其他人的称呼、出生日期、出生时间、出生地点(以及由此计算出的经纬度与时区)、性别(选填)。录入他人资料前,请确认已取得对方同意。",
"· 使用内容:你与服务的对话内容、出生时间校正过程中的回答、生成的个人报告与合盘结果。",
"· 交易信息:点数与会员的订单、兑换码使用与点数流水;在线支付时由支付服务商处理支付信息,我们不保存你的银行卡或支付账户密码。",
"· 反馈信息:你通过「反馈与投诉」提交的内容与所附的会话信息。",
"· 回复评价:你对回答点「赞」时,我们只记录一次计数;你点「踩」时,我们会保存这一轮的提问与回答、模型当时参考的前文对话(可能包含你在对话里提到的出生资料等内容)、所用模型与耗时等运行信息,以及你选填的不满意原因与补充说明。改为点赞或取消点踩时,这份记录随之删除。",
"· 设备与日志信息:为保障安全与排查故障,服务器会记录访问时间、请求地址、错误信息等必要日志【待确认:日志是否包含 IP 地址及保存期限】。浏览器中会保存登录状态 Cookie 与少量本地偏好(例如当前选中的人物)。",
],
},
{
id: "use",
title: "二、我们如何使用这些信息",
paragraphs: [
"· 计算星盘、分盘、大运、年运等数据,生成对话回答、个人报告与出生时间校正建议;",
"· 登录验证、账号安全、防止滥用(例如验证码发送与请求频率限制);",
"· 点数扣除与退回、订单处理与客户服务;",
"· 内容安全检查:对提问与模型回答进行检查,命中规则时拦截或替换,并记录去除身份信息的命中日志以便改进规则;",
"· 排查回答质量问题:由经授权的工作人员查看你点「踩」时保存的那一轮对话,找出答非所问、内容不准等问题的原因并改进服务;每次查看都会记入内部审计日志;",
"· 以去除个人身份信息的汇总统计改进服务(例如出生时间校正的问题数量与收敛情况,不含出生资料与对话原文)。",
"我们不会用你的出生资料或对话内容做与上述目的无关的用途,也不会出售你的个人信息。",
],
},
{
id: "share",
title: "三、委托处理与数据出境",
paragraphs: [
"为提供服务,我们会把完成任务所必需的最少信息交给以下服务商处理,并要求其仅按我们的指示使用:",
"· 人工智能模型服务商:你的提问、相关的星盘计算结果与必要的对话上下文会发送给模型服务商以生成回答。我们使用的模型服务商可能位于中国境外【待确认:正式站启用的模型服务商名单及所在地】。",
"· 邮件服务商 Resend(位于境外):用于发送登录与重置密码的验证码,会收到你的邮箱地址。",
"· 地点搜索服务商(Geoapify、Mapbox、GeoNames 中启用的一家或多家,可能位于境外):你搜索出生地点时,输入的地名会发送给其用于匹配【待确认:正式站启用的地点服务商】。",
"· 占星计算参照服务 VedAstro(位于境外):部分计算可能调用其接口核对结果,会收到出生日期、时间与经纬度【待确认:正式站是否启用】。",
"· 支付服务商:在线支付开放时,订单金额与订单号会发送给支付服务商【待确认:支付服务商名称】。",
"上述境外处理构成个人信息出境。我们将依照《个人信息保护法》等规定履行告知、单独同意与安全评估或标准合同等义务【待确认:出境合规路径】。除上述情形与法律法规要求外,我们不会向第三方提供你的个人信息。",
],
},
{
id: "retain",
title: "四、保存期限",
paragraphs: [
"· 账号、出生资料、对话、报告与校正记录:在你的账号存续期间保存;你删除某条对话或某个人物档案时,相应数据随之删除。",
"· 注销账号:冷静期 7 天满后,上述数据与账号一并删除;法律法规要求保留的订单与点数流水去除个人身份信息后保存,期限依法确定【待确认:保存年限】;反馈与投诉保留处理记录并删除其中的联系方式【待确认:保存年限】。",
"· 内容安全命中日志:去除身份信息后保存【待确认:保存期限】。",
"· 出生时间校正的匿名统计:保存 180 天。",
"· 点「踩」时保存的对话记录:保存 90 天,期满后清空对话内容,只保留评价与不满意原因用于统计;你删除该条对话或注销账号时一并删除。",
"· 服务器日志:【待确认:保存期限】。",
],
},
{
id: "rights",
title: "五、你的权利",
paragraphs: [
"· 查阅与更正:你可以在星盘档案与账户设置中查看、修改你的出生资料与称呼;",
"· 删除:你可以随时删除单条对话、人物档案或报告,也可以注销账号;",
"· 撤回同意:你可以通过注销账号撤回对本政策的同意,撤回不影响此前基于同意已进行的处理;",
`· 其他请求:如需获取个人信息副本或有其他请求,可通过「反馈与投诉」或邮箱 ${EMAIL} 联系我们,我们将在 15 个工作日内答复。`,
],
},
{
id: "security",
title: "六、安全措施",
paragraphs: [
"我们采用传输加密、访问权限控制、密码加密存储、模型密钥加密保存、定期备份等措施保护你的信息【待确认:备份与加密存储的具体范围】。如发生个人信息安全事件,我们将按法律法规要求告知你并向主管部门报告。",
],
},
{
id: "minors",
title: "七、未成年人",
paragraphs: [
"本服务不面向 14 周岁以下的儿童。我们不会主动收集 14 周岁以下儿童的个人信息;如发现误收集,将尽快删除。未满 18 周岁的用户应在监护人同意下使用本服务。",
],
},
{
id: "changes",
title: "八、本政策的更新与联系我们",
paragraphs: [
"本政策更新时,我们会在登录页与账户菜单中提示;重大变更会在你下次登录时请你重新确认。",
`运营主体:${WE};联系地址:${ADDRESS};联系邮箱:${EMAIL}。`,
],
},
],
};
export const LEGAL_DOCUMENTS: Readonly<Record<LegalDocumentId, LegalDocument>> = { terms: TERMS, privacy: PRIVACY };
/** 仍待确认的事实条目,定稿前必须为零。 */
export function pendingLegalConfirmations(documents: readonly LegalDocument[] = [TERMS, PRIVACY]): string[] {
return documents.flatMap(document => document.sections.flatMap(section =>
section.paragraphs.flatMap(paragraph => [...paragraph.matchAll(/【待确认:([^】]+)】/g)].map(match => `${document.title} · ${section.title}:${match[1]}`)),
));
}