PraisonAI 1.0.6__tar.gz → 1.0.9__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.

Potentially problematic release.


This version of PraisonAI might be problematic. Click here for more details.

Files changed (80) hide show
  1. {praisonai-1.0.6 → praisonai-1.0.9}/PKG-INFO +16 -3
  2. {praisonai-1.0.6 → praisonai-1.0.9}/README.md +15 -2
  3. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/cli.py +9 -11
  4. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/deploy.py +1 -1
  5. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/chat.py +29 -240
  6. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/code.py +30 -130
  7. praisonai-1.0.9/praisonai/ui/config/.chainlit/config.toml +120 -0
  8. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/bn.json +231 -0
  9. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/en-US.json +229 -0
  10. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/gu.json +231 -0
  11. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/he-IL.json +231 -0
  12. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/hi.json +231 -0
  13. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/kn.json +231 -0
  14. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/ml.json +231 -0
  15. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/mr.json +231 -0
  16. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/ta.json +231 -0
  17. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/te.json +231 -0
  18. praisonai-1.0.9/praisonai/ui/config/.chainlit/translations/zh-CN.json +229 -0
  19. praisonai-1.0.9/praisonai/ui/config/chainlit.md +1 -0
  20. praisonai-1.0.9/praisonai/ui/config/translations/bn.json +231 -0
  21. praisonai-1.0.9/praisonai/ui/config/translations/en-US.json +229 -0
  22. praisonai-1.0.9/praisonai/ui/config/translations/gu.json +231 -0
  23. praisonai-1.0.9/praisonai/ui/config/translations/he-IL.json +231 -0
  24. praisonai-1.0.9/praisonai/ui/config/translations/hi.json +231 -0
  25. praisonai-1.0.9/praisonai/ui/config/translations/kn.json +231 -0
  26. praisonai-1.0.9/praisonai/ui/config/translations/ml.json +231 -0
  27. praisonai-1.0.9/praisonai/ui/config/translations/mr.json +231 -0
  28. praisonai-1.0.9/praisonai/ui/config/translations/ta.json +231 -0
  29. praisonai-1.0.9/praisonai/ui/config/translations/te.json +231 -0
  30. praisonai-1.0.9/praisonai/ui/config/translations/zh-CN.json +229 -0
  31. praisonai-1.0.9/praisonai/ui/db.py +291 -0
  32. praisonai-1.0.9/praisonai/ui/public/praison.css +3 -0
  33. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/sql_alchemy.py +5 -3
  34. {praisonai-1.0.6 → praisonai-1.0.9}/pyproject.toml +11 -1
  35. {praisonai-1.0.6 → praisonai-1.0.9}/LICENSE +0 -0
  36. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/__init__.py +0 -0
  37. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/__main__.py +0 -0
  38. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/agents_generator.py +0 -0
  39. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/api/call.py +0 -0
  40. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/auto.py +0 -0
  41. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/chainlit_ui.py +0 -0
  42. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/inbuilt_tools/__init__.py +0 -0
  43. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
  44. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/inc/__init__.py +0 -0
  45. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/inc/config.py +0 -0
  46. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/inc/models.py +0 -0
  47. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/android-chrome-192x192.png +0 -0
  48. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/android-chrome-512x512.png +0 -0
  49. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/apple-touch-icon.png +0 -0
  50. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/fantasy.svg +0 -0
  51. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/favicon-16x16.png +0 -0
  52. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/favicon-32x32.png +0 -0
  53. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/favicon.ico +0 -0
  54. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/game.svg +0 -0
  55. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/logo_dark.png +0 -0
  56. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/logo_light.png +0 -0
  57. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/movie.svg +0 -0
  58. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/public/thriller.svg +0 -0
  59. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/__init__.py +0 -0
  60. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/build.py +0 -0
  61. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/config.yaml +0 -0
  62. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/post_install.py +0 -0
  63. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/setup_conda_env.py +0 -0
  64. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup/setup_conda_env.sh +0 -0
  65. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/setup.py +0 -0
  66. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/test.py +0 -0
  67. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/train.py +0 -0
  68. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/README.md +0 -0
  69. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/context.py +0 -0
  70. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/fantasy.svg +0 -0
  71. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/game.svg +0 -0
  72. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/logo_dark.png +0 -0
  73. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/logo_light.png +0 -0
  74. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/movie.svg +0 -0
  75. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/public/thriller.svg +0 -0
  76. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/realtime.py +0 -0
  77. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/realtimeclient/__init__.py +0 -0
  78. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/realtimeclient/realtimedocs.txt +0 -0
  79. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/ui/realtimeclient/tools.py +0 -0
  80. {praisonai-1.0.6 → praisonai-1.0.9}/praisonai/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PraisonAI
3
- Version: 1.0.6
3
+ Version: 1.0.9
4
4
  Summary: PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration.
5
5
  Author: Mervin Praison
6
6
  Requires-Python: >=3.10,<3.13
@@ -116,7 +116,7 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
116
116
 
117
117
  ## Installation Options
118
118
 
119
- ### Basic Installation
119
+ ### Using pip
120
120
  ```bash
121
121
  pip install praisonai
122
122
  ```
@@ -435,12 +435,26 @@ if __name__ == "__main__":
435
435
  ```
436
436
 
437
437
  4. **Install only dev dependencies:**
438
+
438
439
  ```sh
439
440
  poetry install --with dev
440
441
  ```
441
442
 
442
443
  This configuration ensures that your development dependencies are correctly categorized and installed as needed.
443
444
 
445
+ ### Using uv (Fast Python Package Installer)
446
+ ```bash
447
+ # Install uv if you haven't already
448
+ pip install uv
449
+
450
+ # Install from requirements
451
+ uv pip install -r pyproject.toml
452
+
453
+ # Install with extras
454
+ uv pip install -r pyproject.toml --extra code
455
+ uv pip install -r pyproject.toml --extra "crewai,autogen"
456
+ ```
457
+
444
458
  ## Contributing
445
459
 
446
460
  - Fork on GitHub: Use the "Fork" button on the repository page.
@@ -480,4 +494,3 @@ Praison AI is an open-sourced software licensed under the **[MIT license](https:
480
494
 
481
495
  Praison AI is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
482
496
 
483
-
@@ -53,7 +53,7 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
53
53
 
54
54
  ## Installation Options
55
55
 
56
- ### Basic Installation
56
+ ### Using pip
57
57
  ```bash
58
58
  pip install praisonai
59
59
  ```
@@ -372,12 +372,26 @@ if __name__ == "__main__":
372
372
  ```
373
373
 
374
374
  4. **Install only dev dependencies:**
375
+
375
376
  ```sh
376
377
  poetry install --with dev
377
378
  ```
378
379
 
379
380
  This configuration ensures that your development dependencies are correctly categorized and installed as needed.
380
381
 
382
+ ### Using uv (Fast Python Package Installer)
383
+ ```bash
384
+ # Install uv if you haven't already
385
+ pip install uv
386
+
387
+ # Install from requirements
388
+ uv pip install -r pyproject.toml
389
+
390
+ # Install with extras
391
+ uv pip install -r pyproject.toml --extra code
392
+ uv pip install -r pyproject.toml --extra "crewai,autogen"
393
+ ```
394
+
381
395
  ## Contributing
382
396
 
383
397
  - Fork on GitHub: Use the "Fork" button on the repository page.
@@ -416,4 +430,3 @@ Praison AI is an open-sourced software licensed under the **[MIT license](https:
416
430
  ## License
417
431
 
418
432
  Praison AI is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
419
-
@@ -26,9 +26,16 @@ CREWAI_AVAILABLE = False
26
26
  AUTOGEN_AVAILABLE = False
27
27
 
28
28
  try:
29
- # Set CHAINLIT_APP_ROOT only if it doesn't exist
29
+ # Create necessary directories and set CHAINLIT_APP_ROOT
30
30
  if "CHAINLIT_APP_ROOT" not in os.environ:
31
- os.environ["CHAINLIT_APP_ROOT"] = os.path.join(os.path.expanduser("~"), ".praison")
31
+ chainlit_root = os.path.join(os.path.expanduser("~"), ".praison")
32
+ os.environ["CHAINLIT_APP_ROOT"] = chainlit_root
33
+ else:
34
+ chainlit_root = os.environ["CHAINLIT_APP_ROOT"]
35
+
36
+ os.makedirs(chainlit_root, exist_ok=True)
37
+ os.makedirs(os.path.join(chainlit_root, ".files"), exist_ok=True)
38
+
32
39
  from chainlit.cli import chainlit_run
33
40
  CHAINLIT_AVAILABLE = True
34
41
  except ImportError:
@@ -393,15 +400,6 @@ class PraisonAI:
393
400
  root_path = os.path.join(os.path.expanduser("~"), ".praison")
394
401
  if "CHAINLIT_APP_ROOT" not in os.environ:
395
402
  os.environ["CHAINLIT_APP_ROOT"] = root_path
396
- public_folder = os.path.join(os.path.dirname(praisonai.__file__), 'public')
397
- if not os.path.exists(os.path.join(root_path, "public")):
398
- if os.path.exists(public_folder):
399
- shutil.copytree(public_folder, os.path.join(root_path, "public"), dirs_exist_ok=True)
400
- logging.info("Public folder copied successfully!")
401
- else:
402
- logging.info("Public folder not found in the package.")
403
- else:
404
- logging.info("Public folder already exists.")
405
403
  chat_ui_path = os.path.join(os.path.dirname(praisonai.__file__), 'ui', 'chat.py')
406
404
  chainlit_run([chat_ui_path])
407
405
  else:
@@ -56,7 +56,7 @@ class CloudDeployer:
56
56
  file.write("FROM python:3.11-slim\n")
57
57
  file.write("WORKDIR /app\n")
58
58
  file.write("COPY . .\n")
59
- file.write("RUN pip install flask praisonai==1.0.6 gunicorn markdown\n")
59
+ file.write("RUN pip install flask praisonai==1.0.9 gunicorn markdown\n")
60
60
  file.write("EXPOSE 8080\n")
61
61
  file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
62
62
 
@@ -1,29 +1,32 @@
1
- import chainlit as cl
2
- from chainlit.input_widget import TextInput
3
- from chainlit.types import ThreadDict
4
- from litellm import acompletion
1
+ # Standard library imports
5
2
  import os
6
- import sqlite3
7
3
  from datetime import datetime
8
- from typing import Dict, List, Optional
9
- from dotenv import load_dotenv
10
- load_dotenv()
11
- import chainlit.data as cl_data
12
- from chainlit.step import StepDict
13
- from literalai.helper import utc_now
4
+ from typing import Dict, Optional
14
5
  import logging
15
6
  import json
16
- from sql_alchemy import SQLAlchemyDataLayer
17
- from tavily import TavilyClient
18
- from crawl4ai import AsyncWebCrawler
19
7
  import asyncio
20
- from PIL import Image
21
8
  import io
22
9
  import base64
23
10
 
24
- from sqlalchemy.ext.asyncio import create_async_engine
25
- from sqlalchemy import text
11
+ # Third-party imports
12
+ from dotenv import load_dotenv
13
+ from PIL import Image
14
+ from tavily import TavilyClient
15
+ from crawl4ai import AsyncWebCrawler
26
16
 
17
+ # Local application/library imports
18
+ import chainlit as cl
19
+ from chainlit.input_widget import TextInput
20
+ from chainlit.types import ThreadDict
21
+ import chainlit.data as cl_data
22
+ from litellm import acompletion
23
+ from literalai.helper import utc_now
24
+ from db import DatabaseManager
25
+
26
+ # Load environment variables
27
+ load_dotenv()
28
+
29
+ # Logging configuration
27
30
  logger = logging.getLogger(__name__)
28
31
  log_level = os.getenv("LOGLEVEL", "INFO").upper()
29
32
  logger.handlers = []
@@ -42,233 +45,19 @@ if not CHAINLIT_AUTH_SECRET:
42
45
  now = utc_now()
43
46
  create_step_counter = 0
44
47
 
45
- DATABASE_URL = os.getenv("DATABASE_URL")
46
-
47
- async def create_schema_async():
48
- if not DATABASE_URL:
49
- return
50
- engine = create_async_engine(DATABASE_URL, echo=False)
51
- async with engine.begin() as conn:
52
- # Use double quotes for column names and renamed start/end to startTime/endTime
53
- await conn.execute(text('''
54
- CREATE TABLE IF NOT EXISTS users (
55
- "id" TEXT PRIMARY KEY,
56
- "identifier" TEXT NOT NULL UNIQUE,
57
- "meta" TEXT NOT NULL DEFAULT '{}',
58
- "createdAt" TEXT
59
- );
60
- '''))
61
- await conn.execute(text('''
62
- CREATE TABLE IF NOT EXISTS threads (
63
- "id" TEXT PRIMARY KEY,
64
- "createdAt" TEXT,
65
- "name" TEXT,
66
- "userId" TEXT,
67
- "userIdentifier" TEXT,
68
- "tags" TEXT DEFAULT '[]',
69
- "meta" TEXT NOT NULL DEFAULT '{}',
70
- FOREIGN KEY ("userId") REFERENCES users("id") ON DELETE CASCADE
71
- );
72
- '''))
73
- await conn.execute(text('''
74
- CREATE TABLE IF NOT EXISTS steps (
75
- "id" TEXT PRIMARY KEY,
76
- "name" TEXT NOT NULL,
77
- "type" TEXT NOT NULL,
78
- "threadId" TEXT NOT NULL,
79
- "parentId" TEXT,
80
- "disableFeedback" BOOLEAN NOT NULL DEFAULT FALSE,
81
- "streaming" BOOLEAN NOT NULL DEFAULT FALSE,
82
- "waitForAnswer" BOOLEAN DEFAULT FALSE,
83
- "isError" BOOLEAN NOT NULL DEFAULT FALSE,
84
- "meta" TEXT DEFAULT '{}',
85
- "tags" TEXT DEFAULT '[]',
86
- "input" TEXT,
87
- "output" TEXT,
88
- "createdAt" TEXT,
89
- "startTime" TEXT,
90
- "endTime" TEXT,
91
- "generation" TEXT,
92
- "showInput" TEXT,
93
- "language" TEXT,
94
- "indent" INT,
95
- FOREIGN KEY ("threadId") REFERENCES threads("id") ON DELETE CASCADE
96
- );
97
- '''))
98
- await conn.execute(text('''
99
- CREATE TABLE IF NOT EXISTS elements (
100
- "id" TEXT PRIMARY KEY,
101
- "threadId" TEXT,
102
- "type" TEXT,
103
- "url" TEXT,
104
- "chainlitKey" TEXT,
105
- "name" TEXT NOT NULL,
106
- "display" TEXT,
107
- "objectKey" TEXT,
108
- "size" TEXT,
109
- "page" INT,
110
- "language" TEXT,
111
- "forId" TEXT,
112
- "mime" TEXT,
113
- FOREIGN KEY ("threadId") REFERENCES threads("id") ON DELETE CASCADE
114
- );
115
- '''))
116
- await conn.execute(text('''
117
- CREATE TABLE IF NOT EXISTS feedbacks (
118
- "id" TEXT PRIMARY KEY,
119
- "forId" TEXT NOT NULL,
120
- "value" INT NOT NULL,
121
- "threadId" TEXT,
122
- "comment" TEXT
123
- );
124
- '''))
125
- await conn.execute(text('''
126
- CREATE TABLE IF NOT EXISTS settings (
127
- "id" SERIAL PRIMARY KEY,
128
- "key" TEXT UNIQUE,
129
- "value" TEXT
130
- );
131
- '''))
132
- await engine.dispose()
133
-
134
- def create_schema_sqlite(db_path: str):
135
- os.makedirs(os.path.dirname(db_path), exist_ok=True)
136
- conn = sqlite3.connect(db_path)
137
- cursor = conn.cursor()
138
- # Renamed start to startTime, end to endTime
139
- cursor.execute('''
140
- CREATE TABLE IF NOT EXISTS users (
141
- "id" TEXT PRIMARY KEY,
142
- "identifier" TEXT NOT NULL UNIQUE,
143
- "meta" TEXT NOT NULL DEFAULT '{}',
144
- "createdAt" TEXT
145
- )
146
- ''')
147
- cursor.execute('''
148
- CREATE TABLE IF NOT EXISTS threads (
149
- "id" TEXT PRIMARY KEY,
150
- "createdAt" TEXT,
151
- "name" TEXT,
152
- "userId" TEXT,
153
- "userIdentifier" TEXT,
154
- "tags" TEXT DEFAULT '[]',
155
- "meta" TEXT NOT NULL DEFAULT '{}',
156
- FOREIGN KEY ("userId") REFERENCES users("id") ON DELETE CASCADE
157
- )
158
- ''')
159
- cursor.execute('''
160
- CREATE TABLE IF NOT EXISTS steps (
161
- "id" TEXT PRIMARY KEY,
162
- "name" TEXT NOT NULL,
163
- "type" TEXT NOT NULL,
164
- "threadId" TEXT NOT NULL,
165
- "parentId" TEXT,
166
- "disableFeedback" BOOLEAN NOT NULL DEFAULT 0,
167
- "streaming" BOOLEAN NOT NULL DEFAULT 0,
168
- "waitForAnswer" BOOLEAN DEFAULT 0,
169
- "isError" BOOLEAN NOT NULL DEFAULT 0,
170
- "meta" TEXT DEFAULT '{}',
171
- "tags" TEXT DEFAULT '[]',
172
- "input" TEXT,
173
- "output" TEXT,
174
- "createdAt" TEXT,
175
- "startTime" TEXT,
176
- "endTime" TEXT,
177
- "generation" TEXT,
178
- "showInput" TEXT,
179
- "language" TEXT,
180
- "indent" INT,
181
- FOREIGN KEY ("threadId") REFERENCES threads ("id") ON DELETE CASCADE
182
- )
183
- ''')
184
- cursor.execute('''
185
- CREATE TABLE IF NOT EXISTS elements (
186
- "id" TEXT PRIMARY KEY,
187
- "threadId" TEXT,
188
- "type" TEXT,
189
- "url" TEXT,
190
- "chainlitKey" TEXT,
191
- "name" TEXT NOT NULL,
192
- "display" TEXT,
193
- "objectKey" TEXT,
194
- "size" TEXT,
195
- "page" INT,
196
- "language" TEXT,
197
- "forId" TEXT,
198
- "mime" TEXT,
199
- FOREIGN KEY ("threadId") REFERENCES threads ("id") ON DELETE CASCADE
200
- )
201
- ''')
202
- cursor.execute('''
203
- CREATE TABLE IF NOT EXISTS feedbacks (
204
- "id" TEXT PRIMARY KEY,
205
- "forId" TEXT NOT NULL,
206
- "value" INT NOT NULL,
207
- "threadId" TEXT,
208
- "comment" TEXT
209
- )
210
- ''')
211
- cursor.execute('''
212
- CREATE TABLE IF NOT EXISTS settings (
213
- "id" INTEGER PRIMARY KEY AUTOINCREMENT,
214
- "key" TEXT UNIQUE,
215
- "value" TEXT
216
- )
217
- ''')
218
- conn.commit()
219
- conn.close()
220
-
221
- if DATABASE_URL:
222
- asyncio.run(create_schema_async())
223
- conninfo = DATABASE_URL
224
- else:
225
- DB_PATH = os.path.expanduser("~/.praison/database.sqlite")
226
- create_schema_sqlite(DB_PATH)
227
- conninfo = f"sqlite+aiosqlite:///{DB_PATH}"
48
+ # Initialize database
49
+ db_manager = DatabaseManager()
50
+ db_manager.initialize()
228
51
 
229
52
  def save_setting(key: str, value: str):
230
- if DATABASE_URL:
231
- async def save_setting_async():
232
- engine = create_async_engine(DATABASE_URL, echo=False)
233
- async with engine.begin() as conn:
234
- await conn.execute(text("""
235
- INSERT INTO settings ("key", "value") VALUES (:key, :value)
236
- ON CONFLICT ("key") DO UPDATE SET "value" = EXCLUDED."value"
237
- """), {"key": key, "value": value})
238
- await engine.dispose()
239
- asyncio.run(save_setting_async())
240
- else:
241
- conn = sqlite3.connect(DB_PATH)
242
- cursor = conn.cursor()
243
- cursor.execute(
244
- """
245
- INSERT OR REPLACE INTO settings (id, "key", "value")
246
- VALUES ((SELECT id FROM settings WHERE "key" = ?), ?, ?)
247
- """,
248
- (key, key, value),
249
- )
250
- conn.commit()
251
- conn.close()
53
+ """Save a setting to the database"""
54
+ asyncio.run(db_manager.save_setting(key, value))
252
55
 
253
56
  def load_setting(key: str) -> str:
254
- if DATABASE_URL:
255
- async def load_setting_async():
256
- engine = create_async_engine(DATABASE_URL, echo=False)
257
- async with engine.connect() as conn:
258
- result = await conn.execute(text('SELECT "value" FROM settings WHERE "key" = :key'), {"key": key})
259
- row = result.fetchone()
260
- await engine.dispose()
261
- return row[0] if row else None
262
- return asyncio.run(load_setting_async())
263
- else:
264
- conn = sqlite3.connect(DB_PATH)
265
- cursor = conn.cursor()
266
- cursor.execute('SELECT "value" FROM settings WHERE "key" = ?', (key,))
267
- result = cursor.fetchone()
268
- conn.close()
269
- return result[0] if result else None
57
+ """Load a setting from the database"""
58
+ return asyncio.run(db_manager.load_setting(key))
270
59
 
271
- cl_data._data_layer = SQLAlchemyDataLayer(conninfo=conninfo)
60
+ cl_data._data_layer = db_manager
272
61
 
273
62
  tavily_api_key = os.getenv("TAVILY_API_KEY")
274
63
  tavily_client = TavilyClient(api_key=tavily_api_key) if tavily_api_key else None
@@ -389,7 +178,7 @@ async def setup_agent(settings):
389
178
  if isinstance(metadata, str):
390
179
  try:
391
180
  metadata = json.loads(metadata)
392
- except:
181
+ except json.JSONDecodeError:
393
182
  metadata = {}
394
183
  metadata["model_name"] = model_name
395
184
  await cl_data.update_thread(thread_id, metadata=metadata)
@@ -1,23 +1,29 @@
1
- import chainlit as cl
2
- from chainlit.input_widget import TextInput
3
- from chainlit.types import ThreadDict, StepDict
1
+ # Standard library imports
4
2
  import os
5
- import sqlite3
6
3
  from datetime import datetime
7
- from typing import Dict, List, Optional
8
- from dotenv import load_dotenv
9
- load_dotenv()
10
- import chainlit.data as cl_data
11
4
  import logging
12
5
  import json
13
- from sql_alchemy import SQLAlchemyDataLayer
6
+ import io
7
+ import base64
8
+ import asyncio
9
+
10
+ # Third-party imports
11
+ from dotenv import load_dotenv
12
+ from PIL import Image
14
13
  from context import ContextGatherer
15
14
  from tavily import TavilyClient
16
- from datetime import datetime
17
15
  from crawl4ai import AsyncWebCrawler
18
- from PIL import Image
19
- import io
20
- import base64
16
+
17
+ # Local application/library imports
18
+ import chainlit as cl
19
+ from chainlit.input_widget import TextInput
20
+ from chainlit.types import ThreadDict
21
+ import chainlit.data as cl_data
22
+ from litellm import acompletion
23
+ from db import DatabaseManager
24
+
25
+ # Load environment variables
26
+ load_dotenv()
21
27
 
22
28
  # Set up logging
23
29
  logger = logging.getLogger(__name__)
@@ -41,143 +47,38 @@ if not CHAINLIT_AUTH_SECRET:
41
47
  CHAINLIT_AUTH_SECRET = os.getenv("CHAINLIT_AUTH_SECRET")
42
48
 
43
49
  now = datetime.now()
44
-
45
50
  create_step_counter = 0
46
51
 
47
- DB_PATH = os.path.expanduser("~/.praison/database.sqlite")
48
-
49
- def initialize_db():
50
- os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
51
- conn = sqlite3.connect(DB_PATH)
52
- cursor = conn.cursor()
53
- cursor.execute('''
54
- CREATE TABLE IF NOT EXISTS users (
55
- id UUID PRIMARY KEY,
56
- identifier TEXT NOT NULL UNIQUE,
57
- metadata JSONB NOT NULL,
58
- createdAt TEXT
59
- )
60
- ''')
61
- cursor.execute('''
62
- CREATE TABLE IF NOT EXISTS threads (
63
- id UUID PRIMARY KEY,
64
- createdAt TEXT,
65
- name TEXT,
66
- userId UUID,
67
- userIdentifier TEXT,
68
- tags TEXT[],
69
- metadata JSONB NOT NULL DEFAULT '{}',
70
- FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
71
- )
72
- ''')
73
- cursor.execute('''
74
- CREATE TABLE IF NOT EXISTS steps (
75
- id UUID PRIMARY KEY,
76
- name TEXT NOT NULL,
77
- type TEXT NOT NULL,
78
- threadId UUID NOT NULL,
79
- parentId UUID,
80
- disableFeedback BOOLEAN NOT NULL DEFAULT 0,
81
- streaming BOOLEAN NOT NULL DEFAULT 0,
82
- waitForAnswer BOOLEAN DEFAULT 0,
83
- isError BOOLEAN NOT NULL DEFAULT 0,
84
- metadata JSONB DEFAULT '{}',
85
- tags TEXT[],
86
- input TEXT,
87
- output TEXT,
88
- createdAt TEXT,
89
- start TEXT,
90
- end TEXT,
91
- generation JSONB,
92
- showInput TEXT,
93
- language TEXT,
94
- indent INT,
95
- FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
96
- )
97
- ''')
98
- cursor.execute('''
99
- CREATE TABLE IF NOT EXISTS elements (
100
- id UUID PRIMARY KEY,
101
- threadId UUID,
102
- type TEXT,
103
- url TEXT,
104
- chainlitKey TEXT,
105
- name TEXT NOT NULL,
106
- display TEXT,
107
- objectKey TEXT,
108
- size TEXT,
109
- page INT,
110
- language TEXT,
111
- forId UUID,
112
- mime TEXT,
113
- FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
114
- )
115
- ''')
116
- cursor.execute('''
117
- CREATE TABLE IF NOT EXISTS feedbacks (
118
- id UUID PRIMARY KEY,
119
- forId UUID NOT NULL,
120
- value INT NOT NULL,
121
- threadId UUID,
122
- comment TEXT
123
- )
124
- ''')
125
- cursor.execute('''
126
- CREATE TABLE IF NOT EXISTS settings (
127
- id INTEGER PRIMARY KEY AUTOINCREMENT,
128
- key TEXT UNIQUE,
129
- value TEXT
130
- )
131
- ''')
132
- conn.commit()
133
- conn.close()
52
+ # Initialize database
53
+ db_manager = DatabaseManager()
54
+ db_manager.initialize()
55
+
56
+ deleted_thread_ids = [] # type: List[str]
134
57
 
135
58
  def save_setting(key: str, value: str):
136
59
  """Saves a setting to the database.
137
-
60
+
138
61
  Args:
139
62
  key: The setting key.
140
63
  value: The setting value.
141
64
  """
142
- conn = sqlite3.connect(DB_PATH)
143
- cursor = conn.cursor()
144
- cursor.execute(
145
- """
146
- INSERT OR REPLACE INTO settings (id, key, value)
147
- VALUES ((SELECT id FROM settings WHERE key = ?), ?, ?)
148
- """,
149
- (key, key, value),
150
- )
151
- conn.commit()
152
- conn.close()
65
+ asyncio.run(db_manager.save_setting(key, value))
153
66
 
154
67
  def load_setting(key: str) -> str:
155
68
  """Loads a setting from the database.
156
-
69
+
157
70
  Args:
158
71
  key: The setting key.
159
-
72
+
160
73
  Returns:
161
74
  The setting value, or None if the key is not found.
162
75
  """
163
- conn = sqlite3.connect(DB_PATH)
164
- cursor = conn.cursor()
165
- cursor.execute('SELECT value FROM settings WHERE key = ?', (key,))
166
- result = cursor.fetchone()
167
- conn.close()
168
- return result[0] if result else None
169
-
170
-
171
- # Initialize the database
172
- initialize_db()
173
-
174
- deleted_thread_ids = [] # type: List[str]
76
+ return asyncio.run(db_manager.load_setting(key))
175
77
 
176
- cl_data._data_layer = SQLAlchemyDataLayer(conninfo=f"sqlite+aiosqlite:///{DB_PATH}")
78
+ cl_data._data_layer = db_manager
177
79
 
178
80
  @cl.on_chat_start
179
81
  async def start():
180
- initialize_db()
181
82
  model_name = load_setting("model_name")
182
83
 
183
84
  if (model_name):
@@ -498,7 +399,6 @@ async def on_chat_resume(thread: ThreadDict):
498
399
  ]
499
400
  )
500
401
  await settings.send()
501
- thread_id = thread["id"]
502
402
  cl.user_session.set("thread_id", thread["id"])
503
403
 
504
404
  # Ensure metadata is a dictionary