diff --git a/README.md b/README.md index 63c8961d..2bc7f785 100644 --- a/README.md +++ b/README.md @@ -54,20 +54,55 @@ Read [**README.md**](docs/architecture) for the detailed documentation. ## Getting Started - -### Requirements -``` -Version's requirements - - Python >= 3.10 and < 3.12 - - NodeJs >= 18 - - bun -``` - +- Nvidia Driver installation + + https://linuxconfig.org/how-to-install-nvidia-drivers-on-ubuntu-24-04 + + nvtop to see installed Nvidia Cards + +- Python >= 3.10 and < 3.12 + + sudo apt update && sudo apt upgrade + + sudo apt install python3 python-is-python3 + +- NodeJs >= 18 Installation + [NodeJs >= 18 Installation](https://linuxconfig.org/how-to-install-node-js-on-ubuntu-24-04) + + sudo apt install nodejs + + sudo apt install npm + + node -v + +- Pip Installation + + sudo apt install pip + + python3 -m pip config set global.break-system-packages true + + als Alternative im uv pip installieren ??? + + sudo apt install python3-pip + - Install uv - Python Package manager [download](https://github.com/astral-sh/uv) + + $ pip install uv + - Install bun - JavaScript runtime [download](https://bun.sh/docs/installation) - For ollama [ollama setup guide](docs/Installation/ollama.md) (optinal: if you don't want to use the local models then you can skip this step) + + curl -fsSL https://ollama.com/install.sh | sh + + ./get-ollama-models.sh + + + - For API models, configure the API keys via setting page in UI. + Keys without <> + + ### Installation @@ -99,6 +134,7 @@ To install Devika, follow these steps: ``` 5. Start the Devika server: ```bash + npm install @sveltejs/adapter-node python devika.py ``` 6. if everything is working fine, you see the following output: @@ -113,6 +149,27 @@ To install Devika, follow these steps: ``` 8. Access the Devika web interface by opening a browser and navigating to `http://127.0.0.1:3001` +9. Install xterm in wsl + + sudo apt install xterm + +10. Windows run Xming Server from http://www.straightrunning.com/XmingNotes/#head-16 + +11. Change Fontsize in xterm + + sudo apt install x11-xserver-utils + + vi ~./Xresources + + xterm*font: *-fixed-*-*-*-18-* + + run xrdb -merge ~/.Xresources + +14. Install Code + + sudo snap install --classic code + + ### how to use To start using Devika, follow these steps: diff --git a/app.dockerfile b/app.dockerfile index 693addb6..8b5817ac 100644 --- a/app.dockerfile +++ b/app.dockerfile @@ -1,29 +1,29 @@ -FROM debian:12 +# Pulling stage 1 image, keep alias as layer1 +FROM node:latest as layer1 -# setting up build variable +# Setting necessary arguments ARG VITE_API_BASE_URL ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} -# setting up os env -USER root +# Copy UI source code +copy ui /home/nonroot/client + +# Change Work directory WORKDIR /home/nonroot/client -RUN groupadd -r nonroot && useradd -r -g nonroot -d /home/nonroot/client -s /bin/bash nonroot -# install node js -RUN apt-get update && apt-get upgrade -y -RUN apt-get install -y build-essential software-properties-common curl sudo wget git -RUN curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - -RUN apt-get install nodejs +RUN npm install +# Building APP bundle +RUN npm run build -# copying devika app client only -COPY ui /home/nonroot/client/ui -COPY src /home/nonroot/client/src -COPY config.toml /home/nonroot/client/ +# Pulling stage 2 image, to significantly reduce image size +FROM gcr.io/distroless/nodejs20-debian11 -RUN cd ui && npm install && npm install -g npm && npm install -g bun -RUN chown -R nonroot:nonroot /home/nonroot/client +# Copy build files from layer 1 +COPY --from=layer1 /home/nonroot/client/build /app +COPY --from=layer1 /home/nonroot/client/package.json /app -USER nonroot -WORKDIR /home/nonroot/client/ui +# Change Work directory +WORKDIR /app -ENTRYPOINT [ "npx", "bun", "run", "dev", "--", "--host" ] \ No newline at end of file +# RUN APP +CMD ["index.js"] \ No newline at end of file diff --git a/devika.py b/devika.py index 961b792a..cabb77fe 100644 --- a/devika.py +++ b/devika.py @@ -29,14 +29,16 @@ CORS(app, resources={r"/*": {"origins": # Change the origin to your frontend URL [ "https://localhost:3000", + "https://localhost:3001", "http://localhost:3000", + "http://localhost:3001" ]}}) app.register_blueprint(project_bp) socketio.init_app(app) log = logging.getLogger("werkzeug") -log.disabled = True +log.disabled = False TIKTOKEN_ENC = tiktoken.get_encoding("cl100k_base") @@ -44,7 +46,7 @@ os.environ["TOKENIZERS_PARALLELISM"] = "false" manager = ProjectManager() -AgentState = AgentState() +agent_state = AgentState() config = Config() logger = Logger() @@ -84,17 +86,17 @@ def handle_message(data): agent = Agent(base_model=base_model, search_engine=search_engine) - state = AgentState.get_latest_state(project_name) + state = agent_state.get_latest_state(project_name) if not state: thread = Thread(target=lambda: agent.execute(message, project_name)) thread.start() else: - if AgentState.is_agent_completed(project_name): + if AgentState.is_agent_completed(agent_state, project_name): thread = Thread(target=lambda: agent.subsequent_execute(message, project_name)) thread.start() else: emit_agent("info", {"type": "warning", "message": "previous agent doesn't completed it's task."}) - last_state = AgentState.get_latest_state(project_name) + last_state = agent_state.get_latest_state(project_name) if last_state["agent_is_active"] or not last_state["completed"]: thread = Thread(target=lambda: agent.execute(message, project_name)) thread.start() @@ -107,7 +109,7 @@ def handle_message(data): def is_agent_active(): data = request.json project_name = data.get("project_name") - is_active = AgentState.is_agent_active(project_name) + is_active = agent_state.is_agent_active(project_name) return jsonify({"is_active": is_active}) @@ -116,8 +118,8 @@ def is_agent_active(): def get_agent_state(): data = request.json project_name = data.get("project_name") - agent_state = AgentState.get_latest_state(project_name) - return jsonify({"state": agent_state}) + latest_state = agent_state.get_latest_state(project_name) + return jsonify({"state": latest_state}) @app.route("/api/get-browser-snapshot", methods=["GET"]) @@ -131,11 +133,11 @@ def browser_snapshot(): @route_logger(logger) def get_browser_session(): project_name = request.args.get("project_name") - agent_state = AgentState.get_latest_state(project_name) - if not agent_state: + latest_state = agent_state.get_latest_state(project_name) + if not latest_state: return jsonify({"session": None}) else: - browser_session = agent_state["browser_session"] + browser_session = latest_state["browser_session"] return jsonify({"session": browser_session}) @@ -143,11 +145,11 @@ def get_browser_session(): @route_logger(logger) def get_terminal_session(): project_name = request.args.get("project_name") - agent_state = AgentState.get_latest_state(project_name) - if not agent_state: + latest_state = agent_state.get_latest_state(project_name) + if not latest_state: return jsonify({"terminal_state": None}) else: - terminal_state = agent_state["terminal_session"] + terminal_state = latest_state["terminal_session"] return jsonify({"terminal_state": terminal_state}) @@ -174,7 +176,7 @@ def calculate_tokens(): @route_logger(logger) def token_usage(): project_name = request.args.get("project_name") - token_count = AgentState.get_latest_token_usage(project_name) + token_count = agent_state.get_latest_token_usage(project_name) return jsonify({"token_usage": token_count}) diff --git a/docs/Installation/search_engine.md b/docs/Installation/search_engine.md index 0334457d..62f07993 100644 --- a/docs/Installation/search_engine.md +++ b/docs/Installation/search_engine.md @@ -1,33 +1,53 @@ -# search Engine setup +# Search Engine Setup for Devika -To use the search engine capabilities of Devika, you need to set up the search engine API keys. Currently, Devika supports Bing, Google and DuckDuckGo search engines. If you want to use duckduckgo, you don't need to set up any API keys. +Devika supports three search engines: **Bing**, **Google**, and **DuckDuckGo**. While **DuckDuckGo** does not require any API keys, **Bing** and **Google** do. Follow the steps below to set up the API keys for Bing and Google. -For Bing and Google search engines, you need to set up the API keys. Here's how you can do it: +## 1. Bing Search API Setup -## Bing Search API -- Create Azure account. You can create a free account [here](https://azure.microsoft.com/en-us/free/). -- Go to the [Bing Search API](https://www.microsoft.com/en-us/bing/apis/bing-web-search-api) website. -- click on the `Try now` button. -- Sign in/sign up with your Azure account. -- Create a new resource group (if you don't have any). -![alt text](images/bing.png) -- click on the `Review and create` button. -- if everything is fine, click on the `Create` button. +### Step 1: Create an Azure Account +- Visit the [Azure website](https://azure.microsoft.com/en-us/free/) and create a free account. + +### Step 2: Access the Bing Search API +- Go to the [Bing Search API](https://www.microsoft.com/en-us/bing/apis/bing-web-search-api) page. +- Click on the `Try now` button. +- Sign in or sign up using your Azure account. + +### Step 3: Create a Resource Group +- If you don't have a resource group, create one during the setup process. + +### Step 4: Create a Bing Search API Resource +- Fill in the necessary details for your Bing Search API resource. +- Click on the `Review and create` button. +- If everything is correct, click on the `Create` button. + +### Step 5: Retrieve Your API Keys and Endpoint - Once the resource is created, go to the `Keys and Endpoint` tab. -![alt text](images/bing-1.png) -- Copy either `Key1` or `Key2` and paste it into the `API_KEYS` field with the name `BING` in the `config.toml` file located in the root directory of Devika, or you can set it via the UI. +- ![Keys and Endpoint](images/bing-1.png) +- Copy either `Key1` or `Key2`. +- Paste the key into the `API_KEYS` field with the name `BING` in the `config.toml` file located in the root directory of Devika, or you can set it via the UI. - Copy the `Endpoint` and paste it into the `API_Endpoints` field with the name `BING` in the `config.toml` file located in the root directory of Devika, or you can set it via the UI. +## 2. Google Search API Setup + +### Step 1: Create a Google Cloud Project +- If you don't have one, create a Google Cloud Project via the [Google Cloud Console](https://console.cloud.google.com/). + +### Step 2: Enable the Custom Search API +- Visit the [Google Custom Search API Documentation](https://developers.google.com/custom-search/v1/overview). +- Click on `Get a Key`. +- Select your project or create a new one. +- ![Create Project](images/google.png) +- This will enable the Custom Search API for your project and generate an API key. + +### Step 3: Retrieve Your API Key +- Copy the API key. +- Paste it in the `API_KEYS` field with the name `GOOGLE_SEARCH` in the `config.toml` file located in the root directory of Devika, or you can set it via the UI. + +### Step 4: Create a Custom Search Engine +- Go to the [Google Custom Search Engine](https://programmablesearchengine.google.com/controlpanel/all) website. +- Click on the `Add` button to create a new search engine. +- ![Create Search Engine](images/google-2.png) +- After creating the engine, copy the `Search Engine ID`. +- Paste it in the `API_Endpoints` field with the name `GOOGLE_SEARCH_ENGINE_ID` in the `config.toml` file located in the root directory of Devika, or you can set it via the UI. +``` -## Google Search API -- if don't have then create GCP account [Google Cloud Console](https://console.cloud.google.com/). -- visit [Here](https://developers.google.com/custom-search/v1/overview) is the official documentation. -- click on `Get a Key`. -- select the project you have or create a new project. click on next. -![alt text](images/google.png) -- it enable the Custom Search API for the project and create the API key. -- Copy the API key and paste it in the API_KEYS field with the name `GOOGLE_SEARCH` in the `config.toml` file in the root directory of Devika or you can set it via UI. -- for the search engine id, go to the [Google Custom Search Engine](https://programmablesearchengine.google.com/controlpanel/all) website. -- click on the `Add` button. -![alt text](images/google-2.png) -- After creating the engine. Copy the `Search Engine ID` and paste it in the API_Endpoints field with the name `GOOGLE_SEARCH_ENGINE_ID` in the `config.toml` file in the root directory of Devika or you can set it via UI. diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 7fa3bc16..d81dbae1 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -12,5 +12,5 @@ Devika's system architecture consists of the following key components: 8. **Knowledge Base**: Stores and retrieves project-specific information, code snippets, and learned knowledge for efficient access. 9. **Database**: Persists project data, agent states, and configuration settings. -Read [ARCHITECTURE.md](https://github.com/stitionai/devika/Docs/architecture/ARCHITECTURE.md) for the detailed architecture of Devika. -Read [UNDER_THE_HOOD.md](https://github.com/stitionai/devika/Docs/architecture/UNDER_THE_HOOD.md) for the detailed working of Devika. +Read [ARCHITECTURE.md](https://github.com/stitionai/devika/blob/main/docs/architecture/ARCHITECTURE.md) for the detailed architecture of Devika. +Read [UNDER_THE_HOOD.md](https://github.com/stitionai/devika/blob/main/docs/architecture/UNDER_THE_HOOD.md) for the detailed working of Devika. diff --git a/get-ollama-models.sh b/get-ollama-models.sh new file mode 100644 index 00000000..c5e3ece6 --- /dev/null +++ b/get-ollama-models.sh @@ -0,0 +1,43 @@ +#! /bin/bash +echo "/usr/local/bin/ollama pull llama3.2" +echo +/usr/local/bin/ollama pull llama3.2 +echo +echo "/usr/local/bin/ollama pull llama3.1" +/usr/local/bin/ollama pull llama3.1 +echo +echo "/usr/local/bin/ollama pull llama3" +/usr/local/bin/ollama pull llama3 +echo +echo "/usr/local/bin/ollama pull gemma" +/usr/local/bin/ollama pull gemma +echo +echo "/usr/local/bin/ollama pull qwen" +/usr/local/bin/ollama pull qwen +echo +echo "/usr/local/bin/ollama pull qwen2" +/usr/local/bin/ollama pull qwen2 +echo +echo "/usr/local/bin/ollama pull mistral" +/usr/local/bin/ollama pull mistral +echo +echo "/usr/local/bin/ollama pull phi3:14b" +/usr/local/bin/ollama pull phi3:14b +echo +echo "/usr/local/bin/ollama pull phi3:3.8b" +/usr/local/bin/ollama pull phi3:3.8b +echo +echo "/usr/local/bin/ollama pull codellama" +/usr/local/bin/ollama pull codellama +echo +echo "/usr/local/bin/ollama pull qwen2.5" +/usr/local/bin/ollama pull qwen2.5 +echo +echo "/usr/local/bin/ollama pull llama2" +/usr/local/bin/ollama pull llama2 +echo +echo "/usr/local/bin/ollama pull gemma2" +/usr/local/bin/ollama pull gemma2 +echo +echo "/usr/local/bin/ollama pull llama3.1:70b" +/usr/local/bin/ollama pull llama3.1:70b diff --git a/requirements.txt b/requirements.txt index 91666960..a0a18437 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,3 +31,5 @@ orjson gevent gevent-websocket curl_cffi +vite +shutils diff --git a/sample.config.toml b/sample.config.toml index 62cde107..794ffc02 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -16,11 +16,13 @@ GEMINI = "" MISTRAL = "" GROQ = "" NETLIFY = "" +NEWAI = "" [API_ENDPOINTS] BING = "https://api.bing.microsoft.com/v7.0/search" GOOGLE = "https://www.googleapis.com/customsearch/v1" OLLAMA = "http://127.0.0.1:11434" +NEWAI = "https://api.newai.com/v1" LM_STUDIO = "http://localhost:1234/v1" OPENAI = "https://api.openai.com/v1" diff --git a/src/agents/coder/coder.py b/src/agents/coder/coder.py index 3e021d61..a396d7df 100644 --- a/src/agents/coder/coder.py +++ b/src/agents/coder/coder.py @@ -52,7 +52,7 @@ def validate_response(self, response: str) -> Union[List[Dict[str, str]], bool]: if line.startswith("File: "): if current_file and current_code: result.append({"file": current_file, "code": "\n".join(current_code)}) - current_file = line.split(":")[1].strip() + current_file = line.split(":")[1].replace("`", "").strip() current_code = [] code_block = False elif line.startswith("```"): diff --git a/src/agents/planner/prompt.jinja2 b/src/agents/planner/prompt.jinja2 index 31d26839..8c38aa94 100644 --- a/src/agents/planner/prompt.jinja2 +++ b/src/agents/planner/prompt.jinja2 @@ -22,9 +22,23 @@ Plan: Summary: ``` +For example, consider a project about user registration system, then this would be the exact output(not even change of lowercase and uppercase of Project Name or Plan or Summary, etc). +``` +Project Name: User Registration System + +Your Reply to the Human Prompter: I've broken down the steps to build a basic user registration page with a database that stores user data. Let's get started! + +Current Focus: Establish the database to store user information. + +Plan: +- [ ] Step 1: Create a database using MySQL or PostgreSQL. +- [ ] Step 2: Design a table with columns for user information, such as name, email, password, and other relevant fields. + +Summary: This plan focuses on setting up the database to store user data securely and efficiently. By following these steps, you'll have a solid foundation for your user registration system. +``` Each step should be a clear, concise description of a specific task or action required. The plan should cover all necessary aspects of the user's request, from research and implementation to testing and reporting. -Write the plan with knowing that you have access to the browser and search engine to accomplish the task. +Write the plan knowing that you have access to the browser and search engine to accomplish the task. After listing the steps, provide a brief summary of the plan, highlighting any key considerations, dependencies, or potential challenges. @@ -33,4 +47,4 @@ Remember to tailor the plan to the specific task requested by the user, and prov if the task is simple, and you think you can do it without other assistance, just give one or simple two steps to accomplish the task. don't need to overcomplicate if it's not necessary. -Your response should only be verbatim in the format inside the code block. Any other response format will be rejected. \ No newline at end of file +Your response should only be verbatim in the format inside the code block. Any other response format will be rejected. diff --git a/src/agents/researcher/researcher.py b/src/agents/researcher/researcher.py index cec2b2ff..b52d5252 100644 --- a/src/agents/researcher/researcher.py +++ b/src/agents/researcher/researcher.py @@ -30,8 +30,8 @@ def validate_response(self, response: str) -> dict | bool: return False else: return { - "queries": response["queries"], - "ask_user": response["ask_user"] + "queries": response.get("queries", []), + "ask_user": response.get("ask_user", None) } @retry_wrapper diff --git a/src/browser/search.py b/src/browser/search.py index 030fa5fe..06a9fbad 100644 --- a/src/browser/search.py +++ b/src/browser/search.py @@ -87,8 +87,6 @@ class DuckDuckGoSearch: """DuckDuckGo search engine class. methods are inherited from the duckduckgo_search package. do not change the methods. - - currently, the package is not working with our current setup. """ def __init__(self): from curl_cffi import requests as curl_requests @@ -99,45 +97,84 @@ def __init__(self): def _get_url(self, method, url, data): try: resp = self.asession.request(method, url, data=data) - if resp.status_code == 200: + if resp.status_code == 200 and resp.content: return resp.content - if resp.status_code == (202, 301, 403): - raise Exception(f"Error: {resp.status_code} rate limit error") - if not resp: - return None + elif resp.status_code in (202, 301, 403): + raise Exception(f"Error: {resp.status_code} - Rate limit error") + else: + raise ValueError("Received an invalid or empty response from DuckDuckGo") except Exception as error: if "timeout" in str(error).lower(): - raise TimeoutError("Duckduckgo timed out error") + raise TimeoutError("DuckDuckGo request timed out") + raise ValueError(f"Error fetching DuckDuckGo response: {error}") def duck(self, query): - resp = self._get_url("POST", "https://duckduckgo.com/", data={"q": query}) - vqd = self.extract_vqd(resp) - - params = {"q": query, "kl": 'en-us', "p": "1", "s": "0", "df": "", "vqd": vqd, "ex": ""} - resp = self._get_url("GET", "https://links.duckduckgo.com/d.js", params) - page_data = self.text_extract_json(resp) - - results = [] - for row in page_data: - href = row.get("u") - if href and href != f"http://www.google.com/search?q={query}": - body = self.normalize(row["a"]) - if body: - result = { - "title": self.normalize(row["t"]), - "href": self.normalize_url(href), - "body": self.normalize(row["a"]), - } - results.append(result) - - self.query_result = results + try: + resp = self._get_url("POST", "https://duckduckgo.com/", data={"q": query}) + if not resp: + raise ValueError("Failed to fetch initial DuckDuckGo response") + + if resp is None: + raise ValueError("Invalid response received from DuckDuckGo") + + if resp.status_code != 200: + raise ValueError("Invalid response received from DuckDuckGo (status code: {resp.status_code})") + + vqd = self.extract_vqd(resp) + if not vqd: + raise ValueError("Failed to extract 'vqd' from the response") + + params = {"q": query, "kl": 'en-us', "p": "1", "s": "0", "df": "", "vqd": vqd, "ex": ""} + resp = self._get_url("GET", "https://links.duckduckgo.com/d.js", params) + if not resp: + raise ValueError("Failed to fetch results from DuckDuckGo") + + page_data = self.text_extract_json(resp) + results = [] + for row in page_data: + href = row.get("u") + if href and href != f"http://www.google.com/search?q={query}": + body = self.normalize(row["a"]) + if body: + result = { + "title": self.normalize(row["t"]), + "href": self.normalize_url(href), + "body": self.normalize(row["a"]), + } + results.append(result) + if not self.query_result: + raise ValueError("No results available from search") + + self.query_result = results + + except Exception as e: + print(f"Error during DuckDuckGo search: {e}") def search(self, query): self.duck(query) def get_first_link(self): + if not self.query_result: + raise ValueError("No results available from search") return self.query_result[0]["href"] + @staticmethod + def extract_vqd(html_bytes: bytes) -> str: + if not html_bytes: + raise ValueError("HTML content is empty or None.") + + patterns = [(b'vqd="', 5, b'"'), (b"vqd=", 4, b"&"), (b"vqd='", 5, b"'")] + for start_pattern, offset, end_pattern in patterns: + try: + start = html_bytes.index(start_pattern) + offset + end = html_bytes.index(end_pattern, start) + return html_bytes[start:end].decode() + except (ValueError, AttributeError): + continue + + # Se nenhum padrão foi encontrado, levante uma exceção + raise ValueError("Unable to extract vqd; no matching pattern found.") + @staticmethod def extract_vqd(html_bytes: bytes) -> str: patterns = [(b'vqd="', 5, b'"'), (b"vqd=", 4, b"&"), (b"vqd='", 5, b"'")] diff --git a/src/config.py b/src/config.py index a3303118..080febd7 100644 --- a/src/config.py +++ b/src/config.py @@ -182,6 +182,20 @@ def set_timeout_inference(self, value): def save_config(self): with open("config.toml", "w") as f: toml.dump(self.config, f) + + def get_newai_api_key(self): + return self.config["API_KEYS"]["NEWAI"] + + def get_newai_api_endpoint(self): + return self.config["API_ENDPOINTS"]["NEWAI"] + + def set_newai_api_key(self, key): + self.config["API_KEYS"]["NEWAI"] = key + self.save_config() + + def set_newai_api_endpoint(self, endpoint): + self.config["API_ENDPOINTS"]["NEWAI"] = endpoint + self.save_config() def update_config(self, data): for key, value in data.items(): diff --git a/src/llm/llm.py b/src/llm/llm.py index 24f20d59..9d4f9dbd 100644 --- a/src/llm/llm.py +++ b/src/llm/llm.py @@ -21,7 +21,7 @@ ollama = Ollama() logger = Logger() -agentState = AgentState() +agent_state = AgentState() config = Config() @@ -84,9 +84,9 @@ def model_enum(self, model_name: str) -> Tuple[str, str]: @staticmethod def update_global_token_usage(string: str, project_name: str): token_usage = len(TIKTOKEN_ENC.encode(string)) - agentState.update_token_usage(project_name, token_usage) + agent_state.update_token_usage(project_name, token_usage) - total = agentState.get_latest_token_usage(project_name) + token_usage + total = agent_state.get_latest_token_usage(project_name) + token_usage emit_agent("tokens", {"token_usage": total}) def inference(self, prompt: str, project_name: str) -> str: diff --git a/src/llm/newai_client.py b/src/llm/newai_client.py new file mode 100644 index 00000000..057fd808 --- /dev/null +++ b/src/llm/newai_client.py @@ -0,0 +1,23 @@ +from openai import OpenAI + +from src.config import Config + +class NewAi: + def __init__(self): + config = Config() + api_key = config.get_newai_api_key() + base_url = config.get_newai_api_endpoint() + self.client = OpenAI(api_key=api_key, base_url=base_url) + + def inference(self, model_id: str, prompt: str) -> str: + chat_completion = self.client.chat.completions.create( + messages=[ + { + "role": "user", + "content": prompt.strip(), + } + ], + model=model_id, + temperature=0 + ) + return chat_completion.choices[0].message.content \ No newline at end of file diff --git a/ui/bun.lockb b/ui/bun.lockb index f6fdf255..d1990a07 100755 Binary files a/ui/bun.lockb and b/ui/bun.lockb differ diff --git a/ui/package.json b/ui/package.json index f027961a..c8338448 100644 --- a/ui/package.json +++ b/ui/package.json @@ -27,11 +27,13 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "bits-ui": "^0.21.2", + "@sveltejs/adapter-node": "^5.0.1", + "@sveltejs/adapter-static": "^3.0.1", + "socket.io-client": "^4.7.5", "clsx": "^2.1.0", "dompurify": "^3.1.5", "mode-watcher": "^0.3.0", "paneforge": "^0.0.3", - "socket.io-client": "^4.7.5", "svelte-sonner": "^0.3.21", "tailwind-merge": "^2.2.2", "tailwind-variants": "^0.2.1", diff --git a/ui/svelte.config.js b/ui/svelte.config.js index 4df404aa..5e4d0abc 100644 --- a/ui/svelte.config.js +++ b/ui/svelte.config.js @@ -1,5 +1,6 @@ +import adapter from "@sveltejs/adapter-node"; import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; -import adapter from "@sveltejs/adapter-auto"; + /** @type {import('@sveltejs/kit').Config} */ const config = {