diona 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diona-0.0.0/PKG-INFO +44 -0
- diona-0.0.0/README.md +23 -0
- diona-0.0.0/pyproject.toml +36 -0
- diona-0.0.0/setup.cfg +4 -0
- diona-0.0.0/src/diona/__init__.py +5 -0
- diona-0.0.0/src/diona/ai/client/base/__init__.py +19 -0
- diona-0.0.0/src/diona/ai/client/base/base.py +224 -0
- diona-0.0.0/src/diona/ai/client/base/base_ai_config.py +53 -0
- diona-0.0.0/src/diona/ai/client/base/base_chat.py +70 -0
- diona-0.0.0/src/diona/ai/client/base/base_chat_history.py +21 -0
- diona-0.0.0/src/diona/ai/client/base/base_client.py +85 -0
- diona-0.0.0/src/diona/ai/client/base/client_config.py +34 -0
- diona-0.0.0/src/diona/ai/client/base/interactive.py +25 -0
- diona-0.0.0/src/diona/ai/client/base/message.py +40 -0
- diona-0.0.0/src/diona/ai/client/simplecli/__init__.py +6 -0
- diona-0.0.0/src/diona/ai/client/simplecli/agent/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/agent/parser.py +51 -0
- diona-0.0.0/src/diona/ai/client/simplecli/agent/prompt.py +43 -0
- diona-0.0.0/src/diona/ai/client/simplecli/agent/system.py +124 -0
- diona-0.0.0/src/diona/ai/client/simplecli/command.py +36 -0
- diona-0.0.0/src/diona/ai/client/simplecli/config.py +143 -0
- diona-0.0.0/src/diona/ai/client/simplecli/core/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/core/command.py +151 -0
- diona-0.0.0/src/diona/ai/client/simplecli/core/engine.py +130 -0
- diona-0.0.0/src/diona/ai/client/simplecli/main.py +115 -0
- diona-0.0.0/src/diona/ai/client/simplecli/models.py +74 -0
- diona-0.0.0/src/diona/ai/client/simplecli/providers/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/providers/openai.py +161 -0
- diona-0.0.0/src/diona/ai/client/simplecli/session/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/session/manager.py +229 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/filesystem.py +178 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/git.py +185 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/manager.py +107 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/shell.py +84 -0
- diona-0.0.0/src/diona/ai/client/simplecli/tools/websearch.py +98 -0
- diona-0.0.0/src/diona/ai/client/simplecli/ui/__init__.py +1 -0
- diona-0.0.0/src/diona/ai/client/simplecli/ui/console.py +171 -0
- diona-0.0.0/src/diona/ai/client/simplecli/ui/styles.py +46 -0
- diona-0.0.0/src/diona/ai/fakemodel/__init__.py +4 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/FakeModel.py +58 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/FakeModelExpander.py +65 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/__init__.py +6 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/analyzer.py +47 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/corpus/__init__.py +0 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/corpus/manager.py +23 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/generation/__init__.py +0 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/generation/generator.py +17 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/intent/__init__.py +0 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/intent/classifier.py +40 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/io/__init__.py +0 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/io/input_processor.py +16 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/io/output_formatter.py +10 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/loader.py +47 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/models/__init__.py +0 -0
- diona-0.0.0/src/diona/ai/fakemodel/core/models/data_models.py +13 -0
- diona-0.0.0/src/diona/ai/fakemodel/defaultfakemodel.py +20 -0
- diona-0.0.0/src/diona/ai/fakemodel/models/Ganyu/fakemodelconfig.py +816 -0
- diona-0.0.0/src/diona/ai/fakemodel/models/Ganyu2/fakemodelconfig.py +2376 -0
- diona-0.0.0/src/diona/ai/fakemodel/models/default/fakemodelconfig.py +1540 -0
- diona-0.0.0/src/diona/ai/fakemodel/registry/__init__.py +3 -0
- diona-0.0.0/src/diona/ai/fakemodel/registry/registry.py +65 -0
- diona-0.0.0/src/diona/firstmeet/__init__.py +3 -0
- diona-0.0.0/src/diona/firstmeet/hello.py +2 -0
- diona-0.0.0/src/diona/project/__init__.py +5 -0
- diona-0.0.0/src/diona/project/bus/__init__.py +10 -0
- diona-0.0.0/src/diona/project/bus/bus.py +185 -0
- diona-0.0.0/src/diona/project/bus/interfaces.py +31 -0
- diona-0.0.0/src/diona/project/bus/message.py +54 -0
- diona-0.0.0/src/diona/project/cli/__init__.py +5 -0
- diona-0.0.0/src/diona/project/cli/builtin/__init__.py +9 -0
- diona-0.0.0/src/diona/project/cli/builtin/base.py +15 -0
- diona-0.0.0/src/diona/project/cli/builtin/date.py +20 -0
- diona-0.0.0/src/diona/project/cli/builtin/exit.py +17 -0
- diona-0.0.0/src/diona/project/cli/builtin/help.py +29 -0
- diona-0.0.0/src/diona/project/cli/builtin/list_commands.py +31 -0
- diona-0.0.0/src/diona/project/cli/builtin/time.py +20 -0
- diona-0.0.0/src/diona/project/cli/core/__init__.py +0 -0
- diona-0.0.0/src/diona/project/cli/core/command.py +36 -0
- diona-0.0.0/src/diona/project/cli/core/core.py +100 -0
- diona-0.0.0/src/diona/project/cli/core/task.py +127 -0
- diona-0.0.0/src/diona/project/cli/run.py +8 -0
- diona-0.0.0/src/diona/project/cli/ui/__init__.py +3 -0
- diona-0.0.0/src/diona/project/cli/ui/ui.py +33 -0
- diona-0.0.0/src/diona/project/command/__init__.py +7 -0
- diona-0.0.0/src/diona/project/command/alias.py +7 -0
- diona-0.0.0/src/diona/project/command/command_manager.py +105 -0
- diona-0.0.0/src/diona/project/command/models.py +37 -0
- diona-0.0.0/src/diona/project/command/registry.py +77 -0
- diona-0.0.0/src/diona/project/diona/__init__.py +5 -0
- diona-0.0.0/src/diona/project/diona/main.py +42 -0
- diona-0.0.0/src/diona/project/log/__init__.py +3 -0
- diona-0.0.0/src/diona/project/log/logger.py +61 -0
- diona-0.0.0/src/diona/project/scheduler/__init__.py +13 -0
- diona-0.0.0/src/diona/project/scheduler/executor.py +89 -0
- diona-0.0.0/src/diona/project/scheduler/interfaces.py +131 -0
- diona-0.0.0/src/diona/project/scheduler/manager.py +84 -0
- diona-0.0.0/src/diona/project/scheduler/scheduler.py +49 -0
- diona-0.0.0/src/diona/project/scheduler/task.py +90 -0
- diona-0.0.0/src/diona/project/shell/__init__.py +5 -0
- diona-0.0.0/src/diona/project/shell/config.py +25 -0
- diona-0.0.0/src/diona/project/shell/shell.py +228 -0
- diona-0.0.0/src/diona/project/storage/__init__.py +5 -0
- diona-0.0.0/src/diona/project/storage/cache.py +221 -0
- diona-0.0.0/src/diona/project/storage/interfaces.py +63 -0
- diona-0.0.0/src/diona/project/storage/storage.py +132 -0
- diona-0.0.0/src/diona/storage/hashfs/__init__.py +3 -0
- diona-0.0.0/src/diona/system/__init__.py +0 -0
- diona-0.0.0/src/diona/system/sensitive/__init__.py +0 -0
- diona-0.0.0/src/diona/system/sensitive/browser/__init__.py +15 -0
- diona-0.0.0/src/diona/system/sensitive/browser/cookies/__init__.py +9 -0
- diona-0.0.0/src/diona/system/sensitive/browser/cookies/base.py +35 -0
- diona-0.0.0/src/diona/system/sensitive/browser/cookies/chrome.py +125 -0
- diona-0.0.0/src/diona/system/sensitive/browser/cookies/edge.py +133 -0
- diona-0.0.0/src/diona/system/sensitive/browser/history/__init__.py +9 -0
- diona-0.0.0/src/diona/system/sensitive/browser/history/base.py +35 -0
- diona-0.0.0/src/diona/system/sensitive/browser/history/chrome.py +117 -0
- diona-0.0.0/src/diona/system/sensitive/browser/history/edge.py +125 -0
- diona-0.0.0/src/diona/system/sensitive/browser/logindata/__init__.py +9 -0
- diona-0.0.0/src/diona/system/sensitive/browser/logindata/base.py +35 -0
- diona-0.0.0/src/diona/system/sensitive/browser/logindata/chrome.py +141 -0
- diona-0.0.0/src/diona/system/sensitive/browser/logindata/edge.py +141 -0
- diona-0.0.0/src/diona/system/sensitive/browser/models/__init__.py +13 -0
- diona-0.0.0/src/diona/system/sensitive/browser/models/cookies.py +77 -0
- diona-0.0.0/src/diona/system/sensitive/browser/models/history.py +57 -0
- diona-0.0.0/src/diona/system/sensitive/browser/models/logindata.py +72 -0
- diona-0.0.0/src/diona/system/sensitive/core/__init__.py +7 -0
- diona-0.0.0/src/diona/system/sensitive/core/info_store.py +75 -0
- diona-0.0.0/src/diona/system/sensitive/info/NetworkConfigInfo.py +30 -0
- diona-0.0.0/src/diona/system/sensitive/info/NetworkConfigInfoImpl.py +216 -0
- diona-0.0.0/src/diona/system/sensitive/info/SystemVersionInfo.py +31 -0
- diona-0.0.0/src/diona/system/sensitive/info/SystemVersionInfoImpl.py +214 -0
- diona-0.0.0/src/diona/system/sensitive/info/WirelessNetworkInfo.py +30 -0
- diona-0.0.0/src/diona/system/sensitive/info/WirelessNetworkInfoImpl.py +181 -0
- diona-0.0.0/src/diona/system/sensitive/info/__init__.py +20 -0
- diona-0.0.0/src/diona/system/sensitive/info/constants/NetworkConfigInfoConstants.py +55 -0
- diona-0.0.0/src/diona/system/sensitive/info/constants/SystemVersionInfoConstants.py +53 -0
- diona-0.0.0/src/diona/system/sensitive/info/constants/WirelessNetworkInfoConstants.py +33 -0
- diona-0.0.0/src/diona/system/sensitive/info/models/NetworkConfigInfo.py +54 -0
- diona-0.0.0/src/diona/system/sensitive/info/models/SystemVersionInfo.py +78 -0
- diona-0.0.0/src/diona/system/sensitive/info/models/WirelessNetworkInfo.py +23 -0
- diona-0.0.0/src/diona/system/sensitive/runcontext/__init__.py +21 -0
- diona-0.0.0/src/diona/system/sensitive/runcontext/constants.py +45 -0
- diona-0.0.0/src/diona/system/sensitive/runcontext/context.py +111 -0
- diona-0.0.0/src/diona/system/sensitive/runcontext/models.py +35 -0
- diona-0.0.0/src/diona/system/sensitive/runcontext/utils.py +83 -0
- diona-0.0.0/src/diona/tools/__init__.py +1 -0
- diona-0.0.0/src/diona/tools/crawler/__init__.py +1 -0
- diona-0.0.0/src/diona/tools/crawler/base_spider.py +320 -0
- diona-0.0.0/src/diona/tools/crawler/cookie_manager.py +124 -0
- diona-0.0.0/src/diona/tools/crawler/models.py +66 -0
- diona-0.0.0/src/diona/tools/crawler/zhihu/__init__.py +3 -0
- diona-0.0.0/src/diona/tools/crawler/zhihu/models.py +43 -0
- diona-0.0.0/src/diona/tools/crawler/zhihu/zhihu_spider.py +453 -0
- diona-0.0.0/src/diona/tools/fakedelete/__init__.py +5 -0
- diona-0.0.0/src/diona/tools/fakedelete/command.py +60 -0
- diona-0.0.0/src/diona/tools/fakedelete/constants.py +11 -0
- diona-0.0.0/src/diona/tools/fakedelete/processor.py +45 -0
- diona-0.0.0/src/diona/tools/fakedelete/queue.py +73 -0
- diona-0.0.0/src/diona/tools/fakedelete/scanner.py +87 -0
- diona-0.0.0/src/diona/tools/fakeinstall/__init__.py +5 -0
- diona-0.0.0/src/diona/tools/fakeinstall/command.py +125 -0
- diona-0.0.0/src/diona/tools/fakeinstall/config.py +86 -0
- diona-0.0.0/src/diona/tools/fakeinstall/constants.py +149 -0
- diona-0.0.0/src/diona/tools/fakeinstall/executor.py +115 -0
- diona-0.0.0/src/diona/tools/fakeinstall/generator.py +94 -0
- diona-0.0.0/src/diona/tools/fakeinstall/models.py +13 -0
- diona-0.0.0/src/diona/tools/fakeinstall/utils.py +34 -0
- diona-0.0.0/src/diona/tools/program/__init__.py +7 -0
- diona-0.0.0/src/diona/tools/program/command.py +187 -0
- diona-0.0.0/src/diona/tools/program/file_time_modifier.py +294 -0
- diona-0.0.0/src/diona.egg-info/PKG-INFO +44 -0
- diona-0.0.0/src/diona.egg-info/SOURCES.txt +175 -0
- diona-0.0.0/src/diona.egg-info/dependency_links.txt +1 -0
- diona-0.0.0/src/diona.egg-info/entry_points.txt +2 -0
- diona-0.0.0/src/diona.egg-info/requires.txt +10 -0
- diona-0.0.0/src/diona.egg-info/top_level.txt +1 -0
diona-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: diona
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: A Python package named diona
|
|
5
|
+
Project-URL: Homepage, https://github.com/yourusername/diona
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: openai
|
|
12
|
+
Requires-Dist: pyyaml
|
|
13
|
+
Requires-Dist: python-dotenv
|
|
14
|
+
Requires-Dist: playwright
|
|
15
|
+
Requires-Dist: beautifulsoup4
|
|
16
|
+
Requires-Dist: rich
|
|
17
|
+
Requires-Dist: typer
|
|
18
|
+
Requires-Dist: GitPython
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Requires-Dist: jieba
|
|
21
|
+
|
|
22
|
+
# diona
|
|
23
|
+
|
|
24
|
+
A Python package named diona.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install diona
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import diona
|
|
36
|
+
|
|
37
|
+
print(diona.__version__)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Development
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install -e .
|
|
44
|
+
```
|
diona-0.0.0/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# diona
|
|
2
|
+
|
|
3
|
+
A Python package named diona.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install diona
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import diona
|
|
15
|
+
|
|
16
|
+
print(diona.__version__)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Development
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install -e .
|
|
23
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "diona"
|
|
7
|
+
version = "0.0.0"
|
|
8
|
+
description = "A Python package named diona"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"openai",
|
|
18
|
+
"pyyaml",
|
|
19
|
+
"python-dotenv",
|
|
20
|
+
"playwright",
|
|
21
|
+
"beautifulsoup4",
|
|
22
|
+
"rich",
|
|
23
|
+
"typer",
|
|
24
|
+
"GitPython",
|
|
25
|
+
"requests",
|
|
26
|
+
"jieba"
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/yourusername/diona"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
diona = "diona.project.diona.main:main"
|
diona-0.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .base_ai_config import BaseAIConfig
|
|
2
|
+
from .base_chat import BaseChat
|
|
3
|
+
from .base_chat_history import BaseChatHistory
|
|
4
|
+
from .client_config import ClientConfig
|
|
5
|
+
from .base_client import BaseClient
|
|
6
|
+
from .message import SingleChatMessage, ChatMessage, StreamingChatMessage
|
|
7
|
+
from .interactive import interactive_chat
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'BaseAIConfig',
|
|
11
|
+
'BaseChat',
|
|
12
|
+
'BaseChatHistory',
|
|
13
|
+
'ClientConfig',
|
|
14
|
+
'BaseClient',
|
|
15
|
+
'SingleChatMessage',
|
|
16
|
+
'ChatMessage',
|
|
17
|
+
'StreamingChatMessage',
|
|
18
|
+
'interactive_chat'
|
|
19
|
+
]
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import yaml
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
from openai import OpenAI
|
|
5
|
+
|
|
6
|
+
class BaseAIConfig:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
load_dotenv()
|
|
9
|
+
self.config = self._load_config()
|
|
10
|
+
self.base_url = self._get_config_value('diona.ai.modelset.base-url')
|
|
11
|
+
self.api_key = self._get_api_key()
|
|
12
|
+
self.model = self._get_config_value('diona.ai.modelset.model')
|
|
13
|
+
self.proxy = self._get_config_value('diona.ai.clientset.proxy', False)
|
|
14
|
+
self.use_proxy = self._get_config_value('diona.ai.clientset.use-proxy', False)
|
|
15
|
+
|
|
16
|
+
def _load_config(self):
|
|
17
|
+
config_path = os.path.join(os.getcwd(), 'config.yml')
|
|
18
|
+
if os.path.exists(config_path):
|
|
19
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
20
|
+
return yaml.safe_load(f)
|
|
21
|
+
return {}
|
|
22
|
+
|
|
23
|
+
def _get_config_value(self, key, default=None):
|
|
24
|
+
keys = key.split('.')
|
|
25
|
+
value = self.config
|
|
26
|
+
for k in keys:
|
|
27
|
+
if isinstance(value, dict) and k in value:
|
|
28
|
+
value = value[k]
|
|
29
|
+
else:
|
|
30
|
+
return default
|
|
31
|
+
return value
|
|
32
|
+
|
|
33
|
+
def _get_api_key(self):
|
|
34
|
+
# Priority: 1. Environment variable 2. .env file 3. config.yml
|
|
35
|
+
api_key = os.environ.get('OPENAI_API_KEY')
|
|
36
|
+
if api_key:
|
|
37
|
+
return api_key
|
|
38
|
+
api_key = self._get_config_value('diona.ai.modelset.api-key')
|
|
39
|
+
return api_key
|
|
40
|
+
|
|
41
|
+
def get_base_url(self):
|
|
42
|
+
return self.base_url
|
|
43
|
+
|
|
44
|
+
def get_api_key(self):
|
|
45
|
+
return self.api_key
|
|
46
|
+
|
|
47
|
+
def get_model(self):
|
|
48
|
+
return self.model
|
|
49
|
+
|
|
50
|
+
def get_proxy(self):
|
|
51
|
+
return self.proxy
|
|
52
|
+
|
|
53
|
+
def is_use_proxy(self):
|
|
54
|
+
return self.use_proxy
|
|
55
|
+
|
|
56
|
+
class BaseChat:
|
|
57
|
+
def __init__(self, config):
|
|
58
|
+
self.config = config
|
|
59
|
+
self.client = self._create_client()
|
|
60
|
+
|
|
61
|
+
def _create_client(self):
|
|
62
|
+
kwargs = {
|
|
63
|
+
'api_key': self.config.get_api_key(),
|
|
64
|
+
'base_url': self.config.get_base_url()
|
|
65
|
+
}
|
|
66
|
+
if self.config.is_use_proxy() and self.config.get_proxy():
|
|
67
|
+
kwargs['http_client'] = {
|
|
68
|
+
'proxy': self.config.get_proxy()
|
|
69
|
+
}
|
|
70
|
+
return OpenAI(**kwargs)
|
|
71
|
+
|
|
72
|
+
def chat(self, chat_message):
|
|
73
|
+
response = self.client.chat.completions.create(
|
|
74
|
+
model=self.config.get_model(),
|
|
75
|
+
messages=chat_message.to_ai_messages()
|
|
76
|
+
)
|
|
77
|
+
ai_response = response.choices[0].message
|
|
78
|
+
metadata = {
|
|
79
|
+
'id': response.id,
|
|
80
|
+
'created': response.created,
|
|
81
|
+
'model': response.model,
|
|
82
|
+
'usage': {
|
|
83
|
+
'prompt_tokens': response.usage.prompt_tokens,
|
|
84
|
+
'completion_tokens': response.usage.completion_tokens,
|
|
85
|
+
'total_tokens': response.usage.total_tokens
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return SingleChatMessage(ai_response.role, ai_response.content, metadata)
|
|
89
|
+
|
|
90
|
+
class SingleChatMessage:
|
|
91
|
+
def __init__(self, role, content, metadata=None):
|
|
92
|
+
self.role = role
|
|
93
|
+
self.content = content
|
|
94
|
+
self.metadata = metadata or {}
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_text(cls, text, role='user'):
|
|
98
|
+
return cls(role, text)
|
|
99
|
+
|
|
100
|
+
def to_ai_message(self):
|
|
101
|
+
return {
|
|
102
|
+
'role': self.role,
|
|
103
|
+
'content': self.content
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class BaseChatHistory:
|
|
107
|
+
def __init__(self, max_messages=6):
|
|
108
|
+
self.max_messages = max_messages
|
|
109
|
+
self.messages = []
|
|
110
|
+
|
|
111
|
+
def add_message(self, message):
|
|
112
|
+
self.messages.append(message)
|
|
113
|
+
if len(self.messages) > self.max_messages:
|
|
114
|
+
self.messages.pop(0)
|
|
115
|
+
|
|
116
|
+
def get_messages(self):
|
|
117
|
+
return self.messages
|
|
118
|
+
|
|
119
|
+
def get_chat_message(self):
|
|
120
|
+
return ChatMessage(self.messages)
|
|
121
|
+
|
|
122
|
+
def persist(self):
|
|
123
|
+
# To be implemented by subclass
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
class ClientConfig:
|
|
127
|
+
def __init__(self):
|
|
128
|
+
self.config = self._load_config()
|
|
129
|
+
self.prompt_path = self._get_config_value('diona.ai.clientset.prompt')
|
|
130
|
+
self.system_prompt = self._load_system_prompt()
|
|
131
|
+
|
|
132
|
+
def _load_config(self):
|
|
133
|
+
config_path = os.path.join(os.getcwd(), 'config.yml')
|
|
134
|
+
if os.path.exists(config_path):
|
|
135
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
136
|
+
return yaml.safe_load(f)
|
|
137
|
+
return {}
|
|
138
|
+
|
|
139
|
+
def _get_config_value(self, key, default=None):
|
|
140
|
+
keys = key.split('.')
|
|
141
|
+
value = self.config
|
|
142
|
+
for k in keys:
|
|
143
|
+
if isinstance(value, dict) and k in value:
|
|
144
|
+
value = value[k]
|
|
145
|
+
else:
|
|
146
|
+
return default
|
|
147
|
+
return value
|
|
148
|
+
|
|
149
|
+
def _load_system_prompt(self):
|
|
150
|
+
if self.prompt_path and os.path.exists(self.prompt_path):
|
|
151
|
+
with open(self.prompt_path, 'r', encoding='utf-8') as f:
|
|
152
|
+
return f.read().strip()
|
|
153
|
+
return "You are a helpful assistant"
|
|
154
|
+
|
|
155
|
+
def get_system_prompt(self):
|
|
156
|
+
return self.system_prompt
|
|
157
|
+
|
|
158
|
+
class BaseClient:
|
|
159
|
+
def __init__(self, base_chat, base_chat_history, client_config):
|
|
160
|
+
self.base_chat = base_chat
|
|
161
|
+
self.base_chat_history = base_chat_history
|
|
162
|
+
self.client_config = client_config
|
|
163
|
+
self.session_map = {}
|
|
164
|
+
|
|
165
|
+
def chat(self, session_id, user_input):
|
|
166
|
+
if isinstance(user_input, str):
|
|
167
|
+
user_message = SingleChatMessage.from_text(user_input, 'user')
|
|
168
|
+
else:
|
|
169
|
+
user_message = user_input
|
|
170
|
+
|
|
171
|
+
if session_id not in self.session_map:
|
|
172
|
+
self.session_map[session_id] = BaseChatHistory()
|
|
173
|
+
|
|
174
|
+
chat_history = self.session_map[session_id]
|
|
175
|
+
chat_history.add_message(user_message)
|
|
176
|
+
|
|
177
|
+
# Get current messages and add system prompt
|
|
178
|
+
current_messages = chat_history.get_messages()
|
|
179
|
+
system_prompt = self.client_config.get_system_prompt()
|
|
180
|
+
system_message = SingleChatMessage('system', system_prompt)
|
|
181
|
+
|
|
182
|
+
# Create chat message with system prompt at the beginning
|
|
183
|
+
messages_with_system = [system_message] + current_messages
|
|
184
|
+
chat_message = ChatMessage(messages_with_system)
|
|
185
|
+
|
|
186
|
+
# Get AI response
|
|
187
|
+
ai_response = self.base_chat.chat(chat_message)
|
|
188
|
+
|
|
189
|
+
# Add AI response to history
|
|
190
|
+
chat_history.add_message(ai_response)
|
|
191
|
+
|
|
192
|
+
return ai_response
|
|
193
|
+
|
|
194
|
+
@classmethod
|
|
195
|
+
def create(cls):
|
|
196
|
+
ai_config = BaseAIConfig()
|
|
197
|
+
base_chat = BaseChat(ai_config)
|
|
198
|
+
base_chat_history = BaseChatHistory()
|
|
199
|
+
client_config = ClientConfig()
|
|
200
|
+
return cls(base_chat, base_chat_history, client_config)
|
|
201
|
+
|
|
202
|
+
class ChatMessage:
|
|
203
|
+
def __init__(self, messages):
|
|
204
|
+
self.messages = messages
|
|
205
|
+
|
|
206
|
+
def to_ai_messages(self):
|
|
207
|
+
return [msg.to_ai_message() for msg in self.messages]
|
|
208
|
+
|
|
209
|
+
def interactive_chat():
|
|
210
|
+
client = BaseClient.create()
|
|
211
|
+
session_id = "default"
|
|
212
|
+
|
|
213
|
+
print("Welcome to Diona AI Chat!")
|
|
214
|
+
print("Type 'exit' to quit.")
|
|
215
|
+
|
|
216
|
+
while True:
|
|
217
|
+
user_input = input("<diona@user> ")
|
|
218
|
+
if user_input.strip().lower() == "exit":
|
|
219
|
+
print("Goodbye!")
|
|
220
|
+
break
|
|
221
|
+
|
|
222
|
+
response = client.chat(session_id, user_input)
|
|
223
|
+
print(f"<@assistant> {response.content}")
|
|
224
|
+
print()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import yaml
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
class BaseAIConfig:
|
|
6
|
+
def __init__(self):
|
|
7
|
+
load_dotenv()
|
|
8
|
+
self.config = self._load_config()
|
|
9
|
+
self.base_url = self._get_config_value('diona.ai.modelset.base-url')
|
|
10
|
+
self.api_key = self._get_api_key()
|
|
11
|
+
self.model = self._get_config_value('diona.ai.modelset.model')
|
|
12
|
+
self.proxy = self._get_config_value('diona.ai.clientset.proxy', False)
|
|
13
|
+
self.use_proxy = self._get_config_value('diona.ai.clientset.use-proxy', False)
|
|
14
|
+
|
|
15
|
+
def _load_config(self):
|
|
16
|
+
config_path = os.path.join(os.getcwd(), 'config.yml')
|
|
17
|
+
if os.path.exists(config_path):
|
|
18
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
19
|
+
return yaml.safe_load(f)
|
|
20
|
+
return {}
|
|
21
|
+
|
|
22
|
+
def _get_config_value(self, key, default=None):
|
|
23
|
+
keys = key.split('.')
|
|
24
|
+
value = self.config
|
|
25
|
+
for k in keys:
|
|
26
|
+
if isinstance(value, dict) and k in value:
|
|
27
|
+
value = value[k]
|
|
28
|
+
else:
|
|
29
|
+
return default
|
|
30
|
+
return value
|
|
31
|
+
|
|
32
|
+
def _get_api_key(self):
|
|
33
|
+
# Priority: 1. Environment variable 2. .env file 3. config.yml
|
|
34
|
+
api_key = os.environ.get('OPENAI_API_KEY')
|
|
35
|
+
if api_key:
|
|
36
|
+
return api_key
|
|
37
|
+
api_key = self._get_config_value('diona.ai.modelset.api-key')
|
|
38
|
+
return api_key
|
|
39
|
+
|
|
40
|
+
def get_base_url(self):
|
|
41
|
+
return self.base_url
|
|
42
|
+
|
|
43
|
+
def get_api_key(self):
|
|
44
|
+
return self.api_key
|
|
45
|
+
|
|
46
|
+
def get_model(self):
|
|
47
|
+
return self.model
|
|
48
|
+
|
|
49
|
+
def get_proxy(self):
|
|
50
|
+
return self.proxy
|
|
51
|
+
|
|
52
|
+
def is_use_proxy(self):
|
|
53
|
+
return self.use_proxy
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from openai import OpenAI
|
|
2
|
+
from .message import SingleChatMessage
|
|
3
|
+
|
|
4
|
+
class BaseChat:
|
|
5
|
+
def __init__(self, config):
|
|
6
|
+
self.config = config
|
|
7
|
+
self.client = self._create_client()
|
|
8
|
+
|
|
9
|
+
def _create_client(self):
|
|
10
|
+
kwargs = {
|
|
11
|
+
'api_key': self.config.get_api_key(),
|
|
12
|
+
'base_url': self.config.get_base_url()
|
|
13
|
+
}
|
|
14
|
+
if self.config.is_use_proxy() and self.config.get_proxy():
|
|
15
|
+
kwargs['proxy'] = self.config.get_proxy()
|
|
16
|
+
return OpenAI(**kwargs)
|
|
17
|
+
|
|
18
|
+
def chat(self, chat_message):
|
|
19
|
+
response = self.client.chat.completions.create(
|
|
20
|
+
model=self.config.get_model(),
|
|
21
|
+
messages=chat_message.to_ai_messages()
|
|
22
|
+
)
|
|
23
|
+
ai_response = response.choices[0].message
|
|
24
|
+
metadata = {
|
|
25
|
+
'id': response.id,
|
|
26
|
+
'created': response.created,
|
|
27
|
+
'model': response.model,
|
|
28
|
+
'usage': {
|
|
29
|
+
'prompt_tokens': response.usage.prompt_tokens,
|
|
30
|
+
'completion_tokens': response.usage.completion_tokens,
|
|
31
|
+
'total_tokens': response.usage.total_tokens
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return SingleChatMessage(ai_response.role, ai_response.content, metadata)
|
|
35
|
+
|
|
36
|
+
def chat_stream(self, chat_message):
|
|
37
|
+
response = self.client.chat.completions.create(
|
|
38
|
+
model=self.config.get_model(),
|
|
39
|
+
messages=chat_message.to_ai_messages(),
|
|
40
|
+
stream=True
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
full_content = ""
|
|
44
|
+
role = None
|
|
45
|
+
metadata = {
|
|
46
|
+
'id': None,
|
|
47
|
+
'created': None,
|
|
48
|
+
'model': None
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for chunk in response:
|
|
52
|
+
if chunk.choices:
|
|
53
|
+
choice = chunk.choices[0]
|
|
54
|
+
if choice.delta:
|
|
55
|
+
if choice.delta.role:
|
|
56
|
+
role = choice.delta.role
|
|
57
|
+
if choice.delta.content:
|
|
58
|
+
content_chunk = choice.delta.content
|
|
59
|
+
full_content += content_chunk
|
|
60
|
+
yield content_chunk
|
|
61
|
+
|
|
62
|
+
# Capture metadata from the first chunk
|
|
63
|
+
if not metadata['id']:
|
|
64
|
+
metadata['id'] = chunk.id
|
|
65
|
+
metadata['created'] = chunk.created
|
|
66
|
+
metadata['model'] = chunk.model
|
|
67
|
+
|
|
68
|
+
# After streaming is complete, yield the final message object
|
|
69
|
+
if role and full_content:
|
|
70
|
+
yield SingleChatMessage(role, full_content, metadata)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .message import ChatMessage
|
|
2
|
+
|
|
3
|
+
class BaseChatHistory:
|
|
4
|
+
def __init__(self, max_messages=6):
|
|
5
|
+
self.max_messages = max_messages
|
|
6
|
+
self.messages = []
|
|
7
|
+
|
|
8
|
+
def add_message(self, message):
|
|
9
|
+
self.messages.append(message)
|
|
10
|
+
if len(self.messages) > self.max_messages:
|
|
11
|
+
self.messages.pop(0)
|
|
12
|
+
|
|
13
|
+
def get_messages(self):
|
|
14
|
+
return self.messages
|
|
15
|
+
|
|
16
|
+
def get_chat_message(self):
|
|
17
|
+
return ChatMessage(self.messages)
|
|
18
|
+
|
|
19
|
+
def persist(self):
|
|
20
|
+
# To be implemented by subclass
|
|
21
|
+
pass
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from .base_ai_config import BaseAIConfig
|
|
2
|
+
from .base_chat import BaseChat
|
|
3
|
+
from .base_chat_history import BaseChatHistory
|
|
4
|
+
from .client_config import ClientConfig
|
|
5
|
+
from .message import SingleChatMessage, ChatMessage
|
|
6
|
+
|
|
7
|
+
class BaseClient:
|
|
8
|
+
def __init__(self, base_chat, base_chat_history, client_config):
|
|
9
|
+
self.base_chat = base_chat
|
|
10
|
+
self.base_chat_history = base_chat_history
|
|
11
|
+
self.client_config = client_config
|
|
12
|
+
self.session_map = {}
|
|
13
|
+
|
|
14
|
+
def chat(self, session_id, user_input):
|
|
15
|
+
if isinstance(user_input, str):
|
|
16
|
+
user_message = SingleChatMessage.from_text(user_input, 'user')
|
|
17
|
+
else:
|
|
18
|
+
user_message = user_input
|
|
19
|
+
|
|
20
|
+
if session_id not in self.session_map:
|
|
21
|
+
self.session_map[session_id] = BaseChatHistory()
|
|
22
|
+
|
|
23
|
+
chat_history = self.session_map[session_id]
|
|
24
|
+
chat_history.add_message(user_message)
|
|
25
|
+
|
|
26
|
+
# Get current messages and add system prompt
|
|
27
|
+
current_messages = chat_history.get_messages()
|
|
28
|
+
system_prompt = self.client_config.get_system_prompt()
|
|
29
|
+
system_message = SingleChatMessage('system', system_prompt)
|
|
30
|
+
|
|
31
|
+
# Create chat message with system prompt at the beginning
|
|
32
|
+
messages_with_system = [system_message] + current_messages
|
|
33
|
+
chat_message = ChatMessage(messages_with_system)
|
|
34
|
+
|
|
35
|
+
# Get AI response
|
|
36
|
+
ai_response = self.base_chat.chat(chat_message)
|
|
37
|
+
|
|
38
|
+
# Add AI response to history
|
|
39
|
+
chat_history.add_message(ai_response)
|
|
40
|
+
|
|
41
|
+
return ai_response
|
|
42
|
+
|
|
43
|
+
def chat_stream(self, session_id, user_input):
|
|
44
|
+
if isinstance(user_input, str):
|
|
45
|
+
user_message = SingleChatMessage.from_text(user_input, 'user')
|
|
46
|
+
else:
|
|
47
|
+
user_message = user_input
|
|
48
|
+
|
|
49
|
+
if session_id not in self.session_map:
|
|
50
|
+
self.session_map[session_id] = BaseChatHistory()
|
|
51
|
+
|
|
52
|
+
chat_history = self.session_map[session_id]
|
|
53
|
+
chat_history.add_message(user_message)
|
|
54
|
+
|
|
55
|
+
# Get current messages and add system prompt
|
|
56
|
+
current_messages = chat_history.get_messages()
|
|
57
|
+
system_prompt = self.client_config.get_system_prompt()
|
|
58
|
+
system_message = SingleChatMessage('system', system_prompt)
|
|
59
|
+
|
|
60
|
+
# Create chat message with system prompt at the beginning
|
|
61
|
+
messages_with_system = [system_message] + current_messages
|
|
62
|
+
chat_message = ChatMessage(messages_with_system)
|
|
63
|
+
|
|
64
|
+
# Get AI response stream
|
|
65
|
+
ai_response = None
|
|
66
|
+
for chunk in self.base_chat.chat_stream(chat_message):
|
|
67
|
+
if isinstance(chunk, SingleChatMessage):
|
|
68
|
+
# This is the final message object
|
|
69
|
+
ai_response = chunk
|
|
70
|
+
else:
|
|
71
|
+
# This is a content chunk
|
|
72
|
+
yield chunk
|
|
73
|
+
|
|
74
|
+
# Add AI response to history
|
|
75
|
+
if ai_response:
|
|
76
|
+
chat_history.add_message(ai_response)
|
|
77
|
+
yield ai_response
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def create(cls):
|
|
81
|
+
ai_config = BaseAIConfig()
|
|
82
|
+
base_chat = BaseChat(ai_config)
|
|
83
|
+
base_chat_history = BaseChatHistory()
|
|
84
|
+
client_config = ClientConfig()
|
|
85
|
+
return cls(base_chat, base_chat_history, client_config)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import yaml
|
|
3
|
+
|
|
4
|
+
class ClientConfig:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.config = self._load_config()
|
|
7
|
+
self.prompt_path = self._get_config_value('diona.ai.clientset.prompt')
|
|
8
|
+
self.system_prompt = self._load_system_prompt()
|
|
9
|
+
|
|
10
|
+
def _load_config(self):
|
|
11
|
+
config_path = os.path.join(os.getcwd(), 'config.yml')
|
|
12
|
+
if os.path.exists(config_path):
|
|
13
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
14
|
+
return yaml.safe_load(f)
|
|
15
|
+
return {}
|
|
16
|
+
|
|
17
|
+
def _get_config_value(self, key, default=None):
|
|
18
|
+
keys = key.split('.')
|
|
19
|
+
value = self.config
|
|
20
|
+
for k in keys:
|
|
21
|
+
if isinstance(value, dict) and k in value:
|
|
22
|
+
value = value[k]
|
|
23
|
+
else:
|
|
24
|
+
return default
|
|
25
|
+
return value
|
|
26
|
+
|
|
27
|
+
def _load_system_prompt(self):
|
|
28
|
+
if self.prompt_path and os.path.exists(self.prompt_path):
|
|
29
|
+
with open(self.prompt_path, 'r', encoding='utf-8') as f:
|
|
30
|
+
return f.read().strip()
|
|
31
|
+
return "You are a helpful assistant"
|
|
32
|
+
|
|
33
|
+
def get_system_prompt(self):
|
|
34
|
+
return self.system_prompt
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .base_client import BaseClient
|
|
2
|
+
|
|
3
|
+
def interactive_chat():
|
|
4
|
+
client = BaseClient.create()
|
|
5
|
+
session_id = "default"
|
|
6
|
+
|
|
7
|
+
print("Welcome to Diona AI Chat!")
|
|
8
|
+
print("Type 'exit' to quit.")
|
|
9
|
+
|
|
10
|
+
while True:
|
|
11
|
+
user_input = input("<diona@user> ")
|
|
12
|
+
if user_input.strip().lower() == "exit":
|
|
13
|
+
print("Goodbye!")
|
|
14
|
+
break
|
|
15
|
+
|
|
16
|
+
print("<@assistant> ", end="", flush=True)
|
|
17
|
+
|
|
18
|
+
# Use streaming chat
|
|
19
|
+
for chunk in client.chat_stream(session_id, user_input):
|
|
20
|
+
if isinstance(chunk, str):
|
|
21
|
+
# This is a content chunk, print it immediately
|
|
22
|
+
print(chunk, end="", flush=True)
|
|
23
|
+
|
|
24
|
+
print()
|
|
25
|
+
print()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class SingleChatMessage:
|
|
2
|
+
def __init__(self, role, content, metadata=None):
|
|
3
|
+
self.role = role
|
|
4
|
+
self.content = content
|
|
5
|
+
self.metadata = metadata or {}
|
|
6
|
+
|
|
7
|
+
@classmethod
|
|
8
|
+
def from_text(cls, text, role='user'):
|
|
9
|
+
return cls(role, text)
|
|
10
|
+
|
|
11
|
+
def to_ai_message(self):
|
|
12
|
+
return {
|
|
13
|
+
'role': self.role,
|
|
14
|
+
'content': self.content
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class ChatMessage:
|
|
18
|
+
def __init__(self, messages):
|
|
19
|
+
self.messages = messages
|
|
20
|
+
|
|
21
|
+
def to_ai_messages(self):
|
|
22
|
+
return [msg.to_ai_message() for msg in self.messages]
|
|
23
|
+
|
|
24
|
+
class StreamingChatMessage:
|
|
25
|
+
def __init__(self, role=None):
|
|
26
|
+
self.role = role
|
|
27
|
+
self.content = ""
|
|
28
|
+
self.metadata = {}
|
|
29
|
+
|
|
30
|
+
def add_chunk(self, chunk):
|
|
31
|
+
self.content += chunk
|
|
32
|
+
|
|
33
|
+
def set_role(self, role):
|
|
34
|
+
self.role = role
|
|
35
|
+
|
|
36
|
+
def set_metadata(self, metadata):
|
|
37
|
+
self.metadata = metadata
|
|
38
|
+
|
|
39
|
+
def to_single_chat_message(self):
|
|
40
|
+
return SingleChatMessage(self.role, self.content, self.metadata)
|