deepdoc 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {deepdoc-2.0.0 → deepdoc-2.1.0}/PKG-INFO +9 -11
- {deepdoc-2.0.0 → deepdoc-2.1.0}/README.md +8 -10
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/__init__.py +1 -1
- deepdoc-2.1.0/deepdoc/changelog_writer.py +161 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/answer_mixin.py +8 -6
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/persistence.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/providers.py +108 -3
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/retrieval_mixin.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/routes.py +23 -4
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/service.py +0 -7
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/settings.py +8 -6
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/cli.py +52 -7
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/config.py +17 -11
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/generator/evidence.py +2 -6
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/generator/generation.py +11 -14
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/generator/post_processors.py +14 -3
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/generator/validation.py +1 -0
- deepdoc-2.1.0/deepdoc/llm/client.py +177 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/nestjs.py +16 -5
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/repo_resolver.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/persistence_v2.py +1 -3
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/pipeline_v2.py +5 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/bucket_injection.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/bucket_refinement.py +4 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/engine.py +13 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/heuristics.py +17 -211
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/nav_shaping.py +18 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/bucket_types.py +37 -27
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/artifacts.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/common.py +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/database.py +2 -2
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/utils.py +2 -2
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/engine.py +15 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/scaffold_files.py +3 -2
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/smart_update_v2.py +24 -10
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/PKG-INFO +9 -11
- {deepdoc-2.0.0 → deepdoc-2.1.0}/pyproject.toml +1 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_changelog.py +3 -1
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_index.py +1 -1
- deepdoc-2.0.0/deepdoc/changelog_writer.py +0 -106
- deepdoc-2.0.0/deepdoc/llm/client.py +0 -84
- {deepdoc-2.0.0 → deepdoc-2.1.0}/LICENSE +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/__main__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/_legacy_types.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/benchmark_v2.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/call_graph.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/chunker.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/deep_research.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/docs_summary.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/embeddings.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/indexer.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/linking.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/live_fallback_mixin.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/scaffold.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/source_archive.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/symbol_index.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/chatbot/types.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/generator/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/llm/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/llm/json_utils.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/llm/litellm_compat.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/manifest.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/openapi.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/api_detector.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/base.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/go_parser.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/js_ts_parser.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/php_parser.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/python_parser.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/registry.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/base.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/common.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/detector.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/django.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/express.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/falcon.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/fastify.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/go.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/js_shared.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/laravel.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/python_shared.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/routes/registry.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/parser/vue_parser.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/common.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/endpoint_refs.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/flow_candidates.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/specializations.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/topology.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/planner/utils.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/page_types.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/selectors.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/system.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts/update.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/prompts_v2.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/py.typed +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/clustering.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/endpoints.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/integrations.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/scanner/runtime.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/__init__.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/chatbot_components.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/common.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/mdx_utils.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/site/builder/templates.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/source_metadata.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/updater_v2.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc/v2_models.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/SOURCES.txt +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/dependency_links.txt +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/entry_points.txt +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/requires.txt +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/deepdoc.egg-info/top_level.txt +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/setup.cfg +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_benchmark_scorecard.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_call_graph.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_config.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_embeddings.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_eval.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_persistence.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_providers.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_query.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_relationship.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_scaffold.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_chatbot_source_archive.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_classify.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_cli_generate.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_cli_serve.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_cli_update.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_flow_candidates.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_framework_fixtures.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_framework_support.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_fumadocs_builder.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_generation_evidence.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_internal_docs_metadata.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_litellm_compat.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_llm_json_utils.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_parallel_pipeline.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_parser_ranges.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_planner_consolidation.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_planner_granularity.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_route_registry.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_runtime_scan.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_smart_update.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_stale.py +0 -0
- {deepdoc-2.0.0 → deepdoc-2.1.0}/tests/test_state.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepdoc
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Auto-generate beautiful docs from any codebase
|
|
5
5
|
Author: Pranav Kumar
|
|
6
6
|
License: MIT
|
|
@@ -406,13 +406,13 @@ deepdoc update --deploy # Update + deploy
|
|
|
406
406
|
1. Loads the saved sync baseline, plan, and generation ledger from `.deepdoc/`.
|
|
407
407
|
2. Diffs committed changes from the last synced commit to the current `HEAD`.
|
|
408
408
|
3. Chooses a strategy automatically:
|
|
409
|
-
- incremental
|
|
410
|
-
- targeted replan
|
|
411
|
-
- full replan
|
|
409
|
+
- **incremental** — regenerate only the stale bucket pages
|
|
410
|
+
- **targeted replan** — new/deleted files or endpoint structure changes; re-plans affected buckets then regenerates them. Full replan is never triggered automatically for normal code changes.
|
|
412
411
|
4. Compares the saved scan cache with the current scan so semantic endpoint changes can refresh impacted docs even when ownership files do not line up directly.
|
|
413
|
-
5. Regenerates only the affected bucket pages
|
|
414
|
-
6.
|
|
415
|
-
7.
|
|
412
|
+
5. Regenerates only the affected bucket pages. Deleted files are cleaned up in-place: orphaned buckets and their MDX pages are removed, partially-emptied buckets are marked stale and regenerated.
|
|
413
|
+
6. Appends an entry to `.deepdoc/changelog.json` and regenerates `docs/whats-changed.mdx` so the docs site always shows a current commit-by-commit change log.
|
|
414
|
+
7. Incrementally refreshes the chatbot corpora from the same update run.
|
|
415
|
+
8. Rebuilds site config and nav afterward.
|
|
416
416
|
|
|
417
417
|
If git is unavailable, it falls back to hash-based staleness detection for recovery.
|
|
418
418
|
|
|
@@ -421,7 +421,7 @@ Generation writes quality artifacts under `.deepdoc/`:
|
|
|
421
421
|
- `.deepdoc/generation_quality.json` records invalid/degraded pages, coverage metrics, local setup warnings, and consistency summary data.
|
|
422
422
|
- `.deepdoc/consistency_warnings.json` records warning-only cross-page identifier consistency findings.
|
|
423
423
|
|
|
424
|
-
Generated MDX pages include provenance frontmatter such as `deepdoc_generated_commit`, `deepdoc_generated_at`, `deepdoc_generated_version`, `deepdoc_status`, and `
|
|
424
|
+
Generated MDX pages include provenance frontmatter such as `deepdoc_generated_commit`, `deepdoc_generated_at`, `deepdoc_generated_version`, `deepdoc_status`, `deepdoc_evidence_files`, and `deepdoc_prereqs` (prerequisite page slugs). The generated Fumadocs site renders a subtle "Last generated from commit ..." badge and wires prev/next navigation arrows automatically. Pages with prerequisites show a "Read first:" callout at the top.
|
|
425
425
|
|
|
426
426
|
**Options:**
|
|
427
427
|
|
|
@@ -740,9 +740,7 @@ site:
|
|
|
740
740
|
| `site.favicon` | `""` | Path to favicon |
|
|
741
741
|
| `site.logo` | `""` | Path to logo |
|
|
742
742
|
| **Compatibility** | | |
|
|
743
|
-
| `compatibility.deprecated_version_warning.enabled` | `true` | Warn when existing generated docs were produced by a
|
|
744
|
-
| `compatibility.deprecated_version_warning.minimum_version` | `1.0.0` | Minimum generated DeepDoc version before an upgrade warning appears |
|
|
745
|
-
| `compatibility.deprecated_version_warning.upgrade_command` | `python3 -m pip install --upgrade deepdoc` | Command shown in the upgrade warning |
|
|
743
|
+
| `compatibility.deprecated_version_warning.enabled` | `true` | Warn when existing generated docs were produced by a different major version of DeepDoc (e.g. docs from v1.x with CLI v2.x). Suppressed for minor/patch version gaps. |
|
|
746
744
|
|
|
747
745
|
---
|
|
748
746
|
|
|
@@ -367,13 +367,13 @@ deepdoc update --deploy # Update + deploy
|
|
|
367
367
|
1. Loads the saved sync baseline, plan, and generation ledger from `.deepdoc/`.
|
|
368
368
|
2. Diffs committed changes from the last synced commit to the current `HEAD`.
|
|
369
369
|
3. Chooses a strategy automatically:
|
|
370
|
-
- incremental
|
|
371
|
-
- targeted replan
|
|
372
|
-
- full replan
|
|
370
|
+
- **incremental** — regenerate only the stale bucket pages
|
|
371
|
+
- **targeted replan** — new/deleted files or endpoint structure changes; re-plans affected buckets then regenerates them. Full replan is never triggered automatically for normal code changes.
|
|
373
372
|
4. Compares the saved scan cache with the current scan so semantic endpoint changes can refresh impacted docs even when ownership files do not line up directly.
|
|
374
|
-
5. Regenerates only the affected bucket pages
|
|
375
|
-
6.
|
|
376
|
-
7.
|
|
373
|
+
5. Regenerates only the affected bucket pages. Deleted files are cleaned up in-place: orphaned buckets and their MDX pages are removed, partially-emptied buckets are marked stale and regenerated.
|
|
374
|
+
6. Appends an entry to `.deepdoc/changelog.json` and regenerates `docs/whats-changed.mdx` so the docs site always shows a current commit-by-commit change log.
|
|
375
|
+
7. Incrementally refreshes the chatbot corpora from the same update run.
|
|
376
|
+
8. Rebuilds site config and nav afterward.
|
|
377
377
|
|
|
378
378
|
If git is unavailable, it falls back to hash-based staleness detection for recovery.
|
|
379
379
|
|
|
@@ -382,7 +382,7 @@ Generation writes quality artifacts under `.deepdoc/`:
|
|
|
382
382
|
- `.deepdoc/generation_quality.json` records invalid/degraded pages, coverage metrics, local setup warnings, and consistency summary data.
|
|
383
383
|
- `.deepdoc/consistency_warnings.json` records warning-only cross-page identifier consistency findings.
|
|
384
384
|
|
|
385
|
-
Generated MDX pages include provenance frontmatter such as `deepdoc_generated_commit`, `deepdoc_generated_at`, `deepdoc_generated_version`, `deepdoc_status`, and `
|
|
385
|
+
Generated MDX pages include provenance frontmatter such as `deepdoc_generated_commit`, `deepdoc_generated_at`, `deepdoc_generated_version`, `deepdoc_status`, `deepdoc_evidence_files`, and `deepdoc_prereqs` (prerequisite page slugs). The generated Fumadocs site renders a subtle "Last generated from commit ..." badge and wires prev/next navigation arrows automatically. Pages with prerequisites show a "Read first:" callout at the top.
|
|
386
386
|
|
|
387
387
|
**Options:**
|
|
388
388
|
|
|
@@ -701,9 +701,7 @@ site:
|
|
|
701
701
|
| `site.favicon` | `""` | Path to favicon |
|
|
702
702
|
| `site.logo` | `""` | Path to logo |
|
|
703
703
|
| **Compatibility** | | |
|
|
704
|
-
| `compatibility.deprecated_version_warning.enabled` | `true` | Warn when existing generated docs were produced by a
|
|
705
|
-
| `compatibility.deprecated_version_warning.minimum_version` | `1.0.0` | Minimum generated DeepDoc version before an upgrade warning appears |
|
|
706
|
-
| `compatibility.deprecated_version_warning.upgrade_command` | `python3 -m pip install --upgrade deepdoc` | Command shown in the upgrade warning |
|
|
704
|
+
| `compatibility.deprecated_version_warning.enabled` | `true` | Warn when existing generated docs were produced by a different major version of DeepDoc (e.g. docs from v1.x with CLI v2.x). Suppressed for minor/patch version gaps. |
|
|
707
705
|
|
|
708
706
|
---
|
|
709
707
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .persistence_v2 import append_changelog_entry, load_changelog, load_plan, save_plan
|
|
6
|
+
|
|
7
|
+
_STRATEGY_LABEL = {
|
|
8
|
+
"incremental": "Incremental update",
|
|
9
|
+
"targeted_replan": "Targeted replan",
|
|
10
|
+
"full_replan": "Full replan",
|
|
11
|
+
"full_generate": "Full generation",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def record_and_write(
|
|
16
|
+
repo_root: Path,
|
|
17
|
+
output_dir: Path,
|
|
18
|
+
*,
|
|
19
|
+
commit: str,
|
|
20
|
+
commit_message: str,
|
|
21
|
+
commit_date: str,
|
|
22
|
+
strategy: str,
|
|
23
|
+
pages_updated: list[str],
|
|
24
|
+
files_changed: list[str],
|
|
25
|
+
is_initial: bool = False,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Append one changelog entry and regenerate whats-changed.mdx."""
|
|
28
|
+
entry = {
|
|
29
|
+
"commit": commit[:8],
|
|
30
|
+
"date": commit_date,
|
|
31
|
+
"commit_message": commit_message,
|
|
32
|
+
"strategy": strategy,
|
|
33
|
+
"pages_updated": pages_updated,
|
|
34
|
+
"files_changed": files_changed[:20],
|
|
35
|
+
"is_initial": is_initial,
|
|
36
|
+
}
|
|
37
|
+
append_changelog_entry(repo_root, entry)
|
|
38
|
+
write_whats_changed_page(repo_root, output_dir)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_whats_changed_page(repo_root: Path, output_dir: Path) -> None:
|
|
42
|
+
"""Write docs/whats-changed.mdx from .deepdoc/changelog.json."""
|
|
43
|
+
entries = load_changelog(repo_root)
|
|
44
|
+
mdx = _build_mdx(entries)
|
|
45
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
(output_dir / "whats-changed.mdx").write_text(mdx, encoding="utf-8")
|
|
47
|
+
_ensure_in_nav(repo_root)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _build_mdx(entries: list[dict]) -> str:
|
|
51
|
+
lines = [
|
|
52
|
+
"---",
|
|
53
|
+
'title: "What\'s Changed"',
|
|
54
|
+
'description: "A commit-by-commit log of every documentation update — which pages changed, which source files triggered the change, and how the update was handled."',
|
|
55
|
+
"---",
|
|
56
|
+
"",
|
|
57
|
+
"# What's Changed",
|
|
58
|
+
"",
|
|
59
|
+
"Every time you run `deepdoc generate` or `deepdoc update`, this page is regenerated automatically.",
|
|
60
|
+
"Each entry shows the commit that triggered the run, the strategy DeepDoc chose, the pages that were",
|
|
61
|
+
"updated, and the source files that caused the change.",
|
|
62
|
+
"",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
if not entries:
|
|
66
|
+
lines.append(
|
|
67
|
+
"<Callout>No changelog entries yet. Run `deepdoc generate` to create the first entry.</Callout>"
|
|
68
|
+
)
|
|
69
|
+
return "\n".join(lines)
|
|
70
|
+
|
|
71
|
+
lines.append("<Accordions>")
|
|
72
|
+
for entry in entries:
|
|
73
|
+
date = entry.get("date", "")
|
|
74
|
+
msg = entry.get("commit_message", "update")
|
|
75
|
+
sha = entry.get("commit", "")
|
|
76
|
+
pages = entry.get("pages_updated", [])
|
|
77
|
+
files = entry.get("files_changed", [])
|
|
78
|
+
strategy = entry.get("strategy", "")
|
|
79
|
+
is_initial = entry.get("is_initial", False)
|
|
80
|
+
strategy_label = _STRATEGY_LABEL.get(strategy, strategy)
|
|
81
|
+
|
|
82
|
+
title = f"{date} — {msg[:72]} ({sha})"
|
|
83
|
+
lines.append(f'<Accordion title="{title}">')
|
|
84
|
+
lines.append("")
|
|
85
|
+
|
|
86
|
+
# Commit metadata row
|
|
87
|
+
lines.append("| | |")
|
|
88
|
+
lines.append("|---|---|")
|
|
89
|
+
lines.append(f"| **Commit** | `{sha}` |")
|
|
90
|
+
lines.append(f"| **Date** | {date} |")
|
|
91
|
+
lines.append(f"| **Strategy** | {strategy_label} |")
|
|
92
|
+
lines.append(f"| **Message** | {msg} |")
|
|
93
|
+
lines.append("")
|
|
94
|
+
|
|
95
|
+
if is_initial:
|
|
96
|
+
lines.append(
|
|
97
|
+
f"**Initial generation** — {len(pages)} page(s) created from scratch."
|
|
98
|
+
)
|
|
99
|
+
if pages:
|
|
100
|
+
lines.append("")
|
|
101
|
+
lines.append("**Pages generated:**")
|
|
102
|
+
lines.append("")
|
|
103
|
+
for s in pages:
|
|
104
|
+
lines.append(f"- [{_slug_to_title(s)}](/{s})")
|
|
105
|
+
else:
|
|
106
|
+
# Pages updated
|
|
107
|
+
if pages:
|
|
108
|
+
lines.append(f"**{len(pages)} page(s) updated:**")
|
|
109
|
+
lines.append("")
|
|
110
|
+
for s in pages:
|
|
111
|
+
lines.append(f"- [{_slug_to_title(s)}](/{s})")
|
|
112
|
+
else:
|
|
113
|
+
lines.append(
|
|
114
|
+
"<Callout type='info'>No pages were regenerated — only metadata or chatbot corpora were refreshed.</Callout>"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Source files that changed
|
|
118
|
+
if files:
|
|
119
|
+
lines.append("")
|
|
120
|
+
lines.append(f"**Source files that triggered this update ({len(files)}):**")
|
|
121
|
+
lines.append("")
|
|
122
|
+
for f in files[:20]:
|
|
123
|
+
lines.append(f"- `{f}`")
|
|
124
|
+
if len(files) > 20:
|
|
125
|
+
lines.append(f"- *...and {len(files) - 20} more*")
|
|
126
|
+
|
|
127
|
+
# What the strategy means
|
|
128
|
+
lines.append("")
|
|
129
|
+
if strategy == "incremental":
|
|
130
|
+
lines.append(
|
|
131
|
+
"> **Incremental update** — only the pages whose source files changed were regenerated. All other pages were left untouched."
|
|
132
|
+
)
|
|
133
|
+
elif strategy == "targeted_replan":
|
|
134
|
+
lines.append(
|
|
135
|
+
"> **Targeted replan** — new or deleted files were detected. DeepDoc re-evaluated which buckets own those files, updated the plan, and regenerated affected pages."
|
|
136
|
+
)
|
|
137
|
+
elif strategy == "full_replan":
|
|
138
|
+
lines.append(
|
|
139
|
+
"> **Full replan** — the engine schema changed or a force-replan was requested. All buckets were re-planned and regenerated."
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
lines.append("")
|
|
143
|
+
lines.append("</Accordion>")
|
|
144
|
+
|
|
145
|
+
lines.append("</Accordions>")
|
|
146
|
+
return "\n".join(lines)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _slug_to_title(slug: str) -> str:
|
|
150
|
+
return slug.replace("-", " ").title()
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _ensure_in_nav(repo_root: Path) -> None:
|
|
154
|
+
"""Add whats-changed to Start Here section of the saved plan if not already there."""
|
|
155
|
+
plan = load_plan(repo_root)
|
|
156
|
+
if plan is None or not hasattr(plan, "nav_structure"):
|
|
157
|
+
return
|
|
158
|
+
section = plan.nav_structure.setdefault("Start Here", [])
|
|
159
|
+
if "whats-changed" not in section:
|
|
160
|
+
section.append("whats-changed")
|
|
161
|
+
save_plan(plan, repo_root)
|
|
@@ -570,13 +570,14 @@ class AnswerMixin:
|
|
|
570
570
|
reason="mentioned_source",
|
|
571
571
|
)
|
|
572
572
|
|
|
573
|
-
|
|
573
|
+
seen_ranges: set[tuple[str, int, int]] = set()
|
|
574
|
+
result: list[dict[str, Any]] = []
|
|
574
575
|
for row in rows:
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
return
|
|
576
|
+
key = (row["file_path"], row.get("start_line", 0), row.get("end_line", 0))
|
|
577
|
+
if key not in seen_ranges:
|
|
578
|
+
seen_ranges.add(key)
|
|
579
|
+
result.append(row)
|
|
580
|
+
return result[:8]
|
|
580
581
|
|
|
581
582
|
def _apply_evidence_contract(
|
|
582
583
|
self,
|
|
@@ -774,6 +775,7 @@ class AnswerMixin:
|
|
|
774
775
|
for text in texts:
|
|
775
776
|
for raw_path, raw_start, raw_end in pattern.findall(str(text or "")):
|
|
776
777
|
path = raw_path.strip("`'\".,:;()[]{}")
|
|
778
|
+
path = re.sub(r"^\./", "", path)
|
|
777
779
|
if self._is_reference_doc_path(path):
|
|
778
780
|
continue
|
|
779
781
|
if not self._is_code_workspace_path(path, allow_config=True):
|
|
@@ -440,7 +440,7 @@ def similarity_search(
|
|
|
440
440
|
return [
|
|
441
441
|
RetrievedChunk(record=records[idx], score=float(score))
|
|
442
442
|
for score, idx in zip(scores[0], order[0], strict=False)
|
|
443
|
-
if idx >= 0 and idx < len(records)
|
|
443
|
+
if idx >= 0 and idx < len(records) and score > -0.5
|
|
444
444
|
]
|
|
445
445
|
except Exception:
|
|
446
446
|
pass
|
|
@@ -185,7 +185,82 @@ class LiteLLMEmbeddingClient:
|
|
|
185
185
|
|
|
186
186
|
|
|
187
187
|
def build_chat_client(cfg: dict[str, Any]) -> LiteLLMChatClient:
|
|
188
|
-
|
|
188
|
+
answer_cfg = get_chatbot_cfg(cfg).get("answer", {})
|
|
189
|
+
provider = (answer_cfg.get("provider") or "").strip()
|
|
190
|
+
model = (answer_cfg.get("model") or "").strip()
|
|
191
|
+
|
|
192
|
+
# If chatbot.answer is not explicitly configured, inherit from the doc-gen llm.* config.
|
|
193
|
+
# This means a single deepdoc init --provider X covers both doc generation and chatbot.
|
|
194
|
+
if not provider or not model:
|
|
195
|
+
llm_cfg = cfg.get("llm", {})
|
|
196
|
+
llm_provider = (llm_cfg.get("provider") or "").strip()
|
|
197
|
+
llm_model = (llm_cfg.get("model") or "").strip()
|
|
198
|
+
if llm_provider and llm_model:
|
|
199
|
+
answer_cfg = {
|
|
200
|
+
**answer_cfg,
|
|
201
|
+
"provider": llm_provider,
|
|
202
|
+
"model": llm_model,
|
|
203
|
+
"api_key_env": llm_cfg.get("api_key_env") or answer_cfg.get("api_key_env", ""),
|
|
204
|
+
"base_url": llm_cfg.get("base_url") or answer_cfg.get("base_url", ""),
|
|
205
|
+
"api_version": llm_cfg.get("api_version") or answer_cfg.get("api_version", ""),
|
|
206
|
+
}
|
|
207
|
+
provider, model = llm_provider, llm_model
|
|
208
|
+
|
|
209
|
+
if not provider or not model:
|
|
210
|
+
raise ValueError(
|
|
211
|
+
"\n\n"
|
|
212
|
+
"╔══════════════════════════════════════════════════════════════════════╗\n"
|
|
213
|
+
"║ CHATBOT NOT CONFIGURED — ACTION REQUIRED ║\n"
|
|
214
|
+
"╠══════════════════════════════════════════════════════════════════════╣\n"
|
|
215
|
+
"║ ║\n"
|
|
216
|
+
"║ No LLM is configured for the chatbot. ║\n"
|
|
217
|
+
"║ ║\n"
|
|
218
|
+
"║ OPTION 1 — reuse your doc-gen LLM (zero extra config): ║\n"
|
|
219
|
+
"║ Just make sure llm.provider and llm.model are set. ║\n"
|
|
220
|
+
"║ The chatbot will automatically use the same provider and key. ║\n"
|
|
221
|
+
"║ ║\n"
|
|
222
|
+
"║ OPTION 2 — use a separate (e.g. cheaper) model for chat: ║\n"
|
|
223
|
+
"║ ║\n"
|
|
224
|
+
"║ chatbot: ║\n"
|
|
225
|
+
"║ answer: ║\n"
|
|
226
|
+
"║ provider: <your-provider> # openai, anthropic, azure, etc. ║\n"
|
|
227
|
+
"║ model: <your-model> # matching model name ║\n"
|
|
228
|
+
"║ api_key_env: <YOUR_KEY_ENV> # env var holding your key ║\n"
|
|
229
|
+
"║ ║\n"
|
|
230
|
+
"║ Any LiteLLM-compatible provider works: ║\n"
|
|
231
|
+
"║ https://docs.litellm.ai/docs/providers ║\n"
|
|
232
|
+
"╚══════════════════════════════════════════════════════════════════════╝\n"
|
|
233
|
+
)
|
|
234
|
+
is_azure = provider.lower() == "azure" or model.lower().startswith("azure/")
|
|
235
|
+
if is_azure:
|
|
236
|
+
base_url = (answer_cfg.get("base_url") or "").strip()
|
|
237
|
+
api_version = (answer_cfg.get("api_version") or "").strip()
|
|
238
|
+
missing = []
|
|
239
|
+
if not base_url or base_url.startswith("https://<"):
|
|
240
|
+
missing.append("base_url (your Azure OpenAI endpoint URL)")
|
|
241
|
+
if not api_version:
|
|
242
|
+
missing.append("api_version (e.g. 2024-02-01)")
|
|
243
|
+
if missing:
|
|
244
|
+
items = "\n".join(f"║ • {item:<64}║" for item in missing)
|
|
245
|
+
raise ValueError(
|
|
246
|
+
"\n\n"
|
|
247
|
+
"╔══════════════════════════════════════════════════════════════════════╗\n"
|
|
248
|
+
"║ AZURE CHATBOT NOT FULLY CONFIGURED — ACTION REQUIRED ║\n"
|
|
249
|
+
"╠══════════════════════════════════════════════════════════════════════╣\n"
|
|
250
|
+
"║ ║\n"
|
|
251
|
+
"║ Azure OpenAI requires additional settings that are missing: ║\n"
|
|
252
|
+
"║ ║\n"
|
|
253
|
+
f"{items}\n"
|
|
254
|
+
"║ ║\n"
|
|
255
|
+
"║ Add them to .deepdoc.yaml under llm: or chatbot.answer: ║\n"
|
|
256
|
+
"║ ║\n"
|
|
257
|
+
"║ llm: ║\n"
|
|
258
|
+
"║ base_url: https://<resource>.openai.azure.com ║\n"
|
|
259
|
+
"║ api_version: 2024-02-01 ║\n"
|
|
260
|
+
"╚══════════════════════════════════════════════════════════════════════╝\n"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return LiteLLMChatClient(answer_cfg)
|
|
189
264
|
|
|
190
265
|
|
|
191
266
|
def build_embedding_client(
|
|
@@ -198,8 +273,36 @@ def build_embedding_client(
|
|
|
198
273
|
|
|
199
274
|
if backend == "fastembed":
|
|
200
275
|
return FastembedEmbeddingClient(embeddings_cfg)
|
|
201
|
-
|
|
202
|
-
|
|
276
|
+
|
|
277
|
+
provider = (embeddings_cfg.get("provider") or "").strip()
|
|
278
|
+
model = (embeddings_cfg.get("model") or "").strip()
|
|
279
|
+
if not provider or not model:
|
|
280
|
+
raise ValueError(
|
|
281
|
+
"\n\n"
|
|
282
|
+
"╔══════════════════════════════════════════════════════════════════════╗\n"
|
|
283
|
+
"║ EMBEDDINGS NOT CONFIGURED — ACTION REQUIRED ║\n"
|
|
284
|
+
"╠══════════════════════════════════════════════════════════════════════╣\n"
|
|
285
|
+
"║ ║\n"
|
|
286
|
+
"║ chatbot.embeddings.backend is set to 'litellm' but ║\n"
|
|
287
|
+
"║ chatbot.embeddings.provider and .model are not set. ║\n"
|
|
288
|
+
"║ ║\n"
|
|
289
|
+
"║ Either switch to the local (no-API-key) backend: ║\n"
|
|
290
|
+
"║ ║\n"
|
|
291
|
+
"║ chatbot: ║\n"
|
|
292
|
+
"║ embeddings: ║\n"
|
|
293
|
+
"║ backend: fastembed # runs locally, no key needed ║\n"
|
|
294
|
+
"║ ║\n"
|
|
295
|
+
"║ Or configure a cloud embedding provider: ║\n"
|
|
296
|
+
"║ ║\n"
|
|
297
|
+
"║ chatbot: ║\n"
|
|
298
|
+
"║ embeddings: ║\n"
|
|
299
|
+
"║ backend: litellm ║\n"
|
|
300
|
+
"║ provider: <your-provider> # e.g. openai, azure ║\n"
|
|
301
|
+
"║ model: <your-model> # e.g. text-embedding-3-large ║\n"
|
|
302
|
+
"║ api_key_env: <YOUR_KEY_ENV> # env var holding your key ║\n"
|
|
303
|
+
"╚══════════════════════════════════════════════════════════════════════╝\n"
|
|
304
|
+
)
|
|
305
|
+
return LiteLLMEmbeddingClient(embeddings_cfg)
|
|
203
306
|
|
|
204
307
|
|
|
205
308
|
class FastembedEmbeddingClient:
|
|
@@ -207,6 +310,8 @@ class FastembedEmbeddingClient:
|
|
|
207
310
|
|
|
208
311
|
def __init__(self, service_cfg: dict[str, Any]) -> None:
|
|
209
312
|
self.service_cfg = service_cfg
|
|
313
|
+
# Fallback model if not set in config — explicit choice, not a vendor endorsement.
|
|
314
|
+
# Full model list: https://qdrant.github.io/fastembed/examples/Supported_Models/
|
|
210
315
|
self.model = service_cfg.get(
|
|
211
316
|
"fastembed_model", "nomic-ai/nomic-embed-text-v1.5"
|
|
212
317
|
)
|
|
@@ -213,7 +213,7 @@ class RetrievalMixin:
|
|
|
213
213
|
hits = [
|
|
214
214
|
RetrievedChunk(
|
|
215
215
|
record=by_chunk_id[chunk_id],
|
|
216
|
-
score=
|
|
216
|
+
score=self._lexical_score(by_chunk_id[chunk_id], query_signals),
|
|
217
217
|
)
|
|
218
218
|
for chunk_id in chunk_ids
|
|
219
219
|
if chunk_id in by_chunk_id
|
|
@@ -8,7 +8,7 @@ import threading
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
|
-
from pydantic import BaseModel, Field
|
|
11
|
+
from pydantic import BaseModel, Field, field_validator
|
|
12
12
|
|
|
13
13
|
from .settings import chatbot_allowed_origins
|
|
14
14
|
|
|
@@ -19,6 +19,13 @@ class QueryRequest(BaseModel):
|
|
|
19
19
|
question: str
|
|
20
20
|
history: list[dict[str, str]] = Field(default_factory=list)
|
|
21
21
|
|
|
22
|
+
@field_validator("question")
|
|
23
|
+
@classmethod
|
|
24
|
+
def question_not_empty(cls, v: str) -> str:
|
|
25
|
+
if not v or not v.strip():
|
|
26
|
+
raise ValueError("question must not be empty")
|
|
27
|
+
return v
|
|
28
|
+
|
|
22
29
|
|
|
23
30
|
class DeepResearchRequest(QueryRequest):
|
|
24
31
|
"""Incoming deep-research payload."""
|
|
@@ -110,7 +117,11 @@ def create_fastapi_app(repo_root: Path, cfg: dict[str, Any]):
|
|
|
110
117
|
|
|
111
118
|
def event_stream():
|
|
112
119
|
while True:
|
|
113
|
-
|
|
120
|
+
try:
|
|
121
|
+
item = tokens.get(timeout=30)
|
|
122
|
+
except queue.Empty:
|
|
123
|
+
yield "event: ping\ndata: {}\n\n"
|
|
124
|
+
continue
|
|
114
125
|
if item is None:
|
|
115
126
|
break
|
|
116
127
|
event_name, payload = item
|
|
@@ -154,7 +165,11 @@ def create_fastapi_app(repo_root: Path, cfg: dict[str, Any]):
|
|
|
154
165
|
|
|
155
166
|
def event_stream():
|
|
156
167
|
while True:
|
|
157
|
-
|
|
168
|
+
try:
|
|
169
|
+
item = tokens.get(timeout=30)
|
|
170
|
+
except queue.Empty:
|
|
171
|
+
yield "event: ping\ndata: {}\n\n"
|
|
172
|
+
continue
|
|
158
173
|
if item is None:
|
|
159
174
|
break
|
|
160
175
|
event_name, payload = item
|
|
@@ -223,7 +238,11 @@ def create_fastapi_app(repo_root: Path, cfg: dict[str, Any]):
|
|
|
223
238
|
|
|
224
239
|
def event_stream():
|
|
225
240
|
while True:
|
|
226
|
-
|
|
241
|
+
try:
|
|
242
|
+
item = events.get(timeout=30)
|
|
243
|
+
except queue.Empty:
|
|
244
|
+
yield "event: ping\ndata: {}\n\n"
|
|
245
|
+
continue
|
|
227
246
|
if item is None:
|
|
228
247
|
break
|
|
229
248
|
event_name, payload = item
|
|
@@ -535,13 +535,6 @@ class ChatbotQueryService(RetrievalMixin, AnswerMixin, LiveFallbackMixin):
|
|
|
535
535
|
trace_callback=emit,
|
|
536
536
|
)
|
|
537
537
|
response["trace"] = trace
|
|
538
|
-
response["file_inventory"] = self._collect_file_inventory(
|
|
539
|
-
question,
|
|
540
|
-
response,
|
|
541
|
-
result.all_sources,
|
|
542
|
-
retrieval_cfg,
|
|
543
|
-
trace,
|
|
544
|
-
)
|
|
545
538
|
response["response_mode"] = "code_deep"
|
|
546
539
|
response["research_mode"] = "code_deep"
|
|
547
540
|
response = self._finalize_answer_response(question, response, mode="code_deep")
|
|
@@ -20,8 +20,8 @@ DEFAULT_CHATBOT_CONFIG: dict[str, Any] = {
|
|
|
20
20
|
],
|
|
21
21
|
},
|
|
22
22
|
"answer": {
|
|
23
|
-
"provider": "
|
|
24
|
-
"model": "
|
|
23
|
+
"provider": "", # must be set in .deepdoc.yaml — run: deepdoc init --with-chatbot
|
|
24
|
+
"model": "",
|
|
25
25
|
"api_key_env": "DEEPDOC_CHAT_API_KEY",
|
|
26
26
|
"base_url": "",
|
|
27
27
|
"api_version": "",
|
|
@@ -31,11 +31,13 @@ DEFAULT_CHATBOT_CONFIG: dict[str, Any] = {
|
|
|
31
31
|
"continuation_context_chars": 12000,
|
|
32
32
|
},
|
|
33
33
|
"embeddings": {
|
|
34
|
-
"backend": "
|
|
35
|
-
|
|
34
|
+
"backend": "fastembed", # local by default — no API key needed; set to "litellm" for cloud embeddings
|
|
35
|
+
# Local model — runs offline, no API key. Explicit choice; swap to any model from:
|
|
36
|
+
# https://qdrant.github.io/fastembed/examples/Supported_Models/
|
|
37
|
+
"fastembed_model": "nomic-ai/nomic-embed-text-v1.5",
|
|
36
38
|
"fastembed_batch_size": 4,
|
|
37
|
-
"provider": "
|
|
38
|
-
"model": "
|
|
39
|
+
"provider": "", # only required when backend="litellm"
|
|
40
|
+
"model": "",
|
|
39
41
|
"api_key_env": "DEEPDOC_EMBED_API_KEY",
|
|
40
42
|
"base_url": "",
|
|
41
43
|
"api_version": "",
|