Skip to content

Integrates You.com chatbot in web-mode using session cookie. Supports conversation history + "create" chatMode (image generation). #834

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/background/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
isUsingOllamaApiModel,
isUsingAzureOpenAiApiModel,
isUsingClaudeApiModel,
isUsingYouWebModel,
isUsingChatGLMApiModel,
isUsingGithubThirdPartyApiModel,
isUsingGeminiWebModel,
Expand All @@ -41,8 +42,10 @@ import {
getBingAccessToken,
getChatGptAccessToken,
getClaudeSessionKey,
getYouSessionKey,
registerPortListener,
} from '../services/wrappers.mjs'
import { generateAnswersWithYouWebApi } from '../services/apis/you-web.mjs'
import { refreshMenu } from './menus.mjs'
import { registerCommands } from './commands.mjs'
import { generateAnswersWithBardWebApi } from '../services/apis/bard-web.mjs'
Expand Down Expand Up @@ -119,6 +122,9 @@ async function executeApi(session, port, config) {
} else if (isUsingClaudeWebModel(session)) {
const sessionKey = await getClaudeSessionKey()
await generateAnswersWithClaudeWebApi(port, session.question, session, sessionKey)
} else if (isUsingYouWebModel(session)) {
const sessionKey = await getYouSessionKey()
await generateAnswersWithYouWebApi(port, session.question, session, sessionKey)
} else if (isUsingMoonshotWebModel(session)) {
await generateAnswersWithMoonshotWebApi(port, session.question, session, config)
} else if (isUsingBingWebModel(session)) {
Expand Down
103 changes: 90 additions & 13 deletions src/config/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,33 @@ export const chatgptWebModelKeys = [
export const bingWebModelKeys = ['bingFree4', 'bingFreeSydney']
export const bardWebModelKeys = ['bardWebFree']
export const claudeWebModelKeys = ['claude2WebFree']
export const youWebModelKeys = [
'create',
'openai_o1',
'openai_o1_preview',
'openai_o1_mini',
'gpt_4o_mini',
'gpt_4o',
'gpt_4_turbo',
'gpt_4',
'grok_2',
'claude_3_5_sonnet',
'claude_3_opus',
'claude_3_sonnet',
'claude_3_5_haiku',
'llama3_3_70b',
'llama3_2_90b',
'llama3_1_405b',
'mistral_large_2',
'gemini_1_5_flash',
'gemini_1_5_pro',
'databricks_dbrx_instruct',
'qwen2p5_72b',
'qwen2p5_coder_32b',
'command_r_plus',
'solar_1_mini',
'dolphin_2_5',
]
export const moonshotWebModelKeys = ['moonshotWebFree']
export const gptApiModelKeys = ['gptApiInstruct', 'gptApiDavinci']
export const chatgptApiModelKeys = [
Expand Down Expand Up @@ -100,10 +127,14 @@ export const ModelGroups = {
value: chatgptWebModelKeys,
desc: 'ChatGPT (Web)',
},
claudeWebModelKeys: {
claudeWebModelKeys: {
value: claudeWebModelKeys,
desc: 'Claude.ai (Web)',
},
youWebModelKeys: {
value: youWebModelKeys,
desc: 'You.com (Web)',
},
moonshotWebModelKeys: {
value: moonshotWebModelKeys,
desc: 'Kimi.Moonshot (Web)',
Expand Down Expand Up @@ -217,6 +248,8 @@ export const Models = {
moonshotWebFree: { value: '', desc: 'Kimi.Moonshot (Web, 100k)' },

bardWebFree: { value: '', desc: 'Gemini (Web)' },
youWebFree: { value: "", desc: "You.com (Web)" }, // Added You.com model
create: { value: "create", desc: "You.com (Web, Create Mode)" }, // Added You.com create model

chatglmTurbo: { value: 'GLM-4-Air', desc: 'ChatGLM (GLM-4-Air, 128k)' },
chatglm4: { value: 'GLM-4-0520', desc: 'ChatGLM (GLM-4-0520, 128k)' },
Expand All @@ -233,6 +266,33 @@ export const Models = {

gptApiInstruct: { value: 'gpt-3.5-turbo-instruct', desc: 'GPT-3.5-turbo Instruct' },
gptApiDavinci: { value: 'text-davinci-003', desc: 'GPT-3.5' },

create: { value: 'create', desc: 'YouWeb create' },
Copy link
Preview

Copilot AI May 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate create key in the Models object (also defined at line 251). Please remove or consolidate one of the definitions to avoid key collisions.

Suggested change
create: { value: 'create', desc: 'YouWeb create' },
// Removed duplicate 'create' key to avoid key collisions

Copilot uses AI. Check for mistakes.

openai_o1: { value: 'openai_o1', desc: 'YouWeb openai_o1' },
openai_o1_preview: { value: 'openai_o1_preview', desc: 'YouWeb openai_o1_preview' },
openai_o1_mini: { value: 'openai_o1_mini', desc: 'YouWeb openai_o1_mini' },
gpt_4o_mini: { value: 'gpt_4o_mini', desc: 'YouWeb gpt_4o_mini' },
gpt_4o: { value: 'gpt_4o', desc: 'YouWeb gpt_4o' },
gpt_4_turbo: { value: 'gpt_4_turbo', desc: 'YouWeb gpt_4_turbo' },
gpt_4: { value: 'gpt_4', desc: 'YouWeb gpt_4' },
grok_2: { value: 'grok_2', desc: 'YouWeb grok_2' },
claude_3_5_sonnet: { value: 'claude_3_5_sonnet', desc: 'YouWeb claude_3_5_sonnet' },
claude_3_opus: { value: 'claude_3_opus', desc: 'YouWeb claude_3_opus' },
claude_3_sonnet: { value: 'claude_3_sonnet', desc: 'YouWeb claude_3_sonnet' },
claude_3_5_haiku: { value: 'claude_3_5_haiku', desc: 'YouWeb claude_3_5_haiku' },
llama3_3_70b: { value: 'llama3_3_70b', desc: 'YouWeb llama3_3_70b' },
llama3_2_90b: { value: 'llama3_2_90b', desc: 'YouWeb llama3_2_90b' },
llama3_1_405b: { value: 'llama3_1_405b', desc: 'YouWeb llama3_1_405b' },
mistral_large_2: { value: 'mistral_large_2', desc: 'YouWeb mistral_large_2' },
gemini_1_5_flash: { value: 'gemini_1_5_flash', desc: 'YouWeb gemini_1_5_flash' },
gemini_1_5_pro: { value: 'gemini_1_5_pro', desc: 'YouWeb gemini_1_5_pro' },
databricks_dbrx_instruct: { value: 'databricks_dbrx_instruct', desc: 'YouWeb databricks_dbrx_instruct' },
qwen2p5_72b: { value: 'qwen2p5_72b', desc: 'YouWeb qwen2p5_72b' },
qwen2p5_coder_32b: { value: 'qwen2p5_coder_32b', desc: 'YouWeb qwen2p5_coder_32b' },
command_r_plus: { value: 'command_r_plus', desc: 'YouWeb command_r_plus' },
solar_1_mini: { value: 'solar_1_mini', desc: 'YouWeb solar_1_mini' },
dolphin_2_5: { value: 'dolphin_2_5', desc: 'YouWeb dolphin_2_5' },


customModel: { value: '', desc: 'Custom Model' },
ollamaModel: { value: '', desc: 'Ollama API' },
Expand Down Expand Up @@ -355,18 +415,31 @@ export const defaultConfig = {
// It allows the content of activeApiModes to change with version updates when the user has not customized ApiModes.
// If it were directly written into customApiModes, the value would become fixed, even if the user has not made any customizations.
activeApiModes: [
'chatgptFree35',
'chatgptFree4o',
'chatgptApi35',
'chatgptApi4o_128k',
'claude2WebFree',
'claude35SonnetApi',
'bingFree4',
'moonshotWebFree',
'moonshot_v1_8k',
'chatglmTurbo',
'customModel',
'azureOpenAi',
'create',
'openai_o1',
'openai_o1_preview',
'openai_o1_mini',
'gpt_4o_mini',
'gpt_4o',
'gpt_4_turbo',
'gpt_4',
'grok_2',
'claude_3_5_sonnet',
'claude_3_opus',
'claude_3_sonnet',
'claude_3_5_haiku',
'llama3_3_70b',
'llama3_2_90b',
'llama3_1_405b',
'mistral_large_2',
'gemini_1_5_flash',
'gemini_1_5_pro',
'databricks_dbrx_instruct',
'qwen2p5_72b',
'qwen2p5_coder_32b',
'command_r_plus',
'solar_1_mini',
'dolphin_2_5',
],
customApiModes: [
{
Expand Down Expand Up @@ -470,6 +543,10 @@ export function isUsingClaudeWebModel(configOrSession) {
return isInApiModeGroup(claudeWebModelKeys, configOrSession)
}

export function isUsingYouWebModel(configOrSession) {
return isInApiModeGroup(youWebModelKeys, configOrSession)
}

export function isUsingMoonshotWebModel(configOrSession) {
return isInApiModeGroup(moonshotWebModelKeys, configOrSession)
}
Expand Down
114 changes: 114 additions & 0 deletions src/services/apis/you-web.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// path/to/services/apis/you-web.mjs

import { pushRecord, setAbortController } from '../../services/apis/shared.mjs'
import { fetchSSE } from '../../utils/fetch-sse.mjs'
import { getUserConfig, youWebModelKeys } from '../../config/index.mjs'
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
import { getModelValue, isUsingModelName } from '../../utils/model-name-convert.mjs'

/**
* @param {Runtime.Port} port
* @param {string} question
* @param {Session} session
* @param {string} sessionCookie
*/
export async function generateAnswersWithYouWebApi(port, question, session, sessionCookie) {
const { controller, cleanController } = setAbortController(port)
const config = await getUserConfig()
const model = getModelValue(session)

const apiUrl = 'https://you.com/api/streamingSearch'

// Use the existing chatId from the session or generate a new one
if (!session.chatId) {
session.chatId = generateUUID() // You need a function to generate UUIDs
}

// Always include the conversation history
const conversationContext = getConversationPairs(session.conversationRecords, false)

const traceId = `${session.chatId}|${session.messageId}|${new Date().toISOString()}`

const params = new URLSearchParams()
params.append('page', '1')
params.append('count', '10')
params.append('safeSearch', 'Off')
params.append('q', question)
params.append('chatId', session.chatId) // Use the existing or new chatId
params.append('traceId', traceId)
params.append('conversationTurnId', session.messageId)
params.append('selectedAiModel', model)

// Conditional chatMode based on modelName
let chatMode = 'custom'
if (isUsingModelName('create', session)) {
chatMode = 'create'
}
params.append('selectedChatMode', chatMode)

params.append('pastChatLength', session.conversationRecords.length.toString())
params.append('queryTraceId', traceId)
params.append('use_personalization_extraction', 'false')
params.append('domain', 'youchat')
params.append('mkt', 'en-US')
params.append('chat', JSON.stringify(conversationContext))

const url = `${apiUrl}?${params.toString()}`

let answer = ''

await fetchSSE(url, {
method: 'GET',
signal: controller.signal,
headers: {
'Content-Type': 'text/event-stream;charset=utf-8',
Copy link
Preview

Copilot AI May 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] For SSE GET requests, it's more appropriate to set an Accept: 'text/event-stream' header instead of Content-Type to signal the expected response format.

Suggested change
'Content-Type': 'text/event-stream;charset=utf-8',
'Accept': 'text/event-stream',

Copilot uses AI. Check for mistakes.

Cookie: `sessionKey=${sessionCookie}`,
'User-Agent': navigator.userAgent,
},
onMessage(message) {
if (message.trim() === '[DONE]') {
finishMessage()
return
}

let data
try {
data = JSON.parse(message)
} catch (error) {
console.error('SSE message parse error:', error)
return
}

if (data.youChatToken) {
answer += data.youChatToken
port.postMessage({ answer: answer, done: false, session: null })
}
},
onStart() {
// Handle start if needed
},
onEnd() {
finishMessage()
Copy link
Preview

Copilot AI May 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling finishMessage() here will push the record and post a completed message, but the onEnd callback also calls finishMessage(), leading to duplicate pushes and messages. Consider invoking it in only one place.

Suggested change
finishMessage()
if (!isFinished) {
finishMessage()
isFinished = true
}

Copilot uses AI. Check for mistakes.

port.postMessage({ done: true })
cleanController()
},
onError(error) {
cleanController()
port.postMessage({ error: error.message, done: true })
},
})

function finishMessage() {
pushRecord(session, question, answer)
port.postMessage({ answer: answer, done: true, session: session })
}
}

// Helper function to generate UUIDs (you can use a library for this if you prefer)
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
}
4 changes: 4 additions & 0 deletions src/services/wrappers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export async function getClaudeSessionKey() {
return (await Browser.cookies.get({ url: 'https://claude.ai/', name: 'sessionKey' }))?.value
}

export async function getYouSessionKey() {
return (await Browser.cookies.get({ url: 'https://you.com/', name: 'sessionKey' }))?.value
}

export function handlePortError(session, port, err) {
console.error(err)
if (err.message) {
Expand Down