forked from retoor/devplacepy
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d4ae7dd4c |
File diff suppressed because one or more lines are too long
@@ -22,7 +22,7 @@ from .comments import _drop_blocked, _build_comment_items, load_comments, get_re
|
|||||||
from .content import resolve_by_slug, resolve_object_url, get_uids_by_username_match, text_search_clause, get_daily_topic, get_featured_news
|
from .content import resolve_by_slug, resolve_object_url, get_uids_by_username_match, text_search_clause, get_daily_topic, get_featured_news
|
||||||
from .attachments_data import get_attachments, get_attachments_by_type, get_news_images_by_uids, delete_attachment_record, delete_attachments, _delete_attachment_file, get_user_media, get_deleted_media
|
from .attachments_data import get_attachments, get_attachments_by_type, get_news_images_by_uids, delete_attachment_record, delete_attachments, _delete_attachment_file, get_user_media, get_deleted_media
|
||||||
from .stats import _stats_cache, get_site_stats, _analytics_cache, get_platform_analytics, _gist_languages_cache, get_gist_languages
|
from .stats import _stats_cache, get_site_stats, _analytics_cache, get_platform_analytics, _gist_languages_cache, get_gist_languages
|
||||||
from .schema import BUG_TABLE_RENAMES, migrate_bug_tables_to_issue_tables, init_db, _refresh_query_planner_stats, OLD_GATEWAY_URL, migrate_ai_gateway_settings, backfill_api_keys, _backfill_gamification
|
from .schema import init_db, _refresh_query_planner_stats, OLD_GATEWAY_URL, migrate_ai_gateway_settings, backfill_api_keys, _backfill_gamification
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"dataset",
|
"dataset",
|
||||||
@@ -222,8 +222,6 @@ __all__ = [
|
|||||||
"get_platform_analytics",
|
"get_platform_analytics",
|
||||||
"_gist_languages_cache",
|
"_gist_languages_cache",
|
||||||
"get_gist_languages",
|
"get_gist_languages",
|
||||||
"BUG_TABLE_RENAMES",
|
|
||||||
"migrate_bug_tables_to_issue_tables",
|
|
||||||
"init_db",
|
"init_db",
|
||||||
"_refresh_query_planner_stats",
|
"_refresh_query_planner_stats",
|
||||||
"OLD_GATEWAY_URL",
|
"OLD_GATEWAY_URL",
|
||||||
|
|||||||
@@ -6,30 +6,6 @@ from .soft_delete import SOFT_DELETE_TABLES, ensure_soft_delete_columns
|
|||||||
from .ranking import _authors_cache
|
from .ranking import _authors_cache
|
||||||
|
|
||||||
|
|
||||||
BUG_TABLE_RENAMES = (
|
|
||||||
("bug_tickets", "issue_tickets"),
|
|
||||||
("bug_comment_authors", "issue_comment_authors"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_bug_tables_to_issue_tables() -> None:
|
|
||||||
for source_name, destination_name in BUG_TABLE_RENAMES:
|
|
||||||
if source_name not in db.tables:
|
|
||||||
continue
|
|
||||||
source = db[source_name]
|
|
||||||
destination = get_table(destination_name)
|
|
||||||
copied = 0
|
|
||||||
for row in source.all():
|
|
||||||
payload = {key: value for key, value in row.items() if key != "id"}
|
|
||||||
destination.insert_ignore(payload, ["uid"])
|
|
||||||
copied += 1
|
|
||||||
logger.info(
|
|
||||||
"Migrated %s rows from %s into %s", copied, source_name, destination_name
|
|
||||||
)
|
|
||||||
source.drop()
|
|
||||||
logger.info("Dropped table %s after migration", source_name)
|
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
tables = db.tables
|
tables = db.tables
|
||||||
_index(db, "users", "idx_users_username", ["username"])
|
_index(db, "users", "idx_users_username", ["username"])
|
||||||
@@ -356,7 +332,6 @@ def init_db():
|
|||||||
_index(
|
_index(
|
||||||
db, "issue_comment_authors", "idx_issue_comment_authors_number", ["gitea_number"]
|
db, "issue_comment_authors", "idx_issue_comment_authors_number", ["gitea_number"]
|
||||||
)
|
)
|
||||||
migrate_bug_tables_to_issue_tables()
|
|
||||||
_index(db, "service_state", "idx_service_state_name", ["name"])
|
_index(db, "service_state", "idx_service_state_name", ["name"])
|
||||||
if "devii_conversations" in db.tables:
|
if "devii_conversations" in db.tables:
|
||||||
conversations = get_table("devii_conversations")
|
conversations = get_table("devii_conversations")
|
||||||
|
|||||||
@@ -227,8 +227,7 @@ def _session_context(request: Request, uid: str, job: dict, session: dict) -> di
|
|||||||
user = get_current_user(request)
|
user = get_current_user(request)
|
||||||
viewer_is_admin = is_admin(user)
|
viewer_is_admin = is_admin(user)
|
||||||
done = bool(report) or job.get("status") == queue.DONE
|
done = bool(report) or job.get("status") == queue.DONE
|
||||||
cost_usd = report.get("cost_usd", 0.0) if report else 0.0
|
return {
|
||||||
ctx = {
|
|
||||||
"uid": uid,
|
"uid": uid,
|
||||||
"status": queue.DONE if done else job.get("status", ""),
|
"status": queue.DONE if done else job.get("status", ""),
|
||||||
"query": report.get("query") or session.get("query"),
|
"query": report.get("query") or session.get("query"),
|
||||||
@@ -248,7 +247,6 @@ def _session_context(request: Request, uid: str, job: dict, session: dict) -> di
|
|||||||
"export_md_url": f"/tools/deepsearch/{uid}/export.md" if done else None,
|
"export_md_url": f"/tools/deepsearch/{uid}/export.md" if done else None,
|
||||||
"export_json_url": f"/tools/deepsearch/{uid}/export.json" if done else None,
|
"export_json_url": f"/tools/deepsearch/{uid}/export.json" if done else None,
|
||||||
"export_pdf_url": f"/tools/deepsearch/{uid}/export.pdf" if done else None,
|
"export_pdf_url": f"/tools/deepsearch/{uid}/export.pdf" if done else None,
|
||||||
"cost_usd": cost_usd if viewer_is_admin else None,
|
|
||||||
"viewer_is_admin": viewer_is_admin,
|
"viewer_is_admin": viewer_is_admin,
|
||||||
"viewer_owns": _owns(request, session),
|
"viewer_owns": _owns(request, session),
|
||||||
"created_at": session.get("created_at"),
|
"created_at": session.get("created_at"),
|
||||||
@@ -257,7 +255,6 @@ def _session_context(request: Request, uid: str, job: dict, session: dict) -> di
|
|||||||
"user": user,
|
"user": user,
|
||||||
"meta_robots": "noindex,nofollow",
|
"meta_robots": "noindex,nofollow",
|
||||||
}
|
}
|
||||||
return ctx
|
|
||||||
|
|
||||||
@router.get("/{uid}/session")
|
@router.get("/{uid}/session")
|
||||||
async def deepsearch_session(request: Request, uid: str):
|
async def deepsearch_session(request: Request, uid: str):
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ class DeepsearchSessionOut(_Out):
|
|||||||
export_md_url: Optional[str] = None
|
export_md_url: Optional[str] = None
|
||||||
export_json_url: Optional[str] = None
|
export_json_url: Optional[str] = None
|
||||||
export_pdf_url: Optional[str] = None
|
export_pdf_url: Optional[str] = None
|
||||||
cost_usd: Optional[float] = None
|
|
||||||
viewer_is_admin: bool = False
|
viewer_is_admin: bool = False
|
||||||
viewer_owns: bool = False
|
viewer_owns: bool = False
|
||||||
created_at: Optional[str] = None
|
created_at: Optional[str] = None
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import time
|
|||||||
|
|
||||||
from devplacepy import stealth
|
from devplacepy import stealth
|
||||||
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
|
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
|
||||||
from devplacepy.services.openai_gateway.usage import parse_usage_headers
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -42,10 +41,7 @@ async def request_completion(
|
|||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
raise RuntimeError(f"chat gateway returned {response.status_code}")
|
raise RuntimeError(f"chat gateway returned {response.status_code}")
|
||||||
data: dict = response.json()
|
data: dict = response.json()
|
||||||
cost_info = parse_usage_headers(response.headers) or {}
|
return data, data.get("usage") or {}, elapsed_ms
|
||||||
usage = data.get("usage") or {}
|
|
||||||
usage["cost_usd"] = cost_info.get("cost_usd", 0.0)
|
|
||||||
return data, usage, elapsed_ms
|
|
||||||
|
|
||||||
|
|
||||||
async def complete_chat(
|
async def complete_chat(
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ from __future__ import annotations
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Callable, Tuple
|
from typing import Callable
|
||||||
|
|
||||||
from devplacepy import stealth
|
from devplacepy import stealth
|
||||||
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
|
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
|
||||||
from devplacepy.services.openai_gateway.usage import parse_usage_headers
|
|
||||||
|
|
||||||
from .phases import PHASE_PLANNING
|
from .phases import PHASE_PLANNING
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ def _noop(frame: dict) -> None:
|
|||||||
|
|
||||||
async def plan_queries(
|
async def plan_queries(
|
||||||
query: str, api_key: str, emit: Callable[[dict], None] = _noop
|
query: str, api_key: str, emit: Callable[[dict], None] = _noop
|
||||||
) -> Tuple[list[str], float]:
|
) -> list[str]:
|
||||||
emit(
|
emit(
|
||||||
{
|
{
|
||||||
"type": "substep",
|
"type": "substep",
|
||||||
@@ -90,8 +89,6 @@ async def plan_queries(
|
|||||||
)
|
)
|
||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
raise RuntimeError(f"planner gateway returned {response.status_code}")
|
raise RuntimeError(f"planner gateway returned {response.status_code}")
|
||||||
cost_info = parse_usage_headers(response.headers) or {}
|
|
||||||
planner_cost = cost_info.get("cost_usd", 0.0)
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
content = (
|
content = (
|
||||||
(data.get("choices") or [{}])[0].get("message", {}).get("content") or ""
|
(data.get("choices") or [{}])[0].get("message", {}).get("content") or ""
|
||||||
@@ -105,7 +102,7 @@ async def plan_queries(
|
|||||||
"message": f"Planned {len(parsed)} search angles",
|
"message": f"Planned {len(parsed)} search angles",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return parsed, planner_cost
|
return parsed
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("deepsearch query planner failed, using fallback: %s", exc)
|
logger.warning("deepsearch query planner failed, using fallback: %s", exc)
|
||||||
fallback = _fallback(query)
|
fallback = _fallback(query)
|
||||||
@@ -116,4 +113,4 @@ async def plan_queries(
|
|||||||
"message": f"Planner unavailable, using {len(fallback)} heuristic angles",
|
"message": f"Planner unavailable, using {len(fallback)} heuristic angles",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return fallback, 0.0
|
return fallback
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class Orchestration:
|
|||||||
source_diversity: float = 0.0
|
source_diversity: float = 0.0
|
||||||
score: int = 0
|
score: int = 0
|
||||||
synthesis: str = "agents"
|
synthesis: str = "agents"
|
||||||
total_cost_usd: float = 0.0
|
|
||||||
|
|
||||||
|
|
||||||
def _domain(url: str) -> str:
|
def _domain(url: str) -> str:
|
||||||
@@ -166,7 +165,6 @@ async def _complete(
|
|||||||
"tokens_in": int(raw_usage.get("prompt_tokens") or prompt_chars // 4),
|
"tokens_in": int(raw_usage.get("prompt_tokens") or prompt_chars // 4),
|
||||||
"tokens_out": int(raw_usage.get("completion_tokens") or len(text) // 4),
|
"tokens_out": int(raw_usage.get("completion_tokens") or len(text) // 4),
|
||||||
"elapsed_ms": elapsed_ms,
|
"elapsed_ms": elapsed_ms,
|
||||||
"cost_usd": float(raw_usage.get("cost_usd", 0.0)),
|
|
||||||
}
|
}
|
||||||
return text, usage
|
return text, usage
|
||||||
|
|
||||||
@@ -298,7 +296,6 @@ def _agent_done(emit: Callable[[dict], None], agent: str, usage: dict) -> None:
|
|||||||
"elapsed_ms": usage.get("elapsed_ms", 0),
|
"elapsed_ms": usage.get("elapsed_ms", 0),
|
||||||
"tokens_in": usage.get("tokens_in", 0),
|
"tokens_in": usage.get("tokens_in", 0),
|
||||||
"tokens_out": usage.get("tokens_out", 0),
|
"tokens_out": usage.get("tokens_out", 0),
|
||||||
"cost_usd": usage.get("cost_usd", 0.0),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -349,7 +346,6 @@ async def orchestrate(
|
|||||||
emit: Callable[[dict], None],
|
emit: Callable[[dict], None],
|
||||||
store=None,
|
store=None,
|
||||||
queries: list[str] | None = None,
|
queries: list[str] | None = None,
|
||||||
planner_cost_usd: float = 0.0,
|
|
||||||
) -> Orchestration:
|
) -> Orchestration:
|
||||||
diversity = source_diversity(pages)
|
diversity = source_diversity(pages)
|
||||||
if not pages:
|
if not pages:
|
||||||
@@ -422,12 +418,6 @@ async def orchestrate(
|
|||||||
score = int(
|
score = int(
|
||||||
min(SCORE_MAX, (confidence * 0.5 + diversity * 0.3 + coverage * 0.2) * SCORE_MAX)
|
min(SCORE_MAX, (confidence * 0.5 + diversity * 0.3 + coverage * 0.2) * SCORE_MAX)
|
||||||
)
|
)
|
||||||
total_cost = (
|
|
||||||
planner_cost_usd
|
|
||||||
+ float(summary_usage.get("cost_usd", 0.0))
|
|
||||||
+ float(findings_usage.get("cost_usd", 0.0))
|
|
||||||
+ float(linker_usage.get("cost_usd", 0.0))
|
|
||||||
)
|
|
||||||
return Orchestration(
|
return Orchestration(
|
||||||
summary=summary,
|
summary=summary,
|
||||||
findings=findings,
|
findings=findings,
|
||||||
@@ -435,7 +425,6 @@ async def orchestrate(
|
|||||||
source_diversity=diversity,
|
source_diversity=diversity,
|
||||||
score=score,
|
score=score,
|
||||||
synthesis="agents",
|
synthesis="agents",
|
||||||
total_cost_usd=total_cost,
|
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("deepsearch orchestration failed, using heuristic: %s", exc)
|
logger.warning("deepsearch orchestration failed, using heuristic: %s", exc)
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ async def _run(payload: dict, output_dir: Path) -> dict:
|
|||||||
should_stop = _make_stop(output_dir)
|
should_stop = _make_stop(output_dir)
|
||||||
|
|
||||||
_stage("planning", "Planning research queries", PHASE_PLANNING)
|
_stage("planning", "Planning research queries", PHASE_PLANNING)
|
||||||
queries, planner_cost = await plan_queries(query, api_key, _emit)
|
queries = await plan_queries(query, api_key, _emit)
|
||||||
_emit({"type": "queries", "queries": queries})
|
_emit({"type": "queries", "queries": queries})
|
||||||
|
|
||||||
_stage("searching", "Searching the web", PHASE_SEARCHING)
|
_stage("searching", "Searching the web", PHASE_SEARCHING)
|
||||||
@@ -203,8 +203,7 @@ async def _run(payload: dict, output_dir: Path) -> dict:
|
|||||||
|
|
||||||
_stage("analysis", "Running research agents", PHASE_ANALYSIS)
|
_stage("analysis", "Running research agents", PHASE_ANALYSIS)
|
||||||
result = await orchestrate(
|
result = await orchestrate(
|
||||||
query, outcome.pages, api_key, _emit, store=store, queries=queries,
|
query, outcome.pages, api_key, _emit, store=store, queries=queries
|
||||||
planner_cost_usd=planner_cost,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_stage("synthesis", "Compiling cited report", PHASE_SYNTHESIS)
|
_stage("synthesis", "Compiling cited report", PHASE_SYNTHESIS)
|
||||||
@@ -229,7 +228,6 @@ async def _run(payload: dict, output_dir: Path) -> dict:
|
|||||||
"chunk_count": chunk_count,
|
"chunk_count": chunk_count,
|
||||||
"embed_backend": embed_backend,
|
"embed_backend": embed_backend,
|
||||||
"collection": collection,
|
"collection": collection,
|
||||||
"cost_usd": result.total_cost_usd,
|
|
||||||
}
|
}
|
||||||
(output_dir / "report.json").write_text(
|
(output_dir / "report.json").write_text(
|
||||||
json.dumps(report, ensure_ascii=False), encoding="utf-8"
|
json.dumps(report, ensure_ascii=False), encoding="utf-8"
|
||||||
@@ -246,7 +244,6 @@ async def _run(payload: dict, output_dir: Path) -> dict:
|
|||||||
"synthesis": report["synthesis"],
|
"synthesis": report["synthesis"],
|
||||||
"page_count": report["page_count"],
|
"page_count": report["page_count"],
|
||||||
"chunk_count": report["chunk_count"],
|
"chunk_count": report["chunk_count"],
|
||||||
"cost_usd": report["cost_usd"],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return report
|
return report
|
||||||
|
|||||||
@@ -16,9 +16,6 @@
|
|||||||
<span class="ds-metric"><strong>{{ source_diversity }}</strong> diversity</span>
|
<span class="ds-metric"><strong>{{ source_diversity }}</strong> diversity</span>
|
||||||
<span class="ds-metric"><strong>{{ page_count }}</strong> sources</span>
|
<span class="ds-metric"><strong>{{ page_count }}</strong> sources</span>
|
||||||
<span class="ds-metric"><strong>{{ chunk_count }}</strong> chunks</span>
|
<span class="ds-metric"><strong>{{ chunk_count }}</strong> chunks</span>
|
||||||
{% if viewer_is_admin and cost_usd is not none %}
|
|
||||||
<span class="ds-metric"><strong>${{ "%.6f"|format(cost_usd) }}</strong> cost</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% if export_md_url %}
|
{% if export_md_url %}
|
||||||
<div class="ds-exports">
|
<div class="ds-exports">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026-07-19T17:31:36 INFO logging initialised at /workspace/repo/dpc.log
|
2026-07-19T17:34:12 INFO logging initialised at /workspace/repo/dpc.log
|
||||||
2026-07-19T17:31:36 DEBUG model=molodetz-pro fps=30
|
2026-07-19T17:34:12 DEBUG model=molodetz-pro fps=30
|
||||||
2026-07-19T17:31:36 INFO read task from file: /workspace/prompts/research-10.txt
|
2026-07-19T17:34:12 INFO read task from file: /workspace/prompts/research-9.txt
|
||||||
2026-07-19T17:31:36 INFO settings merged: model=<default> allow=0 deny=0 ask=0
|
2026-07-19T17:34:12 INFO settings merged: model=<default> allow=0 deny=0 ask=0
|
||||||
2026-07-19T19:05:24 INFO logging initialised at /workspace/repo/dpc.log
|
2026-07-19T17:38:50 INFO logging initialised at /workspace/repo/dpc.log
|
||||||
2026-07-19T19:05:24 DEBUG model=molodetz-pro fps=30
|
2026-07-19T17:38:50 DEBUG model=molodetz-pro fps=30
|
||||||
2026-07-19T19:05:24 INFO read task from file: /workspace/prompts/execution-1.txt
|
2026-07-19T17:38:50 INFO read task from file: /workspace/prompts/execution-1.txt
|
||||||
2026-07-19T19:05:24 INFO settings merged: model=<default> allow=0 deny=0 ask=0
|
2026-07-19T17:38:50 INFO settings merged: model=<default> allow=0 deny=0 ask=0
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ def _seed_done_session(owner_id="ds-session-owner"):
|
|||||||
"source_diversity": 0.5,
|
"source_diversity": 0.5,
|
||||||
"page_count": 3,
|
"page_count": 3,
|
||||||
"chunk_count": 12,
|
"chunk_count": 12,
|
||||||
"cost_usd": 0.123456,
|
|
||||||
}
|
}
|
||||||
result = {
|
result = {
|
||||||
"query": "the question",
|
"query": "the question",
|
||||||
@@ -48,7 +47,6 @@ def _seed_done_session(owner_id="ds-session-owner"):
|
|||||||
"source_diversity": 0.5,
|
"source_diversity": 0.5,
|
||||||
"page_count": 3,
|
"page_count": 3,
|
||||||
"chunk_count": 12,
|
"chunk_count": 12,
|
||||||
"cost_usd": 0.123456,
|
|
||||||
"report": report,
|
"report": report,
|
||||||
}
|
}
|
||||||
get_table("jobs").update(
|
get_table("jobs").update(
|
||||||
@@ -99,7 +97,6 @@ def test_session_json_shape(app_server):
|
|||||||
assert body["sources"]
|
assert body["sources"]
|
||||||
assert "viewer_is_admin" in body
|
assert "viewer_is_admin" in body
|
||||||
assert "viewer_owns" in body
|
assert "viewer_owns" in body
|
||||||
assert body.get("cost_usd") is None # guest user, not admin
|
|
||||||
finally:
|
finally:
|
||||||
_clear()
|
_clear()
|
||||||
|
|
||||||
@@ -111,7 +108,6 @@ def test_session_html_renders_without_jinja_global_collision(app_server):
|
|||||||
assert r.status_code == 200, r.text
|
assert r.status_code == 200, r.text
|
||||||
assert "the question" in r.text
|
assert "the question" in r.text
|
||||||
assert "dp-deepsearch-chat" in r.text
|
assert "dp-deepsearch-chat" in r.text
|
||||||
assert "0.123456" not in r.text # guest user, cost hidden
|
|
||||||
finally:
|
finally:
|
||||||
_clear()
|
_clear()
|
||||||
|
|
||||||
@@ -146,7 +142,6 @@ def test_session_reads_disk_report_before_result_commit(app_server):
|
|||||||
"synthesis": "agents",
|
"synthesis": "agents",
|
||||||
"page_count": 12,
|
"page_count": 12,
|
||||||
"chunk_count": 61,
|
"chunk_count": 61,
|
||||||
"cost_usd": 0.123456,
|
|
||||||
}
|
}
|
||||||
session_dir = DEEPSEARCH_DIR / uid
|
session_dir = DEEPSEARCH_DIR / uid
|
||||||
session_dir.mkdir(parents=True, exist_ok=True)
|
session_dir.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -208,26 +203,3 @@ def test_export_json(app_server):
|
|||||||
def test_export_unknown_uid_404(app_server):
|
def test_export_unknown_uid_404(app_server):
|
||||||
r = requests.get(f"{BASE_URL}/tools/deepsearch/nope/export.md")
|
r = requests.get(f"{BASE_URL}/tools/deepsearch/nope/export.md")
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
def test_session_admin_sees_cost(app_server, seeded_db):
|
|
||||||
try:
|
|
||||||
uid = _seed_done_session("alice_test")
|
|
||||||
s = requests.Session()
|
|
||||||
creds = seeded_db["alice"]
|
|
||||||
s.post(
|
|
||||||
f"{BASE_URL}/auth/login",
|
|
||||||
data={"email": creds["email"], "password": creds["password"]},
|
|
||||||
allow_redirects=True,
|
|
||||||
)
|
|
||||||
r = s.get(f"{BASE_URL}/tools/deepsearch/{uid}/session", headers=_json_headers())
|
|
||||||
assert r.status_code == 200, r.text
|
|
||||||
body = r.json()
|
|
||||||
assert body.get("cost_usd") == 0.123456
|
|
||||||
|
|
||||||
html = s.get(f"{BASE_URL}/tools/deepsearch/{uid}/session")
|
|
||||||
assert html.status_code == 200, html.text
|
|
||||||
assert "0.123456" in html.text
|
|
||||||
assert "cost" in html.text
|
|
||||||
finally:
|
|
||||||
_clear()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user