Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Claude): add activity #9139

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
22 changes: 22 additions & 0 deletions websites/C/Claude/Claude.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"claude.talkingWithAI": {
"description": "Displayed when the user is engaging in a conversation with the AI.",
"message": "Talking with AI about something"
},
"claude.aiResponding": {
"description": "Displayed when the AI is generating a response.",
"message": "AI is responding..."
},
"claude.conversationStats": {
"description": "Displayed to show the number of times the user asked a question and total words used, e.g., 'asked (3) times | (150) words'.",
"message": "asked ({0}) times | ({1}) words"
},
"claude.startNewConversation": {
"description": "Button text to start a new conversation.",
"message": "Start new conversation"
},
"claude.thinkingOfPrompt": {
"description": "Displayed when the AI is thinking of a new prompt.",
"message": "Thinking of a new prompt..."
}
}
39 changes: 39 additions & 0 deletions websites/C/Claude/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "https://schemas.premid.app/metadata/1.12",
"apiVersion": 1,
"author": {
"id": "1180088441459978261",
"name": "KohnoseLami"
},
"contributors": [],
"service": "Claude",
"description": {
"en": "Claude is a family of large language models developed by Anthropic. The first model was released in March 2023.\n\nThe Claude 3 family, released in March 2024, consists of three models: Haiku optimized for speed, Sonnet balancing capabilities and performance, and Opus designed for complex reasoning tasks. These models can process both text and images, with Claude 3 Opus demonstrating enhanced capabilities in areas like mathematics, programming, and logical reasoning compared to previous versions.",
"ja_JP": "Claude(クロード)とは、Anthropic社が開発した大規模言語モデルを用いた対話型生成AIである。2023年3月14日に一般公開され、以降複数のバージョンがリリースされている。\n\n2024年3月に公開されたClaude 3 OpusはメンサのIQテストでIQスコア101を記録した。「フレンドリーで熱心な同僚」をコンセプトの一つとしている。"
},
"url": "claude.ai",
"version": "1.0.0",
"logo": "https://i.imgur.com/t2w5Nso.png",
"thumbnail": "https://i.imgur.com/qFa0XUT.jpeg",
"color": "#DA7756",
"category": "other",
"tags": [
"ai",
"language",
"human-like",
"conversations",
"multi-purpose"
],
"settings": [
{
"id": "lang",
"multiLanguage": true
},
{
"id": "showTitle",
"title": "Show chat title",
"icon": "fa-solid fa-message-quote",
"value": true
}
]
}
59 changes: 59 additions & 0 deletions websites/C/Claude/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions websites/C/Claude/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"franc-min": "^6.2.0"
}
}
90 changes: 90 additions & 0 deletions websites/C/Claude/presence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { franc } from "franc-min";

const presence = new Presence({
clientId: "1326893434073776181",
}),
getStrings = async () => {
return presence.getStrings(
{
talkingWithAI: "claude.talkingWithAI",
aiResponding: "claude.aiResponding",
conversationStats: "claude.conversationStats",
startNewConversation: "claude.startNewConversation",
thinkingOfPrompt: "claude.thinkingOfPrompt",
},
await presence.getSetting<string>("lang").catch(() => "en")
);
},
browsingTimestamp = Math.floor(Date.now() / 1000);
let oldLang: string = null,
strings: Awaited<ReturnType<typeof getStrings>>;

const enum Assets {
Logo = "https://i.imgur.com/t2w5Nso.png",
Talking = "https://i.imgur.com/rnAQvqx.png",
}

presence.on("UpdateData", async () => {
const [lang, showTitle] = await Promise.all([
presence.getSetting<string>("lang").catch(() => "en"),
presence.getSetting<boolean>("showTitle"),
]);

if (oldLang !== lang) {
oldLang = lang;
strings = await getStrings();
}

const { pathname } = document.location,
presenceData: PresenceData = {
largeImageKey: Assets.Logo,
startTimestamp: browsingTimestamp,
},
messageElements = Array.from(
document.querySelectorAll(
'div[class*="font-user-message"],div[class*="font-claude-message"]'
)
),
isTalking =
messageElements
.at(-1)
?.parentElement.getAttribute("data-is-streaming") === "true";

let wordCount = 0;
for (const element of messageElements) {
const text = element.textContent
.replace(/(, )|(,\n)|(,)|([.] )|([.])/gm, " ")
.replace(/([0-9]*)|(\/)|(')|(,)|( )/gm, "");
wordCount += Array.from(
new Intl.Segmenter(franc(text), { granularity: "word" }).segment(text)
).length;
}

if (pathname.split("/")[1] === "chat") {
// check if the document title is the default title. If so, get the chat title from the UI. Otherwise, get it from the document title
if (document.title === "Claude" && showTitle) {
presenceData.details = document.querySelector(
`a[href="/chat/${pathname.split("/")[2]}"]`
)?.textContent;
} else
presenceData.details = showTitle ? document.title : strings.talkingWithAI;
presenceData.state = isTalking
? strings.aiResponding
: strings.conversationStats
.replace(
"{0}",
`${
messageElements.filter(e =>
e.classList.contains("font-user-message")
).length
}`
)
.replace("{1}", `${wordCount}`);
presenceData.smallImageKey = isTalking ? Assets.Talking : null;
} else {
presenceData.details = strings.startNewConversation;
presenceData.state = strings.thinkingOfPrompt;
}

presence.setActivity(presenceData);
});
Loading