mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-30 21:59:46 +02:00
chore: ran linting
This commit is contained in:
parent
b9b4d0b377
commit
cd25175b84
14 changed files with 78 additions and 82 deletions
|
|
@ -90,7 +90,9 @@ def _has_zero_version(conn, table: str) -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _build_publication_ddl(documents_has_zero_ver: bool, user_has_zero_ver: bool) -> str:
|
def _build_publication_ddl(
|
||||||
|
documents_has_zero_ver: bool, user_has_zero_ver: bool
|
||||||
|
) -> str:
|
||||||
doc_cols = DOCUMENT_COLS + (['"_0_version"'] if documents_has_zero_ver else [])
|
doc_cols = DOCUMENT_COLS + (['"_0_version"'] if documents_has_zero_ver else [])
|
||||||
user_cols = USER_COLS + (['"_0_version"'] if user_has_zero_ver else [])
|
user_cols = USER_COLS + (['"_0_version"'] if user_has_zero_ver else [])
|
||||||
doc_col_list = ", ".join(doc_cols)
|
doc_col_list = ", ".join(doc_cols)
|
||||||
|
|
|
||||||
|
|
@ -286,9 +286,7 @@ def initialize_openrouter_integration():
|
||||||
|
|
||||||
if new_configs:
|
if new_configs:
|
||||||
config.GLOBAL_LLM_CONFIGS.extend(new_configs)
|
config.GLOBAL_LLM_CONFIGS.extend(new_configs)
|
||||||
free_count = sum(
|
free_count = sum(1 for c in new_configs if c.get("billing_tier") == "free")
|
||||||
1 for c in new_configs if c.get("billing_tier") == "free"
|
|
||||||
)
|
|
||||||
premium_count = sum(
|
premium_count = sum(
|
||||||
1 for c in new_configs if c.get("billing_tier") == "premium"
|
1 for c in new_configs if c.get("billing_tier") == "premium"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -277,9 +277,7 @@ async def resolve_or_get_pinned_llm_config_id(
|
||||||
c for c in _global_candidates() if int(c.get("id", 0)) not in excluded_ids
|
c for c in _global_candidates() if int(c.get("id", 0)) not in excluded_ids
|
||||||
]
|
]
|
||||||
if not candidates:
|
if not candidates:
|
||||||
raise ValueError(
|
raise ValueError("No usable global LLM configs are available for Auto mode")
|
||||||
"No usable global LLM configs are available for Auto mode"
|
|
||||||
)
|
|
||||||
candidate_by_id = {int(c["id"]): c for c in candidates}
|
candidate_by_id = {int(c["id"]): c for c in candidates}
|
||||||
|
|
||||||
# Reuse an existing valid pin without re-checking current quota (no silent
|
# Reuse an existing valid pin without re-checking current quota (no silent
|
||||||
|
|
|
||||||
|
|
@ -405,9 +405,7 @@ class OpenRouterIntegrationService:
|
||||||
# Re-blend health scores against the freshly fetched catalogue. Also
|
# Re-blend health scores against the freshly fetched catalogue. Also
|
||||||
# re-stamps health for any YAML-curated cfg with provider==OPENROUTER
|
# re-stamps health for any YAML-curated cfg with provider==OPENROUTER
|
||||||
# so a hand-picked dead OR model is gated like a dynamic one.
|
# so a hand-picked dead OR model is gated like a dynamic one.
|
||||||
await self._enrich_health_safely(
|
await self._enrich_health_safely(static_configs + new_configs, log_summary=True)
|
||||||
static_configs + new_configs, log_summary=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Rebuild the LiteLLM router so freshly fetched configs flow through
|
# Rebuild the LiteLLM router so freshly fetched configs flow through
|
||||||
# (dynamic OR premium entries now opt into the pool, free ones stay
|
# (dynamic OR premium entries now opt into the pool, free ones stay
|
||||||
|
|
@ -415,8 +413,8 @@ class OpenRouterIntegrationService:
|
||||||
# reset cached context-window profiles).
|
# reset cached context-window profiles).
|
||||||
try:
|
try:
|
||||||
from app.config import config as _app_config
|
from app.config import config as _app_config
|
||||||
from app.services.llm_router_service import LLMRouterService
|
|
||||||
from app.services.llm_router_service import (
|
from app.services.llm_router_service import (
|
||||||
|
LLMRouterService,
|
||||||
_router_instance_cache as _chat_router_cache,
|
_router_instance_cache as _chat_router_cache,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -426,9 +424,7 @@ class OpenRouterIntegrationService:
|
||||||
)
|
)
|
||||||
_chat_router_cache.clear()
|
_chat_router_cache.clear()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(
|
logger.warning("OpenRouter refresh: router rebuild skipped (%s)", exc)
|
||||||
"OpenRouter refresh: router rebuild skipped (%s)", exc
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _tier_counts(configs: list[dict]) -> dict[str, int]:
|
def _tier_counts(configs: list[dict]) -> dict[str, int]:
|
||||||
|
|
@ -475,19 +471,11 @@ class OpenRouterIntegrationService:
|
||||||
return
|
return
|
||||||
|
|
||||||
premium_pool = sorted(
|
premium_pool = sorted(
|
||||||
[
|
[c for c in or_cfgs if str(c.get("billing_tier", "")).lower() == "premium"],
|
||||||
c
|
|
||||||
for c in or_cfgs
|
|
||||||
if str(c.get("billing_tier", "")).lower() == "premium"
|
|
||||||
],
|
|
||||||
key=lambda c: -int(c.get("quality_score_static") or 0),
|
key=lambda c: -int(c.get("quality_score_static") or 0),
|
||||||
)[:_HEALTH_ENRICH_TOP_N_PREMIUM]
|
)[:_HEALTH_ENRICH_TOP_N_PREMIUM]
|
||||||
free_pool = sorted(
|
free_pool = sorted(
|
||||||
[
|
[c for c in or_cfgs if str(c.get("billing_tier", "")).lower() == "free"],
|
||||||
c
|
|
||||||
for c in or_cfgs
|
|
||||||
if str(c.get("billing_tier", "")).lower() == "free"
|
|
||||||
],
|
|
||||||
key=lambda c: -int(c.get("quality_score_static") or 0),
|
key=lambda c: -int(c.get("quality_score_static") or 0),
|
||||||
)[:_HEALTH_ENRICH_TOP_N_FREE]
|
)[:_HEALTH_ENRICH_TOP_N_FREE]
|
||||||
# De-duplicate while preserving order: a cfg shouldn't fall in both
|
# De-duplicate while preserving order: a cfg shouldn't fall in both
|
||||||
|
|
@ -507,9 +495,7 @@ class OpenRouterIntegrationService:
|
||||||
api_key = str(self._settings.get("api_key") or "")
|
api_key = str(self._settings.get("api_key") or "")
|
||||||
semaphore = asyncio.Semaphore(_HEALTH_ENRICH_CONCURRENCY)
|
semaphore = asyncio.Semaphore(_HEALTH_ENRICH_CONCURRENCY)
|
||||||
|
|
||||||
async with httpx.AsyncClient(
|
async with httpx.AsyncClient(timeout=_HEALTH_FETCH_TIMEOUT_SEC) as client:
|
||||||
timeout=_HEALTH_FETCH_TIMEOUT_SEC
|
|
||||||
) as client:
|
|
||||||
results = await asyncio.gather(
|
results = await asyncio.gather(
|
||||||
*(
|
*(
|
||||||
self._fetch_endpoints(client, semaphore, api_key, cfg)
|
self._fetch_endpoints(client, semaphore, api_key, cfg)
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ sort and a SHA256 pick.
|
||||||
|
|
||||||
Score components (0-100 scale, higher is better):
|
Score components (0-100 scale, higher is better):
|
||||||
|
|
||||||
* ``static_score_or`` – derived from the bulk ``/api/v1/models`` payload
|
* ``static_score_or`` - derived from the bulk ``/api/v1/models`` payload
|
||||||
(provider prestige + ``created`` recency + pricing band + context window
|
(provider prestige + ``created`` recency + pricing band + context window
|
||||||
+ capabilities + narrow tiny/legacy slug penalty).
|
+ capabilities + narrow tiny/legacy slug penalty).
|
||||||
* ``static_score_yaml`` – same shape for hand-curated YAML configs, plus
|
* ``static_score_yaml`` - same shape for hand-curated YAML configs, plus
|
||||||
an operator-trust bonus (the operator deliberately picked this model).
|
an operator-trust bonus (the operator deliberately picked this model).
|
||||||
* ``aggregate_health`` – run on per-model ``/api/v1/models/{id}/endpoints``
|
* ``aggregate_health`` - run on per-model ``/api/v1/models/{id}/endpoints``
|
||||||
responses; returns ``(gated, score_or_none)``.
|
responses; returns ``(gated, score_or_none)``.
|
||||||
|
|
||||||
The blended ``quality_score`` (0.5 * static + 0.5 * health) is computed in
|
The blended ``quality_score`` (0.5 * static + 0.5 * health) is computed in
|
||||||
|
|
@ -281,9 +281,7 @@ def static_score_yaml(cfg: dict) -> int:
|
||||||
model_name = cfg.get("model_name") or ""
|
model_name = cfg.get("model_name") or ""
|
||||||
litellm_params = cfg.get("litellm_params") or {}
|
litellm_params = cfg.get("litellm_params") or {}
|
||||||
lookup_name = (
|
lookup_name = (
|
||||||
litellm_params.get("base_model")
|
litellm_params.get("base_model") or litellm_params.get("model") or model_name
|
||||||
or litellm_params.get("model")
|
|
||||||
or model_name
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx = 0
|
ctx = 0
|
||||||
|
|
|
||||||
|
|
@ -1814,7 +1814,9 @@ async def _stream_agent_events(
|
||||||
resolved_path = _extract_resolved_file_path(
|
resolved_path = _extract_resolved_file_path(
|
||||||
tool_name=tool_name,
|
tool_name=tool_name,
|
||||||
tool_output=tool_output,
|
tool_output=tool_output,
|
||||||
tool_input={"file_path": staged_file_path} if staged_file_path else None,
|
tool_input={"file_path": staged_file_path}
|
||||||
|
if staged_file_path
|
||||||
|
else None,
|
||||||
)
|
)
|
||||||
result_text = _tool_output_to_text(tool_output)
|
result_text = _tool_output_to_text(tool_output)
|
||||||
if _tool_output_has_error(tool_output):
|
if _tool_output_has_error(tool_output):
|
||||||
|
|
@ -2441,8 +2443,7 @@ async def stream_new_chat(
|
||||||
await _preflight_llm(llm)
|
await _preflight_llm(llm)
|
||||||
mark_healthy(llm_config_id)
|
mark_healthy(llm_config_id)
|
||||||
_perf_log.info(
|
_perf_log.info(
|
||||||
"[stream_new_chat] auto_pin_preflight ok config_id=%s "
|
"[stream_new_chat] auto_pin_preflight ok config_id=%s took=%.3fs",
|
||||||
"took=%.3fs",
|
|
||||||
llm_config_id,
|
llm_config_id,
|
||||||
time.perf_counter() - _t_preflight,
|
time.perf_counter() - _t_preflight,
|
||||||
)
|
)
|
||||||
|
|
@ -2891,7 +2892,11 @@ async def stream_new_chat(
|
||||||
|
|
||||||
# Inject title update mid-stream as soon as the background
|
# Inject title update mid-stream as soon as the background
|
||||||
# task finishes.
|
# task finishes.
|
||||||
if title_task is not None and title_task.done() and not title_emitted:
|
if (
|
||||||
|
title_task is not None
|
||||||
|
and title_task.done()
|
||||||
|
and not title_emitted
|
||||||
|
):
|
||||||
generated_title, title_usage = title_task.result()
|
generated_title, title_usage = title_task.result()
|
||||||
if title_usage:
|
if title_usage:
|
||||||
accumulator.add(**title_usage)
|
accumulator.add(**title_usage)
|
||||||
|
|
@ -2944,7 +2949,9 @@ async def stream_new_chat(
|
||||||
)
|
)
|
||||||
).resolved_llm_config_id
|
).resolved_llm_config_id
|
||||||
|
|
||||||
llm, agent_config, llm_load_error = await _load_llm_bundle(llm_config_id)
|
llm, agent_config, llm_load_error = await _load_llm_bundle(
|
||||||
|
llm_config_id
|
||||||
|
)
|
||||||
if llm_load_error:
|
if llm_load_error:
|
||||||
raise stream_exc
|
raise stream_exc
|
||||||
|
|
||||||
|
|
@ -3480,8 +3487,7 @@ async def stream_resume_chat(
|
||||||
await _preflight_llm(llm)
|
await _preflight_llm(llm)
|
||||||
mark_healthy(llm_config_id)
|
mark_healthy(llm_config_id)
|
||||||
_perf_log.info(
|
_perf_log.info(
|
||||||
"[stream_resume] auto_pin_preflight ok config_id=%s "
|
"[stream_resume] auto_pin_preflight ok config_id=%s took=%.3fs",
|
||||||
"took=%.3fs",
|
|
||||||
llm_config_id,
|
llm_config_id,
|
||||||
time.perf_counter() - _t_preflight,
|
time.perf_counter() - _t_preflight,
|
||||||
)
|
)
|
||||||
|
|
@ -3684,7 +3690,9 @@ async def stream_resume_chat(
|
||||||
)
|
)
|
||||||
).resolved_llm_config_id
|
).resolved_llm_config_id
|
||||||
|
|
||||||
llm, agent_config, llm_load_error = await _load_llm_bundle(llm_config_id)
|
llm, agent_config, llm_load_error = await _load_llm_bundle(
|
||||||
|
llm_config_id
|
||||||
|
)
|
||||||
if llm_load_error:
|
if llm_load_error:
|
||||||
raise stream_exc
|
raise stream_exc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -574,7 +574,7 @@ async def test_top_k_picks_only_high_score_models(monkeypatch):
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
config,
|
config,
|
||||||
"GLOBAL_LLM_CONFIGS",
|
"GLOBAL_LLM_CONFIGS",
|
||||||
high_score_cfgs + [low_score_trap],
|
[*high_score_cfgs, low_score_trap],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _allowed(*_args, **_kwargs):
|
async def _allowed(*_args, **_kwargs):
|
||||||
|
|
|
||||||
|
|
@ -96,9 +96,12 @@ def test_router_pool_includes_or_premium_excludes_or_free():
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch("app.services.llm_router_service.Router") as mock_router, patch(
|
with (
|
||||||
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
patch("app.services.llm_router_service.Router") as mock_router,
|
||||||
) as mock_ctx_fb:
|
patch(
|
||||||
|
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
||||||
|
) as mock_ctx_fb,
|
||||||
|
):
|
||||||
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
||||||
mock_router.return_value = object()
|
mock_router.return_value = object()
|
||||||
LLMRouterService.initialize(configs)
|
LLMRouterService.initialize(configs)
|
||||||
|
|
@ -124,9 +127,10 @@ def test_router_pool_includes_or_premium_excludes_or_free():
|
||||||
assert "openrouter/openai/gpt-4o" in prem
|
assert "openrouter/openai/gpt-4o" in prem
|
||||||
assert LLMRouterService.is_premium_model("openrouter/openai/gpt-4o") is True
|
assert LLMRouterService.is_premium_model("openrouter/openai/gpt-4o") is True
|
||||||
# Dynamic OR free never enters the pool, so it's never counted as premium.
|
# Dynamic OR free never enters the pool, so it's never counted as premium.
|
||||||
assert LLMRouterService.is_premium_model(
|
assert (
|
||||||
"openrouter/meta-llama/llama-3.3-70b:free"
|
LLMRouterService.is_premium_model("openrouter/meta-llama/llama-3.3-70b:free")
|
||||||
) is False
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_router_pool_filter_mechanics_respect_override():
|
def test_router_pool_filter_mechanics_respect_override():
|
||||||
|
|
@ -147,9 +151,12 @@ def test_router_pool_filter_mechanics_respect_override():
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch("app.services.llm_router_service.Router") as mock_router, patch(
|
with (
|
||||||
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
patch("app.services.llm_router_service.Router") as mock_router,
|
||||||
) as mock_ctx_fb:
|
patch(
|
||||||
|
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
||||||
|
) as mock_ctx_fb,
|
||||||
|
):
|
||||||
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
||||||
mock_router.return_value = object()
|
mock_router.return_value = object()
|
||||||
LLMRouterService.initialize(configs)
|
LLMRouterService.initialize(configs)
|
||||||
|
|
@ -167,13 +174,17 @@ def test_rebuild_refreshes_pool_after_configs_change():
|
||||||
configs_v1 = [
|
configs_v1 = [
|
||||||
_fake_yaml_config(id=-1, model_name="gpt-4o", billing_tier="premium"),
|
_fake_yaml_config(id=-1, model_name="gpt-4o", billing_tier="premium"),
|
||||||
]
|
]
|
||||||
configs_v2 = configs_v1 + [
|
configs_v2 = [
|
||||||
|
*configs_v1,
|
||||||
_fake_yaml_config(id=-2, model_name="gpt-4o-mini", billing_tier="free"),
|
_fake_yaml_config(id=-2, model_name="gpt-4o-mini", billing_tier="free"),
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch("app.services.llm_router_service.Router") as mock_router, patch(
|
with (
|
||||||
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
patch("app.services.llm_router_service.Router") as mock_router,
|
||||||
) as mock_ctx_fb:
|
patch(
|
||||||
|
"app.services.llm_router_service.LLMRouterService._build_context_fallback_groups"
|
||||||
|
) as mock_ctx_fb,
|
||||||
|
):
|
||||||
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
mock_ctx_fb.side_effect = lambda ml: (ml, None)
|
||||||
mock_router.return_value = object()
|
mock_router.return_value = object()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,5 +214,3 @@ def test_generate_configs_drops_non_text_and_non_tool_models():
|
||||||
assert "openai/gpt-4o" in model_names
|
assert "openai/gpt-4o" in model_names
|
||||||
assert "openai/dall-e" not in model_names
|
assert "openai/dall-e" not in model_names
|
||||||
assert "openai/completion-only" not in model_names
|
assert "openai/completion-only" not in model_names
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,7 @@ openrouter_integration:
|
||||||
assert "deprecated" in captured
|
assert "deprecated" in captured
|
||||||
|
|
||||||
|
|
||||||
def test_new_keys_take_priority_over_legacy_back_compat(
|
def test_new_keys_take_priority_over_legacy_back_compat(monkeypatch, tmp_path, capsys):
|
||||||
monkeypatch, tmp_path, capsys
|
|
||||||
):
|
|
||||||
"""If both legacy and new keys are present, new keys win (setdefault)."""
|
"""If both legacy and new keys are present, new keys win (setdefault)."""
|
||||||
_write_yaml(
|
_write_yaml(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,12 @@ def test_context_signal_bands(ctx, expected):
|
||||||
|
|
||||||
|
|
||||||
def test_capabilities_signal_caps_at_five():
|
def test_capabilities_signal_caps_at_five():
|
||||||
assert capabilities_signal(
|
assert (
|
||||||
["tools", "structured_outputs", "reasoning", "include_reasoning"]
|
capabilities_signal(
|
||||||
) <= 5
|
["tools", "structured_outputs", "reasoning", "include_reasoning"]
|
||||||
|
)
|
||||||
|
<= 5
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_capabilities_signal_tools_only():
|
def test_capabilities_signal_tools_only():
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ from app.tasks.chat.stream_new_chat import (
|
||||||
StreamResult,
|
StreamResult,
|
||||||
_classify_stream_exception,
|
_classify_stream_exception,
|
||||||
_contract_enforcement_active,
|
_contract_enforcement_active,
|
||||||
_extract_resolved_file_path,
|
|
||||||
_evaluate_file_contract_outcome,
|
_evaluate_file_contract_outcome,
|
||||||
|
_extract_resolved_file_path,
|
||||||
_log_chat_stream_error,
|
_log_chat_stream_error,
|
||||||
_tool_output_has_error,
|
_tool_output_has_error,
|
||||||
)
|
)
|
||||||
|
|
@ -222,7 +222,7 @@ async def test_preflight_swallows_non_rate_limit_errors_and_re_raises_429(monkey
|
||||||
|
|
||||||
from app.tasks.chat.stream_new_chat import _preflight_llm
|
from app.tasks.chat.stream_new_chat import _preflight_llm
|
||||||
|
|
||||||
class _RateLimitedExc(Exception):
|
class _RateLimitedError(Exception):
|
||||||
"""Class-name carries 'RateLimit' so _is_provider_rate_limited triggers."""
|
"""Class-name carries 'RateLimit' so _is_provider_rate_limited triggers."""
|
||||||
|
|
||||||
rate_calls: list[dict] = []
|
rate_calls: list[dict] = []
|
||||||
|
|
@ -230,7 +230,7 @@ async def test_preflight_swallows_non_rate_limit_errors_and_re_raises_429(monkey
|
||||||
|
|
||||||
async def _fake_acompletion_429(**kwargs):
|
async def _fake_acompletion_429(**kwargs):
|
||||||
rate_calls.append(kwargs)
|
rate_calls.append(kwargs)
|
||||||
raise _RateLimitedExc("simulated 429")
|
raise _RateLimitedError("simulated 429")
|
||||||
|
|
||||||
async def _fake_acompletion_other(**kwargs):
|
async def _fake_acompletion_other(**kwargs):
|
||||||
other_calls.append(kwargs)
|
other_calls.append(kwargs)
|
||||||
|
|
@ -245,7 +245,7 @@ async def test_preflight_swallows_non_rate_limit_errors_and_re_raises_429(monkey
|
||||||
import litellm # type: ignore[import-not-found]
|
import litellm # type: ignore[import-not-found]
|
||||||
|
|
||||||
monkeypatch.setattr(litellm, "acompletion", _fake_acompletion_429)
|
monkeypatch.setattr(litellm, "acompletion", _fake_acompletion_429)
|
||||||
with pytest.raises(_RateLimitedExc):
|
with pytest.raises(_RateLimitedError):
|
||||||
await _preflight_llm(fake_llm)
|
await _preflight_llm(fake_llm)
|
||||||
assert len(rate_calls) == 1
|
assert len(rate_calls) == 1
|
||||||
assert rate_calls[0]["max_tokens"] == 1
|
assert rate_calls[0]["max_tokens"] == 1
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import remarkMath from "remark-math";
|
||||||
import { openEditorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
import { openEditorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
||||||
import { ImagePreview, ImageRoot, ImageZoom } from "@/components/assistant-ui/image";
|
import { ImagePreview, ImageRoot, ImageZoom } from "@/components/assistant-ui/image";
|
||||||
import "katex/dist/katex.min.css";
|
import "katex/dist/katex.min.css";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { processChildrenWithCitations } from "@/components/citations/citation-renderer";
|
import { processChildrenWithCitations } from "@/components/citations/citation-renderer";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import {
|
import {
|
||||||
|
|
@ -33,7 +34,6 @@ import { useElectronAPI } from "@/hooks/use-platform";
|
||||||
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
||||||
import { type CitationUrlMap, preprocessCitationMarkdown } from "@/lib/citations/citation-parser";
|
import { type CitationUrlMap, preprocessCitationMarkdown } from "@/lib/citations/citation-parser";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
function MarkdownCodeBlockSkeleton() {
|
function MarkdownCodeBlockSkeleton() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -207,13 +207,7 @@ function isStandaloneDocumentsPathText(node: ReactNode): string | null {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FilePathLink({
|
function FilePathLink({ path, className }: { path: string; className?: string }) {
|
||||||
path,
|
|
||||||
className,
|
|
||||||
}: {
|
|
||||||
path: string;
|
|
||||||
className?: string;
|
|
||||||
}) {
|
|
||||||
const openEditorPanel = useSetAtom(openEditorPanelAtom);
|
const openEditorPanel = useSetAtom(openEditorPanelAtom);
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const electronAPI = useElectronAPI();
|
const electronAPI = useElectronAPI();
|
||||||
|
|
@ -221,7 +215,9 @@ function FilePathLink({
|
||||||
const parsedSearchSpaceId = Array.isArray(searchSpaceIdParam)
|
const parsedSearchSpaceId = Array.isArray(searchSpaceIdParam)
|
||||||
? Number(searchSpaceIdParam[0])
|
? Number(searchSpaceIdParam[0])
|
||||||
: Number(searchSpaceIdParam);
|
: Number(searchSpaceIdParam);
|
||||||
const resolvedSearchSpaceId = Number.isFinite(parsedSearchSpaceId) ? parsedSearchSpaceId : undefined;
|
const resolvedSearchSpaceId = Number.isFinite(parsedSearchSpaceId)
|
||||||
|
? parsedSearchSpaceId
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
type DeleteDocumentRequest,
|
type DeleteDocumentRequest,
|
||||||
deleteDocumentRequest,
|
deleteDocumentRequest,
|
||||||
deleteDocumentResponse,
|
deleteDocumentResponse,
|
||||||
|
documentTitleRead,
|
||||||
type GetDocumentByChunkRequest,
|
type GetDocumentByChunkRequest,
|
||||||
type GetDocumentChunksRequest,
|
type GetDocumentChunksRequest,
|
||||||
type GetDocumentRequest,
|
type GetDocumentRequest,
|
||||||
|
|
@ -28,7 +29,6 @@ import {
|
||||||
getSurfsenseDocsRequest,
|
getSurfsenseDocsRequest,
|
||||||
getSurfsenseDocsResponse,
|
getSurfsenseDocsResponse,
|
||||||
type SearchDocumentsRequest,
|
type SearchDocumentsRequest,
|
||||||
documentTitleRead,
|
|
||||||
type SearchDocumentTitlesRequest,
|
type SearchDocumentTitlesRequest,
|
||||||
searchDocumentsRequest,
|
searchDocumentsRequest,
|
||||||
searchDocumentsResponse,
|
searchDocumentsResponse,
|
||||||
|
|
@ -270,15 +270,15 @@ class DocumentsApiService {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
getDocumentByVirtualPath = async (request: {
|
getDocumentByVirtualPath = async (request: { search_space_id: number; virtual_path: string }) => {
|
||||||
search_space_id: number;
|
|
||||||
virtual_path: string;
|
|
||||||
}) => {
|
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
search_space_id: String(request.search_space_id),
|
search_space_id: String(request.search_space_id),
|
||||||
virtual_path: request.virtual_path,
|
virtual_path: request.virtual_path,
|
||||||
});
|
});
|
||||||
return baseApiService.get(`/api/v1/documents/by-virtual-path?${params.toString()}`, documentTitleRead);
|
return baseApiService.get(
|
||||||
|
`/api/v1/documents/by-virtual-path?${params.toString()}`,
|
||||||
|
documentTitleRead
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue