@kelvdra/scraper
Version:
A simple scraper by kelvdra.
212 lines (209 loc) • 6.89 kB
JavaScript
import axios from "axios"
import { randomUUID } from "crypto"
class CiciAI {
constructor() {
this.botId = "7241547611541340167";
this.senderId = "7584067883349640200";
this.conversationId = "485805516280081";
this.aid = "489823";
}
rnd() {
return Math.floor(Math.random() * 1e17) + 1;
}
hex() {
return Math.floor(Math.random() * 1e17).toString(16);
}
str() {
return Math.random().toString(36).slice(2, 9);
}
parse(raw) {
try {
console.log("Parsing response...");
const result = [];
const sources = [];
const dataRgx = /data:\s*(\{[^}]+\})/g;
const originRgx = /"origin_content"\s*:\s*"([^"]+)"/g;
let m;
while (m = dataRgx.exec(raw)) {
try {
const json = JSON.parse(m[1]);
const body = json?.downlink_body?.fetch_chunk_message_downlink_body;
const content = body?.content ? JSON.parse(body.content) : null;
const tags = content?.text_tags || [];
tags.forEach(tag => {
const info = JSON.parse(tag?.tag_info || "{}");
if (info?.url && info?.title) {
sources.push({
url: info.url,
title: info.title
});
}
});
} catch {}
}
while (m = originRgx.exec(raw)) {
result.push(m[1]);
}
return {
chat: result.join("") || "No response",
sources: sources.length ? sources : []
};
} catch (error) {
console.error("Parse error:", error?.message);
return {
chat: "",
sources: []
};
}
}
async chat(input) {
const prompt = typeof input === "string" ? input : input?.prompt;
if (!prompt) throw new Error("Prompt required");
const {
nickname = "Kelvdra AI",
voiceId = "92",
...rest
} = typeof input === "object" ? input : {}
try {
if (!prompt) throw new Error("Prompt required");
console.log("Sending request...");
const random = this.rnd();
const cdid = "2" + this.hex().padStart(23, "0");
const uid = this.rnd();
const iid = this.rnd();
const deviceId = this.rnd();
const timestamp = Math.floor(Date.now() / 1e3);
const {
data
} = await axios.post("https://api-normal-i18n.ciciai.com/im/sse/send/message", {
channel: 3,
cmd: 100,
sequence_id: randomUUID(),
uplink_body: {
send_message_body: {
ack_only: false,
applet_payload: {},
bot_id: this.botId,
bot_type: 1,
client_controller_param: {
answer_with_suggest: true,
local_language_code: rest?.lang || "en",
local_nickname: nickname,
local_voice_id: voiceId
},
content: JSON.stringify({
im_cmd: -1,
text: prompt
}),
content_type: 1,
conversation_id: this.conversationId,
conversation_type: 3,
create_time: timestamp,
ext: {
create_time_ms: Date.now().toString(),
record_status: "1",
wiki: "1",
search_engine_type: "1",
media_search_type: "0",
answer_with_suggest: "1",
system_language: rest?.lang || "en",
enter_method_trace: "",
previous_page_trace: "",
is_audio: "false",
voice_mix_input: "0",
tts: "1",
ugc_plugin_auth_infos: "[]",
is_app_background: "0",
is_douyin_installed: "0",
is_luna_installed: "0",
media_player_business_scene: "",
need_deep_think: "0",
need_net_search: "0",
send_message_scene: "keyboard"
},
client_fallback_param: {
last_section_id: "",
last_message_index: -1
},
local_message_id: this.hex(),
sender_id: this.senderId,
status: 0,
unique_key: this.hex()
}
},
version: "1"
}, {
params: {
flow_im_arch: "v2",
device_platform: "android",
os: "android",
ssmix: "a",
_rticket: random,
cdid: cdid,
channel: "googleplay",
aid: this.aid,
app_name: "nova_ai",
version_code: this.rnd() % 1e6,
version_name: this.str(),
manifest_version_code: this.rnd() % 1e6,
update_version_code: this.rnd() % 1e6,
resolution: `${this.rnd() % 2e3 + 720}x${this.rnd() % 3e3 + 1280}`,
dpi: this.rnd() % 500 + 200,
device_type: `SM-${this.str().toUpperCase()}`,
device_brand: "samsung",
language: rest?.lang || "en",
os_api: this.rnd() % 20 + 28,
os_version: `${this.rnd() % 5 + 10}.0`,
ac: "wifi",
uid: uid,
carrier_region: rest?.region || "ID",
sys_region: rest?.sysRegion || "US",
tz_name: rest?.timezone || "Asia/Jakarta",
is_new_user: "1",
region: rest?.sysRegion || "US",
lang: rest?.lang || "en",
pkg_type: "release_version",
iid: iid,
device_id: deviceId,
flow_sdk_version: this.rnd() % 1e6,
"use-olympus-account": "1"
},
headers: {
"Accept-Encoding": "gzip",
Connection: "Keep-Alive",
"Content-Type": "application/json; encoding=utf-8",
Host: "api-normal-i18n.ciciai.com",
"passport-sdk-version": "505174",
req_biz_id: "Message",
"sdk-version": "2",
"User-Agent": `com.larus.wolf/${this.rnd() % 9e6 + 8e6} (Linux; U; Android 12; en_US; SM-${this.str().toUpperCase()}; Build/SP1A.210812.016;tt-ok/3.12.13.18)`,
"x-tt-store-region": (rest?.region || "id").toLowerCase(),
"x-tt-store-region-src": "uid",
"X-Tt-Token": rest?.token || "0329aceacb51f4b2d468e8709307dcc44604a72f48ba71143b3403209f8f98cf37f4111f4fe8bac693d57dd0580c0e13a32d8d230813a3064feaf53b9d8fd9e5ae0256d50c4b29427687873645bd92d3b842a-1.0.0"
}
});
console.log("Processing response...");
return this.parse(data);
} catch (error) {
console.error("Request error:", error?.message);
throw new Error(error?.response?.data?.message || error?.message || "Request failed");
}
}
}
export async function ciciAi(query) {
try {
const result = new CiciAI()
const data = result.chat(query)
return {
creator: "@kelvdra/scraper",
status: true,
result: data
}
} catch (error) {
return {
creator: "@kelvdra/scraper",
status: true,
result: error
}
}
}