cocoindex 0.1.29__tar.gz → 0.1.31__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.
Files changed (192) hide show
  1. {cocoindex-0.1.29 → cocoindex-0.1.31}/.env.lib_debug +1 -1
  2. {cocoindex-0.1.29 → cocoindex-0.1.31}/Cargo.lock +1 -1
  3. {cocoindex-0.1.29 → cocoindex-0.1.31}/Cargo.toml +1 -1
  4. {cocoindex-0.1.29 → cocoindex-0.1.31}/PKG-INFO +1 -1
  5. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/code_embedding/README.md +1 -1
  6. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/code_embedding/pyproject.toml +1 -1
  7. cocoindex-0.1.31/examples/docs_to_knowledge_graph/README.md +76 -0
  8. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/pyproject.toml +1 -1
  9. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/README.md +2 -2
  10. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/pyproject.toml +1 -1
  11. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/README.md +1 -1
  12. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/pyproject.toml +1 -1
  13. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/README.md +1 -1
  14. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/pyproject.toml +1 -1
  15. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/README.md +1 -1
  16. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/pyproject.toml +1 -1
  17. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding_qdrant/README.md +1 -1
  18. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding_qdrant/pyproject.toml +1 -1
  19. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/auth_registry.py +5 -2
  20. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/cli.py +55 -11
  21. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/flow.py +3 -0
  22. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/functions.py +7 -3
  23. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/lib.py +6 -59
  24. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/op.py +5 -4
  25. cocoindex-0.1.31/python/cocoindex/setting.py +77 -0
  26. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/storages.py +4 -5
  27. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/typing.py +5 -0
  28. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/schema.rs +39 -51
  29. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/builder/analyzed_flow.rs +2 -2
  30. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/builder/analyzer.rs +259 -198
  31. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/builder/flow_builder.rs +172 -330
  32. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/builder/plan.rs +2 -0
  33. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/dumper.rs +6 -8
  34. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/evaluator.rs +74 -50
  35. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/row_indexer.rs +22 -16
  36. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/stats.rs +17 -11
  37. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/py/mod.rs +55 -1
  38. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/server.rs +11 -8
  39. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/service/flows.rs +5 -5
  40. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/driver.rs +2 -2
  41. cocoindex-0.1.29/examples/docs_to_knowledge_graph/README.md +0 -67
  42. {cocoindex-0.1.29 → cocoindex-0.1.31}/.cargo/config.toml +0 -0
  43. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/ISSUE_TEMPLATE//360/237/220/233-bug-report.md" +0 -0
  44. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/ISSUE_TEMPLATE//360/237/222/241-feature-request.md" +0 -0
  45. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/scripts/update_version.sh +0 -0
  46. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/workflows/CI.yml +0 -0
  47. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/workflows/_test.yml +0 -0
  48. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/workflows/docs.yml +0 -0
  49. {cocoindex-0.1.29 → cocoindex-0.1.31}/.github/workflows/release.yml +0 -0
  50. {cocoindex-0.1.29 → cocoindex-0.1.31}/.gitignore +0 -0
  51. {cocoindex-0.1.29 → cocoindex-0.1.31}/.vscode/settings.json +0 -0
  52. {cocoindex-0.1.29 → cocoindex-0.1.31}/CODE_OF_CONDUCT.md +0 -0
  53. {cocoindex-0.1.29 → cocoindex-0.1.31}/CONTRIBUTING.md +0 -0
  54. {cocoindex-0.1.29 → cocoindex-0.1.31}/LICENSE +0 -0
  55. {cocoindex-0.1.29 → cocoindex-0.1.31}/README.md +0 -0
  56. {cocoindex-0.1.29 → cocoindex-0.1.31}/dev/neo4j.yaml +0 -0
  57. {cocoindex-0.1.29 → cocoindex-0.1.31}/dev/postgres.yaml +0 -0
  58. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/.gitignore +0 -0
  59. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/README.md +0 -0
  60. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/about/community.md +0 -0
  61. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/about/contributing.md +0 -0
  62. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/ai/llm.mdx +0 -0
  63. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/basics.md +0 -0
  64. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/cli.mdx +0 -0
  65. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/custom_function.mdx +0 -0
  66. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/data_example.svg +0 -0
  67. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/data_types.mdx +0 -0
  68. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/flow_def.mdx +0 -0
  69. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/flow_example.svg +0 -0
  70. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/flow_methods.mdx +0 -0
  71. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/core/initialization.mdx +0 -0
  72. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/getting_started/installation.md +0 -0
  73. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/getting_started/markdown_files.zip +0 -0
  74. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/getting_started/overview.md +0 -0
  75. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/getting_started/quickstart.md +0 -0
  76. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/ops/functions.md +0 -0
  77. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/ops/sources.md +0 -0
  78. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docs/ops/storages.md +0 -0
  79. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/docusaurus.config.ts +0 -0
  80. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/package.json +0 -0
  81. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/sidebars.ts +0 -0
  82. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/src/components/HomepageFeatures/index.tsx +0 -0
  83. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/src/components/HomepageFeatures/styles.module.css +0 -0
  84. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/src/css/custom.css +0 -0
  85. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/src/theme/Root.js +0 -0
  86. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/static/.nojekyll +0 -0
  87. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/static/img/docusaurus.png +0 -0
  88. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/static/img/favicon.ico +0 -0
  89. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/static/img/icon.svg +0 -0
  90. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/static/robots.txt +0 -0
  91. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/tsconfig.json +0 -0
  92. {cocoindex-0.1.29 → cocoindex-0.1.31}/docs/yarn.lock +0 -0
  93. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/code_embedding/.env +0 -0
  94. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/code_embedding/main.py +0 -0
  95. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/.env +0 -0
  96. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/main.py +0 -0
  97. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/markdown_files/1706.03762v7.md +0 -0
  98. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/markdown_files/1810.04805v2.md +0 -0
  99. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/docs_to_knowledge_graph/markdown_files/rfc8259.md +0 -0
  100. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/.env.example +0 -0
  101. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/.gitignore +0 -0
  102. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/data/1706.03762v7.docx +0 -0
  103. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/data/1810.04805v2.docx +0 -0
  104. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/gdrive_text_embedding/main.py +0 -0
  105. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/.env +0 -0
  106. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/main.py +0 -0
  107. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/manuals/array.pdf +0 -0
  108. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/manuals/base64.pdf +0 -0
  109. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/manuals/copy.pdf +0 -0
  110. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/manuals_llm_extraction/manuals/glob.pdf +0 -0
  111. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/.env +0 -0
  112. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/main.py +0 -0
  113. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/pdf_files/1706.03762v7.pdf +0 -0
  114. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/pdf_files/1810.04805v2.pdf +0 -0
  115. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/pdf_embedding/pdf_files/rfc8259.pdf +0 -0
  116. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/.env +0 -0
  117. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/Text_Embedding.ipynb +0 -0
  118. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/main.py +0 -0
  119. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/markdown_files/1706.03762v7.md +0 -0
  120. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/markdown_files/1810.04805v2.md +0 -0
  121. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding/markdown_files/rfc8259.md +0 -0
  122. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding_qdrant/.env +0 -0
  123. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding_qdrant/main.py +0 -0
  124. {cocoindex-0.1.29 → cocoindex-0.1.31}/examples/text_embedding_qdrant/markdown_files/rfc8259.md +0 -0
  125. {cocoindex-0.1.29 → cocoindex-0.1.31}/pyproject.toml +0 -0
  126. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/__init__.py +0 -0
  127. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/convert.py +0 -0
  128. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/index.py +0 -0
  129. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/llm.py +0 -0
  130. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/py.typed +0 -0
  131. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/query.py +0 -0
  132. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/runtime.py +0 -0
  133. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/setup.py +0 -0
  134. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/sources.py +0 -0
  135. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/tests/__init__.py +0 -0
  136. {cocoindex-0.1.29 → cocoindex-0.1.31}/python/cocoindex/tests/test_convert.py +0 -0
  137. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/field_attrs.rs +0 -0
  138. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/json_schema.rs +0 -0
  139. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/mod.rs +0 -0
  140. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/spec.rs +0 -0
  141. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/base/value.rs +0 -0
  142. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/builder/mod.rs +0 -0
  143. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/db_tracking.rs +0 -0
  144. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/db_tracking_setup.rs +0 -0
  145. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/live_updater.rs +0 -0
  146. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/memoization.rs +0 -0
  147. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/mod.rs +0 -0
  148. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/query.rs +0 -0
  149. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/execution/source_indexer.rs +0 -0
  150. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/lib.rs +0 -0
  151. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/lib_context.rs +0 -0
  152. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/llm/anthropic.rs +0 -0
  153. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/llm/gemini.rs +0 -0
  154. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/llm/mod.rs +0 -0
  155. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/llm/ollama.rs +0 -0
  156. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/llm/openai.rs +0 -0
  157. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/factory_bases.rs +0 -0
  158. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/functions/extract_by_llm.rs +0 -0
  159. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/functions/mod.rs +0 -0
  160. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/functions/parse_json.rs +0 -0
  161. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/functions/split_recursively.rs +0 -0
  162. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/interface.rs +0 -0
  163. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/mod.rs +0 -0
  164. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/py_factory.rs +0 -0
  165. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/registration.rs +0 -0
  166. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/registry.rs +0 -0
  167. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/sdk.rs +0 -0
  168. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/sources/google_drive.rs +0 -0
  169. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/sources/local_file.rs +0 -0
  170. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/sources/mod.rs +0 -0
  171. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/storages/mod.rs +0 -0
  172. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/storages/neo4j.rs +0 -0
  173. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/storages/postgres.rs +0 -0
  174. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/storages/qdrant.rs +0 -0
  175. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/ops/storages/spec.rs +0 -0
  176. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/prelude.rs +0 -0
  177. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/py/convert.rs +0 -0
  178. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/service/error.rs +0 -0
  179. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/service/mod.rs +0 -0
  180. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/service/search.rs +0 -0
  181. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/settings.rs +0 -0
  182. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/auth_registry.rs +0 -0
  183. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/components.rs +0 -0
  184. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/db_metadata.rs +0 -0
  185. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/mod.rs +0 -0
  186. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/setup/states.rs +0 -0
  187. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/db.rs +0 -0
  188. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/fingerprint.rs +0 -0
  189. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/immutable.rs +0 -0
  190. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/mod.rs +0 -0
  191. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/retriable.rs +0 -0
  192. {cocoindex-0.1.29 → cocoindex-0.1.31}/src/utils/yaml_ser.rs +0 -0
@@ -1,4 +1,4 @@
1
1
  export RUST_LOG=warn,cocoindex_engine=trace,tower_http=trace
2
2
  export RUST_BACKTRACE=1
3
3
 
4
- export COCOINDEX_SERVER_CORS_ORIGIN=http://localhost:3000
4
+ export COCOINDEX_SERVER_CORS_ORIGINS=http://localhost:3000,https://cocoindex.io
@@ -533,7 +533,7 @@ dependencies = [
533
533
 
534
534
  [[package]]
535
535
  name = "cocoindex"
536
- version = "0.1.29"
536
+ version = "0.1.31"
537
537
  dependencies = [
538
538
  "anyhow",
539
539
  "async-openai",
@@ -2,7 +2,7 @@
2
2
  name = "cocoindex"
3
3
  # Version used for local development is always higher than others to take precedence.
4
4
  # Will be overridden for specific release versions.
5
- version = "0.1.29"
5
+ version = "0.1.31"
6
6
  edition = "2021"
7
7
 
8
8
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.29
3
+ Version: 0.1.31
4
4
  Requires-Dist: sentence-transformers>=3.3.1
5
5
  Requires-Dist: click>=8.1.8
6
6
  Requires-Dist: rich>=14.0.0
@@ -46,7 +46,7 @@ CocoInsight is in Early Access now (Free) 😊 You found us! A quick 3 minute vi
46
46
  Run CocoInsight to understand your RAG data pipeline:
47
47
 
48
48
  ```
49
- python main.py cocoindex server -c https://cocoindex.io
49
+ python main.py cocoindex server -ci
50
50
  ```
51
51
 
52
52
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight).
@@ -3,4 +3,4 @@ name = "code-embedding"
3
3
  version = "0.1.0"
4
4
  description = "Simple example for cocoindex: build embedding index based on source code."
5
5
  requires-python = ">=3.10"
6
- dependencies = ["cocoindex>=0.1.26", "python-dotenv>=1.0.1"]
6
+ dependencies = ["cocoindex>=0.1.30", "python-dotenv>=1.0.1"]
@@ -0,0 +1,76 @@
1
+ # Build Real-Time Knowledge Graph For Documents with LLM
2
+
3
+ We will process a list of documents and use LLM to extract relationships between the concepts in each document.
4
+ We will generate two kinds of relationships:
5
+
6
+ 1. Relationships between subjects and objects. E.g., "CocoIndex supports Incremental Processing"
7
+ 2. Mentions of entities in a document. E.g., "core/basics.mdx" mentions `CocoIndex` and `Incremental Processing`.
8
+
9
+ You can find a step by step blog for this project [here](https://cocoindex.io/blogs/knowledge-graph-for-docs)
10
+
11
+ Please drop [Cocoindex on Github](https://github.com/cocoindex-io/cocoindex) a star to support us if you like our work. Thank you so much with a warm coconut hug 🥥🤗. [![GitHub](https://img.shields.io/github/stars/cocoindex-io/cocoindex?color=5B5BD6)](https://github.com/cocoindex-io/cocoindex)
12
+
13
+ ![example-explanation](https://github.com/user-attachments/assets/07ddbd60-106f-427f-b7cc-16b73b142d27)
14
+
15
+
16
+ ## Prerequisite
17
+ * [Install Postgres](https://cocoindex.io/docs/getting_started/installation#-install-postgres) if you don't have one.
18
+ * [Install Neo4j](https://cocoindex.io/docs/ops/storages#neo4j) if you don't have one.
19
+ * [Configure your OpenAI API key](https://cocoindex.io/docs/ai/llm#openai).
20
+
21
+ ## Documentation
22
+ You can read the official CocoIndex Documentation for Property Graph Targets [here](https://cocoindex.io/docs/ops/storages#property-graph-targets).
23
+
24
+ ## Run
25
+
26
+ ### Build the index
27
+
28
+ Install dependencies:
29
+
30
+ ```bash
31
+ pip install -e .
32
+ ```
33
+
34
+ Setup:
35
+
36
+ ```bash
37
+ python main.py cocoindex setup
38
+ ```
39
+
40
+ Update index:
41
+
42
+ ```bash
43
+ python main.py cocoindex update
44
+ ```
45
+
46
+ ### Browse the knowledge graph
47
+
48
+ After the knowledge graph is build, you can explore the knowledge graph you built in Neo4j Browser.
49
+
50
+ For the dev enviroment, you can connect neo4j browser using credentials:
51
+ - username: `neo4j`
52
+ - password: `cocoindex`
53
+ which is pre-configured in the our docker compose [config.yaml](https://raw.githubusercontent.com/cocoindex-io/cocoindex/refs/heads/main/dev/neo4j.yaml).
54
+
55
+ You can open it at [http://localhost:7474](http://localhost:7474), and run the following Cypher query to get all relationships:
56
+
57
+ ```cypher
58
+ MATCH p=()-->() RETURN p
59
+ ```
60
+ <img width="1366" alt="neo4j-for-coco-docs" src="https://github.com/user-attachments/assets/3c8b6329-6fee-4533-9480-571399b57e57" />
61
+
62
+
63
+
64
+ ## CocoInsight
65
+ I used CocoInsight (Free beta now) to troubleshoot the index generation and understand the data lineage of the pipeline.
66
+ It just connects to your local CocoIndex server, with Zero pipeline data retention. Run following command to start CocoInsight:
67
+
68
+ ```bash
69
+ python main.py cocoindex server -ci
70
+ ```
71
+
72
+ And then open the url https://cocoindex.io/cocoinsight.
73
+
74
+ <img width="1430" alt="cocoinsight" src="https://github.com/user-attachments/assets/d5ada581-cceb-42bf-a949-132df674f3dd" />
75
+
76
+
@@ -3,4 +3,4 @@ name = "manuals-to-kg"
3
3
  version = "0.1.0"
4
4
  description = "Simple example for cocoindex: extract triples from files and build knowledge graph."
5
5
  requires-python = ">=3.10"
6
- dependencies = ["cocoindex>=0.1.26", "python-dotenv>=1.0.1"]
6
+ dependencies = ["cocoindex>=0.1.30", "python-dotenv>=1.0.1"]
@@ -53,13 +53,13 @@ CocoInsight is in Early Access now (Free) 😊 You found us! A quick 3 minute vi
53
53
  Run CocoInsight to understand your RAG data pipeline:
54
54
 
55
55
  ```sh
56
- python main.py cocoindex server -c https://cocoindex.io
56
+ python main.py cocoindex server -ci
57
57
  ```
58
58
 
59
59
  You can also add a `-L` flag to make the server keep updating the index to reflect source changes at the same time:
60
60
 
61
61
  ```sh
62
- python main.py cocoindex server -c https://cocoindex.io -L
62
+ python main.py cocoindex server -ci -L
63
63
  ```
64
64
 
65
65
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight).
@@ -3,4 +3,4 @@ name = "gdrive-text-embedding"
3
3
  version = "0.1.0"
4
4
  description = "Simple example for cocoindex: build embedding index based on Google Drive files."
5
5
  requires-python = ">=3.11"
6
- dependencies = ["cocoindex>=0.1.26", "python-dotenv>=1.0.1"]
6
+ dependencies = ["cocoindex>=0.1.30", "python-dotenv>=1.0.1"]
@@ -65,7 +65,7 @@ CocoInsight is a tool to help you understand your data pipeline and data index.
65
65
  Run CocoInsight to understand your RAG data pipeline:
66
66
 
67
67
  ```
68
- python main.py cocoindex server -c https://cocoindex.io
68
+ python main.py cocoindex server -ci
69
69
  ```
70
70
 
71
71
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight). It connects to your local CocoIndex server with zero data retention.
@@ -4,7 +4,7 @@ version = "0.1.0"
4
4
  description = "Simple example for cocoindex: extract structured information from a Markdown file using LLM."
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
- "cocoindex>=0.1.26",
7
+ "cocoindex>=0.1.30",
8
8
  "python-dotenv>=1.0.1",
9
9
  "marker-pdf>=1.5.2",
10
10
  ]
@@ -35,7 +35,7 @@ CocoInsight is in Early Access now (Free) 😊 You found us! A quick 3 minute vi
35
35
  Run CocoInsight to understand your RAG data pipeline:
36
36
 
37
37
  ```
38
- python main.py cocoindex server -c https://cocoindex.io
38
+ python main.py cocoindex server -ci
39
39
  ```
40
40
 
41
41
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight).
@@ -4,7 +4,7 @@ version = "0.1.0"
4
4
  description = "Simple example for cocoindex: build embedding index based on local PDF files."
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
- "cocoindex>=0.1.26",
7
+ "cocoindex>=0.1.30",
8
8
  "python-dotenv>=1.0.1",
9
9
  "marker-pdf>=1.5.2",
10
10
  ]
@@ -39,7 +39,7 @@ CocoInsight is in Early Access now (Free) 😊 You found us! A quick 3 minute vi
39
39
  Run CocoInsight to understand your RAG data pipeline:
40
40
 
41
41
  ```
42
- python main.py cocoindex server -c https://cocoindex.io
42
+ python main.py cocoindex server -ci
43
43
  ```
44
44
 
45
45
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight).
@@ -3,4 +3,4 @@ name = "text-embedding"
3
3
  version = "0.1.0"
4
4
  description = "Simple example for cocoindex: build embedding index based on local text files."
5
5
  requires-python = ">=3.10"
6
- dependencies = ["cocoindex>=0.1.26", "python-dotenv>=1.0.1"]
6
+ dependencies = ["cocoindex>=0.1.30", "python-dotenv>=1.0.1"]
@@ -63,7 +63,7 @@ CocoInsight is in Early Access now (Free) 😊 You found us! A quick 3 minute vi
63
63
  Run CocoInsight to understand your RAG data pipeline:
64
64
 
65
65
  ```bash
66
- python main.py cocoindex server -c https://cocoindex.io
66
+ python main.py cocoindex server -ci
67
67
  ```
68
68
 
69
69
  Then open the CocoInsight UI at [https://cocoindex.io/cocoinsight](https://cocoindex.io/cocoinsight).
@@ -3,4 +3,4 @@ name = "text-embedding-qdrant"
3
3
  version = "0.1.0"
4
4
  description = "Simple example for cocoindex: build embedding index based on local text files."
5
5
  requires-python = ">=3.10"
6
- dependencies = ["cocoindex>=0.1.26", "python-dotenv>=1.0.1"]
6
+ dependencies = ["cocoindex>=0.1.30", "python-dotenv>=1.0.1"]
@@ -3,16 +3,19 @@ Auth registry is used to register and reference auth entries.
3
3
  """
4
4
 
5
5
  from dataclasses import dataclass
6
+ from typing import Generic, TypeVar
6
7
 
7
8
  from . import _engine
8
9
  from .convert import dump_engine_object
9
10
 
11
+ T = TypeVar("T")
12
+
10
13
  @dataclass
11
- class AuthEntryReference:
14
+ class AuthEntryReference(Generic[T]):
12
15
  """Reference an auth entry by its key."""
13
16
  key: str
14
17
 
15
- def add_auth_entry(key: str, value) -> AuthEntryReference:
18
+ def add_auth_entry(key: str, value: T) -> AuthEntryReference[T]:
16
19
  """Add an auth entry to the registry. Returns its reference."""
17
20
  _engine.add_auth_entry(key, dump_engine_object(value))
18
21
  return AuthEntryReference(key)
@@ -1,9 +1,11 @@
1
1
  import asyncio
2
2
  import click
3
3
  import datetime
4
+
4
5
  from rich.console import Console
6
+ from rich.table import Table
5
7
 
6
- from . import flow, lib
8
+ from . import flow, lib, setting
7
9
  from .setup import sync_setup, drop_setup, flow_names_with_setup, apply_setup_changes
8
10
  from .runtime import execution_context
9
11
 
@@ -21,7 +23,7 @@ def ls(show_all: bool):
21
23
  """
22
24
  List all flows.
23
25
  """
24
- current_flow_names = [fl.name for fl in flow.flows()]
26
+ current_flow_names = flow.flow_names()
25
27
  persisted_flow_names = flow_names_with_setup()
26
28
  remaining_persisted_flow_names = set(persisted_flow_names)
27
29
 
@@ -56,12 +58,27 @@ def ls(show_all: bool):
56
58
  @click.option("--color/--no-color", default=True)
57
59
  def show(flow_name: str | None, color: bool):
58
60
  """
59
- Show the flow spec in a readable format with colored output.
61
+ Show the flow spec in a readable format with colored output,
62
+ including the schema.
60
63
  """
61
64
  flow = _flow_by_name(flow_name)
62
65
  console = Console(no_color=not color)
63
66
  console.print(flow._render_text())
64
67
 
68
+ table = Table(
69
+ title=f"Schema for Flow: {flow.name}",
70
+ show_header=True,
71
+ header_style="bold magenta"
72
+ )
73
+ table.add_column("Field", style="cyan")
74
+ table.add_column("Type", style="green")
75
+ table.add_column("Attributes", style="yellow")
76
+
77
+ for field_name, field_type, attr_str in flow._render_schema():
78
+ table.add_row(field_name, field_type, attr_str)
79
+
80
+ console.print(table)
81
+
65
82
  @cli.command()
66
83
  def setup():
67
84
  """
@@ -149,32 +166,59 @@ def evaluate(flow_name: str | None, output_dir: str | None, cache: bool = True):
149
166
  options = flow.EvaluateAndDumpOptions(output_dir=output_dir, use_cache=cache)
150
167
  fl.evaluate_and_dump(options)
151
168
 
152
- _default_server_settings = lib.ServerSettings.from_env()
169
+ # Create ServerSettings lazily upon first call, as environment variables may be loaded from files, etc.
170
+ COCOINDEX_HOST = 'https://cocoindex.io'
153
171
 
154
172
  @cli.command()
155
173
  @click.option(
156
- "-a", "--address", type=str, default=_default_server_settings.address,
157
- help="The address to bind the server to, in the format of IP:PORT.")
174
+ "-a", "--address", type=str,
175
+ help="The address to bind the server to, in the format of IP:PORT. "
176
+ "If unspecified, the address specified in COCOINDEX_SERVER_ADDRESS will be used.")
177
+ @click.option(
178
+ "-c", "--cors-origin", type=str,
179
+ help="The origins of the clients (e.g. CocoInsight UI) to allow CORS from. "
180
+ "Multiple origins can be specified as a comma-separated list. "
181
+ "e.g. `https://cocoindex.io,http://localhost:3000`. "
182
+ "Origins specified in COCOINDEX_SERVER_CORS_ORIGINS will also be included.")
158
183
  @click.option(
159
- "-c", "--cors-origin", type=str, default=_default_server_settings.cors_origin,
160
- help="The origin of the client (e.g. CocoInsight UI) to allow CORS from. "
161
- "e.g. `http://cocoindex.io` if you want to allow CocoInsight to access the server.")
184
+ "-ci", "--cors-cocoindex", is_flag=True, show_default=True, default=False,
185
+ help=f"Allow {COCOINDEX_HOST} to access the server.")
186
+ @click.option(
187
+ "-cl", "--cors-local", type=int,
188
+ help="Allow http://localhost:<port> to access the server.")
162
189
  @click.option(
163
190
  "-L", "--live-update", is_flag=True, show_default=True, default=False,
164
191
  help="Continuously watch changes from data sources and apply to the target index.")
165
192
  @click.option(
166
193
  "-q", "--quiet", is_flag=True, show_default=True, default=False,
167
194
  help="Avoid printing anything to the standard output, e.g. statistics.")
168
- def server(address: str, live_update: bool, quiet: bool, cors_origin: str | None):
195
+ def server(address: str | None, live_update: bool, quiet: bool, cors_origin: str | None,
196
+ cors_cocoindex: bool, cors_local: int | None):
169
197
  """
170
198
  Start a HTTP server providing REST APIs.
171
199
 
172
200
  It will allow tools like CocoInsight to access the server.
173
201
  """
174
- lib.start_server(lib.ServerSettings(address=address, cors_origin=cors_origin))
202
+ server_settings = setting.ServerSettings.from_env()
203
+ cors_origins: set[str] = set(server_settings.cors_origins or [])
204
+ if cors_origin is not None:
205
+ cors_origins.update(setting.ServerSettings.parse_cors_origins(cors_origin))
206
+ if cors_cocoindex:
207
+ cors_origins.add(COCOINDEX_HOST)
208
+ if cors_local is not None:
209
+ cors_origins.add(f"http://localhost:{cors_local}")
210
+ server_settings.cors_origins = list(cors_origins)
211
+
212
+ if address is not None:
213
+ server_settings.address = address
214
+
215
+ lib.start_server(server_settings)
216
+
175
217
  if live_update:
176
218
  options = flow.FlowLiveUpdaterOptions(live_mode=True, print_stats=not quiet)
177
219
  execution_context.run(flow.update_all_flows(options))
220
+ if COCOINDEX_HOST in cors_origins:
221
+ click.echo(f"Open CocoInsight at: {COCOINDEX_HOST}/cocoinsight")
178
222
  input("Press Enter to stop...")
179
223
 
180
224
 
@@ -503,6 +503,9 @@ class Flow:
503
503
  return self._format_flow(flow_dict)
504
504
  except json.JSONDecodeError:
505
505
  return Text(flow_spec_str)
506
+
507
+ def _render_schema(self) -> list[tuple[str, str, str]]:
508
+ return self._lazy_engine_flow().get_schema()
506
509
 
507
510
  def __str__(self):
508
511
  return str(self._render_text())
@@ -1,10 +1,13 @@
1
1
  """All builtin functions."""
2
- from typing import Annotated, Any
2
+ from typing import Annotated, Any, TYPE_CHECKING
3
3
 
4
- import sentence_transformers
5
4
  from .typing import Float32, Vector, TypeAttr
6
5
  from . import op, llm
7
6
 
7
+ # Libraries that are heavy to import. Lazily import them later.
8
+ if TYPE_CHECKING:
9
+ import sentence_transformers
10
+
8
11
  class ParseJson(op.FunctionSpec):
9
12
  """Parse a text into a JSON object."""
10
13
 
@@ -35,9 +38,10 @@ class SentenceTransformerEmbedExecutor:
35
38
  """Executor for SentenceTransformerEmbed."""
36
39
 
37
40
  spec: SentenceTransformerEmbed
38
- _model: sentence_transformers.SentenceTransformer
41
+ _model: "sentence_transformers.SentenceTransformer"
39
42
 
40
43
  def analyze(self, text):
44
+ import sentence_transformers # pylint: disable=import-outside-toplevel
41
45
  args = self.spec.args or {}
42
46
  self._model = sentence_transformers.SentenceTransformer(self.spec.model, **args)
43
47
  dim = self._model.get_sentence_embedding_dimension()
@@ -1,76 +1,23 @@
1
1
  """
2
2
  Library level functions and states.
3
3
  """
4
- import os
5
4
  import sys
6
5
  import functools
7
6
  import inspect
8
7
 
9
- from typing import Callable, Self
10
- from dataclasses import dataclass
8
+ from typing import Callable
11
9
 
12
10
  from . import _engine
13
- from . import flow, query, cli
11
+ from . import flow, query, cli, setting
14
12
  from .convert import dump_engine_object
15
13
 
16
14
 
17
- def _load_field(target: dict[str, str], name: str, env_name: str, required: bool = False):
18
- value = os.getenv(env_name)
19
- if value is None:
20
- if required:
21
- raise ValueError(f"{env_name} is not set")
22
- else:
23
- target[name] = value
24
-
25
- @dataclass
26
- class DatabaseConnectionSpec:
27
- url: str
28
- user: str | None = None
29
- password: str | None = None
30
-
31
- @dataclass
32
- class Settings:
33
- """Settings for the cocoindex library."""
34
- database: DatabaseConnectionSpec
35
-
36
- @classmethod
37
- def from_env(cls) -> Self:
38
- """Load settings from environment variables."""
39
-
40
- db_kwargs: dict[str, str] = dict()
41
- _load_field(db_kwargs, "url", "COCOINDEX_DATABASE_URL", required=True)
42
- _load_field(db_kwargs, "user", "COCOINDEX_DATABASE_USER")
43
- _load_field(db_kwargs, "password", "COCOINDEX_DATABASE_PASSWORD")
44
- database = DatabaseConnectionSpec(**db_kwargs)
45
- return cls(database=database)
46
-
47
-
48
- def init(settings: Settings):
15
+ def init(settings: setting.Settings):
49
16
  """Initialize the cocoindex library."""
50
17
  _engine.init(dump_engine_object(settings))
51
18
 
52
- @dataclass
53
- class ServerSettings:
54
- """Settings for the cocoindex server."""
55
-
56
- # The address to bind the server to.
57
- address: str = "127.0.0.1:8080"
58
-
59
- # The origin of the client (e.g. CocoInsight UI) to allow CORS from.
60
- cors_origin: str | None = None
61
-
62
- @classmethod
63
- def from_env(cls) -> Self:
64
- """Load settings from environment variables."""
65
-
66
- kwargs: dict[str, str] = dict()
67
- _load_field(kwargs, "address", "COCOINDEX_SERVER_ADDRESS")
68
- _load_field(kwargs, "cors_origin", "COCOINDEX_SERVER_CORS_ORIGIN")
69
-
70
- return cls(**kwargs)
71
-
72
19
 
73
- def start_server(settings: ServerSettings):
20
+ def start_server(settings: setting.ServerSettings):
74
21
  """Start the cocoindex server."""
75
22
  flow.ensure_all_flows_built()
76
23
  query.ensure_all_handlers_built()
@@ -81,7 +28,7 @@ def stop():
81
28
  _engine.stop()
82
29
 
83
30
  def main_fn(
84
- settings: Settings | None = None,
31
+ settings: setting.Settings | None = None,
85
32
  cocoindex_cmd: str = 'cocoindex',
86
33
  ) -> Callable[[Callable], Callable]:
87
34
  """
@@ -92,7 +39,7 @@ def main_fn(
92
39
  """
93
40
 
94
41
  def _pre_init() -> None:
95
- effective_settings = settings or Settings.from_env()
42
+ effective_settings = settings or setting.Settings.from_env()
96
43
  init(effective_settings)
97
44
 
98
45
  def _should_run_cli() -> bool:
@@ -5,10 +5,10 @@ import asyncio
5
5
  import dataclasses
6
6
  import inspect
7
7
 
8
- from typing import get_type_hints, Protocol, Any, Callable, Awaitable, dataclass_transform
8
+ from typing import Protocol, Any, Callable, Awaitable, dataclass_transform
9
9
  from enum import Enum
10
10
 
11
- from .typing import encode_enriched_type
11
+ from .typing import encode_enriched_type, resolve_forward_ref
12
12
  from .convert import encode_engine_value, make_engine_value_decoder
13
13
  from . import _engine
14
14
 
@@ -214,10 +214,11 @@ def executor_class(**args) -> Callable[[type], type]:
214
214
  """
215
215
  Decorate a class to provide an executor for an op.
216
216
  """
217
- type_hints = get_type_hints(cls)
217
+ # Use `__annotations__` instead of `get_type_hints`, to avoid resolving forward references.
218
+ type_hints = cls.__annotations__
218
219
  if 'spec' not in type_hints:
219
220
  raise TypeError("Expect a `spec` field with type hint")
220
- spec_cls = type_hints['spec']
221
+ spec_cls = resolve_forward_ref(type_hints['spec'])
221
222
  sig = inspect.signature(cls.__call__)
222
223
  return _register_op_factory(
223
224
  category=spec_cls._op_category,
@@ -0,0 +1,77 @@
1
+ """
2
+ Data types for settings of the cocoindex library.
3
+ """
4
+ import os
5
+
6
+ from typing import Callable, Self, Any, overload
7
+ from dataclasses import dataclass
8
+
9
+
10
+ @dataclass
11
+ class DatabaseConnectionSpec:
12
+ """
13
+ Connection spec for relational database.
14
+ Used by both internal and target storage.
15
+ """
16
+ url: str
17
+ user: str | None = None
18
+ password: str | None = None
19
+
20
+ def _load_field(target: dict[str, Any], name: str, env_name: str, required: bool = False,
21
+ parse: Callable[[str], Any] | None = None):
22
+ value = os.getenv(env_name)
23
+ if value is None:
24
+ if required:
25
+ raise ValueError(f"{env_name} is not set")
26
+ else:
27
+ target[name] = value if parse is None else parse(value)
28
+
29
+ @dataclass
30
+ class Settings:
31
+ """Settings for the cocoindex library."""
32
+ database: DatabaseConnectionSpec
33
+
34
+ @classmethod
35
+ def from_env(cls) -> Self:
36
+ """Load settings from environment variables."""
37
+
38
+ db_kwargs: dict[str, str] = dict()
39
+ _load_field(db_kwargs, "url", "COCOINDEX_DATABASE_URL", required=True)
40
+ _load_field(db_kwargs, "user", "COCOINDEX_DATABASE_USER")
41
+ _load_field(db_kwargs, "password", "COCOINDEX_DATABASE_PASSWORD")
42
+ database = DatabaseConnectionSpec(**db_kwargs)
43
+ return cls(database=database)
44
+
45
+ @dataclass
46
+ class ServerSettings:
47
+ """Settings for the cocoindex server."""
48
+
49
+ # The address to bind the server to.
50
+ address: str = "127.0.0.1:8080"
51
+
52
+ # The origins of the clients (e.g. CocoInsight UI) to allow CORS from.
53
+ cors_origins: list[str] | None = None
54
+
55
+ @classmethod
56
+ def from_env(cls) -> Self:
57
+ """Load settings from environment variables."""
58
+ kwargs: dict[str, Any] = dict()
59
+ _load_field(kwargs, "address", "COCOINDEX_SERVER_ADDRESS")
60
+ _load_field(kwargs, "cors_origins", "COCOINDEX_SERVER_CORS_ORIGINS",
61
+ parse=ServerSettings.parse_cors_origins)
62
+ return cls(**kwargs)
63
+
64
+ @overload
65
+ @staticmethod
66
+ def parse_cors_origins(s: str) -> list[str]: ...
67
+
68
+ @overload
69
+ @staticmethod
70
+ def parse_cors_origins(s: str | None) -> list[str] | None: ...
71
+
72
+ @staticmethod
73
+ def parse_cors_origins(s):
74
+ """
75
+ Parse the CORS origins from a string.
76
+ """
77
+ return [o for e in s.split(",") if (o := e.strip()) != ""] if s is not None else None
@@ -5,11 +5,11 @@ from typing import Sequence
5
5
  from . import op
6
6
  from . import index
7
7
  from .auth_registry import AuthEntryReference
8
+ from .setting import DatabaseConnectionSpec
8
9
 
9
10
  class Postgres(op.StorageSpec):
10
11
  """Storage powered by Postgres and pgvector."""
11
-
12
- database: AuthEntryReference | None = None
12
+ database: AuthEntryReference[DatabaseConnectionSpec] | None = None
13
13
  table_name: str | None = None
14
14
 
15
15
  @dataclass
@@ -72,15 +72,14 @@ NodeReferenceMapping = NodeFromFields
72
72
 
73
73
  class Neo4j(op.StorageSpec):
74
74
  """Graph storage powered by Neo4j."""
75
-
76
- connection: AuthEntryReference
75
+ connection: AuthEntryReference[Neo4jConnection]
77
76
  mapping: Nodes | Relationships
78
77
 
79
78
  class Neo4jDeclaration(op.DeclarationSpec):
80
79
  """Declarations for Neo4j."""
81
80
 
82
81
  kind = "Neo4j"
83
- connection: AuthEntryReference
82
+ connection: AuthEntryReference[Neo4jConnection]
84
83
  nodes_label: str
85
84
  primary_key_fields: Sequence[str]
86
85
  vector_indexes: Sequence[index.VectorIndexDef] = ()