Xyro123 commited on
Commit
92c2fa2
·
verified ·
1 Parent(s): 637450d

Upload 3 files

Browse files
Files changed (3) hide show
  1. app/app.py +189 -0
  2. app/settings.py +152 -0
  3. app/utils.py +51 -0
app/app.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import chainlit as cl
2
+ from openai import AuthenticationError
3
+
4
+ from aicore.logger import _logger
5
+ from aicore.config import LlmConfig
6
+ from aicore.const import STREAM_END_TOKEN, STREAM_START_TOKEN, REASONING_START_TOKEN, REASONING_STOP_TOKEN
7
+
8
+ from aicore.llm import Llm
9
+
10
+ from ulid import ulid
11
+ import asyncio
12
+ import time
13
+
14
+ from utils import MODELS_PROVIDERS_MAP, PROVIDERS_API_KEYS, REASONER_PROVIDERS_MAP, check_openai_api_key, trim_messages
15
+ from settings import PROFILES_SETTINGS
16
+
17
+ DEFAULT_REASONER_CONFIG = LlmConfig(
18
+ provider="groq",
19
+ api_key=PROVIDERS_API_KEYS.get("groq"),
20
+ model="deepseek-r1-distill-llama-70b",
21
+ temperature=0.5,
22
+ max_tokens=1024
23
+ )
24
+
25
+ DEFAULT_LLM_CONFIG = {
26
+ "Reasoner4All": LlmConfig(
27
+ provider="groq",
28
+ api_key=PROVIDERS_API_KEYS.get("groq"),
29
+ model="meta-llama/llama-4-scout-17b-16e-instruct",
30
+ temperature=0,
31
+ max_tokens=4196,
32
+ # reasoner=DEFAULT_REASONER_CONFIG
33
+ ),
34
+ "OpenAi": LlmConfig(
35
+ provider="openai",
36
+ api_key=PROVIDERS_API_KEYS.get("openai", ""),
37
+ model="gpt-4o-mini",
38
+ temperature=0,
39
+ max_tokens=4196,
40
+ # reasoner=DEFAULT_REASONER_CONFIG
41
+ )
42
+ }
43
+
44
+ @cl.set_chat_profiles
45
+ async def chat_profile():
46
+ return [
47
+ cl.ChatProfile(
48
+ name="Reasoner4All",
49
+ markdown_description="Talk with the lastest Llm models! Powered by AiCore, check it on GitHub, link in Readme",
50
+ icon="https://picsum.photos/200",
51
+ ),
52
+ cl.ChatProfile(
53
+ name="OpenAi",
54
+ markdown_description="Talk with the lastest Llm models! Powered by AiCore, check it on GitHub, link in Readme",
55
+ icon="https://picsum.photos/200",
56
+ )
57
+ ]
58
+
59
+ @cl.on_settings_update
60
+ async def setup_agent(settings):
61
+ provider = MODELS_PROVIDERS_MAP.get(settings.get("Model"), "openai")
62
+ llm_config = LlmConfig(
63
+ provider=provider,
64
+ api_key=PROVIDERS_API_KEYS.get(provider) or settings.get("Api Key"),
65
+ model=settings.get("Model"),
66
+ temperature=settings.get("Temperature"),
67
+ max_tokens=settings.get("Max Tokens")
68
+ )
69
+ if settings.get("Use Reasoner"):
70
+ reasoner_provder = REASONER_PROVIDERS_MAP.get(settings.get("Reasoner Model"), "openai")
71
+ reasoner_config = LlmConfig(
72
+ provider=reasoner_provder,
73
+ api_key=PROVIDERS_API_KEYS.get(reasoner_provder) or settings.get("Reasoner Api Key"),
74
+ model=settings.get("Reasoner Model"),
75
+ temperature=settings.get("Reasoner Temperature"),
76
+ max_tokens=settings.get("Reasoner Max Tokens")
77
+ )
78
+ llm_config.reasoner = reasoner_config
79
+
80
+ llm = Llm.from_config(llm_config)
81
+ llm.session_id = ulid()
82
+ llm.system_prompt = settings.get("System Prompt")
83
+ if llm.reasoner:
84
+ llm.reasoner.system_prompt = settings.get("Reasoner System Prompt")
85
+
86
+ cl.user_session.set(
87
+ "llm", llm
88
+ )
89
+
90
+ @cl.on_chat_start
91
+ async def start_chat():
92
+ user_profile = cl.user_session.get("chat_profile")
93
+ cl.user_session.set("history", [])
94
+ llm_config = DEFAULT_LLM_CONFIG.get(user_profile)
95
+ llm = Llm.from_config(llm_config)
96
+ llm.session_id = ulid()
97
+ cl.user_session.set(
98
+ "llm", llm
99
+ )
100
+
101
+ settings = await cl.ChatSettings(
102
+ PROFILES_SETTINGS.get(user_profile)
103
+ ).send()
104
+
105
+
106
+ async def run_concurrent_tasks(llm, message):
107
+ asyncio.create_task(llm.acomplete(message))
108
+ asyncio.create_task(_logger.distribute())
109
+ # Stream logger output while LLM is running
110
+ while True:
111
+ async for chunk in _logger.get_session_logs(llm.session_id):
112
+ yield chunk # Yield each chunk directly
113
+
114
+ @cl.on_message
115
+ async def main(message: cl.Message):
116
+ llm = cl.user_session.get("llm")
117
+ if not llm.config.api_key:
118
+ while True:
119
+ api_key_msg = await cl.AskUserMessage(content="Please provide a valid api_key", timeout=10).send()
120
+ if api_key_msg:
121
+ api_key = api_key_msg.get("output")
122
+ valid = check_openai_api_key(api_key)
123
+ if valid:
124
+ await cl.Message(
125
+ content=f"Config updated with key.",
126
+ ).send()
127
+ llm.config.api_key = api_key
128
+ cl.user_session.set("llm", llm)
129
+ break
130
+
131
+ start = time.time()
132
+ thinking=False
133
+
134
+ history = cl.user_session.get("history")
135
+ history.append(message.content)
136
+ history = trim_messages(history, llm.tokenizer)
137
+ model_id = None
138
+ try:
139
+ if llm.reasoner is not None or llm.config.model in REASONER_PROVIDERS_MAP:
140
+ # Streaming the thinking
141
+ async with cl.Step(name=f"{llm.reasoner.config.provider} - {llm.reasoner.config.model} to think", type="llm") as thinking_step:
142
+ msg = cl.Message(content="")
143
+ async for chunk in run_concurrent_tasks(
144
+ llm,
145
+ message=history
146
+ ):
147
+ if chunk == STREAM_START_TOKEN:
148
+ continue
149
+ if chunk == REASONING_START_TOKEN:
150
+ thinking = True
151
+ continue
152
+ # chunk = " - *reasoning*\n```html\n"
153
+ if chunk == REASONING_STOP_TOKEN:
154
+ thinking = False
155
+ thought_for = round(time.time() - start)
156
+ thinking_step.name = f"{llm.reasoner.config.model} to think for {thought_for}s"
157
+ await thinking_step.update()
158
+ chunk = f"```{llm.config.model}```\n"
159
+ model_id = f"```{llm.config.model}```\n"
160
+
161
+ if chunk == STREAM_END_TOKEN:
162
+ break
163
+
164
+ if thinking:
165
+ await thinking_step.stream_token(chunk)
166
+ else:
167
+ await msg.stream_token(chunk)
168
+ else:
169
+ msg = cl.Message(content="")
170
+ async for chunk in run_concurrent_tasks(
171
+ llm,
172
+ message=history
173
+ ):
174
+ if chunk == STREAM_START_TOKEN:
175
+ continue
176
+
177
+ if chunk == STREAM_END_TOKEN:
178
+ break
179
+
180
+ await msg.stream_token(chunk)
181
+
182
+ hst_msg = msg.content.replace(model_id, "") if model_id else msg.content
183
+ history.append(hst_msg)
184
+ await msg.send()
185
+
186
+ except Exception as e:
187
+ await cl.ErrorMessage("Internal Server Error").send()
188
+
189
+ ### TODO add future todos, include support for images and pdf upload for conversation
app/settings.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from chainlit.input_widget import Select, Slider, Switch, TextInput
2
+ from utils import MODELS_PROVIDERS_MAP, REASONER_PROVIDERS_MAP
3
+
4
+ OPEN_LLM_SETTINGS = [
5
+ Select(
6
+ id="Model",
7
+ label="Llm",
8
+ values=list(MODELS_PROVIDERS_MAP.keys()),
9
+ initial_index=-1,
10
+ ),
11
+ Slider(
12
+ id="Temperature",
13
+ label="Temperature",
14
+ initial=0,
15
+ min=0,
16
+ max=1,
17
+ step=0.1,
18
+ ),
19
+ Slider(
20
+ id="Max Tokens",
21
+ label="Max Tokens",
22
+ initial=4196,
23
+ min=512,
24
+ max=8192,
25
+ step=256,
26
+ ),
27
+ TextInput(
28
+ id="System Prompt",
29
+ label="System Prompt",
30
+ initial="You are a helpful assistant."
31
+ ),
32
+ Switch(
33
+ id="Use Reasoner",
34
+ label="Use reasoner model",
35
+ initial=False
36
+ )
37
+ ]
38
+
39
+ REASONER_SETTINGS = [
40
+ Select(
41
+ id="Reasoner Model",
42
+ label="Reasoner Llm",
43
+ values=list(REASONER_PROVIDERS_MAP.keys()),
44
+ initial_index=0,
45
+ ),
46
+ Slider(
47
+ id="Reasoner Temperature",
48
+ label="Reasoner Temperature",
49
+ initial=0.5,
50
+ min=0,
51
+ max=1,
52
+ step=0.1,
53
+ ),
54
+ Slider(
55
+ id="Reasoner Max Tokens",
56
+ label="Reasoner Max Tokens",
57
+ initial=1024,
58
+ min=512,
59
+ max=4096,
60
+ step=256,
61
+ ),
62
+ TextInput(
63
+ id="Reasoner System Prompt",
64
+ label="Reasoner System Prompt",
65
+ initial="You are a helpfull assistant with reasoning capabilites that breaks down problems into the detailed steps required to solve them"
66
+ ),
67
+ ]
68
+
69
+
70
+ OPEN_AI_REASONER_SETTINGS = [
71
+ Select(
72
+ id="Reasoner Model",
73
+ label="Reasoner Llm",
74
+ values=list(REASONER_PROVIDERS_MAP.keys()),
75
+ initial_index=0,
76
+ ),
77
+ TextInput(
78
+ id="Reasoner Api Key",
79
+ label="Reasoner Api Key",
80
+ initial="your api key goes here..."
81
+ ),
82
+ Slider(
83
+ id="Reasoner Temperature",
84
+ label="Reasoner Temperature",
85
+ initial=0.5,
86
+ min=0,
87
+ max=1,
88
+ step=0.1,
89
+ ),
90
+ Slider(
91
+ id="Reasoner Max Tokens",
92
+ label="Reasoner Max Tokens",
93
+ initial=1024,
94
+ min=512,
95
+ max=4096,
96
+ step=256,
97
+ ),
98
+ TextInput(
99
+ id="Reasoner System Prompt",
100
+ label="Reasoner System Prompt",
101
+ initial="You are a helpfull assistant with reasoning capabilites that breaks down problems into the detailed steps required to solve them"
102
+ ),
103
+ ]
104
+
105
+ OPEN_AI_SETTINGS = [
106
+ TextInput(
107
+ id="Model",
108
+ label="Llm",
109
+ initial="gpt-4o-mini"
110
+ ),
111
+ TextInput(
112
+ id="Api Key",
113
+ label="Api Key",
114
+ initial="your api key goes here..."
115
+ ),
116
+ TextInput(
117
+ id="Base Url",
118
+ label="Base Url",
119
+ initial="leave this empty to connect to chatGPT"
120
+ ),
121
+ Slider(
122
+ id="Temperature",
123
+ label="Temperature",
124
+ initial=0,
125
+ min=0,
126
+ max=1,
127
+ step=0.1,
128
+ ),
129
+ Slider(
130
+ id="Max Tokens",
131
+ label="Max Tokens",
132
+ initial=4196,
133
+ min=512,
134
+ max=8192,
135
+ step=256,
136
+ ),
137
+ TextInput(
138
+ id="System Prompt",
139
+ label="System Prompt",
140
+ initial="You are a helpful assistant."
141
+ ),
142
+ Switch(
143
+ id="Use Reasoner",
144
+ label="Use reasoner model",
145
+ initial=False
146
+ )
147
+ ]
148
+
149
+ PROFILES_SETTINGS = {
150
+ "Reasoner4All": OPEN_LLM_SETTINGS + REASONER_SETTINGS,
151
+ "OpenAi": OPEN_AI_SETTINGS + OPEN_AI_REASONER_SETTINGS
152
+ }
app/utils.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from typing import Optional
3
+ import openai
4
+ import os
5
+
6
+ CONFIG_DIR = Path("./config")
7
+
8
+ REASONER_PROVIDERS_MAP = {
9
+ "deepseek-r1-distill-llama-70b": "groq",
10
+ "deepseek-ai/deepseek-r1": "nvidia",
11
+ "deepseek/deepseek-r1:free": "openrouter"
12
+ }
13
+
14
+ MODELS_PROVIDERS_MAP = {
15
+ "mistral-small-latest": "mistral",
16
+ "open-mistral-nemo": "mistral",
17
+ "mistral-large-latest": "mistral",
18
+ "gemini-2.5-pro-exp-03-25": "gemini",
19
+ "gemini-2.0-flash-thinking-exp-01-21": "gemini",
20
+ "gemini-2.0-flash-exp": "gemini",
21
+ "qwen-2.5-32b": "groq",
22
+ "qwen-2.5-coder-32b": "groq",
23
+ "qwen-qwq-32b": "groq",
24
+ "gemma2-9b-it": "groq",
25
+ "llama-3.3-70b-versatile": "groq",
26
+ "llama-3.2-3b-preview": "groq",
27
+ "meta-llama/llama-4-scout-17b-16e-instruct": "groq"
28
+ }
29
+
30
+ PROVIDERS_API_KEYS = {
31
+ "gemini": os.environ.get("GEMINI_API_KEY"),
32
+ "groq": os.environ.get("GROQ_API_KEY"),
33
+ "mistral": os.environ.get("MISTRAL_API_KEY"),
34
+ "nvidia": os.environ.get("NVIDIA_API_KEY"),
35
+ "openrouter": os.environ.get("OPENROUTER_API_KEY")
36
+ }
37
+
38
+ def check_openai_api_key(api_key, base_url=None):
39
+ client = openai.OpenAI(api_key=api_key, base_url=base_url)
40
+ try:
41
+ client.models.list()
42
+ except openai.AuthenticationError:
43
+ return False
44
+ else:
45
+ return True
46
+
47
+ def trim_messages(messages, tokenizer_fn, max_tokens :Optional[int]=None):
48
+ max_tokens = max_tokens or int(os.environ.get("MAX_HISTORY_TOKENS", 1028))
49
+ while messages and sum(len(tokenizer_fn(msg)) for msg in messages) > max_tokens:
50
+ messages.pop(0) # Remove from the beginning
51
+ return messages