prettier fix
This commit is contained in:
parent
528dfe01a1
commit
669c019fd8
@ -10,16 +10,16 @@ packaging.
|
||||
Install dependencies and run the development app:
|
||||
|
||||
```
|
||||
1. npm install
|
||||
2. npm start
|
||||
1. pnpm install
|
||||
2. pnpm start
|
||||
```
|
||||
|
||||
## Style
|
||||
|
||||
Run `npx prettier --write .` before committing. Prettier uses the settings in
|
||||
Run `pnpm prettier --write .` before committing. Prettier uses the settings in
|
||||
`.prettierrc` (four-space indentation, print width 150, semicolons and single
|
||||
quotes). `src/assets` and `node_modules` are ignored via `.prettierignore`.
|
||||
The project does not provide linting; `npm run lint` simply prints
|
||||
The project does not provide linting; `pnpm run lint` simply prints
|
||||
"No linting configured".
|
||||
|
||||
## Code standards
|
||||
|
||||
@ -76,8 +76,8 @@ module.exports = {
|
||||
genericName: 'AI Assistant',
|
||||
description: 'AI assistant for interviews and learning',
|
||||
categories: ['Development', 'Education'],
|
||||
icon: 'src/assets/logo.png'
|
||||
}
|
||||
icon: 'src/assets/logo.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -5,7 +5,6 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@google/genai':
|
||||
@ -59,7 +58,6 @@ importers:
|
||||
version: 39.2.7
|
||||
|
||||
packages:
|
||||
|
||||
'@electron-forge/cli@7.11.1':
|
||||
resolution: { integrity: sha512-pk8AoLsr7t7LBAt0cFD06XFA6uxtPdvtLx06xeal7O9o7GHGCbj29WGwFoJ8Br/ENM0Ho868S3PrAn1PtBXt5g== }
|
||||
engines: { node: '>= 16.4.0' }
|
||||
@ -2176,7 +2174,6 @@ packages:
|
||||
engines: { node: '>=18' }
|
||||
|
||||
snapshots:
|
||||
|
||||
'@electron-forge/cli@7.11.1(encoding@0.1.13)':
|
||||
dependencies:
|
||||
'@electron-forge/core': 7.11.1(encoding@0.1.13)
|
||||
|
||||
@ -3,7 +3,11 @@ import { html, css, LitElement } from '../../assets/lit-core-2.7.4.min.js';
|
||||
export class AppHeader extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
@ -155,7 +159,9 @@ export class AppHeader extends LitElement {
|
||||
white-space: normal;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.15s ease, visibility 0.15s ease;
|
||||
transition:
|
||||
opacity 0.15s ease,
|
||||
visibility 0.15s ease;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 1000;
|
||||
@ -224,7 +230,9 @@ export class AppHeader extends LitElement {
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.15s ease, visibility 0.15s ease;
|
||||
transition:
|
||||
opacity 0.15s ease,
|
||||
visibility 0.15s ease;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 1000;
|
||||
@ -421,7 +429,7 @@ export class AppHeader extends LitElement {
|
||||
const names = {
|
||||
'gemini': 'Gemini',
|
||||
'openai-realtime': 'OpenAI Realtime',
|
||||
'openai-sdk': 'OpenAI SDK'
|
||||
'openai-sdk': 'OpenAI SDK',
|
||||
};
|
||||
return names[this.aiProvider] || this.aiProvider;
|
||||
}
|
||||
@ -471,39 +479,59 @@ export class AppHeader extends LitElement {
|
||||
<span>${elapsedTime}</span>
|
||||
<div class="status-wrapper">
|
||||
<span class="status-text ${isError ? 'error' : ''}">${shortStatus}</span>
|
||||
${isError ? html`
|
||||
${isError
|
||||
? html`
|
||||
<div class="status-tooltip">
|
||||
<div class="tooltip-label">Error Details</div>
|
||||
<div class="tooltip-content">${this.statusText}</div>
|
||||
</div>
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
</div>
|
||||
${this.isClickThrough ? html`<span class="click-through-indicator">click-through</span>` : ''}
|
||||
`
|
||||
: ''}
|
||||
${this.currentView === 'main'
|
||||
? html`
|
||||
${this.updateAvailable ? html`
|
||||
${this.updateAvailable
|
||||
? html`
|
||||
<button class="update-button" @click=${this._openUpdatePage}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M13.836 2.477a.75.75 0 0 1 .75.75v3.182a.75.75 0 0 1-.75.75h-3.182a.75.75 0 0 1 0-1.5h1.37l-.84-.841a4.5 4.5 0 0 0-7.08.932.75.75 0 0 1-1.3-.75 6 6 0 0 1 9.44-1.242l.842.84V3.227a.75.75 0 0 1 .75-.75Zm-.911 7.5A.75.75 0 0 1 13.199 11a6 6 0 0 1-9.44 1.241l-.84-.84v1.371a.75.75 0 0 1-1.5 0V9.591a.75.75 0 0 1 .75-.75H5.35a.75.75 0 0 1 0 1.5H3.98l.841.841a4.5 4.5 0 0 0 7.08-.932.75.75 0 0 1 1.025-.273Z" clip-rule="evenodd" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M13.836 2.477a.75.75 0 0 1 .75.75v3.182a.75.75 0 0 1-.75.75h-3.182a.75.75 0 0 1 0-1.5h1.37l-.84-.841a4.5 4.5 0 0 0-7.08.932.75.75 0 0 1-1.3-.75 6 6 0 0 1 9.44-1.242l.842.84V3.227a.75.75 0 0 1 .75-.75Zm-.911 7.5A.75.75 0 0 1 13.199 11a6 6 0 0 1-9.44 1.241l-.84-.84v1.371a.75.75 0 0 1-1.5 0V9.591a.75.75 0 0 1 .75-.75H5.35a.75.75 0 0 1 0 1.5H3.98l.841.841a4.5 4.5 0 0 0 7.08-.932.75.75 0 0 1 1.025-.273Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Update available
|
||||
</button>
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
<button class="icon-button" @click=${this.onHistoryClick}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm.75-13a.75.75 0 0 0-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 0 0 0-1.5h-3.25V5Z" clip-rule="evenodd" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm.75-13a.75.75 0 0 0-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 0 0 0-1.5h-3.25V5Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-button" @click=${this.onCustomizeClick}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M7.84 1.804A1 1 0 0 1 8.82 1h2.36a1 1 0 0 1 .98.804l.331 1.652a6.993 6.993 0 0 1 1.929 1.115l1.598-.54a1 1 0 0 1 1.186.447l1.18 2.044a1 1 0 0 1-.205 1.251l-1.267 1.113a7.047 7.047 0 0 1 0 2.228l1.267 1.113a1 1 0 0 1 .206 1.25l-1.18 2.045a1 1 0 0 1-1.187.447l-1.598-.54a6.993 6.993 0 0 1-1.929 1.115l-.33 1.652a1 1 0 0 1-.98.804H8.82a1 1 0 0 1-.98-.804l-.331-1.652a6.993 6.993 0 0 1-1.929-1.115l-1.598.54a1 1 0 0 1-1.186-.447l-1.18-2.044a1 1 0 0 1 .205-1.251l1.267-1.114a7.05 7.05 0 0 1 0-2.227L1.821 7.773a1 1 0 0 1-.206-1.25l1.18-2.045a1 1 0 0 1 1.187-.447l1.598.54A6.992 6.992 0 0 1 7.51 3.456l.33-1.652ZM10 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" clip-rule="evenodd" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M7.84 1.804A1 1 0 0 1 8.82 1h2.36a1 1 0 0 1 .98.804l.331 1.652a6.993 6.993 0 0 1 1.929 1.115l1.598-.54a1 1 0 0 1 1.186.447l1.18 2.044a1 1 0 0 1-.205 1.251l-1.267 1.113a7.047 7.047 0 0 1 0 2.228l1.267 1.113a1 1 0 0 1 .206 1.25l-1.18 2.045a1 1 0 0 1-1.187.447l-1.598-.54a6.993 6.993 0 0 1-1.929 1.115l-.33 1.652a1 1 0 0 1-.98.804H8.82a1 1 0 0 1-.98-.804l-.331-1.652a6.993 6.993 0 0 1-1.929-1.115l-1.598.54a1 1 0 0 1-1.186-.447l-1.18-2.044a1 1 0 0 1 .205-1.251l1.267-1.114a7.05 7.05 0 0 1 0-2.227L1.821 7.773a1 1 0 0 1-.206-1.25l1.18-2.045a1 1 0 0 1 1.187-.447l1.598.54A6.992 6.992 0 0 1 7.51 3.456l.33-1.652ZM10 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-button" @click=${this.onHelpClick}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM8.94 6.94a.75.75 0 1 1-1.061-1.061 3 3 0 1 1 2.871 5.026v.345a.75.75 0 0 1-1.5 0v-.5c0-.72.57-1.172 1.081-1.287A1.5 1.5 0 1 0 8.94 6.94ZM10 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM8.94 6.94a.75.75 0 1 1-1.061-1.061 3 3 0 1 1 2.871 5.026v.345a.75.75 0 0 1-1.5 0v-.5c0-.72.57-1.172 1.081-1.287A1.5 1.5 0 1 0 8.94 6.94ZM10 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
`
|
||||
@ -516,14 +544,18 @@ export class AppHeader extends LitElement {
|
||||
</button>
|
||||
<button @click=${this.onCloseClick} class="icon-button window-close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
|
||||
<path
|
||||
d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
`
|
||||
: html`
|
||||
<button @click=${this.isNavigationView() ? this.onBackClick : this.onCloseClick} class="icon-button window-close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
|
||||
<path
|
||||
d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
`}
|
||||
|
||||
@ -12,7 +12,11 @@ export class CheatingDaddyApp extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
cursor: default;
|
||||
@ -152,17 +156,14 @@ export class CheatingDaddyApp extends LitElement {
|
||||
const [config, prefs, openaiSdkCreds] = await Promise.all([
|
||||
cheatingDaddy.storage.getConfig(),
|
||||
cheatingDaddy.storage.getPreferences(),
|
||||
cheatingDaddy.storage.getOpenAISDKCredentials()
|
||||
cheatingDaddy.storage.getOpenAISDKCredentials(),
|
||||
]);
|
||||
|
||||
// Check onboarding status
|
||||
this.currentView = config.onboarded ? 'main' : 'onboarding';
|
||||
|
||||
// Apply background appearance (color + transparency)
|
||||
this.applyBackgroundAppearance(
|
||||
prefs.backgroundColor ?? '#1e1e1e',
|
||||
prefs.backgroundTransparency ?? 0.8
|
||||
);
|
||||
this.applyBackgroundAppearance(prefs.backgroundColor ?? '#1e1e1e', prefs.backgroundTransparency ?? 0.8);
|
||||
|
||||
// Load preferences
|
||||
this.selectedProfile = prefs.selectedProfile || 'interview';
|
||||
@ -176,7 +177,7 @@ export class CheatingDaddyApp extends LitElement {
|
||||
this.modelInfo = {
|
||||
model: openaiSdkCreds.model || 'gpt-4o',
|
||||
visionModel: openaiSdkCreds.visionModel || 'gpt-4o',
|
||||
whisperModel: openaiSdkCreds.whisperModel || 'whisper-1'
|
||||
whisperModel: openaiSdkCreds.whisperModel || 'whisper-1',
|
||||
};
|
||||
|
||||
this._storageLoaded = true;
|
||||
@ -191,18 +192,20 @@ export class CheatingDaddyApp extends LitElement {
|
||||
|
||||
hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : { r: 30, g: 30, b: 30 };
|
||||
b: parseInt(result[3], 16),
|
||||
}
|
||||
: { r: 30, g: 30, b: 30 };
|
||||
}
|
||||
|
||||
lightenColor(rgb, amount) {
|
||||
return {
|
||||
r: Math.min(255, rgb.r + amount),
|
||||
g: Math.min(255, rgb.g + amount),
|
||||
b: Math.min(255, rgb.b + amount)
|
||||
b: Math.min(255, rgb.b + amount),
|
||||
};
|
||||
}
|
||||
|
||||
@ -525,11 +528,11 @@ export class CheatingDaddyApp extends LitElement {
|
||||
|
||||
render() {
|
||||
const viewClassMap = {
|
||||
'assistant': 'assistant-view',
|
||||
'onboarding': 'onboarding-view',
|
||||
'customize': 'settings-view',
|
||||
'help': 'help-view',
|
||||
'history': 'history-view',
|
||||
assistant: 'assistant-view',
|
||||
onboarding: 'onboarding-view',
|
||||
customize: 'settings-view',
|
||||
help: 'help-view',
|
||||
history: 'history-view',
|
||||
};
|
||||
const mainContentClass = `main-content ${viewClassMap[this.currentView] || 'with-border'}`;
|
||||
|
||||
@ -602,7 +605,7 @@ export class CheatingDaddyApp extends LitElement {
|
||||
if (result.success) {
|
||||
this.screenSources = result.sources;
|
||||
this.showScreenPicker = true;
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
this._screenPickerResolve = resolve;
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -9,7 +9,11 @@ export class AssistantView extends LitElement {
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@ -51,12 +55,24 @@ export class AssistantView extends LitElement {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.response-container h1 { font-size: 1.6em; }
|
||||
.response-container h2 { font-size: 1.4em; }
|
||||
.response-container h3 { font-size: 1.2em; }
|
||||
.response-container h4 { font-size: 1.1em; }
|
||||
.response-container h5 { font-size: 1em; }
|
||||
.response-container h6 { font-size: 0.9em; }
|
||||
.response-container h1 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
.response-container h2 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
.response-container h3 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.response-container h4 {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.response-container h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
.response-container h6 {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.response-container p {
|
||||
margin: 0.6em 0;
|
||||
@ -268,7 +284,9 @@ export class AssistantView extends LitElement {
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.15s ease, visibility 0.15s ease;
|
||||
transition:
|
||||
opacity 0.15s ease,
|
||||
visibility 0.15s ease;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 100;
|
||||
@ -655,12 +673,17 @@ export class AssistantView extends LitElement {
|
||||
<div class="capture-buttons">
|
||||
<button class="region-select-btn" @click=${this.handleRegionSelect} title="Select region to analyze (like Win+Shift+S)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M4.25 2A2.25 2.25 0 0 0 2 4.25v2.5A.75.75 0 0 0 3.5 6.75v-2.5a.75.75 0 0 1 .75-.75h2.5A.75.75 0 0 0 6.75 2h-2.5Zm9.5 0a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 1 .75.75v2.5a.75.75 0 0 0 1.5 0v-2.5A2.25 2.25 0 0 0 16.25 2h-2.5ZM3.5 13.25a.75.75 0 0 0-1.5 0v2.5A2.25 2.25 0 0 0 4.25 18h2.5a.75.75 0 0 0 0-1.5h-2.5a.75.75 0 0 1-.75-.75v-2.5Zm13.5 0a.75.75 0 0 0 1.5 0v2.5A2.25 2.25 0 0 1 16.25 18h-2.5a.75.75 0 0 1 0-1.5h2.5a.75.75 0 0 0 .75-.75v-2.5Z" clip-rule="evenodd" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.25 2A2.25 2.25 0 0 0 2 4.25v2.5A.75.75 0 0 0 3.5 6.75v-2.5a.75.75 0 0 1 .75-.75h2.5A.75.75 0 0 0 6.75 2h-2.5Zm9.5 0a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 1 .75.75v2.5a.75.75 0 0 0 1.5 0v-2.5A2.25 2.25 0 0 0 16.25 2h-2.5ZM3.5 13.25a.75.75 0 0 0-1.5 0v2.5A2.25 2.25 0 0 0 4.25 18h2.5a.75.75 0 0 0 0-1.5h-2.5a.75.75 0 0 1-.75-.75v-2.5Zm13.5 0a.75.75 0 0 0 1.5 0v2.5A2.25 2.25 0 0 1 16.25 18h-2.5a.75.75 0 0 1 0-1.5h2.5a.75.75 0 0 0 .75-.75v-2.5Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<span>Select region</span>
|
||||
</button>
|
||||
<div class="screen-answer-btn-wrapper">
|
||||
${this.aiProvider === 'gemini' ? html`
|
||||
${this.aiProvider === 'gemini'
|
||||
? html`
|
||||
<div class="tooltip">
|
||||
<div class="tooltip-row">
|
||||
<span class="tooltip-label">Flash</span>
|
||||
@ -672,13 +695,18 @@ export class AssistantView extends LitElement {
|
||||
</div>
|
||||
<div class="tooltip-note">Resets every 24 hours</div>
|
||||
</div>
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
<button class="screen-answer-btn" @click=${this.handleScreenAnswer}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M15.98 1.804a1 1 0 0 0-1.96 0l-.24 1.192a1 1 0 0 1-.784.785l-1.192.238a1 1 0 0 0 0 1.962l1.192.238a1 1 0 0 1 .785.785l.238 1.192a1 1 0 0 0 1.962 0l.238-1.192a1 1 0 0 1 .785-.785l1.192-.238a1 1 0 0 0 0-1.962l-1.192-.238a1 1 0 0 1-.785-.785l-.238-1.192ZM6.949 5.684a1 1 0 0 0-1.898 0l-.683 2.051a1 1 0 0 1-.633.633l-2.051.683a1 1 0 0 0 0 1.898l2.051.684a1 1 0 0 1 .633.632l.683 2.051a1 1 0 0 0 1.898 0l.683-2.051a1 1 0 0 1 .633-.633l2.051-.683a1 1 0 0 0 0-1.898l-2.051-.683a1 1 0 0 1-.633-.633L6.95 5.684ZM13.949 13.684a1 1 0 0 0-1.898 0l-.184.551a1 1 0 0 1-.632.633l-.551.183a1 1 0 0 0 0 1.898l.551.183a1 1 0 0 1 .633.633l.183.551a1 1 0 0 0 1.898 0l.184-.551a1 1 0 0 1 .632-.633l.551-.183a1 1 0 0 0 0-1.898l-.551-.184a1 1 0 0 1-.633-.632l-.183-.551Z" />
|
||||
<path
|
||||
d="M15.98 1.804a1 1 0 0 0-1.96 0l-.24 1.192a1 1 0 0 1-.784.785l-1.192.238a1 1 0 0 0 0 1.962l1.192.238a1 1 0 0 1 .785.785l.238 1.192a1 1 0 0 0 1.962 0l.238-1.192a1 1 0 0 1 .785-.785l1.192-.238a1 1 0 0 0 0-1.962l-1.192-.238a1 1 0 0 1-.785-.785l-.238-1.192ZM6.949 5.684a1 1 0 0 0-1.898 0l-.683 2.051a1 1 0 0 1-.633.633l-2.051.683a1 1 0 0 0 0 1.898l2.051.684a1 1 0 0 1 .633.632l.683 2.051a1 1 0 0 0 1.898 0l.683-2.051a1 1 0 0 1 .633-.633l2.051-.683a1 1 0 0 0 0-1.898l-2.051-.683a1 1 0 0 1-.633-.633L6.95 5.684ZM13.949 13.684a1 1 0 0 0-1.898 0l-.184.551a1 1 0 0 1-.632.633l-.551.183a1 1 0 0 0 0 1.898l.551.183a1 1 0 0 1 .633.633l.183.551a1 1 0 0 0 1.898 0l.184-.551a1 1 0 0 1 .632-.633l.551-.183a1 1 0 0 0 0-1.898l-.551-.184a1 1 0 0 1-.633-.632l-.183-.551Z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Full screen</span>
|
||||
${this.aiProvider === 'gemini' ? html`<span class="usage-count">(${this.getTotalUsed()}/${this.getTotalAvailable()})</span>` : ''}
|
||||
${this.aiProvider === 'gemini'
|
||||
? html`<span class="usage-count">(${this.getTotalUsed()}/${this.getTotalAvailable()})</span>`
|
||||
: ''}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,7 +4,11 @@ import { resizeLayout } from '../../utils/windowResize.js';
|
||||
export class CustomizeView extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
@ -634,31 +638,87 @@ export class CustomizeView extends LitElement {
|
||||
|
||||
renderSidebarIcon(icon) {
|
||||
const icons = {
|
||||
user: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 21V19C19 17.9391 18.5786 16.9217 17.8284 16.1716C17.0783 15.4214 16.0609 15 15 15H9C7.93913 15 6.92172 15.4214 6.17157 16.1716C5.42143 16.9217 5 17.9391 5 19V21"></path>
|
||||
user: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M19 21V19C19 17.9391 18.5786 16.9217 17.8284 16.1716C17.0783 15.4214 16.0609 15 15 15H9C7.93913 15 6.92172 15.4214 6.17157 16.1716C5.42143 16.9217 5 17.9391 5 19V21"
|
||||
></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>`,
|
||||
mic: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
mic: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
|
||||
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
|
||||
<line x1="12" y1="19" x2="12" y2="23"></line>
|
||||
<line x1="8" y1="23" x2="16" y2="23"></line>
|
||||
</svg>`,
|
||||
globe: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
globe: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="2" y1="12" x2="22" y2="12"></line>
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
|
||||
</svg>`,
|
||||
display: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
display: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
||||
<line x1="8" y1="21" x2="16" y2="21"></line>
|
||||
<line x1="12" y1="17" x2="12" y2="21"></line>
|
||||
</svg>`,
|
||||
camera: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
camera: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
|
||||
<circle cx="12" cy="13" r="4"></circle>
|
||||
</svg>`,
|
||||
keyboard: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
keyboard: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect x="2" y="4" width="20" height="16" rx="2" ry="2"></rect>
|
||||
<path d="M6 8h.001"></path>
|
||||
<path d="M10 8h.001"></path>
|
||||
@ -669,11 +729,29 @@ export class CustomizeView extends LitElement {
|
||||
<path d="M16 12h.001"></path>
|
||||
<path d="M7 16h10"></path>
|
||||
</svg>`,
|
||||
search: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
search: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||||
</svg>`,
|
||||
cpu: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
cpu: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect>
|
||||
<rect x="9" y="9" width="6" height="6"></rect>
|
||||
<line x1="9" y1="1" x2="9" y2="4"></line>
|
||||
@ -685,7 +763,16 @@ export class CustomizeView extends LitElement {
|
||||
<line x1="1" y1="9" x2="4" y2="9"></line>
|
||||
<line x1="1" y1="14" x2="4" y2="14"></line>
|
||||
</svg>`,
|
||||
warning: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
warning: html`<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
|
||||
<line x1="12" y1="9" x2="12" y2="13"></line>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||
@ -701,7 +788,7 @@ export class CustomizeView extends LitElement {
|
||||
cheatingDaddy.storage.getKeybinds(),
|
||||
cheatingDaddy.storage.getCredentials(),
|
||||
cheatingDaddy.storage.getOpenAICredentials(),
|
||||
cheatingDaddy.storage.getOpenAISDKCredentials()
|
||||
cheatingDaddy.storage.getOpenAISDKCredentials(),
|
||||
]);
|
||||
|
||||
this.googleSearchEnabled = prefs.googleSearchEnabled ?? true;
|
||||
@ -1072,21 +1159,21 @@ export class CustomizeView extends LitElement {
|
||||
async handleOpenAIApiKeyInput(e) {
|
||||
this.openaiApiKey = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAICredentials({
|
||||
apiKey: e.target.value
|
||||
apiKey: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAIBaseUrlInput(e) {
|
||||
this.openaiBaseUrl = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAICredentials({
|
||||
baseUrl: e.target.value
|
||||
baseUrl: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAIModelInput(e) {
|
||||
this.openaiModel = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAICredentials({
|
||||
model: e.target.value
|
||||
model: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1094,35 +1181,35 @@ export class CustomizeView extends LitElement {
|
||||
async handleOpenAISdkApiKeyInput(e) {
|
||||
this.openaiSdkApiKey = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAISDKCredentials({
|
||||
apiKey: e.target.value
|
||||
apiKey: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAISdkBaseUrlInput(e) {
|
||||
this.openaiSdkBaseUrl = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAISDKCredentials({
|
||||
baseUrl: e.target.value
|
||||
baseUrl: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAISdkModelInput(e) {
|
||||
this.openaiSdkModel = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAISDKCredentials({
|
||||
model: e.target.value
|
||||
model: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAISdkVisionModelInput(e) {
|
||||
this.openaiSdkVisionModel = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAISDKCredentials({
|
||||
visionModel: e.target.value
|
||||
visionModel: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
async handleOpenAISdkWhisperModelInput(e) {
|
||||
this.openaiSdkWhisperModel = e.target.value;
|
||||
await cheatingDaddy.storage.setOpenAISDKCredentials({
|
||||
whisperModel: e.target.value
|
||||
whisperModel: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1209,9 +1296,7 @@ export class CustomizeView extends LitElement {
|
||||
<select class="form-control" .value=${this.selectedProfile} @change=${this.handleProfileSelect}>
|
||||
${profiles.map(
|
||||
profile => html`
|
||||
<option value=${profile.value} ?selected=${this.selectedProfile === profile.value}>
|
||||
${profile.name}
|
||||
</option>
|
||||
<option value=${profile.value} ?selected=${this.selectedProfile === profile.value}>${profile.name}</option>
|
||||
`
|
||||
)}
|
||||
</select>
|
||||
@ -1221,15 +1306,12 @@ export class CustomizeView extends LitElement {
|
||||
<label class="form-label">Custom AI Instructions</label>
|
||||
<textarea
|
||||
class="form-control"
|
||||
placeholder="Add specific instructions for how you want the AI to behave during ${
|
||||
profileNames[this.selectedProfile] || 'this interaction'
|
||||
}..."
|
||||
placeholder="Add specific instructions for how you want the AI to behave during ${profileNames[this.selectedProfile] ||
|
||||
'this interaction'}..."
|
||||
.value=${this.customPrompt}
|
||||
@input=${this.handleCustomPromptInput}
|
||||
></textarea>
|
||||
<div class="form-description">
|
||||
Personalize the AI's behavior with specific instructions
|
||||
</div>
|
||||
<div class="form-description">Personalize the AI's behavior with specific instructions</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1247,9 +1329,7 @@ export class CustomizeView extends LitElement {
|
||||
<option value="mic_only">Microphone Only (Me)</option>
|
||||
<option value="both">Both Speaker & Microphone</option>
|
||||
</select>
|
||||
<div class="form-description">
|
||||
Choose which audio sources to capture for the AI.
|
||||
</div>
|
||||
<div class="form-description">Choose which audio sources to capture for the AI.</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -1270,9 +1350,7 @@ export class CustomizeView extends LitElement {
|
||||
<select class="form-control" .value=${this.selectedLanguage} @change=${this.handleLanguageSelect}>
|
||||
${languages.map(
|
||||
language => html`
|
||||
<option value=${language.value} ?selected=${this.selectedLanguage === language.value}>
|
||||
${language.name}
|
||||
</option>
|
||||
<option value=${language.value} ?selected=${this.selectedLanguage === language.value}>${language.name}</option>
|
||||
`
|
||||
)}
|
||||
</select>
|
||||
@ -1295,17 +1373,9 @@ export class CustomizeView extends LitElement {
|
||||
<span class="current-selection">${currentTheme?.name || 'Dark'}</span>
|
||||
</label>
|
||||
<select class="form-control" .value=${this.theme} @change=${this.handleThemeChange}>
|
||||
${themes.map(
|
||||
theme => html`
|
||||
<option value=${theme.value} ?selected=${this.theme === theme.value}>
|
||||
${theme.name}
|
||||
</option>
|
||||
`
|
||||
)}
|
||||
${themes.map(theme => html` <option value=${theme.value} ?selected=${this.theme === theme.value}>${theme.name}</option> `)}
|
||||
</select>
|
||||
<div class="form-description">
|
||||
Choose a color theme for the interface
|
||||
</div>
|
||||
<div class="form-description">Choose a color theme for the interface</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@ -1318,10 +1388,7 @@ export class CustomizeView extends LitElement {
|
||||
<option value="compact" ?selected=${this.layoutMode === 'compact'}>Compact</option>
|
||||
</select>
|
||||
<div class="form-description">
|
||||
${this.layoutMode === 'compact'
|
||||
? 'Smaller window with reduced padding'
|
||||
: 'Standard layout with comfortable spacing'
|
||||
}
|
||||
${this.layoutMode === 'compact' ? 'Smaller window with reduced padding' : 'Standard layout with comfortable spacing'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1379,7 +1446,9 @@ export class CustomizeView extends LitElement {
|
||||
<div class="form-group">
|
||||
<label class="form-label">
|
||||
Image Quality
|
||||
<span class="current-selection">${this.selectedImageQuality.charAt(0).toUpperCase() + this.selectedImageQuality.slice(1)}</span>
|
||||
<span class="current-selection"
|
||||
>${this.selectedImageQuality.charAt(0).toUpperCase() + this.selectedImageQuality.slice(1)}</span
|
||||
>
|
||||
</label>
|
||||
<select class="form-control" .value=${this.selectedImageQuality} @change=${this.handleImageQualitySelect}>
|
||||
<option value="high" ?selected=${this.selectedImageQuality === 'high'}>High Quality</option>
|
||||
@ -1391,8 +1460,7 @@ export class CustomizeView extends LitElement {
|
||||
? 'Best quality, uses more tokens'
|
||||
: this.selectedImageQuality === 'medium'
|
||||
? 'Balanced quality and token usage'
|
||||
: 'Lower quality, uses fewer tokens'
|
||||
}
|
||||
: 'Lower quality, uses fewer tokens'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1446,9 +1514,9 @@ export class CustomizeView extends LitElement {
|
||||
|
||||
renderAIProviderSection() {
|
||||
const providerNames = {
|
||||
'gemini': 'Google Gemini',
|
||||
gemini: 'Google Gemini',
|
||||
'openai-realtime': 'OpenAI Realtime',
|
||||
'openai-sdk': 'OpenAI SDK (BotHub, etc.)'
|
||||
'openai-sdk': 'OpenAI SDK (BotHub, etc.)',
|
||||
};
|
||||
|
||||
return html`
|
||||
@ -1464,12 +1532,11 @@ export class CustomizeView extends LitElement {
|
||||
<option value="openai-realtime" ?selected=${this.aiProvider === 'openai-realtime'}>OpenAI Realtime API</option>
|
||||
<option value="openai-sdk" ?selected=${this.aiProvider === 'openai-sdk'}>OpenAI SDK (BotHub, Azure, etc.)</option>
|
||||
</select>
|
||||
<div class="form-description">
|
||||
Choose which AI provider to use for conversations and screen analysis
|
||||
</div>
|
||||
<div class="form-description">Choose which AI provider to use for conversations and screen analysis</div>
|
||||
</div>
|
||||
|
||||
${this.aiProvider === 'gemini' ? html`
|
||||
${this.aiProvider === 'gemini'
|
||||
? html`
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Gemini API Key</label>
|
||||
<input
|
||||
@ -1480,10 +1547,15 @@ export class CustomizeView extends LitElement {
|
||||
@input=${this.handleGeminiApiKeyInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
Get your API key from <a href="https://aistudio.google.com/app/apikey" target="_blank" style="color: var(--text-color);">Google AI Studio</a>
|
||||
Get your API key from
|
||||
<a href="https://aistudio.google.com/app/apikey" target="_blank" style="color: var(--text-color);"
|
||||
>Google AI Studio</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
` : this.aiProvider === 'openai-realtime' ? html`
|
||||
`
|
||||
: this.aiProvider === 'openai-realtime'
|
||||
? html`
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">OpenAI API Key</label>
|
||||
<input
|
||||
@ -1494,7 +1566,10 @@ export class CustomizeView extends LitElement {
|
||||
@input=${this.handleOpenAIApiKeyInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
Get your API key from <a href="https://platform.openai.com/api-keys" target="_blank" style="color: var(--text-color);">OpenAI Platform</a>
|
||||
Get your API key from
|
||||
<a href="https://platform.openai.com/api-keys" target="_blank" style="color: var(--text-color);"
|
||||
>OpenAI Platform</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1507,9 +1582,7 @@ export class CustomizeView extends LitElement {
|
||||
.value=${this.openaiBaseUrl}
|
||||
@input=${this.handleOpenAIBaseUrlInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
Override the base URL for OpenAI-compatible APIs
|
||||
</div>
|
||||
<div class="form-description">Override the base URL for OpenAI-compatible APIs</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group full-width">
|
||||
@ -1521,11 +1594,10 @@ export class CustomizeView extends LitElement {
|
||||
.value=${this.openaiModel}
|
||||
@input=${this.handleOpenAIModelInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
Realtime API model to use
|
||||
<div class="form-description">Realtime API model to use</div>
|
||||
</div>
|
||||
</div>
|
||||
` : html`
|
||||
`
|
||||
: html`
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">API Key</label>
|
||||
<input
|
||||
@ -1535,9 +1607,7 @@ export class CustomizeView extends LitElement {
|
||||
.value=${this.openaiSdkApiKey}
|
||||
@input=${this.handleOpenAISdkApiKeyInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
API key for your provider (BotHub, Azure, OpenRouter, etc.)
|
||||
</div>
|
||||
<div class="form-description">API key for your provider (BotHub, Azure, OpenRouter, etc.)</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group full-width">
|
||||
@ -1549,9 +1619,7 @@ export class CustomizeView extends LitElement {
|
||||
.value=${this.openaiSdkBaseUrl}
|
||||
@input=${this.handleOpenAISdkBaseUrlInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
API endpoint URL (e.g., https://bothub.chat/api/v2/openai/v1)
|
||||
</div>
|
||||
<div class="form-description">API endpoint URL (e.g., https://bothub.chat/api/v2/openai/v1)</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
@ -1586,13 +1654,14 @@ export class CustomizeView extends LitElement {
|
||||
.value=${this.openaiSdkWhisperModel}
|
||||
@input=${this.handleOpenAISdkWhisperModelInput}
|
||||
/>
|
||||
<div class="form-description">
|
||||
Model for audio transcription
|
||||
</div>
|
||||
<div class="form-description">Model for audio transcription</div>
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="form-description full-width" style="margin-top: 12px; padding: 12px; background: var(--bg-secondary); border-left: 2px solid var(--border-default); border-radius: 3px;">
|
||||
<div
|
||||
class="form-description full-width"
|
||||
style="margin-top: 12px; padding: 12px; background: var(--bg-secondary); border-left: 2px solid var(--border-default); border-radius: 3px;"
|
||||
>
|
||||
<strong>Note:</strong> You must restart the AI session for provider changes to take effect.
|
||||
</div>
|
||||
</div>
|
||||
@ -1628,20 +1697,19 @@ export class CustomizeView extends LitElement {
|
||||
<div class="form-group">
|
||||
<label class="form-label" style="color: var(--error-color);">Data Management</label>
|
||||
<div class="form-description" style="margin-bottom: 12px;">
|
||||
<strong>Warning:</strong> This action will permanently delete all local data including API keys, preferences, and session history. This cannot be undone.
|
||||
<strong>Warning:</strong> This action will permanently delete all local data including API keys, preferences, and session
|
||||
history. This cannot be undone.
|
||||
</div>
|
||||
<button
|
||||
class="danger-button"
|
||||
@click=${this.clearLocalData}
|
||||
?disabled=${this.isClearing}
|
||||
>
|
||||
<button class="danger-button" @click=${this.clearLocalData} ?disabled=${this.isClearing}>
|
||||
${this.isClearing ? 'Clearing...' : 'Clear All Local Data'}
|
||||
</button>
|
||||
${this.clearStatusMessage ? html`
|
||||
${this.clearStatusMessage
|
||||
? html`
|
||||
<div class="status-message ${this.clearStatusType === 'success' ? 'status-success' : 'status-error'}">
|
||||
${this.clearStatusMessage}
|
||||
</div>
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -1690,9 +1758,7 @@ export class CustomizeView extends LitElement {
|
||||
`
|
||||
)}
|
||||
</nav>
|
||||
<div class="settings-content">
|
||||
${this.renderSectionContent()}
|
||||
</div>
|
||||
<div class="settings-content">${this.renderSectionContent()}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -4,7 +4,11 @@ import { resizeLayout } from '../../utils/windowResize.js';
|
||||
export class HelpView extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
@ -292,26 +296,61 @@ export class HelpView extends LitElement {
|
||||
</div>
|
||||
<div class="community-links">
|
||||
<div class="community-link" @click=${() => this.handleExternalLinkClick('https://cheatingdaddy.com')}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 11.9976C14 9.5059 11.683 7 8.85714 7C8.52241 7 7.41904 7.00001 7.14286 7.00001C4.30254 7.00001 2 9.23752 2 11.9976C2 14.376 3.70973 16.3664 6 16.8714C6.36756 16.9525 6.75006 16.9952 7.14286 16.9952"></path>
|
||||
<path d="M10 11.9976C10 14.4893 12.317 16.9952 15.1429 16.9952C15.4776 16.9952 16.581 16.9952 16.8571 16.9952C19.6975 16.9952 22 14.7577 22 11.9976C22 9.6192 20.2903 7.62884 18 7.12383C17.6324 7.04278 17.2499 6.99999 16.8571 6.99999"></path>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M14 11.9976C14 9.5059 11.683 7 8.85714 7C8.52241 7 7.41904 7.00001 7.14286 7.00001C4.30254 7.00001 2 9.23752 2 11.9976C2 14.376 3.70973 16.3664 6 16.8714C6.36756 16.9525 6.75006 16.9952 7.14286 16.9952"
|
||||
></path>
|
||||
<path
|
||||
d="M10 11.9976C10 14.4893 12.317 16.9952 15.1429 16.9952C15.4776 16.9952 16.581 16.9952 16.8571 16.9952C19.6975 16.9952 22 14.7577 22 11.9976C22 9.6192 20.2903 7.62884 18 7.12383C17.6324 7.04278 17.2499 6.99999 16.8571 6.99999"
|
||||
></path>
|
||||
</svg>
|
||||
Website
|
||||
</div>
|
||||
<div class="community-link" @click=${() => this.handleExternalLinkClick('https://github.com/sohzm/cheating-daddy')}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 22.0268V19.1568C16.0375 18.68 15.9731 18.2006 15.811 17.7506C15.6489 17.3006 15.3929 16.8902 15.06 16.5468C18.2 16.1968 21.5 15.0068 21.5 9.54679C21.4997 8.15062 20.9627 6.80799 20 5.79679C20.4558 4.5753 20.4236 3.22514 19.91 2.02679C19.91 2.02679 18.73 1.67679 16 3.50679C13.708 2.88561 11.292 2.88561 8.99999 3.50679C6.26999 1.67679 5.08999 2.02679 5.08999 2.02679C4.57636 3.22514 4.54413 4.5753 4.99999 5.79679C4.03011 6.81549 3.49251 8.17026 3.49999 9.57679C3.49999 14.9968 6.79998 16.1868 9.93998 16.5768C9.61098 16.9168 9.35725 17.3222 9.19529 17.7667C9.03334 18.2112 8.96679 18.6849 8.99999 19.1568V22.0268"></path>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M16 22.0268V19.1568C16.0375 18.68 15.9731 18.2006 15.811 17.7506C15.6489 17.3006 15.3929 16.8902 15.06 16.5468C18.2 16.1968 21.5 15.0068 21.5 9.54679C21.4997 8.15062 20.9627 6.80799 20 5.79679C20.4558 4.5753 20.4236 3.22514 19.91 2.02679C19.91 2.02679 18.73 1.67679 16 3.50679C13.708 2.88561 11.292 2.88561 8.99999 3.50679C6.26999 1.67679 5.08999 2.02679 5.08999 2.02679C4.57636 3.22514 4.54413 4.5753 4.99999 5.79679C4.03011 6.81549 3.49251 8.17026 3.49999 9.57679C3.49999 14.9968 6.79998 16.1868 9.93998 16.5768C9.61098 16.9168 9.35725 17.3222 9.19529 17.7667C9.03334 18.2112 8.96679 18.6849 8.99999 19.1568V22.0268"
|
||||
></path>
|
||||
<path d="M9 20.0267C6 20.9999 3.5 20.0267 2 17.0267"></path>
|
||||
</svg>
|
||||
GitHub
|
||||
</div>
|
||||
<div class="community-link" @click=${() => this.handleExternalLinkClick('https://discord.gg/GCBdubnXfJ')}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M5.5 16C10.5 18.5 13.5 18.5 18.5 16"></path>
|
||||
<path d="M15.5 17.5L16.5 19.5C16.5 19.5 20.6713 18.1717 22 16C22 15 22.5301 7.85339 19 5.5C17.5 4.5 15 4 15 4L14 6H12"></path>
|
||||
<path d="M8.52832 17.5L7.52832 19.5C7.52832 19.5 3.35699 18.1717 2.02832 16C2.02832 15 1.49823 7.85339 5.02832 5.5C6.52832 4.5 9.02832 4 9.02832 4L10.0283 6H12.0283"></path>
|
||||
<path d="M8.5 14C7.67157 14 7 13.1046 7 12C7 10.8954 7.67157 10 8.5 10C9.32843 10 10 10.8954 10 12C10 13.1046 9.32843 14 8.5 14Z"></path>
|
||||
<path d="M15.5 14C14.6716 14 14 13.1046 14 12C14 10.8954 14.6716 10 15.5 10C16.3284 10 17 10.8954 17 12C17 13.1046 16.3284 14 15.5 14Z"></path>
|
||||
<path
|
||||
d="M15.5 17.5L16.5 19.5C16.5 19.5 20.6713 18.1717 22 16C22 15 22.5301 7.85339 19 5.5C17.5 4.5 15 4 15 4L14 6H12"
|
||||
></path>
|
||||
<path
|
||||
d="M8.52832 17.5L7.52832 19.5C7.52832 19.5 3.35699 18.1717 2.02832 16C2.02832 15 1.49823 7.85339 5.02832 5.5C6.52832 4.5 9.02832 4 9.02832 4L10.0283 6H12.0283"
|
||||
></path>
|
||||
<path
|
||||
d="M8.5 14C7.67157 14 7 13.1046 7 12C7 10.8954 7.67157 10 8.5 10C9.32843 10 10 10.8954 10 12C10 13.1046 9.32843 14 8.5 14Z"
|
||||
></path>
|
||||
<path
|
||||
d="M15.5 14C14.6716 14 14 13.1046 14 12C14 10.8954 14.6716 10 15.5 10C16.3284 10 17 10.8954 17 12C17 13.1046 16.3284 14 15.5 14Z"
|
||||
></path>
|
||||
</svg>
|
||||
Discord
|
||||
</div>
|
||||
@ -395,9 +434,7 @@ export class HelpView extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description" style="margin-top: 12px; text-align: center;">
|
||||
You can customize these shortcuts in Settings.
|
||||
</div>
|
||||
<div class="description" style="margin-top: 12px; text-align: center;">You can customize these shortcuts in Settings.</div>
|
||||
</div>
|
||||
|
||||
<div class="option-group">
|
||||
@ -469,9 +506,7 @@ export class HelpView extends LitElement {
|
||||
<div class="description" style="margin-bottom: 12px;">
|
||||
If you're experiencing issues with audio capture or other features, check the application logs for diagnostic information.
|
||||
</div>
|
||||
<button class="open-logs-btn" @click=${this.openLogsFolder}>
|
||||
📁 Open Logs Folder
|
||||
</button>
|
||||
<button class="open-logs-btn" @click=${this.openLogsFolder}>📁 Open Logs Folder</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -4,7 +4,11 @@ import { resizeLayout } from '../../utils/windowResize.js';
|
||||
export class HistoryView extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
@ -505,18 +509,22 @@ export class HistoryView extends LitElement {
|
||||
|
||||
return html`
|
||||
<div class="session-context">
|
||||
${profile ? html`
|
||||
${profile
|
||||
? html`
|
||||
<div class="session-context-row">
|
||||
<span class="context-label">Profile:</span>
|
||||
<span class="context-value">${profileNames[profile] || profile}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${customPrompt ? html`
|
||||
`
|
||||
: ''}
|
||||
${customPrompt
|
||||
? html`
|
||||
<div class="session-context-row">
|
||||
<span class="context-label">Custom Prompt:</span>
|
||||
<span class="custom-prompt-value">${customPrompt}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -559,9 +567,14 @@ export class HistoryView extends LitElement {
|
||||
return html`<div class="empty-state">No screen analysis data available</div>`;
|
||||
}
|
||||
|
||||
return screenAnalysisHistory.map(analysis => html`
|
||||
<div class="message screen"><div class="analysis-meta">${this.formatTimestamp(analysis.timestamp)} • ${analysis.model || 'unknown model'}</div>${analysis.response}</div>
|
||||
`);
|
||||
return screenAnalysisHistory.map(
|
||||
analysis => html`
|
||||
<div class="message screen">
|
||||
<div class="analysis-meta">${this.formatTimestamp(analysis.timestamp)} • ${analysis.model || 'unknown model'}</div>
|
||||
${analysis.response}
|
||||
</div>
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
renderConversationView() {
|
||||
@ -604,22 +617,13 @@ export class HistoryView extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-tabs">
|
||||
<button
|
||||
class="view-tab ${this.activeTab === 'conversation' ? 'active' : ''}"
|
||||
@click=${() => this.handleTabClick('conversation')}
|
||||
>
|
||||
<button class="view-tab ${this.activeTab === 'conversation' ? 'active' : ''}" @click=${() => this.handleTabClick('conversation')}>
|
||||
Conversation ${hasConversation ? `(${conversationHistory.length})` : ''}
|
||||
</button>
|
||||
<button
|
||||
class="view-tab ${this.activeTab === 'screen' ? 'active' : ''}"
|
||||
@click=${() => this.handleTabClick('screen')}
|
||||
>
|
||||
<button class="view-tab ${this.activeTab === 'screen' ? 'active' : ''}" @click=${() => this.handleTabClick('screen')}>
|
||||
Screen ${hasScreenAnalysis ? `(${screenAnalysisHistory.length})` : ''}
|
||||
</button>
|
||||
<button
|
||||
class="view-tab ${this.activeTab === 'context' ? 'active' : ''}"
|
||||
@click=${() => this.handleTabClick('context')}
|
||||
>
|
||||
<button class="view-tab ${this.activeTab === 'context' ? 'active' : ''}" @click=${() => this.handleTabClick('context')}>
|
||||
Context ${hasContext ? '' : '(empty)'}
|
||||
</button>
|
||||
</div>
|
||||
@ -638,11 +642,7 @@ export class HistoryView extends LitElement {
|
||||
return html`<div class="history-container">${this.renderConversationView()}</div>`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="history-container">
|
||||
${this.renderSessionsList()}
|
||||
</div>
|
||||
`;
|
||||
return html` <div class="history-container">${this.renderSessionsList()}</div> `;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,11 @@ import { resizeLayout } from '../../utils/windowResize.js';
|
||||
export class MainView extends LitElement {
|
||||
static styles = css`
|
||||
* {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-family:
|
||||
'Inter',
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
sans-serif;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
@ -54,7 +58,8 @@ export class MainView extends LitElement {
|
||||
}
|
||||
|
||||
@keyframes blink-red {
|
||||
0%, 100% {
|
||||
0%,
|
||||
100% {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
50% {
|
||||
|
||||
@ -512,7 +512,9 @@ export class OnboardingView extends LitElement {
|
||||
<div class="onboarding-container">
|
||||
<button class="close-button" @click=${this.handleClose} title="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
|
||||
<path
|
||||
d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<canvas class="gradient-canvas"></canvas>
|
||||
|
||||
@ -8,7 +8,7 @@ const CONFIG_VERSION = 1;
|
||||
const DEFAULT_CONFIG = {
|
||||
configVersion: CONFIG_VERSION,
|
||||
onboarded: false,
|
||||
layout: 'normal'
|
||||
layout: 'normal',
|
||||
};
|
||||
|
||||
const DEFAULT_CREDENTIALS = {
|
||||
@ -22,7 +22,7 @@ const DEFAULT_CREDENTIALS = {
|
||||
openaiSdkBaseUrl: '',
|
||||
openaiSdkModel: 'gpt-4o',
|
||||
openaiSdkVisionModel: 'gpt-4o',
|
||||
openaiSdkWhisperModel: 'whisper-1'
|
||||
openaiSdkWhisperModel: 'whisper-1',
|
||||
};
|
||||
|
||||
const DEFAULT_PREFERENCES = {
|
||||
@ -36,13 +36,13 @@ const DEFAULT_PREFERENCES = {
|
||||
fontSize: 'medium',
|
||||
backgroundTransparency: 0.8,
|
||||
googleSearchEnabled: false,
|
||||
aiProvider: 'gemini'
|
||||
aiProvider: 'gemini',
|
||||
};
|
||||
|
||||
const DEFAULT_KEYBINDS = null; // null means use system defaults
|
||||
|
||||
const DEFAULT_LIMITS = {
|
||||
data: [] // Array of { date: 'YYYY-MM-DD', flash: { count: 0 }, flashLite: { count: 0 } }
|
||||
data: [], // Array of { date: 'YYYY-MM-DD', flash: { count: 0 }, flashLite: { count: 0 } }
|
||||
};
|
||||
|
||||
// Get the config directory path based on OS
|
||||
@ -208,7 +208,7 @@ function getOpenAICredentials() {
|
||||
return {
|
||||
apiKey: creds.openaiApiKey || '',
|
||||
baseUrl: creds.openaiBaseUrl || '',
|
||||
model: creds.openaiModel || 'gpt-4o-realtime-preview-2024-12-17'
|
||||
model: creds.openaiModel || 'gpt-4o-realtime-preview-2024-12-17',
|
||||
};
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ function getOpenAISDKCredentials() {
|
||||
baseUrl: creds.openaiSdkBaseUrl || '',
|
||||
model: creds.openaiSdkModel || 'gpt-4o',
|
||||
visionModel: creds.openaiSdkVisionModel || 'gpt-4o',
|
||||
whisperModel: creds.openaiSdkWhisperModel || 'whisper-1'
|
||||
whisperModel: creds.openaiSdkWhisperModel || 'whisper-1',
|
||||
};
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ function getTodayLimits() {
|
||||
const newEntry = {
|
||||
date: today,
|
||||
flash: { count: 0 },
|
||||
flashLite: { count: 0 }
|
||||
flashLite: { count: 0 },
|
||||
};
|
||||
limits.data.push(newEntry);
|
||||
setLimits(limits);
|
||||
@ -322,7 +322,7 @@ function incrementLimitCount(model) {
|
||||
todayEntry = {
|
||||
date: today,
|
||||
flash: { count: 0 },
|
||||
flashLite: { count: 0 }
|
||||
flashLite: { count: 0 },
|
||||
};
|
||||
limits.data.push(todayEntry);
|
||||
} else {
|
||||
@ -376,7 +376,7 @@ function saveSession(sessionId, data) {
|
||||
customPrompt: data.customPrompt || existingSession?.customPrompt || null,
|
||||
// Conversation data
|
||||
conversationHistory: data.conversationHistory || existingSession?.conversationHistory || [],
|
||||
screenAnalysisHistory: data.screenAnalysisHistory || existingSession?.screenAnalysisHistory || []
|
||||
screenAnalysisHistory: data.screenAnalysisHistory || existingSession?.screenAnalysisHistory || [],
|
||||
};
|
||||
return writeJsonFile(sessionPath, sessionData);
|
||||
}
|
||||
@ -393,7 +393,8 @@ function getAllSessions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(historyDir)
|
||||
const files = fs
|
||||
.readdirSync(historyDir)
|
||||
.filter(f => f.endsWith('.json'))
|
||||
.sort((a, b) => {
|
||||
// Sort by timestamp descending (newest first)
|
||||
@ -402,7 +403,8 @@ function getAllSessions() {
|
||||
return tsB - tsA;
|
||||
});
|
||||
|
||||
return files.map(file => {
|
||||
return files
|
||||
.map(file => {
|
||||
const sessionId = file.replace('.json', '');
|
||||
const data = readJsonFile(path.join(historyDir, file), null);
|
||||
if (data) {
|
||||
@ -413,11 +415,12 @@ function getAllSessions() {
|
||||
messageCount: data.conversationHistory?.length || 0,
|
||||
screenAnalysisCount: data.screenAnalysisHistory?.length || 0,
|
||||
profile: data.profile || null,
|
||||
customPrompt: data.customPrompt || null
|
||||
customPrompt: data.customPrompt || null,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean);
|
||||
})
|
||||
.filter(Boolean);
|
||||
} catch (error) {
|
||||
console.error('Error reading sessions:', error.message);
|
||||
return [];
|
||||
@ -504,5 +507,5 @@ module.exports = {
|
||||
deleteAllSessions,
|
||||
|
||||
// Clear all
|
||||
clearAllData
|
||||
clearAllData,
|
||||
};
|
||||
|
||||
@ -52,9 +52,7 @@ function buildContextMessage() {
|
||||
|
||||
if (validTurns.length === 0) return null;
|
||||
|
||||
const contextLines = validTurns.map(turn =>
|
||||
`[Interviewer]: ${turn.transcription.trim()}\n[Your answer]: ${turn.ai_response.trim()}`
|
||||
);
|
||||
const contextLines = validTurns.map(turn => `[Interviewer]: ${turn.transcription.trim()}\n[Your answer]: ${turn.ai_response.trim()}`);
|
||||
|
||||
return `Session reconnected. Here's the conversation so far:\n\n${contextLines.join('\n\n')}\n\nContinue from here.`;
|
||||
}
|
||||
@ -74,7 +72,7 @@ function initializeNewSession(profile = null, customPrompt = null) {
|
||||
sendToRenderer('save-session-context', {
|
||||
sessionId: currentSessionId,
|
||||
profile: profile,
|
||||
customPrompt: customPrompt || ''
|
||||
customPrompt: customPrompt || '',
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -110,7 +108,7 @@ function saveScreenAnalysis(prompt, response, model) {
|
||||
timestamp: Date.now(),
|
||||
prompt: prompt,
|
||||
response: response.trim(),
|
||||
model: model
|
||||
model: model,
|
||||
};
|
||||
|
||||
screenAnalysisHistory.push(analysisEntry);
|
||||
@ -122,7 +120,7 @@ function saveScreenAnalysis(prompt, response, model) {
|
||||
analysis: analysisEntry,
|
||||
fullHistory: screenAnalysisHistory,
|
||||
profile: currentProfile,
|
||||
customPrompt: currentCustomPrompt
|
||||
customPrompt: currentCustomPrompt,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +65,8 @@ function writeLog(level, args) {
|
||||
|
||||
try {
|
||||
const timestamp = new Date().toISOString();
|
||||
const message = args.map(arg => {
|
||||
const message = args
|
||||
.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
@ -74,7 +75,8 @@ function writeLog(level, args) {
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
}).join(' ');
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
logFile.write(`[${timestamp}] [${level}] ${message}\n`);
|
||||
} catch (err) {
|
||||
|
||||
@ -311,7 +311,9 @@ async function sendImageToOpenAI(base64Data, prompt, config) {
|
||||
const { apiKey, baseUrl, model } = config;
|
||||
|
||||
// OpenAI doesn't support images in Realtime API yet, use standard Chat Completions
|
||||
const apiEndpoint = baseUrl ? `${baseUrl.replace('wss://', 'https://').replace('/v1/realtime', '')}/v1/chat/completions` : 'https://api.openai.com/v1/chat/completions';
|
||||
const apiEndpoint = baseUrl
|
||||
? `${baseUrl.replace('wss://', 'https://').replace('/v1/realtime', '')}/v1/chat/completions`
|
||||
: 'https://api.openai.com/v1/chat/completions';
|
||||
|
||||
try {
|
||||
const response = await fetch(apiEndpoint, {
|
||||
|
||||
@ -22,12 +22,18 @@ const isWindows = process.platform === 'win32';
|
||||
|
||||
// Send logs to main process for file logging
|
||||
function logToMain(level, ...args) {
|
||||
const message = args.map(arg => {
|
||||
const message = args
|
||||
.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try { return JSON.stringify(arg); } catch { return String(arg); }
|
||||
try {
|
||||
return JSON.stringify(arg);
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
}).join(' ');
|
||||
})
|
||||
.join(' ');
|
||||
ipcRenderer.send('renderer-log', { level, message });
|
||||
|
||||
// Also log to console
|
||||
@ -130,7 +136,7 @@ const storage = {
|
||||
async getTodayLimits() {
|
||||
const result = await ipcRenderer.invoke('storage:get-today-limits');
|
||||
return result.success ? result.data : { flash: { count: 0 }, flashLite: { count: 0 } };
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Cache for preferences to avoid async calls in hot paths
|
||||
@ -335,7 +341,7 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
enabled: t.enabled,
|
||||
muted: t.muted,
|
||||
readyState: t.readyState,
|
||||
settings: t.getSettings()
|
||||
settings: t.getSettings(),
|
||||
})),
|
||||
});
|
||||
|
||||
@ -475,9 +481,12 @@ function setupWindowsLoopbackProcessing() {
|
||||
// Resume AudioContext if suspended (Chrome policy)
|
||||
if (audioContext.state === 'suspended') {
|
||||
logToMain('warn', 'AudioContext suspended, attempting resume...');
|
||||
audioContext.resume().then(() => {
|
||||
audioContext
|
||||
.resume()
|
||||
.then(() => {
|
||||
logToMain('info', 'AudioContext resumed successfully');
|
||||
}).catch(err => {
|
||||
})
|
||||
.catch(err => {
|
||||
logToMain('error', 'Failed to resume AudioContext:', err.message);
|
||||
});
|
||||
}
|
||||
@ -524,7 +533,6 @@ function setupWindowsLoopbackProcessing() {
|
||||
audioProcessor.connect(audioContext.destination);
|
||||
|
||||
logToMain('info', 'Windows audio processing pipeline connected');
|
||||
|
||||
} catch (err) {
|
||||
logToMain('error', 'Error setting up Windows audio:', err.message, err.stack);
|
||||
cheatingDaddy.setStatus('Audio error: ' + err.message);
|
||||
@ -760,17 +768,7 @@ async function captureRegionFromScreenshot(rect, screenshotDataUrl) {
|
||||
const cropContext = cropCanvas.getContext('2d');
|
||||
|
||||
// Draw only the selected region
|
||||
cropContext.drawImage(
|
||||
img,
|
||||
scaledRect.left,
|
||||
scaledRect.top,
|
||||
scaledRect.width,
|
||||
scaledRect.height,
|
||||
0,
|
||||
0,
|
||||
scaledRect.width,
|
||||
scaledRect.height
|
||||
);
|
||||
cropContext.drawImage(img, scaledRect.left, scaledRect.top, scaledRect.width, scaledRect.height, 0, 0, scaledRect.width, scaledRect.height);
|
||||
|
||||
// Convert to blob and send
|
||||
cropCanvas.toBlob(
|
||||
@ -983,7 +981,7 @@ ipcRenderer.on('save-session-context', async (event, data) => {
|
||||
try {
|
||||
await storage.saveSession(data.sessionId, {
|
||||
profile: data.profile,
|
||||
customPrompt: data.customPrompt
|
||||
customPrompt: data.customPrompt,
|
||||
});
|
||||
console.log('Session context saved:', data.sessionId, 'profile:', data.profile);
|
||||
} catch (error) {
|
||||
@ -997,7 +995,7 @@ ipcRenderer.on('save-screen-analysis', async (event, data) => {
|
||||
await storage.saveSession(data.sessionId, {
|
||||
screenAnalysisHistory: data.fullHistory,
|
||||
profile: data.profile,
|
||||
customPrompt: data.customPrompt
|
||||
customPrompt: data.customPrompt,
|
||||
});
|
||||
console.log('Screen analysis saved:', data.sessionId);
|
||||
} catch (error) {
|
||||
@ -1032,60 +1030,102 @@ const theme = {
|
||||
themes: {
|
||||
dark: {
|
||||
background: '#1e1e1e',
|
||||
text: '#e0e0e0', textSecondary: '#a0a0a0', textMuted: '#6b6b6b',
|
||||
border: '#333333', accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff', btnPrimaryText: '#000000', btnPrimaryHover: '#e0e0e0',
|
||||
tooltipBg: '#1a1a1a', tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(255,255,255,0.1)'
|
||||
text: '#e0e0e0',
|
||||
textSecondary: '#a0a0a0',
|
||||
textMuted: '#6b6b6b',
|
||||
border: '#333333',
|
||||
accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff',
|
||||
btnPrimaryText: '#000000',
|
||||
btnPrimaryHover: '#e0e0e0',
|
||||
tooltipBg: '#1a1a1a',
|
||||
tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(255,255,255,0.1)',
|
||||
},
|
||||
light: {
|
||||
background: '#ffffff',
|
||||
text: '#1a1a1a', textSecondary: '#555555', textMuted: '#888888',
|
||||
border: '#e0e0e0', accent: '#000000',
|
||||
btnPrimaryBg: '#1a1a1a', btnPrimaryText: '#ffffff', btnPrimaryHover: '#333333',
|
||||
tooltipBg: '#1a1a1a', tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(0,0,0,0.1)'
|
||||
text: '#1a1a1a',
|
||||
textSecondary: '#555555',
|
||||
textMuted: '#888888',
|
||||
border: '#e0e0e0',
|
||||
accent: '#000000',
|
||||
btnPrimaryBg: '#1a1a1a',
|
||||
btnPrimaryText: '#ffffff',
|
||||
btnPrimaryHover: '#333333',
|
||||
tooltipBg: '#1a1a1a',
|
||||
tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(0,0,0,0.1)',
|
||||
},
|
||||
midnight: {
|
||||
background: '#0d1117',
|
||||
text: '#c9d1d9', textSecondary: '#8b949e', textMuted: '#6e7681',
|
||||
border: '#30363d', accent: '#58a6ff',
|
||||
btnPrimaryBg: '#58a6ff', btnPrimaryText: '#0d1117', btnPrimaryHover: '#79b8ff',
|
||||
tooltipBg: '#161b22', tooltipText: '#c9d1d9',
|
||||
keyBg: 'rgba(88,166,255,0.15)'
|
||||
text: '#c9d1d9',
|
||||
textSecondary: '#8b949e',
|
||||
textMuted: '#6e7681',
|
||||
border: '#30363d',
|
||||
accent: '#58a6ff',
|
||||
btnPrimaryBg: '#58a6ff',
|
||||
btnPrimaryText: '#0d1117',
|
||||
btnPrimaryHover: '#79b8ff',
|
||||
tooltipBg: '#161b22',
|
||||
tooltipText: '#c9d1d9',
|
||||
keyBg: 'rgba(88,166,255,0.15)',
|
||||
},
|
||||
sepia: {
|
||||
background: '#f4ecd8',
|
||||
text: '#5c4b37', textSecondary: '#7a6a56', textMuted: '#998875',
|
||||
border: '#d4c8b0', accent: '#8b4513',
|
||||
btnPrimaryBg: '#5c4b37', btnPrimaryText: '#f4ecd8', btnPrimaryHover: '#7a6a56',
|
||||
tooltipBg: '#5c4b37', tooltipText: '#f4ecd8',
|
||||
keyBg: 'rgba(92,75,55,0.15)'
|
||||
text: '#5c4b37',
|
||||
textSecondary: '#7a6a56',
|
||||
textMuted: '#998875',
|
||||
border: '#d4c8b0',
|
||||
accent: '#8b4513',
|
||||
btnPrimaryBg: '#5c4b37',
|
||||
btnPrimaryText: '#f4ecd8',
|
||||
btnPrimaryHover: '#7a6a56',
|
||||
tooltipBg: '#5c4b37',
|
||||
tooltipText: '#f4ecd8',
|
||||
keyBg: 'rgba(92,75,55,0.15)',
|
||||
},
|
||||
nord: {
|
||||
background: '#2e3440',
|
||||
text: '#eceff4', textSecondary: '#d8dee9', textMuted: '#4c566a',
|
||||
border: '#3b4252', accent: '#88c0d0',
|
||||
btnPrimaryBg: '#88c0d0', btnPrimaryText: '#2e3440', btnPrimaryHover: '#8fbcbb',
|
||||
tooltipBg: '#3b4252', tooltipText: '#eceff4',
|
||||
keyBg: 'rgba(136,192,208,0.15)'
|
||||
text: '#eceff4',
|
||||
textSecondary: '#d8dee9',
|
||||
textMuted: '#4c566a',
|
||||
border: '#3b4252',
|
||||
accent: '#88c0d0',
|
||||
btnPrimaryBg: '#88c0d0',
|
||||
btnPrimaryText: '#2e3440',
|
||||
btnPrimaryHover: '#8fbcbb',
|
||||
tooltipBg: '#3b4252',
|
||||
tooltipText: '#eceff4',
|
||||
keyBg: 'rgba(136,192,208,0.15)',
|
||||
},
|
||||
dracula: {
|
||||
background: '#282a36',
|
||||
text: '#f8f8f2', textSecondary: '#bd93f9', textMuted: '#6272a4',
|
||||
border: '#44475a', accent: '#ff79c6',
|
||||
btnPrimaryBg: '#ff79c6', btnPrimaryText: '#282a36', btnPrimaryHover: '#ff92d0',
|
||||
tooltipBg: '#44475a', tooltipText: '#f8f8f2',
|
||||
keyBg: 'rgba(255,121,198,0.15)'
|
||||
text: '#f8f8f2',
|
||||
textSecondary: '#bd93f9',
|
||||
textMuted: '#6272a4',
|
||||
border: '#44475a',
|
||||
accent: '#ff79c6',
|
||||
btnPrimaryBg: '#ff79c6',
|
||||
btnPrimaryText: '#282a36',
|
||||
btnPrimaryHover: '#ff92d0',
|
||||
tooltipBg: '#44475a',
|
||||
tooltipText: '#f8f8f2',
|
||||
keyBg: 'rgba(255,121,198,0.15)',
|
||||
},
|
||||
abyss: {
|
||||
background: '#0a0a0a',
|
||||
text: '#d4d4d4', textSecondary: '#808080', textMuted: '#505050',
|
||||
border: '#1a1a1a', accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff', btnPrimaryText: '#0a0a0a', btnPrimaryHover: '#d4d4d4',
|
||||
tooltipBg: '#141414', tooltipText: '#d4d4d4',
|
||||
keyBg: 'rgba(255,255,255,0.08)'
|
||||
}
|
||||
text: '#d4d4d4',
|
||||
textSecondary: '#808080',
|
||||
textMuted: '#505050',
|
||||
border: '#1a1a1a',
|
||||
accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff',
|
||||
btnPrimaryText: '#0a0a0a',
|
||||
btnPrimaryHover: '#d4d4d4',
|
||||
tooltipBg: '#141414',
|
||||
tooltipText: '#d4d4d4',
|
||||
keyBg: 'rgba(255,255,255,0.08)',
|
||||
},
|
||||
},
|
||||
|
||||
current: 'dark',
|
||||
@ -1102,29 +1142,31 @@ const theme = {
|
||||
sepia: 'Sepia',
|
||||
nord: 'Nord',
|
||||
dracula: 'Dracula',
|
||||
abyss: 'Abyss'
|
||||
abyss: 'Abyss',
|
||||
};
|
||||
return Object.keys(this.themes).map(key => ({
|
||||
value: key,
|
||||
name: names[key] || key,
|
||||
colors: this.themes[key]
|
||||
colors: this.themes[key],
|
||||
}));
|
||||
},
|
||||
|
||||
hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : { r: 30, g: 30, b: 30 };
|
||||
b: parseInt(result[3], 16),
|
||||
}
|
||||
: { r: 30, g: 30, b: 30 };
|
||||
},
|
||||
|
||||
lightenColor(rgb, amount) {
|
||||
return {
|
||||
r: Math.min(255, rgb.r + amount),
|
||||
g: Math.min(255, rgb.g + amount),
|
||||
b: Math.min(255, rgb.b + amount)
|
||||
b: Math.min(255, rgb.b + amount),
|
||||
};
|
||||
},
|
||||
|
||||
@ -1132,7 +1174,7 @@ const theme = {
|
||||
return {
|
||||
r: Math.max(0, rgb.r - amount),
|
||||
g: Math.max(0, rgb.g - amount),
|
||||
b: Math.max(0, rgb.b - amount)
|
||||
b: Math.max(0, rgb.b - amount),
|
||||
};
|
||||
},
|
||||
|
||||
@ -1212,7 +1254,7 @@ const theme = {
|
||||
async save(themeName) {
|
||||
await storage.updatePreference('theme', themeName);
|
||||
this.apply(themeName);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Consolidated cheatingDaddy object - all functions in one place
|
||||
|
||||
@ -553,7 +553,10 @@ function setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef) {
|
||||
const primaryDisplay = screen.getPrimaryDisplay();
|
||||
|
||||
// Calculate bounds that cover all displays
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
let minX = Infinity,
|
||||
minY = Infinity,
|
||||
maxX = -Infinity,
|
||||
maxY = -Infinity;
|
||||
displays.forEach(display => {
|
||||
minX = Math.min(minX, display.bounds.x);
|
||||
minY = Math.min(minY, display.bounds.y);
|
||||
@ -712,7 +715,7 @@ function setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef) {
|
||||
|
||||
regionSelectionWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(htmlContent)}`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
ipcMain.once('region-selected', (event, rect) => {
|
||||
if (regionSelectionWindow && !regionSelectionWindow.isDestroyed()) {
|
||||
regionSelectionWindow.close();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user