summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/background/message-router.js17
-rw-r--r--src/background/ollama-client.js26
-rw-r--r--src/content/content.js12
3 files changed, 46 insertions, 9 deletions
diff --git a/src/background/message-router.js b/src/background/message-router.js
index c93fc9d..9428312 100644
--- a/src/background/message-router.js
+++ b/src/background/message-router.js
@@ -31,13 +31,16 @@ const ERROR_MESSAGES = {
[ERROR_CODES.TEXT_EMPTY]: '選択文字列が空です。',
[ERROR_CODES.TEXT_TOO_LONG]: `選択文字列が長すぎます(上限 ${MAX_SELECTION_LENGTH} 文字)。`,
[ERROR_CODES.OLLAMA_UNAVAILABLE]: 'Ollamaに接続できません。Ollamaが起動しているか確認してください。',
- [ERROR_CODES.MODEL_NOT_FOUND]: '指定されたモデルが見つかりません。',
+ [ERROR_CODES.MODEL_NOT_FOUND]: '指定されたモデルが見つかりません。設定画面でモデルを選び直してください。',
[ERROR_CODES.INVALID_SETTINGS]: '設定値が不正です。設定画面を確認してください。',
[ERROR_CODES.REQUEST_ABORTED]: '翻訳を中断しました。',
[ERROR_CODES.STREAM_ERROR]: '翻訳中にエラーが発生しました。',
[ERROR_CODES.UNKNOWN_ERROR]: '不明なエラーが発生しました。'
};
+/** Message shown when no model is configured at all. */
+const NO_MODEL_MESSAGE = 'モデルが設定されていません。ツールバーアイコンまたは設定画面でモデルを選択してください。';
+
/**
* Handle one content-script port connection.
* @param {object} port runtime.Port
@@ -84,7 +87,7 @@ async function runTranslation(port, requestId, text) {
return;
}
if (!settings.model) {
- postError(port, requestId, ERROR_CODES.INVALID_SETTINGS, 'No model configured');
+ postError(port, requestId, ERROR_CODES.INVALID_SETTINGS, NO_MODEL_MESSAGE);
return;
}
@@ -128,11 +131,15 @@ async function runTranslation(port, requestId, text) {
* @param {object} port
* @param {string} requestId
* @param {string} code
- * @param {string} message
+ * @param {string} detail optional concrete reason shown to the user
*/
-function postError(port, requestId, code, message) {
+function postError(port, requestId, code, detail) {
+ const base = ERROR_MESSAGES[code] || ERROR_MESSAGES[ERROR_CODES.UNKNOWN_ERROR];
+ // Append the concrete server/detail reason when provided so the popover
+ // shows WHY it failed (e.g. the Ollama error body for HTTP 400).
+ const message = detail && detail !== base ? `${base}\n(${detail})` : base;
try {
- port.postMessage({ type: BG_TO_CONTENT.ERROR, requestId, code, message: ERROR_MESSAGES[code] || ERROR_MESSAGES[ERROR_CODES.UNKNOWN_ERROR] });
+ port.postMessage({ type: BG_TO_CONTENT.ERROR, requestId, code, message });
} catch {
// port may be disconnected
}
diff --git a/src/background/ollama-client.js b/src/background/ollama-client.js
index 0286230..e53d997 100644
--- a/src/background/ollama-client.js
+++ b/src/background/ollama-client.js
@@ -16,6 +16,24 @@ import { isValidOllamaHost } from '../shared/settings-schema.js';
import { ERROR_CODES } from '../shared/constants.js';
/**
+ * Extract a short error message from an Ollama JSON error body.
+ * @param {string} raw
+ * @returns {string} message or '' when not parseable
+ */
+function extractOllamaError(raw) {
+ if (!raw) return '';
+ try {
+ const parsed = JSON.parse(raw);
+ if (parsed && typeof parsed.error === 'string') {
+ return parsed.error.slice(0, 200);
+ }
+ } catch {
+ // not JSON
+ }
+ return '';
+}
+
+/**
* Translate a fetch/HTTP failure into a stable error code.
* @param {Response|undefined} response
* @returns {string} error code
@@ -73,7 +91,9 @@ export async function listModels(host, signal) {
throw toExtensionError(error);
}
if (!response.ok) {
- const e = new Error(`Ollama /api/tags failed: ${response.status}`);
+ const detail = await response.text().catch(() => '');
+ const serverMessage = extractOllamaError(detail);
+ const e = new Error(`Ollama /api/tags failed: ${response.status}${serverMessage ? ` - ${serverMessage}` : ''}`);
e.code = response.status === 404 ? ERROR_CODES.MODEL_NOT_FOUND : ERROR_CODES.STREAM_ERROR;
throw e;
}
@@ -119,7 +139,9 @@ export async function chatStream({ host, model, messages, think, options, onChun
}
if (!response.ok) {
- const e = new Error(`Ollama /api/chat failed: ${response.status}`);
+ const detail = await response.text().catch(() => '');
+ const serverMessage = extractOllamaError(detail);
+ const e = new Error(`Ollama /api/chat failed: ${response.status}${serverMessage ? ` - ${serverMessage}` : ''}`);
e.code =
response.status === 404
? ERROR_CODES.MODEL_NOT_FOUND
diff --git a/src/content/content.js b/src/content/content.js
index fa5f416..07e6cdc 100644
--- a/src/content/content.js
+++ b/src/content/content.js
@@ -630,12 +630,20 @@
document.addEventListener('mouseup', onSelectionEvent, { passive: true });
document.addEventListener('keyup', onSelectionEvent, { passive: true });
- // Reposition or hide UI when the viewport changes (Design 5.4).
+ // Reposition the UI while the viewport changes (Design 5.4). Keep the
+ // icon visible whenever a selection exists - hiding it on scroll left
+ // users without any way to translate until they re-selected.
window.addEventListener(
'scroll',
() => {
if (popover.state === POPOVER_STATES.HIDDEN) {
- actionButton.hide();
+ const selection = readSelection();
+ if (selection) {
+ currentSelectionRect = selection.rect;
+ actionButton.show(selection.rect);
+ } else {
+ actionButton.hide();
+ }
return;
}
const selection = readSelection();