(bump:minor) Feat: Add mechanism for user-site update and auto creating releases (#56)
* move flowsettings.py and launch.py to root * update docs * sync sub package versions * rename launch.py to app.py and make run scripts work with installation package * add update scripts * auto version for root package * rename authors and update doc dir * Update auto-bump-and-release.yaml to trigger on push to main branch * latest as branch instead of tag * pin deps versions * cache the changelogs
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
# Example of MVP pipeline for _example_
|
||||
|
||||
## Prerequisite
|
||||
|
||||
To run the system out-of-the-box, please supply the following environment
|
||||
variables:
|
||||
|
||||
```
|
||||
OPENAI_API_KEY=
|
||||
OPENAI_API_BASE=
|
||||
OPENAI_API_VERSION=
|
||||
SERPAPI_API_KEY=
|
||||
COHERE_API_KEY=
|
||||
OPENAI_API_KEY_EMBEDDING=
|
||||
|
||||
# optional
|
||||
KH_APP_NAME=
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```
|
||||
gradio launch.py
|
||||
```
|
@@ -1,187 +0,0 @@
|
||||
import os
|
||||
from inspect import currentframe, getframeinfo
|
||||
from pathlib import Path
|
||||
|
||||
from decouple import config
|
||||
from theflow.settings.default import * # noqa
|
||||
|
||||
cur_frame = currentframe()
|
||||
if cur_frame is None:
|
||||
raise ValueError("Cannot get the current frame.")
|
||||
this_file = getframeinfo(cur_frame).filename
|
||||
this_dir = Path(this_file).parent
|
||||
|
||||
# App can be ran from anywhere and it's not trivial to decide where to store app data.
|
||||
# So let's use the same directory as the flowsetting.py file.
|
||||
KH_APP_DATA_DIR = this_dir / "ktem_app_data"
|
||||
KH_APP_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# User data directory
|
||||
KH_USER_DATA_DIR = KH_APP_DATA_DIR / "user_data"
|
||||
KH_USER_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# HF models can be big, let's store them in the app data directory so that it's easier
|
||||
# for users to manage their storage.
|
||||
# ref: https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache
|
||||
os.environ["HF_HOME"] = str(KH_APP_DATA_DIR / "huggingface")
|
||||
os.environ["HF_HUB_CACHE"] = str(KH_APP_DATA_DIR / "huggingface")
|
||||
|
||||
COHERE_API_KEY = config("COHERE_API_KEY", default="")
|
||||
KH_MODE = "dev"
|
||||
KH_FEATURE_USER_MANAGEMENT = False
|
||||
KH_FEATURE_USER_MANAGEMENT_ADMIN = str(
|
||||
config("KH_FEATURE_USER_MANAGEMENT_ADMIN", default="admin")
|
||||
)
|
||||
KH_FEATURE_USER_MANAGEMENT_PASSWORD = str(
|
||||
config("KH_FEATURE_USER_MANAGEMENT_PASSWORD", default="XsdMbe8zKP8KdeE@")
|
||||
)
|
||||
KH_ENABLE_ALEMBIC = False
|
||||
KH_DATABASE = f"sqlite:///{KH_USER_DATA_DIR / 'sql.db'}"
|
||||
KH_FILESTORAGE_PATH = str(KH_USER_DATA_DIR / "files")
|
||||
|
||||
KH_DOCSTORE = {
|
||||
"__type__": "kotaemon.storages.SimpleFileDocumentStore",
|
||||
"path": str(KH_USER_DATA_DIR / "docstore"),
|
||||
}
|
||||
KH_VECTORSTORE = {
|
||||
"__type__": "kotaemon.storages.ChromaVectorStore",
|
||||
"path": str(KH_USER_DATA_DIR / "vectorstore"),
|
||||
}
|
||||
KH_LLMS = {}
|
||||
KH_EMBEDDINGS = {}
|
||||
|
||||
# populate options from config
|
||||
if config("AZURE_OPENAI_API_KEY", default="") and config(
|
||||
"AZURE_OPENAI_ENDPOINT", default=""
|
||||
):
|
||||
if config("AZURE_OPENAI_CHAT_DEPLOYMENT", default=""):
|
||||
KH_LLMS["azure"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.llms.AzureChatOpenAI",
|
||||
"temperature": 0,
|
||||
"azure_endpoint": config("AZURE_OPENAI_ENDPOINT", default=""),
|
||||
"api_key": config("AZURE_OPENAI_API_KEY", default=""),
|
||||
"api_version": config("OPENAI_API_VERSION", default="")
|
||||
or "2024-02-15-preview",
|
||||
"azure_deployment": config("AZURE_OPENAI_CHAT_DEPLOYMENT", default=""),
|
||||
"timeout": 20,
|
||||
},
|
||||
"default": False,
|
||||
"accuracy": 5,
|
||||
"cost": 5,
|
||||
}
|
||||
if config("AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT", default=""):
|
||||
KH_EMBEDDINGS["azure"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.embeddings.AzureOpenAIEmbeddings",
|
||||
"azure_endpoint": config("AZURE_OPENAI_ENDPOINT", default=""),
|
||||
"api_key": config("AZURE_OPENAI_API_KEY", default=""),
|
||||
"api_version": config("OPENAI_API_VERSION", default="")
|
||||
or "2024-02-15-preview",
|
||||
"azure_deployment": config(
|
||||
"AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT", default=""
|
||||
),
|
||||
"timeout": 10,
|
||||
},
|
||||
"default": False,
|
||||
}
|
||||
|
||||
if config("OPENAI_API_KEY", default=""):
|
||||
KH_LLMS["openai"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.llms.ChatOpenAI",
|
||||
"temperature": 0,
|
||||
"base_url": config("OPENAI_API_BASE", default="")
|
||||
or "https://api.openai.com/v1",
|
||||
"api_key": config("OPENAI_API_KEY", default=""),
|
||||
"model": config("OPENAI_CHAT_MODEL", default="") or "gpt-3.5-turbo",
|
||||
"timeout": 10,
|
||||
},
|
||||
"default": False,
|
||||
}
|
||||
if len(KH_EMBEDDINGS) < 1:
|
||||
KH_EMBEDDINGS["openai"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.embeddings.OpenAIEmbeddings",
|
||||
"base_url": config("OPENAI_API_BASE", default="")
|
||||
or "https://api.openai.com/v1",
|
||||
"api_key": config("OPENAI_API_KEY", default=""),
|
||||
"model": config(
|
||||
"OPENAI_EMBEDDINGS_MODEL", default="text-embedding-ada-002"
|
||||
)
|
||||
or "text-embedding-ada-002",
|
||||
"timeout": 10,
|
||||
},
|
||||
"default": False,
|
||||
}
|
||||
|
||||
if config("LOCAL_MODEL", default=""):
|
||||
KH_LLMS["local"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.llms.EndpointChatLLM",
|
||||
"endpoint_url": "http://localhost:31415/v1/chat/completions",
|
||||
},
|
||||
"default": False,
|
||||
"cost": 0,
|
||||
}
|
||||
if len(KH_EMBEDDINGS) < 1:
|
||||
KH_EMBEDDINGS["local"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.embeddings.EndpointEmbeddings",
|
||||
"endpoint_url": "http://localhost:31415/v1/embeddings",
|
||||
},
|
||||
"default": False,
|
||||
"cost": 0,
|
||||
}
|
||||
|
||||
if len(KH_EMBEDDINGS) < 1:
|
||||
KH_EMBEDDINGS["local-bge-base-en-v1.5"] = {
|
||||
"spec": {
|
||||
"__type__": "kotaemon.embeddings.FastEmbedEmbeddings",
|
||||
"model_name": "BAAI/bge-base-en-v1.5",
|
||||
},
|
||||
"default": True,
|
||||
}
|
||||
|
||||
KH_REASONINGS = ["ktem.reasoning.simple.FullQAPipeline"]
|
||||
KH_VLM_ENDPOINT = "{0}/openai/deployments/{1}/chat/completions?api-version={2}".format(
|
||||
config("AZURE_OPENAI_ENDPOINT", default=""),
|
||||
config("OPENAI_VISION_DEPLOYMENT_NAME", default="gpt-4-vision"),
|
||||
config("OPENAI_API_VERSION", default=""),
|
||||
)
|
||||
|
||||
|
||||
SETTINGS_APP = {
|
||||
"lang": {
|
||||
"name": "Language",
|
||||
"value": "en",
|
||||
"choices": [("English", "en"), ("Japanese", "ja")],
|
||||
"component": "dropdown",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SETTINGS_REASONING = {
|
||||
"use": {
|
||||
"name": "Reasoning options",
|
||||
"value": None,
|
||||
"choices": [],
|
||||
"component": "radio",
|
||||
},
|
||||
"lang": {
|
||||
"name": "Language",
|
||||
"value": "en",
|
||||
"choices": [("English", "en"), ("Japanese", "ja")],
|
||||
"component": "dropdown",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
KH_INDEX_TYPES = ["ktem.index.file.FileIndex"]
|
||||
KH_INDICES = [
|
||||
{
|
||||
"name": "File",
|
||||
"config": {},
|
||||
"index_type": "ktem.index.file.FileIndex",
|
||||
},
|
||||
]
|
@@ -1,25 +1,83 @@
|
||||
from importlib.metadata import version
|
||||
from pathlib import Path
|
||||
|
||||
import gradio as gr
|
||||
import requests
|
||||
from theflow.settings import settings
|
||||
|
||||
CHANGELOG_CACHE_DIR = Path(settings.KH_APP_DATA_DIR) / "changelogs"
|
||||
|
||||
|
||||
def get_remote_doc(url):
|
||||
try:
|
||||
res = requests.get(url)
|
||||
return res.text
|
||||
except Exception as e:
|
||||
print(f"Failed to fetch document from {url}: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def get_changelogs(version):
|
||||
# try retrieve from cache
|
||||
if (CHANGELOG_CACHE_DIR / f"{version}.md").exists():
|
||||
with open(CHANGELOG_CACHE_DIR / f"{version}.md", "r") as fi:
|
||||
return fi.read()
|
||||
|
||||
release_url = f"https://api.github.com/repos/Cinnamon/kotaemon/releases/{version}"
|
||||
try:
|
||||
res = requests.get(release_url).json()
|
||||
changelogs = res.get("body", "")
|
||||
|
||||
# cache the changelogs
|
||||
with open(CHANGELOG_CACHE_DIR / f"{version}.md", "w") as fi:
|
||||
fi.write(changelogs)
|
||||
|
||||
return changelogs
|
||||
except Exception as e:
|
||||
print(f"Failed to fetch changelogs from {release_url}: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
class HelpPage:
|
||||
def __init__(self, app):
|
||||
self._app = app
|
||||
self.md_dir = Path(__file__).parent.parent / "assets" / "md"
|
||||
self.doc_dir = Path(__file__).parents[4] / "docs"
|
||||
self.doc_dir = Path(settings.KH_DOC_DIR)
|
||||
self.remote_content_url = "https://raw.githubusercontent.com/Cinnamon/kotaemon"
|
||||
|
||||
with gr.Accordion("About"):
|
||||
with (self.md_dir / "about.md").open(encoding="utf-8") as fi:
|
||||
gr.Markdown(fi.read())
|
||||
self.app_version = None
|
||||
try:
|
||||
# Caution: This might produce the wrong version
|
||||
# https://stackoverflow.com/a/59533071
|
||||
self.app_version = version(settings.KH_PACKAGE_NAME)
|
||||
except Exception as e:
|
||||
print(f"Failed to get app version: {e}")
|
||||
|
||||
with gr.Accordion("User Guide"):
|
||||
about_md_dir = self.doc_dir / "about.md"
|
||||
if about_md_dir.exists():
|
||||
with (self.doc_dir / "about.md").open(encoding="utf-8") as fi:
|
||||
about_md = fi.read()
|
||||
else: # fetch from remote
|
||||
about_md = get_remote_doc(
|
||||
f"{self.remote_content_url}/v{self.app_version}/docs/about.md"
|
||||
)
|
||||
if about_md:
|
||||
with gr.Accordion("About"):
|
||||
gr.Markdown(about_md)
|
||||
|
||||
user_guide_md_dir = self.doc_dir / "usage.md"
|
||||
if user_guide_md_dir.exists():
|
||||
with (self.doc_dir / "usage.md").open(encoding="utf-8") as fi:
|
||||
gr.Markdown(fi.read())
|
||||
user_guide_md = fi.read()
|
||||
else: # fetch from remote
|
||||
user_guide_md = get_remote_doc(
|
||||
f"{self.remote_content_url}/v{self.app_version}/docs/usage.md"
|
||||
)
|
||||
if user_guide_md:
|
||||
with gr.Accordion("User Guide"):
|
||||
gr.Markdown(user_guide_md)
|
||||
|
||||
with gr.Accordion("Changelogs"):
|
||||
gr.Markdown(self.get_changelogs())
|
||||
|
||||
def get_changelogs(self):
|
||||
with (self.md_dir / "changelogs.md").open(encoding="utf-8") as fi:
|
||||
return fi.read()
|
||||
if self.app_version:
|
||||
changelogs = get_changelogs("tags/v" + self.app_version)
|
||||
if changelogs:
|
||||
with gr.Accordion(f"Changelogs (v{self.app_version})"):
|
||||
gr.Markdown(changelogs)
|
||||
|
@@ -1,5 +0,0 @@
|
||||
from ktem.main import App
|
||||
|
||||
app = App()
|
||||
demo = app.make()
|
||||
demo.queue().launch(favicon_path=app._favicon, inbrowser=True)
|
@@ -1,37 +1,41 @@
|
||||
[build-system]
|
||||
requires = ["setuptools >= 61.0"]
|
||||
requires = ["setuptools >= 61.0", "wheel", "setuptools-git-versioning>=2.0,<3"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools]
|
||||
include-package-data = true
|
||||
packages.find.exclude = ["ktem_tests*", "env*"]
|
||||
packages.find.include = ["ktem*"]
|
||||
packages.find.exclude = ["tests*", "env*"]
|
||||
|
||||
[tool.setuptools-git-versioning]
|
||||
enabled = true
|
||||
dev_template = "{tag}"
|
||||
dirty_template = "{tag}"
|
||||
tag_filter = "v?\\d+(\\.\\d+)*.*"
|
||||
|
||||
[project]
|
||||
name = "ktem"
|
||||
version = "0.2.0"
|
||||
dynamic = ["version"]
|
||||
requires-python = ">= 3.10"
|
||||
description = "RAG-based Question and Answering Application"
|
||||
dependencies = [
|
||||
"click",
|
||||
"platformdirs",
|
||||
"pluggy",
|
||||
"python-decouple",
|
||||
"sqlalchemy",
|
||||
"sqlmodel",
|
||||
"tiktoken",
|
||||
"gradio>=4.26.0",
|
||||
"markdown",
|
||||
"click>=8.1.7,<9",
|
||||
"platformdirs>=4.2.1,<5",
|
||||
"pluggy>=1.5.0,<2",
|
||||
"python-decouple>=3.8,<4",
|
||||
"SQLAlchemy>=2.0.29,<3",
|
||||
"sqlmodel>=0.0.16,<0.1",
|
||||
"tiktoken>=0.6.0<1",
|
||||
"gradio>=4.26.0,<5",
|
||||
"markdown>=3.6,<4",
|
||||
]
|
||||
readme = "README.md"
|
||||
license = { text = "MIT License" }
|
||||
authors = [
|
||||
{ name = "john", email = "john@cinnamon.is" },
|
||||
{ name = "ian", email = "ian@cinnamon.is" },
|
||||
{ name = "tadashi", email = "tadashi@cinnamon.is" },
|
||||
{ name = "@trducng", email = "john@cinnamon.is" },
|
||||
{ name = "@lone17", email = "ian@cinnamon.is" },
|
||||
{ name = "@taprosoft", email = "tadashi@cinnamon.is" },
|
||||
{ name = "@cin-albert", email = "albert@cinnamon.is" },
|
||||
]
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
|
Reference in New Issue
Block a user