edge_gpt/
conversation_meta.rs

1use std::sync::Arc;
2
3use crate::{util::new_reqwest_client, CookieInFile};
4use reqwest::{
5    cookie::Jar,
6    header::{HeaderMap, HeaderValue},
7};
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use thiserror::Error;
11
12fn create_conversation_headers() -> HeaderMap {
13    let mut headers = HeaderMap::new();
14    headers.insert(
15        "authority",
16        HeaderValue::from_static("edgeservices.bing.com"),
17    );
18    headers.insert("accept", HeaderValue::from_static("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"));
19    headers.insert(
20        "accept-language",
21        HeaderValue::from_static("en-US,en;q=0.9"),
22    );
23    headers.insert("cache-control", HeaderValue::from_static("max-age=0"));
24    headers.insert(
25        "sec-ch-ua",
26        HeaderValue::from_static(
27            "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Microsoft Edge\";v=\"110\"",
28        ),
29    );
30    headers.insert("sec-ch-ua-arch", HeaderValue::from_static("\"x86\""));
31    headers.insert("sec-ch-ua-bitness", HeaderValue::from_static("\"64\""));
32    headers.insert(
33        "sec-ch-ua-full-version",
34        HeaderValue::from_static("\"110.0.1587.69\""),
35    );
36    headers.insert("sec-ch-ua-full-version-list", HeaderValue::from_static("\"Chromium\";v=\"110.0.5481.192\", \"Not A(Brand\";v=\"24.0.0.0\", \"Microsoft Edge\";v=\"110.0.1587.69\""));
37    headers.insert("sec-ch-ua-mobile", HeaderValue::from_static("?0"));
38    headers.insert("sec-ch-ua-model", HeaderValue::from_static("\"\""));
39    headers.insert(
40        "sec-ch-ua-platform",
41        HeaderValue::from_static("\"Windows\""),
42    );
43    headers.insert(
44        "sec-ch-ua-platform-version",
45        HeaderValue::from_static("\"15.0.0\""),
46    );
47    headers.insert("sec-fetch-dest", HeaderValue::from_static("document"));
48    headers.insert("sec-fetch-mode", HeaderValue::from_static("navigate"));
49    headers.insert("sec-fetch-site", HeaderValue::from_static("none"));
50    headers.insert("sec-fetch-user", HeaderValue::from_static("?1"));
51    headers.insert("upgrade-insecure-requests", HeaderValue::from_static("1"));
52    headers.insert("x-edge-shopping-flag", HeaderValue::from_static("1"));
53    headers.insert("x-forwarded-for", HeaderValue::from_static("1.1.1.1"));
54    headers
55}
56
57/// Information of a created conversation
58#[derive(Serialize, Deserialize, Debug, Clone)]
59#[serde(rename_all = "camelCase")]
60pub struct ConversationMeta {
61    /// used for identify a conversation
62    pub conversation_signature: String,
63    /// used for identify a client
64    pub client_id: String,
65    /// used for identify a conversation
66    pub conversation_id: String,
67    result: ConversationMetaResult,
68}
69#[derive(Serialize, Deserialize, Debug, Clone)]
70struct ConversationMetaResult {
71    value: String,
72    message: Option<String>,
73}
74
75impl ConversationMeta {
76    /// Create a conversation with provided cookies, return the [`ConversationMeta`] of the created conversation.
77    pub async fn create(cookies: &[CookieInFile]) -> Result<ConversationMeta> {
78        let uri = "https://edgeservices.bing.com/edgesvc/turing/conversation/create"
79            .parse()
80            .unwrap();
81        let cookie_jar: Jar = Jar::default();
82        for CookieInFile { name, value } in cookies {
83            cookie_jar.add_cookie_str(&format!("{name}={value}; Domain=bing.com"), &uri)
84        }
85        let response = new_reqwest_client()
86            .cookie_provider(Arc::new(cookie_jar))
87            .build()?
88            .get(uri)
89            .headers(create_conversation_headers())
90            .send()
91            .await?
92            .text()
93            .await?;
94        let value: Value = serde_json::from_str(&response)?;
95        let result = value["result"]["value"].as_str();
96        match result {
97            Some("Success") => {}
98            _ => return Err(ConversationMetaCreatingError::Network),
99        }
100        let meta: ConversationMeta = serde_json::from_value(value)?;
101        Ok(meta)
102    }
103}
104
105#[derive(Error, Debug)]
106pub enum ConversationMetaCreatingError {
107    #[error("Failed to send conversation meta creating request")]
108    Network,
109    #[error("Failed to parse conversation meta creating result")]
110    ParseRespond(#[from] serde_json::Error),
111}
112
113impl From<reqwest::Error> for ConversationMetaCreatingError {
114    fn from(_value: reqwest::Error) -> Self {
115        Self::Network
116    }
117}
118
119pub type Result<T> = std::result::Result<T, ConversationMetaCreatingError>;