├── .dockerignore
├── .env.example
├── .github
├── FUNDING.yml
└── workflows
│ └── docker.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── LICENSE-DOCS
├── README.md
├── __init__.py
├── browser-ext
├── contentScript.js
├── manifest.json
├── marked.min.js
├── popup.html
├── popup.js
└── styles.css
├── docker-compose.yml
├── docker
├── crontab
├── entrypoint.sh
├── healthcheck.py
└── supervisord.conf
├── main.py
├── pull_rawdata.sh
├── requirements.txt
└── src
├── api
├── __init__.py
├── app.py
├── dependencies
│ ├── __init__.py
│ └── auth.py
├── models
│ ├── __init__.py
│ └── chat.py
└── routes
│ ├── __init__.py
│ └── chat.py
├── config
├── __init__.py
└── settings.py
├── core
├── __init__.py
├── models
│ ├── __init__.py
│ └── chat.py
└── services
│ ├── __init__.py
│ ├── chat_service.py
│ ├── db_service.py
│ └── embedding.py
├── processing
├── __init__.py
├── document_processor.py
├── file_update_handler.py
└── markdown_converter.py
├── sqls
└── init.sql
├── ui
├── __init__.py
└── streamlit_app.py
└── utils
├── __init__.py
├── errors.py
└── logging.py
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git/
2 | .gitignore
3 | .env
4 | __pycache__/
5 | *.pyc
6 | *.pyo
7 | *.pyd
8 | .Python
9 | env/
10 | venv/
11 | .venv/
12 | raw_data/
13 | markdown/
14 | logs/
15 | .DS_Store
16 | .coverage
17 | .pytest_cache/
18 | *.log
19 | browser-ext/
20 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | OPENAI_API_KEY=your_openai_api_key
2 | OPENAI_API_BASE=https://api.openai.com/v1
3 | POSTGRES_USER=odoo_expert
4 | POSTGRES_PASSWORD=your_secure_password
5 | POSTGRES_DB=odoo_expert_db
6 | POSTGRES_HOST=db
7 | POSTGRES_PORT=5432
8 | LLM_MODEL=gpt-4o
9 | BEARER_TOKEN=comma_separated_bearer_tokens
10 | CORS_ORIGINS=http://localhost:3000,http://localhost:8501,https://www.odoo.com
11 | ODOO_VERSIONS=16.0,17.0,18.0
12 | SYSTEM_PROMPT="You are an expert in Odoo development and architecture.
13 | Answer the question using the provided documentation chunks and conversation history.
14 | In your answer:
15 | 1. Start with a clear, direct response to the question
16 | 2. Support your answer with specific references to the source documents
17 | 3. Use markdown formatting for readability
18 | 4. When citing information, mention which Source (1, 2, etc.) it came from
19 | 5. If different sources provide complementary information, explain how they connect
20 | 6. Consider the conversation history for context
21 |
22 | Format your response like this:
23 |
24 | **Answer:**
25 | [Your main answer here]
26 |
27 | **Sources Used:**
28 | - Source 1: Title chunk['url']
29 | - Source 2: Title chunk['url']
30 | - etc if needed"
31 |
32 | # Data Directories
33 | RAW_DATA_DIR=raw_data
34 | MARKDOWN_DATA_DIR=markdown
35 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: mfydev # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: fanyangmeng # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: Docker Build and Push
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | tags: [ 'v*.*.*' ]
7 | pull_request:
8 | branches: [ "main" ]
9 | workflow_dispatch:
10 |
11 | env:
12 | REGISTRY: docker.io
13 | IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/odoo-expert
14 |
15 | jobs:
16 | build-and-push:
17 | runs-on: ubuntu-latest
18 | permissions:
19 | contents: read
20 | packages: write
21 |
22 | steps:
23 | - name: Checkout repository
24 | uses: actions/checkout@v4
25 |
26 | - name: Set up Docker Buildx
27 | uses: docker/setup-buildx-action@v3
28 |
29 | - name: Log in to Docker Hub
30 | if: github.event_name != 'pull_request'
31 | uses: docker/login-action@v3
32 | with:
33 | username: ${{ secrets.DOCKER_USERNAME }}
34 | password: ${{ secrets.DOCKER_TOKEN }}
35 |
36 | - name: Extract metadata (tags, labels) for Docker
37 | id: meta
38 | uses: docker/metadata-action@v5
39 | with:
40 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
41 | tags: |
42 | type=ref,event=branch
43 | type=ref,event=pr
44 | type=semver,pattern={{version}}
45 | type=semver,pattern={{major}}.{{minor}}
46 | type=sha,prefix=,suffix=,format=short
47 | type=raw,value=latest
48 |
49 | - name: Build and push Docker image
50 | uses: docker/build-push-action@v5
51 | with:
52 | context: .
53 | push: ${{ github.event_name != 'pull_request' }}
54 | tags: ${{ steps.meta.outputs.tags }}
55 | labels: ${{ steps.meta.outputs.labels }}
56 | cache-from: type=gha
57 | cache-to: type=gha,mode=max
58 | platforms: linux/amd64,linux/arm64
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # UV
98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | #uv.lock
102 |
103 | # poetry
104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105 | # This is especially recommended for binary packages to ensure reproducibility, and is more
106 | # commonly ignored for libraries.
107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108 | #poetry.lock
109 |
110 | # pdm
111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112 | #pdm.lock
113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114 | # in version control.
115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116 | .pdm.toml
117 | .pdm-python
118 | .pdm-build/
119 |
120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121 | __pypackages__/
122 |
123 | # Celery stuff
124 | celerybeat-schedule
125 | celerybeat.pid
126 |
127 | # SageMath parsed files
128 | *.sage.py
129 |
130 | # Environments
131 | .env
132 | .venv
133 | env/
134 | venv/
135 | ENV/
136 | env.bak/
137 | venv.bak/
138 |
139 | # Spyder project settings
140 | .spyderproject
141 | .spyproject
142 |
143 | # Rope project settings
144 | .ropeproject
145 |
146 | # mkdocs documentation
147 | /site
148 |
149 | # mypy
150 | .mypy_cache/
151 | .dmypy.json
152 | dmypy.json
153 |
154 | # Pyre type checker
155 | .pyre/
156 |
157 | # pytype static type analyzer
158 | .pytype/
159 |
160 | # Cython debug symbols
161 | cython_debug/
162 |
163 | # PyCharm
164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166 | # and can be added to the global gitignore or merged into this file. For a more nuclear
167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168 | #.idea/
169 |
170 | # PyPI configuration file
171 | .pypirc
172 | .vscode
173 | .DS_Store
174 | *.code-workspace
175 | html/
176 | markdown/
177 | raw_data/
178 | bak/
179 | .file_cache.json
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10-slim as builder
2 |
3 | WORKDIR /app
4 |
5 | # Copy only requirements first
6 | COPY requirements.txt .
7 |
8 | # Install dependencies in virtual environment
9 | RUN python -m venv /opt/venv && \
10 | /opt/venv/bin/pip install --no-cache-dir --upgrade pip && \
11 | /opt/venv/bin/pip install --no-cache-dir -r requirements.txt
12 |
13 | FROM python:3.10-slim
14 |
15 | WORKDIR /app
16 |
17 | # Copy virtual environment from builder
18 | COPY --from=builder /opt/venv /opt/venv
19 | ENV PATH="/opt/venv/bin:$PATH"
20 |
21 | # Install system dependencies
22 | RUN apt-get update && \
23 | apt-get install -y --no-install-recommends \
24 | pandoc \
25 | git \
26 | cron \
27 | curl \
28 | ca-certificates \
29 | supervisor \
30 | && apt-get clean && \
31 | rm -rf /var/lib/apt/lists/* && \
32 | rm -rf /var/cache/apt/*
33 |
34 | # Create directories with proper permissions
35 | RUN mkdir -p raw_data markdown logs /var/log/supervisor && \
36 | chmod -R 755 logs /var/log/supervisor
37 |
38 | # Copy application files
39 | COPY main.py pull_rawdata.sh ./
40 | COPY src/ ./src/
41 | COPY docker/entrypoint.sh ./docker/entrypoint.sh
42 | COPY docker/crontab /etc/cron.d/updater-cron
43 | COPY docker/healthcheck.py ./docker/healthcheck.py
44 | COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
45 |
46 | # Set up permissions and logging
47 | RUN chmod 0644 /etc/cron.d/updater-cron && \
48 | crontab /etc/cron.d/updater-cron && \
49 | chmod +x pull_rawdata.sh && \
50 | chmod +x docker/entrypoint.sh && \
51 | chmod +x docker/healthcheck.py && \
52 | touch /var/log/cron.log && \
53 | chmod 0666 /var/log/cron.log && \
54 | mkdir -p /app/logs && \
55 | touch /app/logs/ui.log /app/logs/api.log /app/logs/updater.log \
56 | /app/logs/ui-error.log /app/logs/api-error.log /app/logs/updater-error.log && \
57 | chmod 0666 /app/logs/*.log
58 |
59 | ENV PYTHONPATH=/app
60 | ENV PYTHONUNBUFFERED=1
61 |
62 | EXPOSE 8000 8501
63 |
64 | HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
65 | CMD python docker/healthcheck.py
66 |
67 | CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/LICENSE-DOCS:
--------------------------------------------------------------------------------
1 | Attribution-ShareAlike 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution-ShareAlike 4.0 International Public
58 | License
59 |
60 | By exercising the Licensed Rights (defined below), You accept and agree
61 | to be bound by the terms and conditions of this Creative Commons
62 | Attribution-ShareAlike 4.0 International Public License ("Public
63 | License"). To the extent this Public License may be interpreted as a
64 | contract, You are granted the Licensed Rights in consideration of Your
65 | acceptance of these terms and conditions, and the Licensor grants You
66 | such rights in consideration of benefits the Licensor receives from
67 | making the Licensed Material available under these terms and
68 | conditions.
69 |
70 |
71 | Section 1 -- Definitions.
72 |
73 | a. Adapted Material means material subject to Copyright and Similar
74 | Rights that is derived from or based upon the Licensed Material
75 | and in which the Licensed Material is translated, altered,
76 | arranged, transformed, or otherwise modified in a manner requiring
77 | permission under the Copyright and Similar Rights held by the
78 | Licensor. For purposes of this Public License, where the Licensed
79 | Material is a musical work, performance, or sound recording,
80 | Adapted Material is always produced where the Licensed Material is
81 | synched in timed relation with a moving image.
82 |
83 | b. Adapter's License means the license You apply to Your Copyright
84 | and Similar Rights in Your contributions to Adapted Material in
85 | accordance with the terms and conditions of this Public License.
86 |
87 | c. BY-SA Compatible License means a license listed at
88 | creativecommons.org/compatiblelicenses, approved by Creative
89 | Commons as essentially the equivalent of this Public License.
90 |
91 | d. Copyright and Similar Rights means copyright and/or similar rights
92 | closely related to copyright including, without limitation,
93 | performance, broadcast, sound recording, and Sui Generis Database
94 | Rights, without regard to how the rights are labeled or
95 | categorized. For purposes of this Public License, the rights
96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 | Rights.
98 |
99 | e. Effective Technological Measures means those measures that, in the
100 | absence of proper authority, may not be circumvented under laws
101 | fulfilling obligations under Article 11 of the WIPO Copyright
102 | Treaty adopted on December 20, 1996, and/or similar international
103 | agreements.
104 |
105 | f. Exceptions and Limitations means fair use, fair dealing, and/or
106 | any other exception or limitation to Copyright and Similar Rights
107 | that applies to Your use of the Licensed Material.
108 |
109 | g. License Elements means the license attributes listed in the name
110 | of a Creative Commons Public License. The License Elements of this
111 | Public License are Attribution and ShareAlike.
112 |
113 | h. Licensed Material means the artistic or literary work, database,
114 | or other material to which the Licensor applied this Public
115 | License.
116 |
117 | i. Licensed Rights means the rights granted to You subject to the
118 | terms and conditions of this Public License, which are limited to
119 | all Copyright and Similar Rights that apply to Your use of the
120 | Licensed Material and that the Licensor has authority to license.
121 |
122 | j. Licensor means the individual(s) or entity(ies) granting rights
123 | under this Public License.
124 |
125 | k. Share means to provide material to the public by any means or
126 | process that requires permission under the Licensed Rights, such
127 | as reproduction, public display, public performance, distribution,
128 | dissemination, communication, or importation, and to make material
129 | available to the public including in ways that members of the
130 | public may access the material from a place and at a time
131 | individually chosen by them.
132 |
133 | l. Sui Generis Database Rights means rights other than copyright
134 | resulting from Directive 96/9/EC of the European Parliament and of
135 | the Council of 11 March 1996 on the legal protection of databases,
136 | as amended and/or succeeded, as well as other essentially
137 | equivalent rights anywhere in the world.
138 |
139 | m. You means the individual or entity exercising the Licensed Rights
140 | under this Public License. Your has a corresponding meaning.
141 |
142 |
143 | Section 2 -- Scope.
144 |
145 | a. License grant.
146 |
147 | 1. Subject to the terms and conditions of this Public License,
148 | the Licensor hereby grants You a worldwide, royalty-free,
149 | non-sublicensable, non-exclusive, irrevocable license to
150 | exercise the Licensed Rights in the Licensed Material to:
151 |
152 | a. reproduce and Share the Licensed Material, in whole or
153 | in part; and
154 |
155 | b. produce, reproduce, and Share Adapted Material.
156 |
157 | 2. Exceptions and Limitations. For the avoidance of doubt, where
158 | Exceptions and Limitations apply to Your use, this Public
159 | License does not apply, and You do not need to comply with
160 | its terms and conditions.
161 |
162 | 3. Term. The term of this Public License is specified in Section
163 | 6(a).
164 |
165 | 4. Media and formats; technical modifications allowed. The
166 | Licensor authorizes You to exercise the Licensed Rights in
167 | all media and formats whether now known or hereafter created,
168 | and to make technical modifications necessary to do so. The
169 | Licensor waives and/or agrees not to assert any right or
170 | authority to forbid You from making technical modifications
171 | necessary to exercise the Licensed Rights, including
172 | technical modifications necessary to circumvent Effective
173 | Technological Measures. For purposes of this Public License,
174 | simply making modifications authorized by this Section 2(a)
175 | (4) never produces Adapted Material.
176 |
177 | 5. Downstream recipients.
178 |
179 | a. Offer from the Licensor -- Licensed Material. Every
180 | recipient of the Licensed Material automatically
181 | receives an offer from the Licensor to exercise the
182 | Licensed Rights under the terms and conditions of this
183 | Public License.
184 |
185 | b. Additional offer from the Licensor -- Adapted Material.
186 | Every recipient of Adapted Material from You
187 | automatically receives an offer from the Licensor to
188 | exercise the Licensed Rights in the Adapted Material
189 | under the conditions of the Adapter's License You apply.
190 |
191 | c. No downstream restrictions. You may not offer or impose
192 | any additional or different terms or conditions on, or
193 | apply any Effective Technological Measures to, the
194 | Licensed Material if doing so restricts exercise of the
195 | Licensed Rights by any recipient of the Licensed
196 | Material.
197 |
198 | 6. No endorsement. Nothing in this Public License constitutes or
199 | may be construed as permission to assert or imply that You
200 | are, or that Your use of the Licensed Material is, connected
201 | with, or sponsored, endorsed, or granted official status by,
202 | the Licensor or others designated to receive attribution as
203 | provided in Section 3(a)(1)(A)(i).
204 |
205 | b. Other rights.
206 |
207 | 1. Moral rights, such as the right of integrity, are not
208 | licensed under this Public License, nor are publicity,
209 | privacy, and/or other similar personality rights; however, to
210 | the extent possible, the Licensor waives and/or agrees not to
211 | assert any such rights held by the Licensor to the limited
212 | extent necessary to allow You to exercise the Licensed
213 | Rights, but not otherwise.
214 |
215 | 2. Patent and trademark rights are not licensed under this
216 | Public License.
217 |
218 | 3. To the extent possible, the Licensor waives any right to
219 | collect royalties from You for the exercise of the Licensed
220 | Rights, whether directly or through a collecting society
221 | under any voluntary or waivable statutory or compulsory
222 | licensing scheme. In all other cases the Licensor expressly
223 | reserves any right to collect such royalties.
224 |
225 |
226 | Section 3 -- License Conditions.
227 |
228 | Your exercise of the Licensed Rights is expressly made subject to the
229 | following conditions.
230 |
231 | a. Attribution.
232 |
233 | 1. If You Share the Licensed Material (including in modified
234 | form), You must:
235 |
236 | a. retain the following if it is supplied by the Licensor
237 | with the Licensed Material:
238 |
239 | i. identification of the creator(s) of the Licensed
240 | Material and any others designated to receive
241 | attribution, in any reasonable manner requested by
242 | the Licensor (including by pseudonym if
243 | designated);
244 |
245 | ii. a copyright notice;
246 |
247 | iii. a notice that refers to this Public License;
248 |
249 | iv. a notice that refers to the disclaimer of
250 | warranties;
251 |
252 | v. a URI or hyperlink to the Licensed Material to the
253 | extent reasonably practicable;
254 |
255 | b. indicate if You modified the Licensed Material and
256 | retain an indication of any previous modifications; and
257 |
258 | c. indicate the Licensed Material is licensed under this
259 | Public License, and include the text of, or the URI or
260 | hyperlink to, this Public License.
261 |
262 | 2. You may satisfy the conditions in Section 3(a)(1) in any
263 | reasonable manner based on the medium, means, and context in
264 | which You Share the Licensed Material. For example, it may be
265 | reasonable to satisfy the conditions by providing a URI or
266 | hyperlink to a resource that includes the required
267 | information.
268 |
269 | 3. If requested by the Licensor, You must remove any of the
270 | information required by Section 3(a)(1)(A) to the extent
271 | reasonably practicable.
272 |
273 | b. ShareAlike.
274 |
275 | In addition to the conditions in Section 3(a), if You Share
276 | Adapted Material You produce, the following conditions also apply.
277 |
278 | 1. The Adapter's License You apply must be a Creative Commons
279 | license with the same License Elements, this version or
280 | later, or a BY-SA Compatible License.
281 |
282 | 2. You must include the text of, or the URI or hyperlink to, the
283 | Adapter's License You apply. You may satisfy this condition
284 | in any reasonable manner based on the medium, means, and
285 | context in which You Share Adapted Material.
286 |
287 | 3. You may not offer or impose any additional or different terms
288 | or conditions on, or apply any Effective Technological
289 | Measures to, Adapted Material that restrict exercise of the
290 | rights granted under the Adapter's License You apply.
291 |
292 |
293 | Section 4 -- Sui Generis Database Rights.
294 |
295 | Where the Licensed Rights include Sui Generis Database Rights that
296 | apply to Your use of the Licensed Material:
297 |
298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
299 | to extract, reuse, reproduce, and Share all or a substantial
300 | portion of the contents of the database;
301 |
302 | b. if You include all or a substantial portion of the database
303 | contents in a database in which You have Sui Generis Database
304 | Rights, then the database in which You have Sui Generis Database
305 | Rights (but not its individual contents) is Adapted Material,
306 | including for purposes of Section 3(b); and
307 |
308 | c. You must comply with the conditions in Section 3(a) if You Share
309 | all or a substantial portion of the contents of the database.
310 |
311 | For the avoidance of doubt, this Section 4 supplements and does not
312 | replace Your obligations under this Public License where the Licensed
313 | Rights include other Copyright and Similar Rights.
314 |
315 |
316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
317 |
318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
328 |
329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
338 |
339 | c. The disclaimer of warranties and limitation of liability provided
340 | above shall be interpreted in a manner that, to the extent
341 | possible, most closely approximates an absolute disclaimer and
342 | waiver of all liability.
343 |
344 |
345 | Section 6 -- Term and Termination.
346 |
347 | a. This Public License applies for the term of the Copyright and
348 | Similar Rights licensed here. However, if You fail to comply with
349 | this Public License, then Your rights under this Public License
350 | terminate automatically.
351 |
352 | b. Where Your right to use the Licensed Material has terminated under
353 | Section 6(a), it reinstates:
354 |
355 | 1. automatically as of the date the violation is cured, provided
356 | it is cured within 30 days of Your discovery of the
357 | violation; or
358 |
359 | 2. upon express reinstatement by the Licensor.
360 |
361 | For the avoidance of doubt, this Section 6(b) does not affect any
362 | right the Licensor may have to seek remedies for Your violations
363 | of this Public License.
364 |
365 | c. For the avoidance of doubt, the Licensor may also offer the
366 | Licensed Material under separate terms or conditions or stop
367 | distributing the Licensed Material at any time; however, doing so
368 | will not terminate this Public License.
369 |
370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
371 | License.
372 |
373 |
374 | Section 7 -- Other Terms and Conditions.
375 |
376 | a. The Licensor shall not be bound by any additional or different
377 | terms or conditions communicated by You unless expressly agreed.
378 |
379 | b. Any arrangements, understandings, or agreements regarding the
380 | Licensed Material not stated herein are separate from and
381 | independent of the terms and conditions of this Public License.
382 |
383 |
384 | Section 8 -- Interpretation.
385 |
386 | a. For the avoidance of doubt, this Public License does not, and
387 | shall not be interpreted to, reduce, limit, restrict, or impose
388 | conditions on any use of the Licensed Material that could lawfully
389 | be made without permission under this Public License.
390 |
391 | b. To the extent possible, if any provision of this Public License is
392 | deemed unenforceable, it shall be automatically reformed to the
393 | minimum extent necessary to make it enforceable. If the provision
394 | cannot be reformed, it shall be severed from this Public License
395 | without affecting the enforceability of the remaining terms and
396 | conditions.
397 |
398 | c. No term or condition of this Public License will be waived and no
399 | failure to comply consented to unless expressly agreed to by the
400 | Licensor.
401 |
402 | d. Nothing in this Public License constitutes or may be interpreted
403 | as a limitation upon, or waiver of, any privileges and immunities
404 | that apply to the Licensor or You, including from the legal
405 | processes of any jurisdiction or authority.
406 |
407 |
408 | =======================================================================
409 |
410 | Creative Commons is not a party to its public
411 | licenses. Notwithstanding, Creative Commons may elect to apply one of
412 | its public licenses to material it publishes and in those instances
413 | will be considered the “Licensor.” The text of the Creative Commons
414 | public licenses is dedicated to the public domain under the CC0 Public
415 | Domain Dedication. Except for the limited purpose of indicating that
416 | material is shared under a Creative Commons public license or as
417 | otherwise permitted by the Creative Commons policies published at
418 | creativecommons.org/policies, Creative Commons does not authorize the
419 | use of the trademark "Creative Commons" or any other trademark or logo
420 | of Creative Commons without its prior written consent including,
421 | without limitation, in connection with any unauthorized modifications
422 | to any of its public licenses or any other arrangements,
423 | understandings, or agreements concerning use of licensed material. For
424 | the avoidance of doubt, this paragraph does not form part of the
425 | public licenses.
426 |
427 | Creative Commons may be contacted at creativecommons.org.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Odoo Expert
2 | RAG-Powered Odoo Documentation Assistant
3 |
4 | Intro, Updates & Demo Video: https://fanyangmeng.blog/introducing-odoo-expert/
5 |
6 | Browser extension now available for Chrome and Edge!
7 |
8 | Check it out: https://microsoftedge.microsoft.com/addons/detail/odoo-expert/mnmapgdlgncmdiofbdacjilfcafgapci
9 |
10 | > ⚠️ PLEASE NOTE:
11 | > This project is not sponsored or endrosed by Odoo S.A. or Odoo Inc. yet. I am developing this project as a personal project with the intention of helping the Odoo community on my own.
12 |
13 | A comprehensive documentation processing and chat system that converts Odoo's documentation to a searchable knowledge base with an AI-powered chat interface. This tool supports multiple Odoo versions (16.0, 17.0, 18.0) and provides semantic search capabilities powered by OpenAI embeddings.
14 |
15 | ## Initial Intention Behind This Project
16 |
17 | The project was conceived with the vision of enhancing the Odoo documentation experience. The goal was to create a system similar to Perplexity or Google, where users could receive AI-powered answers directly within the documentation website, complete with proper source links. This eliminates the need for users to manually navigate through complex documentation structures.
18 |
19 | ## How it works?
20 |
21 | ```mermaid
22 | graph TD
23 | A[Odoo Documentation] -->|pull_rawdata.sh| B[Raw Data]
24 | B -->|process-raw| C[Markdown Files]
25 | C -->|process-docs| D[(Database with Embeddings)]
26 | D -->|serve --mode ui| E[Streamlit UI]
27 | D -->|serve --mode api| F[REST API]
28 |
29 | subgraph "Data Processing Pipeline"
30 | B
31 | C
32 | D
33 | end
34 |
35 | subgraph "Interface Layer"
36 | E
37 | F
38 | end
39 |
40 | style A fill:#f9f,stroke:#333,stroke-width:2px
41 | style D fill:#bbf,stroke:#333,stroke-width:2px
42 | style E fill:#bfb,stroke:#333,stroke-width:2px
43 | style F fill:#bfb,stroke:#333,stroke-width:2px
44 | ```
45 |
46 | The system operates through a pipeline of data processing and serving steps:
47 |
48 | 1. **Documentation Pulling**: Fetches raw documentation from Odoo's repositories
49 | 2. **Format Conversion**: Converts RST files to Markdown for better AI processing
50 | 3. **Embedding Generation**: Processes Markdown files and stores them with embeddings
51 | 4. **Interface Layer**: Provides both UI and API access to the processed knowledge base
52 |
53 | ## Features
54 |
55 | ### Core Functionality
56 |
57 | - Documentation Processing: Automated conversion of RST to Markdown with smart preprocessing
58 | - Semantic Search: Real-time semantic search across documentation versions
59 | - AI-Powered Chat: Context-aware responses with source citations
60 | - Multi-Version Support: Comprehensive support for Odoo versions 16.0, 17.0, and 18.0
61 | - Always updated: Efficiently detect and process documentation updates.
62 |
63 | ### Interface Options
64 |
65 | - Web UI: Streamlit-based interface for interactive querying
66 | - REST API: Authenticated endpoints for programmatic access
67 | - CLI: Command-line interface for document processing and chat
68 |
69 | ## Prerequisites
70 |
71 | - Docker and Docker Compose
72 | - PostgreSQL with pgvector extension
73 | - OpenAI API access
74 | - Git
75 |
76 | if you want to do source install, you need to install the following dependencies:
77 |
78 | - Python 3.10+
79 | - Pandoc
80 | - PostgreSQL with pgvector extension
81 |
82 | ## Installation & Usage
83 |
84 | Assuming the table name is `odoo_docs`. If you have a different table name, please update the table name in the following SQL commands.
85 |
86 | ### Docker Compose Install
87 |
88 | 1. Download the [docker-compose.yml](./docker-compose.yml) file to your local machine.
89 | 2. Set up environment variables in the `.env` file by using the `.env.example` file as a template.
90 | ```bash
91 | OPENAI_API_KEY=your_openai_api_key
92 | OPENAI_API_BASE=https://api.openai.com/v1
93 | POSTGRES_USER=odoo_expert
94 | POSTGRES_PASSWORD=your_secure_password
95 | POSTGRES_DB=odoo_expert_db
96 | POSTGRES_HOST=db
97 | POSTGRES_PORT=5432
98 | LLM_MODEL=gpt-4o
99 | BEARER_TOKEN=comma_separated_bearer_tokens
100 | CORS_ORIGINS=http://localhost:3000,http://localhost:8501,https://www.odoo.com
101 | ODOO_VERSIONS=16.0,17.0,18.0
102 | SYSTEM_PROMPT=same as .env.example
103 | # Data Directories
104 | RAW_DATA_DIR=raw_data
105 | MARKDOWN_DATA_DIR=markdown
106 | ```
107 | 3. Run the following command:
108 | ```bash
109 | docker-compose up -d
110 | ```
111 | 4. Pull the raw data and write to your PostgreSQL's table:
112 | ```bash
113 | # Pull documentation (uses ODOO_VERSIONS from .env)
114 | docker compose run --rm odoo-expert ./pull_rawdata.sh
115 |
116 | # Convert RST to Markdown
117 | docker compose run --rm odoo-expert python main.py process-raw
118 |
119 | # Process documents
120 | docker compose run --rm odoo-expert python main.py process-docs
121 | ```
122 | 5. Access the UI at port 8501 and the API at port 8000
123 | 6. Docker compose will automatically pull the latest changes and update the system once a day, or you can manually update by running the following command:
124 | ```bash
125 | docker compose run --rm odoo-expert python main.py check-updates
126 | ```
127 |
128 | ### Source Install
129 |
130 | 1. Install PostgreSQL and pgvector:
131 | ```bash
132 | # For Debian/Ubuntu
133 | sudo apt-get install postgresql postgresql-contrib
134 |
135 | # Install pgvector extension
136 | git clone https://github.com/pgvector/pgvector.git
137 | cd pgvector
138 | make
139 | make install
140 | ```
141 |
142 | 2. Create database and enable extension:
143 | ```sql
144 | CREATE DATABASE odoo_expert;
145 | \c odoo_expert
146 | CREATE EXTENSION vector;
147 | ```
148 |
149 | 3. Set up the database schema by running the SQL commands in `src/sqls/init.sql`.
150 |
151 | 4. Create a `.env` file from the template and configure your environment variables:
152 | ```bash
153 | cp .env.example .env
154 | # Edit .env with your settings including ODOO_VERSIONS and SYSTEM_PROMPT
155 | ```
156 |
157 | 5. Pull Odoo documentation:
158 | ```bash
159 | chmod +x pull_rawdata.sh
160 | ./pull_rawdata.sh # Will use ODOO_VERSIONS from .env
161 | ```
162 |
163 | 6. Convert RST to Markdown:
164 | ```bash
165 | python main.py process-raw
166 | ```
167 |
168 | 7. Process and embed documents:
169 | ```bash
170 | python main.py process-docs
171 | ```
172 |
173 | 8. Launch the chat interface:
174 | ```bash
175 | python main.py serve --mode ui
176 | ```
177 |
178 | 9. Launch the API:
179 | ```bash
180 | python main.py serve --mode api
181 | ```
182 |
183 | 10. Access the UI at port 8501 and the API at port 8000
184 |
185 | 11. To sync with the latest changes in the Odoo documentation, run:
186 | ```bash
187 | python main.py check-updates
188 | ```
189 |
190 | ## API Endpoints
191 |
192 | The project provides a REST API for programmatic access to the documentation assistant.
193 |
194 | ### Authentication
195 |
196 | All API endpoints require Bearer token authentication. Add your API token in the Authorization header:
197 | ```bash
198 | Authorization: Bearer your-api-token
199 | ```
200 |
201 | ### Endpoints
202 |
203 | POST `/api/chat`
204 | Query the documentation and get AI-powered responses.
205 |
206 | Request body:
207 | ```json
208 | {
209 | "query": "string", // The question about Odoo
210 | "version": integer, // Odoo version (160, 170, or 180)
211 | "conversation_history": [ // Optional
212 | {
213 | "user": "string",
214 | "assistant": "string"
215 | }
216 | ]
217 | }
218 | ```
219 |
220 | Response:
221 | ```json
222 | {
223 | "answer": "string", // AI-generated response
224 | "sources": [ // Reference documents used
225 | {
226 | "url": "string",
227 | "title": "string"
228 | }
229 | ]
230 | }
231 | ```
232 |
233 | Example:
234 | ```bash
235 | curl -X POST "http://localhost:8000/api/chat" \
236 | -H "Authorization: Bearer your-api-token" \
237 | -H "Content-Type: application/json" \
238 | -d '{
239 | "query": "How do I install Odoo?",
240 | "version": 180,
241 | "conversation_history": []
242 | }'
243 | ```
244 |
245 | POST `/api/stream`
246 | Query the documentation and get AI-powered responses in streaming format.
247 |
248 | Request body:
249 | ```json
250 | {
251 | "query": "string", // The question about Odoo
252 | "version": integer, // Odoo version (160, 170, or 180)
253 | "conversation_history": [ // Optional
254 | {
255 | "user": "string",
256 | "assistant": "string"
257 | }
258 | ]
259 | }
260 | ```
261 |
262 | Response:
263 | Stream of text chunks (text/event-stream content type)
264 |
265 | Example:
266 | ```bash
267 | curl -X POST "http://localhost:8000/api/stream" \
268 | -H "Authorization: Bearer your-api-token" \
269 | -H "Content-Type: application/json" \
270 | -d '{
271 | "query": "How do I install Odoo?",
272 | "version": 180,
273 | "conversation_history": []
274 | }'
275 | ```
276 |
277 | ## Browser Extension Setup
278 |
279 | The project includes a browser extension that enhances the Odoo documentation search experience with AI-powered responses. To set up the extension:
280 |
281 | 1. Open Chrome/Edge and navigate to the extensions page:
282 | - Chrome: `chrome://extensions/`
283 | - Edge: `edge://extensions/`
284 |
285 | 2. Enable "Developer mode" in the top right corner
286 |
287 | 3. Click "Load unpacked" and select the `browser-ext` folder from this project
288 |
289 | 4. The Odoo Expert extension icon should appear in your browser toolbar
290 |
291 | 5. Make sure your local API server is running (port 8000)
292 |
293 | The extension will now enhance the search experience on Odoo documentation pages by providing AI-powered responses alongside the traditional search results.
294 |
295 | ## Future Roadmap
296 |
297 | Please see [GitHub Issues](https://github.com/MFYDev/odoo-expert/issues) for the future roadmap.
298 |
299 |
300 | ## Support
301 | If you encounter any issues or have questions, please:
302 |
303 | - Check the known issues
304 | - Create a new issue in the GitHub repository
305 | - Provide detailed information about your environment and the problem
306 |
307 | > ⚠️ **Please do not directly email me for support, as I will not respond to it at all, let's keep the discussion in the GitHub issues for clarity and transparency.**
308 |
309 | ## Contributing
310 | Contributions are welcome! Please feel free to submit a Pull Request.
311 |
312 | Thanks for the following contributors during the development of this project:
313 |
314 | - [Viet Din (Desdaemon)](https://github.com/Desdaemon): Giving me important suggestions on how to improve the performance.
315 |
316 | ## License
317 |
318 | This project is licensed under [Apache License 2.0](./LICENSE): No warranty is provided. You can use this project for any purpose, but you must include the original copyright and license.
319 |
320 | Extra license [CC-BY-SA 4.0](./LICENSE-DOCS) to align with the original Odoo/Documentation license.
321 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MFYDev/odoo-expert/58fe863ce099193afdef005e4a01e3f51f6fae93/__init__.py
--------------------------------------------------------------------------------
/browser-ext/contentScript.js:
--------------------------------------------------------------------------------
1 | function debug(msg, ...args) {
2 | console.log(`[Odoo Expert] ${msg}`, ...args);
3 | }
4 |
5 | // Main initialization function
6 | function initializeAIResponse() {
7 | try {
8 | debug('Initializing AI response section');
9 |
10 | // Check if the AI response section already exists
11 | if (document.getElementById('ai-response-section')) {
12 | debug('AI response section already exists, skipping initialization');
13 | return;
14 | }
15 |
16 | // Create AI response section
17 | const aiSection = document.createElement('div');
18 | aiSection.id = 'ai-response-section';
19 | aiSection.innerHTML = `
20 |
\n`}tablecell(e){const t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`${n}>\n`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${K(e,!0)}`}br(e){return" "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){const s=this.parser.parseInline(n),r=V(e);if(null===r)return s;let i='"+s+"",i}image({href:e,title:t,text:n}){const s=V(e);if(null===s)return K(n);let r=`",r}text(e){return"tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:K(e.text)}}class re{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return""+e}image({text:e}){return""+e}br(){return""}}class ie{options;renderer;textRenderer;constructor(t){this.options=t||e.defaults,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new re}static parse(e,t){return new ie(t).parse(e)}static parseInline(e,t){return new ie(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new se(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new te(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new le;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;const s=n,r=e.hooks[s],i=t[s];le.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ne.lex(e,t??this.defaults)}parser(e,t){return ie.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{const s={...n},r={...this.defaults,...s},i=this.onError(!!r.silent,!!r.async);if(!0===this.defaults.async&&!1===s.async)return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==t)return i(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof t)return i(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(t)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);const l=r.hooks?r.hooks.provideLexer():e?ne.lex:ne.lexInline,o=r.hooks?r.hooks.provideParser():e?ie.parse:ie.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(t):t).then((e=>l(e,r))).then((e=>r.hooks?r.hooks.processAllTokens(e):e)).then((e=>r.walkTokens?Promise.all(this.walkTokens(e,r.walkTokens)).then((()=>e)):e)).then((e=>o(e,r))).then((e=>r.hooks?r.hooks.postprocess(e):e)).catch(i);try{r.hooks&&(t=r.hooks.preprocess(t));let e=l(t,r);r.hooks&&(e=r.hooks.processAllTokens(e)),r.walkTokens&&this.walkTokens(e,r.walkTokens);let n=o(e,r);return r.hooks&&(n=r.hooks.postprocess(n)),n}catch(e){return i(e)}}}onError(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="