Add AI provider and model info support across components
This commit is contained in:
parent
0011bacfa3
commit
501dadd265
@ -186,6 +186,82 @@ export class AppHeader extends LitElement {
|
|||||||
.status-tooltip .tooltip-content {
|
.status-tooltip .tooltip-content {
|
||||||
color: #f14c4c;
|
color: #f14c4c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-badge {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
background: var(--key-background);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: 'SF Mono', Monaco, monospace;
|
||||||
|
max-width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-badge-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-badge-wrapper .model-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
background: var(--tooltip-bg, #1a1a1a);
|
||||||
|
color: var(--tooltip-text, #ffffff);
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-badge-wrapper .model-tooltip::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
right: 16px;
|
||||||
|
border: 6px solid transparent;
|
||||||
|
border-bottom-color: var(--tooltip-bg, #1a1a1a);
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-badge-wrapper:hover .model-tooltip {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-tooltip-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-tooltip-row:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-tooltip-label {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-tooltip-value {
|
||||||
|
font-family: 'SF Mono', Monaco, monospace;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
static properties = {
|
static properties = {
|
||||||
@ -200,6 +276,8 @@ export class AppHeader extends LitElement {
|
|||||||
onHideToggleClick: { type: Function },
|
onHideToggleClick: { type: Function },
|
||||||
isClickThrough: { type: Boolean, reflect: true },
|
isClickThrough: { type: Boolean, reflect: true },
|
||||||
updateAvailable: { type: Boolean },
|
updateAvailable: { type: Boolean },
|
||||||
|
aiProvider: { type: String },
|
||||||
|
modelInfo: { type: Object },
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -216,6 +294,8 @@ export class AppHeader extends LitElement {
|
|||||||
this.isClickThrough = false;
|
this.isClickThrough = false;
|
||||||
this.updateAvailable = false;
|
this.updateAvailable = false;
|
||||||
this._timerInterval = null;
|
this._timerInterval = null;
|
||||||
|
this.aiProvider = 'gemini';
|
||||||
|
this.modelInfo = { model: '', visionModel: '', whisperModel: '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@ -337,6 +417,45 @@ export class AppHeader extends LitElement {
|
|||||||
return navigationViews.includes(this.currentView);
|
return navigationViews.includes(this.currentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProviderDisplayName() {
|
||||||
|
const names = {
|
||||||
|
'gemini': 'Gemini',
|
||||||
|
'openai-realtime': 'OpenAI Realtime',
|
||||||
|
'openai-sdk': 'OpenAI SDK'
|
||||||
|
};
|
||||||
|
return names[this.aiProvider] || this.aiProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderModelInfo() {
|
||||||
|
// Only show model info for OpenAI SDK provider
|
||||||
|
if (this.aiProvider !== 'openai-sdk' || !this.modelInfo) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const { model, visionModel, whisperModel } = this.modelInfo;
|
||||||
|
|
||||||
|
// Show a compact badge with tooltip for model details
|
||||||
|
return html`
|
||||||
|
<div class="model-badge-wrapper">
|
||||||
|
<span class="model-badge" title="Models">${model || 'gpt-4o'}</span>
|
||||||
|
<div class="model-tooltip">
|
||||||
|
<div class="model-tooltip-row">
|
||||||
|
<span class="model-tooltip-label">Text</span>
|
||||||
|
<span class="model-tooltip-value">${model || 'gpt-4o'}</span>
|
||||||
|
</div>
|
||||||
|
<div class="model-tooltip-row">
|
||||||
|
<span class="model-tooltip-label">Vision</span>
|
||||||
|
<span class="model-tooltip-value">${visionModel || 'gpt-4o'}</span>
|
||||||
|
</div>
|
||||||
|
<div class="model-tooltip-row">
|
||||||
|
<span class="model-tooltip-label">Speech</span>
|
||||||
|
<span class="model-tooltip-value">${whisperModel || 'whisper-1'}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const elapsedTime = this.getElapsedTime();
|
const elapsedTime = this.getElapsedTime();
|
||||||
const isError = this.statusText && (this.statusText.toLowerCase().includes('error') || this.statusText.toLowerCase().includes('failed'));
|
const isError = this.statusText && (this.statusText.toLowerCase().includes('error') || this.statusText.toLowerCase().includes('failed'));
|
||||||
@ -348,6 +467,7 @@ export class AppHeader extends LitElement {
|
|||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
${this.currentView === 'assistant'
|
${this.currentView === 'assistant'
|
||||||
? html`
|
? html`
|
||||||
|
${this.renderModelInfo()}
|
||||||
<span>${elapsedTime}</span>
|
<span>${elapsedTime}</span>
|
||||||
<div class="status-wrapper">
|
<div class="status-wrapper">
|
||||||
<span class="status-text ${isError ? 'error' : ''}">${shortStatus}</span>
|
<span class="status-text ${isError ? 'error' : ''}">${shortStatus}</span>
|
||||||
|
|||||||
@ -110,6 +110,8 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
_awaitingNewResponse: { state: true },
|
_awaitingNewResponse: { state: true },
|
||||||
shouldAnimateResponse: { type: Boolean },
|
shouldAnimateResponse: { type: Boolean },
|
||||||
_storageLoaded: { state: true },
|
_storageLoaded: { state: true },
|
||||||
|
aiProvider: { type: String },
|
||||||
|
modelInfo: { type: Object },
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -133,6 +135,8 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
this._currentResponseIsComplete = true;
|
this._currentResponseIsComplete = true;
|
||||||
this.shouldAnimateResponse = false;
|
this.shouldAnimateResponse = false;
|
||||||
this._storageLoaded = false;
|
this._storageLoaded = false;
|
||||||
|
this.aiProvider = 'gemini';
|
||||||
|
this.modelInfo = { model: '', visionModel: '', whisperModel: '' };
|
||||||
|
|
||||||
// Load from storage
|
// Load from storage
|
||||||
this._loadFromStorage();
|
this._loadFromStorage();
|
||||||
@ -140,9 +144,10 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
|
|
||||||
async _loadFromStorage() {
|
async _loadFromStorage() {
|
||||||
try {
|
try {
|
||||||
const [config, prefs] = await Promise.all([
|
const [config, prefs, openaiSdkCreds] = await Promise.all([
|
||||||
cheatingDaddy.storage.getConfig(),
|
cheatingDaddy.storage.getConfig(),
|
||||||
cheatingDaddy.storage.getPreferences()
|
cheatingDaddy.storage.getPreferences(),
|
||||||
|
cheatingDaddy.storage.getOpenAISDKCredentials()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Check onboarding status
|
// Check onboarding status
|
||||||
@ -160,6 +165,14 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
this.selectedScreenshotInterval = prefs.selectedScreenshotInterval || '5';
|
this.selectedScreenshotInterval = prefs.selectedScreenshotInterval || '5';
|
||||||
this.selectedImageQuality = prefs.selectedImageQuality || 'medium';
|
this.selectedImageQuality = prefs.selectedImageQuality || 'medium';
|
||||||
this.layoutMode = config.layout || 'normal';
|
this.layoutMode = config.layout || 'normal';
|
||||||
|
|
||||||
|
// Load AI provider and model info
|
||||||
|
this.aiProvider = prefs.aiProvider || 'gemini';
|
||||||
|
this.modelInfo = {
|
||||||
|
model: openaiSdkCreds.model || 'gpt-4o',
|
||||||
|
visionModel: openaiSdkCreds.visionModel || 'gpt-4o',
|
||||||
|
whisperModel: openaiSdkCreds.whisperModel || 'whisper-1'
|
||||||
|
};
|
||||||
|
|
||||||
this._storageLoaded = true;
|
this._storageLoaded = true;
|
||||||
this.updateLayoutMode();
|
this.updateLayoutMode();
|
||||||
@ -487,6 +500,7 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
.responses=${this.responses}
|
.responses=${this.responses}
|
||||||
.currentResponseIndex=${this.currentResponseIndex}
|
.currentResponseIndex=${this.currentResponseIndex}
|
||||||
.selectedProfile=${this.selectedProfile}
|
.selectedProfile=${this.selectedProfile}
|
||||||
|
.aiProvider=${this.aiProvider}
|
||||||
.onSendText=${message => this.handleSendText(message)}
|
.onSendText=${message => this.handleSendText(message)}
|
||||||
.shouldAnimateResponse=${this.shouldAnimateResponse}
|
.shouldAnimateResponse=${this.shouldAnimateResponse}
|
||||||
@response-index-changed=${this.handleResponseIndexChanged}
|
@response-index-changed=${this.handleResponseIndexChanged}
|
||||||
@ -521,6 +535,8 @@ export class CheatingDaddyApp extends LitElement {
|
|||||||
.currentView=${this.currentView}
|
.currentView=${this.currentView}
|
||||||
.statusText=${this.statusText}
|
.statusText=${this.statusText}
|
||||||
.startTime=${this.startTime}
|
.startTime=${this.startTime}
|
||||||
|
.aiProvider=${this.aiProvider}
|
||||||
|
.modelInfo=${this.modelInfo}
|
||||||
.onCustomizeClick=${() => this.handleCustomizeClick()}
|
.onCustomizeClick=${() => this.handleCustomizeClick()}
|
||||||
.onHelpClick=${() => this.handleHelpClick()}
|
.onHelpClick=${() => this.handleHelpClick()}
|
||||||
.onHistoryClick=${() => this.handleHistoryClick()}
|
.onHistoryClick=${() => this.handleHistoryClick()}
|
||||||
|
|||||||
@ -358,6 +358,7 @@ export class AssistantView extends LitElement {
|
|||||||
shouldAnimateResponse: { type: Boolean },
|
shouldAnimateResponse: { type: Boolean },
|
||||||
flashCount: { type: Number },
|
flashCount: { type: Number },
|
||||||
flashLiteCount: { type: Number },
|
flashLiteCount: { type: Number },
|
||||||
|
aiProvider: { type: String },
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -368,6 +369,7 @@ export class AssistantView extends LitElement {
|
|||||||
this.onSendText = () => {};
|
this.onSendText = () => {};
|
||||||
this.flashCount = 0;
|
this.flashCount = 0;
|
||||||
this.flashLiteCount = 0;
|
this.flashLiteCount = 0;
|
||||||
|
this.aiProvider = 'gemini';
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileNames() {
|
getProfileNames() {
|
||||||
@ -658,23 +660,25 @@ export class AssistantView extends LitElement {
|
|||||||
<span>Select region</span>
|
<span>Select region</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="screen-answer-btn-wrapper">
|
<div class="screen-answer-btn-wrapper">
|
||||||
<div class="tooltip">
|
${this.aiProvider === 'gemini' ? html`
|
||||||
<div class="tooltip-row">
|
<div class="tooltip">
|
||||||
<span class="tooltip-label">Flash</span>
|
<div class="tooltip-row">
|
||||||
<span class="tooltip-value">${this.flashCount}/20</span>
|
<span class="tooltip-label">Flash</span>
|
||||||
|
<span class="tooltip-value">${this.flashCount}/20</span>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip-row">
|
||||||
|
<span class="tooltip-label">Flash Lite</span>
|
||||||
|
<span class="tooltip-value">${this.flashLiteCount}/20</span>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip-note">Resets every 24 hours</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tooltip-row">
|
` : ''}
|
||||||
<span class="tooltip-label">Flash Lite</span>
|
|
||||||
<span class="tooltip-value">${this.flashLiteCount}/20</span>
|
|
||||||
</div>
|
|
||||||
<div class="tooltip-note">Resets every 24 hours</div>
|
|
||||||
</div>
|
|
||||||
<button class="screen-answer-btn" @click=${this.handleScreenAnswer}>
|
<button class="screen-answer-btn" @click=${this.handleScreenAnswer}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
<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>
|
</svg>
|
||||||
<span>Full screen</span>
|
<span>Full screen</span>
|
||||||
<span class="usage-count">(${this.getTotalUsed()}/${this.getTotalAvailable()})</span>
|
${this.aiProvider === 'gemini' ? html`<span class="usage-count">(${this.getTotalUsed()}/${this.getTotalAvailable()})</span>` : ''}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user