feat: add a web UI server (#1345)

* update rdagent cmd

* fix log error message

* use multiProcessing.Process instead of subprocess.Popen

* add traces to gitignore

* add user interactor in RDLoop (finance scenarios)

* add interactor (feedback, hypothesis) for quant scens

* fix the test_end in qlib conf

* add features init config, general instruction to qlib scenarios

* set base features for based exp

* fix bug when combine factors

* move traces folder to git_ignore_folder

* fix bug in features init

* fix quant interact bug

* fix logger warning error

* bug fixes

* modify rdagent logger, now it can set file output

* adjust cli functions and fix logger bug

* fix server port transport problem

* update server_ui in cli

* add web code

* fix CI problem

* black fix

* update web ui README

* update README

* update readme
This commit is contained in:
XianBW
2026-03-18 14:04:52 +08:00
committed by GitHub
parent 7cd64a26fd
commit 14395488b9
141 changed files with 12852 additions and 279 deletions
+1 -1
View File
@@ -187,4 +187,4 @@ static/
AGENTS.md
!rdagent/**/AGENTS.md
scripts/
scripts/
+4 -4
View File
@@ -83,11 +83,11 @@ constraints: deepclean
# Check lint with black.
black:
$(PIPRUN) python -m black --check --diff . --extend-exclude "(test/scripts|test/notebook/testfiles|git_ignore_folder)" -l 120
$(PIPRUN) python -m black --check --diff . --extend-exclude "(test/scripts|test/notebook/testfiles|git_ignore_folder|web)" -l 120
# Check lint with isort.
isort:
$(PIPRUN) python -m isort --check . -s git_ignore_folder -s test/scripts -s test/notebook/testfiles
$(PIPRUN) python -m isort --check . -s git_ignore_folder -s test/scripts -s test/notebook/testfiles -s web
# Check lint with mypy.
# First deal with the core folder, and then gradually increase the scope of detection,
@@ -120,11 +120,11 @@ pre-commit:
# Auto lint with black.
auto-black:
$(PIPRUN) python -m black . --extend-exclude "(test/scripts|test/notebook/testfiles|git_ignore_folder|.venv)" -l 120
$(PIPRUN) python -m black . --extend-exclude "(test/scripts|test/notebook/testfiles|git_ignore_folder|.venv|web)" -l 120
# Auto lint with isort.
auto-isort:
$(PIPRUN) python -m isort . -s git_ignore_folder -s test/scripts -s test/notebook/testfiles -s .venv
$(PIPRUN) python -m isort . -s git_ignore_folder -s test/scripts -s test/notebook/testfiles -s .venv -s web
# Auto lint with toml-sort.
auto-toml-sort:
+44 -11
View File
@@ -31,6 +31,7 @@
# 📰 News
| 🗞️ News | 📝 Description |
| -- | ------ |
| Web UI Release | We release a new frontend that can be built and served by `rdagent server_ui` for real-time interaction and trace viewing, currently excluding the `data_science` scenario. |
| NeurIPS 2025 Acceptance | We are thrilled to announce that our paper [R&D-Agent-Quant](https://arxiv.org/abs/2505.15155) has been accepted to NeurIPS 2025 |
| [Technical Report Release](#overall-technical-report) | Overall framework description and results on MLE-bench |
| [R&D-Agent-Quant Release](#deep-application-in-diverse-scenarios) | Apply R&D-Agent to quant trading |
@@ -337,21 +338,53 @@ The **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)** is implemented b
```
### 🖥️ Monitor the Application Results
- You can run the following command for our demo program to see the run logs.
#### Streamlit UI
```sh
rdagent ui --port 19899 --log-dir <your log folder like "log/"> --data-science
```
Use the Streamlit UI to view run logs, especially for the `data_science` scenario.
- About the `data_science` parameter: If you want to see the logs of the data science scenario, set the `data_science` parameter to `True`; otherwise set it to `False`.
- Although port 19899 is not commonly used, but before you run this demo, you need to check if port 19899 is occupied. If it is, please change it to another port that is not occupied.
```sh
rdagent ui --port 19899 --log-dir <your log folder like "log/"> --data-science
```
You can check if a port is occupied by running the following command.
About the `data_science` parameter: If you want to see the logs of the data science scenario, set the `data_science` parameter to `True`; otherwise set it to `False`.
```sh
rdagent health_check --no-check-env --no-check-docker
```
#### Web UI
We also provide a separate web frontend in `web/` for the Flask backend started by `server_ui`.
**NOTE:** This web UI is different from `rdagent ui`. The current web UI does not support the `data_science` scenario yet. For the `data_science` scenario, please continue to use `rdagent ui --data-science`.
```sh
cd web
npm install
```
To build the frontend for the Flask backend, generate the static assets into the default directory used by `server_ui`:
```sh
cd web
npm run build:flask
```
By default, `server_ui` serves static files from `./git_ignore_folder/static`. If you need a different location, set the `UI_STATIC_PATH` environment variable before starting the backend.
Start the Flask backend and serve the built frontend together with the real-time APIs:
```sh
rdagent server_ui --port 19899
```
After that, open `http://127.0.0.1:19899` in your browser.
#### Common Notes
Port `19899` is used in the examples above. Before starting either UI, check whether this port is already occupied. If it is, please change it to another available port.
You can check whether the port is occupied by running:
```sh
rdagent health_check --no-check-env --no-check-docker
```
# 🏭 Scenarios
+127 -11
View File
@@ -16,10 +16,13 @@ load_dotenv(".env")
import subprocess
from importlib.resources import path as rpath
from typing import Optional
import typer
from typing_extensions import Annotated
from rdagent.app.data_science.loop import main as data_science
from rdagent.app.finetune.llm.loop import main as llm_finetune
from rdagent.app.general_model.general_model import (
extract_models_and_implement as general_model,
)
@@ -33,6 +36,11 @@ from rdagent.log.mle_summary import grade_summary as grade_summary
app = typer.Typer()
CheckoutOption = Annotated[bool, typer.Option("--checkout/--no-checkout", "-c/-C")]
CheckEnvOption = Annotated[bool, typer.Option("--check-env/--no-check-env", "-e/-E")]
CheckDockerOption = Annotated[bool, typer.Option("--check-docker/--no-check-docker", "-d/-D")]
CheckPortsOption = Annotated[bool, typer.Option("--check-ports/--no-check-ports", "-p/-P")]
def ui(port=19899, log_dir="", debug: bool = False, data_science: bool = False):
"""
@@ -56,9 +64,11 @@ def ui(port=19899, log_dir="", debug: bool = False, data_science: bool = False):
def server_ui(port=19899):
"""
start web app to show the log traces in real time
start the Flask log server in real time
"""
subprocess.run(["python", "rdagent/log/server/app.py", f"--port={port}"])
from rdagent.log.server.app import main as log_server_main
log_server_main(port=port)
def ds_user_interact(port=19900):
@@ -69,17 +79,123 @@ def ds_user_interact(port=19900):
subprocess.run(commands)
app.command(name="fin_factor")(fin_factor)
app.command(name="fin_model")(fin_model)
app.command(name="fin_quant")(fin_quant)
app.command(name="fin_factor_report")(fin_factor_report)
app.command(name="general_model")(general_model)
app.command(name="data_science")(data_science)
app.command(name="grade_summary")(grade_summary)
@app.command(name="fin_factor")
def fin_factor_cli(
path: Optional[str] = None,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
all_duration: Optional[str] = None,
checkout: CheckoutOption = True,
):
fin_factor(path=path, step_n=step_n, loop_n=loop_n, all_duration=all_duration, checkout=checkout)
@app.command(name="fin_model")
def fin_model_cli(
path: Optional[str] = None,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
all_duration: Optional[str] = None,
checkout: CheckoutOption = True,
):
fin_model(path=path, step_n=step_n, loop_n=loop_n, all_duration=all_duration, checkout=checkout)
@app.command(name="fin_quant")
def fin_quant_cli(
path: Optional[str] = None,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
all_duration: Optional[str] = None,
checkout: CheckoutOption = True,
):
fin_quant(path=path, step_n=step_n, loop_n=loop_n, all_duration=all_duration, checkout=checkout)
@app.command(name="fin_factor_report")
def fin_factor_report_cli(
report_folder: Optional[str] = None,
path: Optional[str] = None,
all_duration: Optional[str] = None,
checkout: CheckoutOption = True,
):
fin_factor_report(report_folder=report_folder, path=path, all_duration=all_duration, checkout=checkout)
@app.command(name="general_model")
def general_model_cli(report_file_path: str):
general_model(report_file_path)
@app.command(name="data_science")
def data_science_cli(
path: Optional[str] = None,
checkout: CheckoutOption = True,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
timeout: Optional[str] = None,
competition: Optional[str] = None,
):
data_science(
path=path,
checkout=checkout,
step_n=step_n,
loop_n=loop_n,
timeout=timeout,
competition=competition,
)
@app.command(name="llm_finetune")
def llm_finetune_cli(
path: Optional[str] = None,
checkout: CheckoutOption = True,
benchmark: Optional[str] = None,
benchmark_description: Optional[str] = None,
dataset: Optional[str] = None,
base_model: Optional[str] = None,
upper_data_size_limit: Optional[int] = None,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
timeout: Optional[str] = None,
):
llm_finetune(
path=path,
checkout=checkout,
benchmark=benchmark,
benchmark_description=benchmark_description,
dataset=dataset,
base_model=base_model,
upper_data_size_limit=upper_data_size_limit,
step_n=step_n,
loop_n=loop_n,
timeout=timeout,
)
@app.command(name="grade_summary")
def grade_summary_cli(log_folder: str):
grade_summary(log_folder)
app.command(name="ui")(ui)
app.command(name="server_ui")(server_ui)
app.command(name="health_check")(health_check)
app.command(name="collect_info")(collect_info)
@app.command(name="health_check")
def health_check_cli(
check_env: CheckEnvOption = True,
check_docker: CheckDockerOption = True,
check_ports: CheckPortsOption = True,
):
health_check(check_env=check_env, check_docker=check_docker, check_ports=check_ports)
@app.command(name="collect_info")
def collect_info_cli():
collect_info()
app.command(name="ds_user_interact")(ds_user_interact)
+1 -3
View File
@@ -3,8 +3,6 @@ from pathlib import Path
from typing import Optional
import fire
import typer
from typing_extensions import Annotated
from rdagent.app.data_science.conf import DS_RD_SETTING
from rdagent.core.utils import import_class
@@ -14,7 +12,7 @@ from rdagent.scenarios.data_science.loop import DataScienceRDLoop
def main(
path: Optional[str] = None,
checkout: Annotated[bool, typer.Option("--checkout/--no-checkout", "-c/-C")] = True,
checkout: bool = True,
checkout_path: Optional[str] = None,
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
+3 -4
View File
@@ -7,8 +7,7 @@ Standard RDLoop entry point for LLM fine-tuning, consistent with data science im
import asyncio
from typing import Optional, cast
import typer
from typing_extensions import Annotated
import fire
from rdagent.app.finetune.llm.conf import FT_RD_SETTING
from rdagent.log import rdagent_logger as logger
@@ -17,7 +16,7 @@ from rdagent.scenarios.finetune.loop import LLMFinetuneRDLoop
def main(
path: Optional[str] = None,
checkout: Annotated[bool, typer.Option("--checkout/--no-checkout", "-c/-C")] = True,
checkout: bool = True,
user_target_scenario: Optional[str] = None,
benchmark: Optional[str] = None,
benchmark_description: Optional[str] = None,
@@ -98,4 +97,4 @@ def main(
if __name__ == "__main__":
typer.run(main)
fire.Fire(main)
+5 -5
View File
@@ -45,7 +45,7 @@ class ModelBasePropSetting(BasePropSetting):
test_start: str = "2017-01-01"
"""Start date of the test / backtest segment"""
test_end: Optional[str] = None
test_end: Optional[str] = "2020-08-01"
"""End date of the test / backtest segment"""
@@ -89,7 +89,7 @@ class FactorBasePropSetting(BasePropSetting):
test_start: str = "2017-01-01"
"""Start date of the test / backtest segment"""
test_end: Optional[str] = None
test_end: Optional[str] = "2020-08-01"
"""End date of the test / backtest segment"""
@@ -102,10 +102,10 @@ class FactorFromReportPropSetting(FactorBasePropSetting):
report_result_json_file_path: str = "git_ignore_folder/report_list.json"
"""Path to the JSON file listing research reports for factor extraction"""
max_factors_per_exp: int = 10000
max_factors_per_exp: int = 6
"""Maximum number of factors implemented per experiment"""
report_limit: int = 10000
report_limit: int = 20
"""Maximum number of reports to process"""
@@ -166,7 +166,7 @@ class QuantBasePropSetting(BasePropSetting):
test_start: str = "2017-01-01"
"""Start date of the test / backtest segment"""
test_end: Optional[str] = None
test_end: Optional[str] = "2020-08-01"
"""End date of the test / backtest segment"""
+11 -6
View File
@@ -7,8 +7,6 @@ from pathlib import Path
from typing import Any, Optional
import fire
import typer
from typing_extensions import Annotated
from rdagent.app.qlib_rd_loop.conf import FACTOR_PROP_SETTING
from rdagent.components.workflow.rd_loop import RDLoop
@@ -34,8 +32,10 @@ def main(
step_n: Optional[int] = None,
loop_n: Optional[int] = None,
all_duration: str | None = None,
checkout: Annotated[bool, typer.Option("--checkout/--no-checkout", "-c/-C")] = True,
checkout: bool = True,
checkout_path: Optional[str] = None,
base_features_path: Optional[str] = None,
**kwargs,
):
"""
Auto R&D Evolving loop for fintech factors.
@@ -51,10 +51,15 @@ def main(
checkout = Path(checkout_path)
if path is None:
model_loop = FactorRDLoop(FACTOR_PROP_SETTING)
factor_loop = FactorRDLoop(FACTOR_PROP_SETTING)
else:
model_loop = FactorRDLoop.load(path, checkout=checkout)
asyncio.run(model_loop.run(step_n=step_n, loop_n=loop_n, all_duration=all_duration))
factor_loop = FactorRDLoop.load(path, checkout=checkout)
factor_loop._init_base_features(base_features_path)
if "user_interaction_queues" in kwargs and kwargs["user_interaction_queues"] is not None:
factor_loop._set_interactor(*kwargs["user_interaction_queues"])
factor_loop._interact_init_params()
asyncio.run(factor_loop.run(step_n=step_n, loop_n=loop_n, all_duration=all_duration))
if __name__ == "__main__":
@@ -126,6 +126,9 @@ class FactorReportLoop(FactorRDLoop, metaclass=LoopMeta):
]
exp.sub_workspace_list = exp.sub_workspace_list[: FACTOR_FROM_REPORT_PROP_SETTING.max_factors_per_exp]
exp.sub_tasks = exp.sub_tasks[: FACTOR_FROM_REPORT_PROP_SETTING.max_factors_per_exp]
exp.base_features = self.plan["features"]
if exp.based_experiments:
exp.based_experiments[-1].base_features = self.plan["features"]
logger.log_object(exp.hypothesis, tag="hypothesis generation")
logger.log_object(exp.sub_tasks, tag="experiment generation")
return exp
+6
View File
@@ -21,6 +21,8 @@ def main(
loop_n: int | None = None,
all_duration: str | None = None,
checkout: bool = True,
base_features_path: str | None = None,
**kwargs,
):
"""
Auto R&D Evolving loop for fintech models
@@ -36,6 +38,10 @@ def main(
model_loop = ModelRDLoop(MODEL_PROP_SETTING)
else:
model_loop = ModelRDLoop.load(path, checkout=checkout)
model_loop._init_base_features(base_features_path)
if "user_interaction_queues" in kwargs and kwargs["user_interaction_queues"] is not None:
model_loop._set_interactor(*kwargs["user_interaction_queues"])
model_loop._interact_init_params()
asyncio.run(model_loop.run(step_n=step_n, loop_n=loop_n, all_duration=all_duration))
+18
View File
@@ -15,6 +15,7 @@ from rdagent.core.developer import Developer
from rdagent.core.exception import FactorEmptyError, ModelEmptyError
from rdagent.core.proposal import (
Experiment2Feedback,
ExperimentPlan,
Hypothesis2Experiment,
HypothesisFeedback,
HypothesisGen,
@@ -23,6 +24,7 @@ from rdagent.core.scenario import Scenario
from rdagent.core.utils import import_class
from rdagent.log import rdagent_logger as logger
from rdagent.scenarios.qlib.proposal.quant_proposal import QuantTrace
from rdagent.utils.qlib import ALPHA20
class QuantRDLoop(RDLoop):
@@ -62,6 +64,10 @@ class QuantRDLoop(RDLoop):
self.model_summarizer: Experiment2Feedback = import_class(PROP_SETTING.model_summarizer)(scen)
logger.log_object(self.model_summarizer, tag="model summarizer")
self.plan: ExperimentPlan = {
"features": ALPHA20,
"feature_codes": {},
} # for user interaction
self.trace = QuantTrace(scen=scen)
super(RDLoop, self).__init__()
@@ -75,6 +81,11 @@ class QuantRDLoop(RDLoop):
else:
exp = self.model_hypothesis2experiment.convert(hypo, self.trace)
logger.log_object(exp.sub_tasks, tag="experiment generation")
exp.base_features = self.plan["features"]
exp.base_feature_codes = self.plan["feature_codes"]
if exp.based_experiments:
exp.based_experiments[-1].base_features = self.plan["features"]
exp.based_experiments[-1].base_feature_codes = self.plan["feature_codes"]
return {"propose": hypo, "exp_gen": exp}
await asyncio.sleep(1)
@@ -112,6 +123,7 @@ class QuantRDLoop(RDLoop):
feedback = self.factor_summarizer.generate_feedback(prev_out["running"], self.trace)
elif prev_out["direct_exp_gen"]["propose"].action == "model":
feedback = self.model_summarizer.generate_feedback(prev_out["running"], self.trace)
feedback = self._interact_feedback(feedback)
logger.log_object(feedback, tag="feedback")
return feedback
@@ -122,6 +134,8 @@ def main(
loop_n: int | None = None,
all_duration: str | None = None,
checkout: bool = True,
base_features_path: str | None = None,
**kwargs,
):
"""
Auto R&D Evolving loop for fintech factors.
@@ -133,6 +147,10 @@ def main(
quant_loop = QuantRDLoop(QUANT_PROP_SETTING)
else:
quant_loop = QuantRDLoop.load(path, checkout=checkout)
quant_loop._init_base_features(base_features_path)
if "user_interaction_queues" in kwargs and kwargs["user_interaction_queues"] is not None:
quant_loop._set_interactor(*kwargs["user_interaction_queues"])
quant_loop._interact_init_params()
asyncio.run(quant_loop.run(step_n=step_n, loop_n=loop_n, all_duration=all_duration))
+6 -8
View File
@@ -4,10 +4,8 @@ import socket
import docker
import fire
import litellm
import typer
from litellm import completion, embedding
from litellm.utils import ModelResponse
from typing_extensions import Annotated
from rdagent.log import rdagent_logger as logger
from rdagent.utils.env import cleanup_container
@@ -44,10 +42,10 @@ def check_and_list_free_ports(start_port=19899, max_ports=10) -> None:
if not is_port_in_use(port):
free_ports.append(port)
logger.warning(
f"Port 19899 is occupied, please replace it with an available port when running the `rdagent ui` command. Available ports: {free_ports}"
f"Port 19899 is occupied, please replace it with an available port when running the `rdagent ui/server_ui` command. Available ports: {free_ports}"
)
else:
logger.info(f"Port 19899 is not occupied, you can run the `rdagent ui` command")
logger.info(f"Port 19899 is not occupied, you can run the `rdagent ui/server_ui` command")
def test_chat(chat_model, chat_api_key, chat_api_base):
@@ -135,9 +133,9 @@ def env_check():
def health_check(
check_env: Annotated[bool, typer.Option("--check-env/--no-check-env", "-e/-E")] = True,
check_docker: Annotated[bool, typer.Option("--check-docker/--no-check-docker", "-d/-D")] = True,
check_ports: Annotated[bool, typer.Option("--check-ports/--no-check-ports", "-p/-P")] = True,
check_env: bool = True,
check_docker: bool = True,
check_ports: bool = True,
):
"""
Run the RD-Agent health check:
@@ -167,4 +165,4 @@ def health_check(
if __name__ == "__main__":
typer.run(health_check)
fire.Fire(health_check)
+1
View File
@@ -42,6 +42,7 @@ class LLMHypothesisGen(HypothesisGen):
),
hypothesis_output_format=context_dict["hypothesis_output_format"],
hypothesis_specification=context_dict["hypothesis_specification"],
user_instruction=plan.get("user_instruction", None) if plan is not None else None,
)
user_prompt = T(".prompts:hypothesis_gen.user_prompt").r(
targets=self.targets,
+8 -1
View File
@@ -3,10 +3,17 @@ hypothesis_gen:
The user is working on generating new hypotheses for the {{ targets }} in a data-driven research and development process.
The {{ targets }} are used in the following scenario:
{{ scenario }}
{% if user_instruction %}
**User's overall instruction:**
{{ user_instruction }}
{% endif %}
The user has already proposed several hypotheses and conducted evaluations on them. This information will be provided to you. Your task is to analyze previous experiments, reflect on the decision made in each experiment, and consider why experiments with a decision of true were successful while those with a decision of false failed. Then, think about how to improve further — either by refining the existing approach or by exploring an entirely new direction.
If one exists and you agree with it, feel free to use it. If you disagree, please generate an improved version.
{% if hypothesis_specification %}
To assist you in formulating new hypotheses, the user has provided some additional information: {{ hypothesis_specification }}.
To assist you in formulating new hypotheses, the user has provided some additional information:
{{ hypothesis_specification }}
**Important:** If the hypothesis_specification outlines the next steps you need to follow, ensure you adhere to those instructions.
{% endif %}
Please generate the output using the following format and specifications:
+134 -1
View File
@@ -4,6 +4,9 @@ It is from `rdagent/app/qlib_rd_loop/model.py` and try to replace `rdagent/app/q
"""
import asyncio
import json
from multiprocessing import Queue
from pathlib import Path
from typing import Any
from rdagent.components.workflow.conf import BasePropSetting
@@ -11,6 +14,7 @@ from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.developer import Developer
from rdagent.core.proposal import (
Experiment2Feedback,
ExperimentPlan,
Hypothesis,
Hypothesis2Experiment,
HypothesisFeedback,
@@ -20,6 +24,7 @@ from rdagent.core.proposal import (
from rdagent.core.scenario import Scenario
from rdagent.core.utils import import_class
from rdagent.log import rdagent_logger as logger
from rdagent.utils.qlib import ALPHA20, validate_qlib_features
from rdagent.utils.workflow import LoopBase, LoopMeta
@@ -36,6 +41,11 @@ class RDLoop(LoopBase, metaclass=LoopMeta):
else None
)
self.plan: ExperimentPlan = {
"features": ALPHA20,
"feature_codes": {},
} # for user interaction
self.hypothesis2experiment: Hypothesis2Experiment = (
import_class(PROP_SETTING.hypothesis2experiment)()
if hasattr(PROP_SETTING, "hypothesis2experiment") and PROP_SETTING.hypothesis2experiment
@@ -58,8 +68,125 @@ class RDLoop(LoopBase, metaclass=LoopMeta):
super().__init__()
# excluded steps
def _set_interactor(self, user_request_q: Queue, user_response_q: Queue):
self.user_request_q = user_request_q
self.user_response_q = user_response_q
def _init_base_features(self, base_features_path: str | None):
if base_features_path is not None:
try:
base_dir = Path(base_features_path)
base_factors_file = base_dir / "base_factors.json"
feature_codes: dict[str, str] = {}
for py_file in sorted(base_dir.glob("*.py")):
feature_codes[py_file.name] = py_file.read_text()
self.plan["feature_codes"] = feature_codes
if not base_factors_file.exists():
logger.info(f"No base_factors.json found under {base_dir}. Keeping default base features.")
logger.info(f"{len(feature_codes)} feature code files loaded from {base_dir}.")
else:
with base_factors_file.open("r") as f:
features = json.load(f)
if not isinstance(features, dict):
raise ValueError(
"`base_factors.json` must contain a JSON object of feature_name -> expression."
)
if validate_qlib_features(list(features.values())):
self.plan["features"] = features
logger.info(
f"Loaded base features from {base_factors_file}. {len(features)} features loaded and {len(feature_codes)} feature code files loaded."
)
else:
logger.warning(
f"Base feature validation failed for features loaded from {base_factors_file}. Using default features."
)
except Exception as e:
logger.warning(f"Failed to load base features from {base_features_path}: {e}. Using default features.")
else:
logger.info("No base features path provided. Using default features.")
def _interact_init_params(self) -> None:
if not (hasattr(self, "user_request_q") and hasattr(self, "user_response_q")):
return
logger.info("Waiting for user interaction on initial parameters...")
try:
self.user_request_q.put(
{
"user_instruction": None,
}
)
res_dict = self.user_response_q.get()
logger.info("Received user instruction response.")
self.plan.update(res_dict)
if "feature_codes" not in self.plan:
self.plan[
"user_instruction"
] += f"\n\n{str(list(self.plan['feature_codes'].keys()))} has been configured as the base factor; do not generate duplicate factors."
fea_valid_msg = ""
while True:
logger.info("Requesting base feature configuration from user.")
self.user_request_q.put(
{
"features": self.plan["features"],
"feature_validation_msg": fea_valid_msg,
}
)
self.plan["features"] = self.user_response_q.get()
logger.info("Received base feature configuration response.")
if validate_qlib_features(list(self.plan["features"].values())):
logger.info(f"Base feature validation passed. {len(self.plan['features'])} features selected.")
break
else:
logger.info("Base feature validation failed. Asking user to revise.")
fea_valid_msg = "Some features are invalid, please revise."
except (EOFError, OSError):
logger.info("User interaction failed, using default initial parameters.")
return
logger.info("Received user interaction on initial parameters.")
def _interact_hypo(self, hypo: Hypothesis) -> Hypothesis:
if not (hasattr(self, "user_request_q") and hasattr(self, "user_response_q")):
return hypo
logger.info("Waiting for user interaction on hypothesis...")
try:
self.user_request_q.put(hypo.__dict__)
res_dict = self.user_response_q.get()
modified_hypo = type(hypo)(**res_dict)
except (EOFError, OSError, TypeError):
logger.info("User interaction failed, using original hypothesis.")
return hypo
logger.info("Received user interaction on hypothesis.")
return modified_hypo
def _interact_feedback(self, feedback: HypothesisFeedback) -> HypothesisFeedback:
if not (hasattr(self, "user_request_q") and hasattr(self, "user_response_q")):
return feedback
logger.info("Waiting for user interaction on feedback...")
try:
self.user_request_q.put(feedback.__dict__)
res_dict = self.user_response_q.get()
modified_feedback = HypothesisFeedback(**res_dict)
except (EOFError, OSError, TypeError):
logger.info("User interaction failed, using original feedback.")
return feedback
logger.info("Received user interaction on feedback.")
return modified_feedback
def _propose(self):
hypothesis = self.hypothesis_gen.gen(self.trace)
hypothesis = self.hypothesis_gen.gen(self.trace, self.plan)
# user can change the hypothesis here
hypothesis = self._interact_hypo(hypothesis)
logger.log_object(hypothesis, tag="hypothesis generation")
return hypothesis
@@ -74,6 +201,11 @@ class RDLoop(LoopBase, metaclass=LoopMeta):
if self.get_unfinished_loop_cnt(self.loop_idx) < RD_AGENT_SETTINGS.get_max_parallel():
hypo = self._propose()
exp = self._exp_gen(hypo)
exp.base_features = self.plan["features"]
exp.base_feature_codes = self.plan["feature_codes"]
if exp.based_experiments:
exp.based_experiments[-1].base_features = self.plan["features"]
exp.based_experiments[-1].base_feature_codes = self.plan["feature_codes"]
return {"propose": hypo, "exp_gen": exp}
await asyncio.sleep(1)
@@ -99,6 +231,7 @@ class RDLoop(LoopBase, metaclass=LoopMeta):
)
else:
feedback = self.summarizer.generate_feedback(prev_out["running"], self.trace)
feedback = self._interact_feedback(feedback)
logger.log_object(feedback, tag="feedback")
return feedback
+2
View File
@@ -105,12 +105,14 @@ class HypothesisFeedback(ExperimentFeedback):
new_hypothesis: str | None = None,
eda_improvement: str | None = None,
acceptable: bool | None = None,
exception: Exception | None = None,
) -> None:
super().__init__(
reason,
decision=decision,
code_change_summary=code_change_summary,
eda_improvement=eda_improvement,
exception=exception,
)
self.observations = observations
self.hypothesis_evaluation = hypothesis_evaluation
+9 -2
View File
@@ -19,9 +19,16 @@ class LogSettings(ExtendedBaseSettings):
storages: dict[str, list[int | str]] = {}
def set_ui_server_port(self, port: int | None) -> None:
self.ui_server_port = port
if port is None:
self.storages.pop("rdagent.log.ui.storage.WebStorage", None)
return
self.storages["rdagent.log.ui.storage.WebStorage"] = [port, self.trace_path]
def model_post_init(self, _context: Any, /) -> None:
if self.ui_server_port is not None:
self.storages["rdagent.log.ui.storage.WebStorage"] = [self.ui_server_port, self.trace_path]
self.set_ui_server_port(self.ui_server_port)
LOG_SETTINGS = LogSettings()
+34 -17
View File
@@ -7,18 +7,12 @@ from pathlib import Path
from typing import Generator
from loguru import logger
from .conf import LOG_SETTINGS
if LOG_SETTINGS.format_console is not None:
logger.remove()
logger.add(sys.stdout, format=LOG_SETTINGS.format_console)
from psutil import Process
from rdagent.core.utils import SingletonBaseClass, import_class
from .base import Storage
from .conf import LOG_SETTINGS
from .storage import FileStorage
from .utils import get_caller_info
@@ -48,6 +42,18 @@ class RDAgentLog(SingletonBaseClass):
# Thread-/coroutine-local tag; In Linux forked subprocess, it will be copied to the subprocess.
_tag_ctx: ContextVar[str] = ContextVar("_tag_ctx", default="")
_raw_log_key = "_rdagent_raw"
@classmethod
def _configure_console_sinks(cls) -> None:
raw_filter = lambda record: bool(record["extra"].get(cls._raw_log_key, False))
normal_filter = lambda record: not raw_filter(record)
if LOG_SETTINGS.format_console is not None:
logger.add(sys.stdout, format=LOG_SETTINGS.format_console, filter=normal_filter)
else:
logger.add(sys.stdout, filter=normal_filter)
logger.add(sys.stdout, format="{message}", filter=raw_filter)
@property
def _tag(self) -> str: # Get current tag
@@ -58,13 +64,29 @@ class RDAgentLog(SingletonBaseClass):
self._tag_ctx.set(value)
def __init__(self) -> None:
logger.remove()
self._configure_console_sinks()
self.storage = FileStorage(LOG_SETTINGS.trace_path)
self.other_storages: list[Storage] = []
self.refresh_storages_from_settings()
self.main_pid = os.getpid()
def refresh_storages_from_settings(self) -> None:
self.other_storages = []
for storage, args in LOG_SETTINGS.storages.items():
storage_cls = import_class(storage)
self.other_storages.append(storage_cls(*args))
self.main_pid = os.getpid()
def rebind_console_to_current_streams(self) -> None:
"""Rebind loguru sinks to the current stdio objects.
This is needed in forked/spawned subprocesses after stdout/stderr have been
redirected, because loguru keeps references to the original stream objects.
"""
logger.remove()
self._configure_console_sinks()
@contextmanager
def tag(self, tag: str) -> Generator[None, None, None]:
@@ -82,6 +104,8 @@ class RDAgentLog(SingletonBaseClass):
self._tag_ctx.reset(token)
def set_storages_path(self, path: str | Path) -> None:
if isinstance(path, str):
path = Path(path)
for storage in [self.storage] + self.other_storages:
if hasattr(storage, "path"):
storage.path = path
@@ -115,17 +139,10 @@ class RDAgentLog(SingletonBaseClass):
caller_info = get_caller_info(level=3)
tag = f"{self._tag}.{tag}.{self.get_pids()}".strip(".")
if raw:
logger.remove()
logger.add(sys.stderr, format=lambda r: "{message}")
log_func = getattr(logger.patch(lambda r: r.update(caller_info)), level)
patched_logger = logger.patch(lambda r: r.update(caller_info)).bind(**{self._raw_log_key: raw}).opt(raw=raw)
log_func = getattr(patched_logger, level)
log_func(msg)
if raw:
logger.remove()
logger.add(sys.stderr)
def info(self, msg: str, *, tag: str = "", raw: bool = False) -> None:
self._log("info", msg, tag=tag, raw=raw)
+378 -85
View File
@@ -1,69 +1,287 @@
import logging
import os
import random
import signal
import subprocess
import traceback
from collections import defaultdict
from contextlib import redirect_stderr, redirect_stdout
from datetime import datetime, timezone
from multiprocessing import Process, Queue
from pathlib import Path
from queue import Empty
import randomname
import typer
from flask import Flask, jsonify, request, send_from_directory
from flask import Flask, jsonify, request, send_file, send_from_directory
from flask_cors import CORS
from werkzeug.utils import secure_filename
from rdagent.log.storage import FileStorage
from rdagent.log.ui.conf import UI_SETTING
from rdagent.log.ui.storage import WebStorage
from rdagent.log.utils import is_valid_session
app = Flask(__name__, static_folder=UI_SETTING.static_path)
app = Flask(__name__, static_folder=str(Path(UI_SETTING.static_path).resolve()))
CORS(app)
app.config["UI_SERVER_PORT"] = 19899
rdagent_processes = defaultdict()
server_port = 19899
_YELLOW = "\033[33m"
_RESET = "\033[0m"
class _YellowWarningFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
if record.levelno == logging.WARNING:
record.levelname = f"{_YELLOW}{record.levelname}{_RESET}"
return super().format(record)
def _configure_app_logger() -> None:
formatter = _YellowWarningFormatter(
fmt="[%(asctime)s] %(levelname)s in %(module)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
for handler in app.logger.handlers:
handler.setFormatter(formatter)
_configure_app_logger()
_TARGETS_WITHOUT_USER_INTERACTION = {"general_model", "fin_factor_report"}
class RDAgentTask:
def __init__(
self,
target_name: str,
kwargs: dict,
stdout_path: str,
log_trace_path: str,
scenario: str,
trace_name: str,
ui_server_port: int | None = None,
create_process: bool = True,
) -> None:
self.target_name = target_name
self.kwargs = kwargs
self.stdout_path = stdout_path
self.log_trace_path = log_trace_path
self.scenario = scenario
self.trace_name = trace_name
self.ui_server_port = ui_server_port
self.process: Process | None = None
# Two IPC queues for user interaction.
# - `user_request_q`: rdagent subprocess -> server (dicts to render on frontend)
# - `user_response_q`: server -> rdagent subprocess (user input dicts)
# NOTE: Use multiprocessing.Queue because rdagent is started as a separate process.
self.user_request_q: Queue = Queue(maxsize=1024)
self.user_response_q: Queue = Queue(maxsize=1024)
if create_process:
self.process = Process(
target=self._run,
name=f"rdagent:{self.scenario}:{self.trace_name}",
)
self.messages: list[dict] = []
self.pointers: defaultdict[str, int] = defaultdict(int)
def start(self) -> None:
if self.process is not None:
self.process.start()
def is_alive(self) -> bool:
return self.process is not None and self.process.is_alive()
def get_end_code(self) -> int:
if self.process is None or self.process.exitcode is None:
return 0
return self.process.exitcode
def stop(self) -> None:
if self.process is not None and self.process.is_alive():
self.process.terminate()
self.process.join()
# Best-effort cleanup for IPC queues.
for q in (self.user_request_q, self.user_response_q):
try:
q.cancel_join_thread()
except Exception:
pass
try:
q.close()
except Exception:
pass
def _run(self) -> None:
from rdagent.log.conf import LOG_SETTINGS
LOG_SETTINGS.set_ui_server_port(self.ui_server_port)
from rdagent.log import rdagent_logger
rdagent_logger.refresh_storages_from_settings()
rdagent_logger.set_storages_path(self.log_trace_path)
Path(self.stdout_path).parent.mkdir(parents=True, exist_ok=True)
with open(self.stdout_path, "w") as log_file:
with redirect_stdout(log_file), redirect_stderr(log_file):
rdagent_logger.rebind_console_to_current_streams()
try:
# Only interactive targets should receive IPC queues.
if self.target_name not in _TARGETS_WITHOUT_USER_INTERACTION:
self.kwargs.setdefault(
"user_interaction_queues",
(self.user_request_q, self.user_response_q),
)
if self.target_name == "data_science":
from rdagent.app.data_science.loop import main as data_science
data_science(**self.kwargs)
elif self.target_name == "general_model":
from rdagent.app.general_model.general_model import (
extract_models_and_implement as general_model,
)
general_model(**self.kwargs)
elif self.target_name == "fin_factor":
from rdagent.app.qlib_rd_loop.factor import main as fin_factor
fin_factor(**self.kwargs)
elif self.target_name == "fin_factor_report":
from rdagent.app.qlib_rd_loop.factor_from_report import (
main as fin_factor_report,
)
fin_factor_report(**self.kwargs)
elif self.target_name == "fin_model":
from rdagent.app.qlib_rd_loop.model import main as fin_model
fin_model(**self.kwargs)
elif self.target_name == "fin_quant":
from rdagent.app.qlib_rd_loop.quant import main as fin_quant
fin_quant(**self.kwargs)
else:
raise ValueError(f"Unknown target: {self.target_name}")
except Exception:
traceback.print_exc()
rdagent_processes: dict[str, RDAgentTask] = {}
log_folder_path = Path(UI_SETTING.trace_folder).absolute()
def _drain_user_requests_into_messages(task: RDAgentTask) -> None:
"""Move a single pending user-interaction request into `task.messages`.
Assumption: each rdagent process only has one active request at a time.
"""
try:
req = task.user_request_q.get_nowait()
except Empty:
return
except Exception:
return
# Standardize the message shape for the frontend.
# The agent can send either a full message dict, or a raw content dict.
if isinstance(req, dict) and {"tag", "timestamp", "content"}.issubset(req.keys()):
msg = req
else:
msg = {
"tag": "user_interaction.request",
"timestamp": datetime.now(timezone.utc).isoformat(),
"content": req,
}
task.messages.append(msg)
@app.route("/favicon.ico")
def favicon():
return send_from_directory(app.static_folder, "favicon.ico", mimetype="image/vnd.microsoft.icon")
msgs_for_frontend = defaultdict(list)
pointers = defaultdict(lambda: defaultdict(int)) # pointers[trace_id][user_ip]
def _normalize_static_request_path(fn: str) -> str:
static_prefix = UI_SETTING.static_path.strip("./")
if static_prefix and fn.startswith(f"{static_prefix}/"):
return fn[len(static_prefix) + 1 :]
return fn
def _get_or_create_task(trace_id: str) -> RDAgentTask:
task = rdagent_processes.get(trace_id)
if task is None:
task = RDAgentTask(
target_name="",
kwargs={},
stdout_path="",
log_trace_path=trace_id,
scenario="",
trace_name="",
ui_server_port=None,
create_process=False,
)
rdagent_processes[trace_id] = task
return task
def _resolve_stdout_path(trace_id: str) -> Path | None:
normalized_trace_id = str(trace_id or "").strip()
if not normalized_trace_id:
return None
task = rdagent_processes.get(str(log_folder_path / normalized_trace_id))
if task is None or not task.stdout_path:
return None
stdout_path = Path(task.stdout_path).resolve()
try:
if os.path.commonpath([str(stdout_path), str(log_folder_path)]) != str(log_folder_path):
return None
except ValueError:
return None
return stdout_path
def read_trace(log_path: Path, id: str = "") -> None:
fs = FileStorage(log_path)
ws = WebStorage(port=1, path=log_path)
msgs_for_frontend[id] = []
task = _get_or_create_task(id)
task.messages = []
last_timestamp = None
for msg in fs.iter_msg():
data = ws._obj_to_json(obj=msg.content, tag=msg.tag, id=id, timestamp=msg.timestamp.isoformat())
if data:
if isinstance(data, list):
for d in data:
msgs_for_frontend[id].append(d["msg"])
task.messages.append(d["msg"])
last_timestamp = msg.timestamp
else:
msgs_for_frontend[id].append(data["msg"])
task.messages.append(data["msg"])
last_timestamp = msg.timestamp
now = datetime.now(timezone.utc)
if last_timestamp and (now - last_timestamp).total_seconds() > 1800:
msgs_for_frontend[id].append({"tag": "END", "timestamp": now.isoformat(), "content": {}})
task.messages.append(
{
"tag": "END",
"timestamp": now.isoformat(),
"content": {"error_msg": "Trace session has ended.", "end_code": 0},
}
)
# load all traces from the log folder
for p in log_folder_path.glob("*/*/"):
if is_valid_session(p):
read_trace(p, id=str(p))
# for p in log_folder_path.glob("*/*/"):
# read_trace(p, id=str(p))
@app.route("/trace", methods=["POST"])
def update_trace():
global pointers, msgs_for_frontend
data = request.get_json()
trace_id = data.get("id")
return_all = data.get("all")
@@ -75,28 +293,64 @@ def update_trace():
return jsonify({"error": "Trace ID is required"}), 400
trace_id = str(log_folder_path / trace_id)
task = _get_or_create_task(trace_id)
# Make sure any pending user-interaction requests are visible to the frontend.
_drain_user_requests_into_messages(task)
if task.process is not None and not task.is_alive():
if not task.messages or task.messages[-1].get("tag") != "END":
task.messages.append(
{
"tag": "END",
"timestamp": datetime.now(timezone.utc).isoformat(),
"content": {
"error_msg": "RD-Agent process has completed.",
"end_code": task.get_end_code(),
},
}
)
app.logger.warning(f"Process for {trace_id} has ended.")
user_ip = request.remote_addr
if reset:
pointers[trace_id][user_ip] = 0
task.pointers[user_ip] = 0
start_pointer = pointers[trace_id][user_ip]
start_pointer = task.pointers[user_ip]
end_pointer = start_pointer + msg_num
if end_pointer > len(msgs_for_frontend[trace_id]) or return_all:
end_pointer = len(msgs_for_frontend[trace_id])
if end_pointer > len(task.messages) or return_all:
end_pointer = len(task.messages)
returned_msgs = msgs_for_frontend[trace_id][start_pointer:end_pointer]
pointers[trace_id][user_ip] = end_pointer
returned_msgs = task.messages[start_pointer:end_pointer]
task.pointers[user_ip] = end_pointer
if returned_msgs:
app.logger.info([msg["tag"] for msg in returned_msgs])
return jsonify(returned_msgs), 200
@app.route("/stdout", methods=["GET"])
def download_stdout_file():
trace_id = request.args.get("id", "")
stdout_path = _resolve_stdout_path(trace_id)
if stdout_path is None:
return jsonify({"error": "Trace ID is required or invalid"}), 400
if not stdout_path.exists() or not stdout_path.is_file():
return jsonify({"error": "Stdout file not found"}), 404
return send_file(
stdout_path,
as_attachment=True,
download_name=stdout_path.name,
mimetype="text/plain",
)
@app.route("/upload", methods=["POST"])
def upload_file():
# 获取请求体中的字段
global rdagent_processes, server_port
global rdagent_processes
scenario = request.form.get("scenario")
files = request.files.getlist("files")
competition = request.form.get("competition")
@@ -109,21 +363,19 @@ def upload_file():
trace_name = f"{competition}-{randomname.get_name()}"
else:
trace_name = randomname.get_name()
trace_files_path = log_folder_path / scenario / "uploads" / trace_name
trace_files_path = log_folder_path / "uploads" / scenario / trace_name
log_trace_path = (log_folder_path / scenario / trace_name).absolute()
stdout_path = log_folder_path / scenario / f"{trace_name}.stdout"
stdout_path = log_folder_path / scenario / f"{trace_name}.log"
if not stdout_path.exists():
stdout_path.parent.mkdir(parents=True, exist_ok=True)
# save files
for file in files:
if file:
p = (log_folder_path / scenario / "uploads" / trace_name).resolve()
p = (log_folder_path / "uploads" / scenario / trace_name).resolve()
sanitized_filename = secure_filename(file.filename) # Sanitize filename
target_path = (p / sanitized_filename).resolve() # Normalize target path
if not sanitized_filename.lower().endswith(".pdf"):
return jsonify({"error": "Invalid file type"}), 400
# Ensure target_path is within the allowed base directory
if os.path.commonpath([str(target_path), str(p)]) == str(p) and target_path.is_file() == False:
if not p.exists():
@@ -132,42 +384,62 @@ def upload_file():
else:
return jsonify({"error": "Invalid file path"}), 400
target_name = None
kwargs = {}
loop_n_val = int(loop_n) if loop_n else None
all_duration_val = f"{all_duration}h" if all_duration else None
if scenario == "Finance Data Building":
cmds = ["rdagent", "fin_factor"]
if scenario == "Finance Data Building (Reports)":
cmds = ["rdagent", "fin_factor_report", "--report_folder", str(trace_files_path)]
target_name = "fin_factor"
kwargs = {
"loop_n": loop_n_val,
"all_duration": all_duration_val,
"base_features_path": str(trace_files_path),
}
if scenario == "Finance Model Implementation":
cmds = ["rdagent", "fin_model"]
target_name = "fin_model"
kwargs = {
"loop_n": loop_n_val,
"all_duration": all_duration_val,
"base_features_path": str(trace_files_path),
}
if scenario == "Finance Whole Pipeline":
target_name = "fin_quant"
kwargs = {
"loop_n": loop_n_val,
"all_duration": all_duration_val,
"base_features_path": str(trace_files_path),
}
if scenario == "Finance Data Building (Reports)":
target_name = "fin_factor_report"
kwargs = {"report_folder": str(trace_files_path), "all_duration": all_duration_val}
if scenario == "General Model Implementation":
if len(files) == 0: # files is one link
rfp = request.form.get("files")[0]
else: # one file is uploaded
rfp = str(trace_files_path / files[0].filename)
cmds = ["rdagent", "general_model", "--report_file_path", rfp]
if scenario == "Finance Whole Pipeline":
cmds = ["rdagent", "fin_quant"]
target_name = "general_model"
kwargs = {"report_file_path": rfp}
if scenario == "Data Science":
cmds = ["rdagent", "data_science", "--competition", competition]
target_name = "data_science"
kwargs = {"competition": competition, "loop_n": loop_n_val, "timeout": all_duration_val}
# time control parameters
if scenario != "Finance Data Building (Reports)":
if loop_n:
cmds += ["--loop_n", loop_n]
if all_duration:
cmds += ["--timeout", f"{all_duration}h"]
if target_name is None:
return jsonify({"error": "Unknown scenario"}), 400
app.logger.info(f"Started process for {log_trace_path} with parameters: {cmds}")
with stdout_path.open("w") as log_file:
rdagent_processes[str(log_trace_path)] = subprocess.Popen(
cmds,
stdout=log_file,
stderr=log_file,
env={
**os.environ,
"LOG_TRACE_PATH": str(log_trace_path),
"LOG_UI_SERVER_PORT": str(server_port),
},
)
app.logger.info(f"Started process for {log_trace_path} with target: {target_name}, kwargs: {kwargs}")
task = RDAgentTask(
target_name=target_name,
kwargs=kwargs,
stdout_path=str(stdout_path),
log_trace_path=str(log_trace_path),
scenario=scenario,
trace_name=trace_name,
ui_server_port=app.config["UI_SERVER_PORT"],
)
task.start()
app.logger.warning(f"Task {log_trace_path} started.")
rdagent_processes[str(log_trace_path)] = task
return (
jsonify(
{
@@ -182,7 +454,6 @@ def upload_file():
def receive_msgs():
try:
data = request.get_json()
# app.logger.info(data["msg"]["tag"])
if not data:
return jsonify({"error": "No JSON data received"}), 400
except Exception as e:
@@ -190,16 +461,41 @@ def receive_msgs():
if isinstance(data, list):
for d in data:
msgs_for_frontend[d["id"]].append(d["msg"])
task = _get_or_create_task(d["id"])
task.messages.append(d["msg"])
else:
msgs_for_frontend[data["id"]].append(data["msg"])
task = _get_or_create_task(data["id"])
task.messages.append(data["msg"])
return jsonify({"status": "success"}), 200
@app.route("/user_interaction/submit", methods=["POST"])
def submit_user_interaction_response():
"""Frontend submits a user response; server forwards it to the rdagent subprocess via IPC queue."""
data = request.get_json(silent=True) or {}
trace_id = data.get("id")
payload = data.get("payload")
if not trace_id:
return jsonify({"error": "Trace ID is required"}), 400
if payload is None:
return jsonify({"error": "Missing 'payload'"}), 400
trace_id = str(log_folder_path / trace_id)
task = _get_or_create_task(trace_id)
try:
task.user_response_q.put(payload, block=False)
except Exception as e:
return jsonify({"error": f"Failed to enqueue user response: {e}"}), 500
return jsonify({"status": "success"}), 200
@app.route("/control", methods=["POST"])
def control_process():
global rdagent_processes, msgs_for_frontend
global rdagent_processes
data = request.get_json()
app.logger.info(data)
if not data or "id" not in data or "action" not in data:
@@ -208,32 +504,31 @@ def control_process():
id = str(log_folder_path / data["id"])
action = data["action"]
if action != "stop":
return jsonify({"error": "Only 'stop' action is supported"}), 400
if id not in rdagent_processes or rdagent_processes[id] is None:
return jsonify({"error": "No running process for given id"}), 400
process = rdagent_processes[id]
task = rdagent_processes[id]
if process.poll() is not None:
msgs_for_frontend[id].append({"tag": "END", "timestamp": datetime.now(timezone.utc).isoformat(), "content": {}})
return jsonify({"error": "Process has already terminated"}), 400
if task.process is None:
return jsonify({"error": "No running process for given id"}), 400
try:
if action == "pause":
os.kill(process.pid, signal.SIGSTOP)
return jsonify({"status": "paused"}), 200
elif action == "resume":
os.kill(process.pid, signal.SIGCONT)
return jsonify({"status": "resumed"}), 200
elif action == "stop":
process.terminate()
process.wait()
del rdagent_processes[id]
msgs_for_frontend[id].append(
{"tag": "END", "timestamp": datetime.now(timezone.utc).isoformat(), "content": {}}
if task.is_alive():
task.stop()
if not task.messages or task.messages[-1].get("tag") != "END":
task.messages.append(
{
"tag": "END",
"timestamp": datetime.now(timezone.utc).isoformat(),
"content": {"error_msg": "RD-Agent process was stopped by user.", "end_code": -1},
}
)
return jsonify({"status": "stopped"}), 200
else:
return jsonify({"error": "Unknown action"}), 400
app.logger.warning(f"Process for {id} has been stopped.")
return jsonify({"status": "stopped"}), 200
except Exception as e:
return jsonify({"error": f"Failed to {action} process, {e}"}), 500
@@ -241,9 +536,8 @@ def control_process():
@app.route("/test", methods=["GET"])
def test():
# return 'Hello, World!'
global msgs_for_frontend, pointers
msgs = {k: [i["tag"] for i in v] for k, v in msgs_for_frontend.items()}
pointers = pointers
msgs = {k: [i["tag"] for i in task.messages] for k, task in rdagent_processes.items()}
pointers = {k: dict(task.pointers) for k, task in rdagent_processes.items()}
return jsonify({"msgs": msgs, "pointers": pointers}), 200
@@ -256,12 +550,11 @@ def index():
@app.route("/<path:fn>", methods=["GET"])
def server_static_files(fn):
return send_from_directory(app.static_folder, fn)
return send_from_directory(app.static_folder, _normalize_static_request_path(fn))
def main(port: int = 19899):
global server_port
server_port = port
app.config["UI_SERVER_PORT"] = port
app.run(debug=False, host="0.0.0.0", port=port)
+1 -1
View File
@@ -16,7 +16,7 @@ class UIBasePropSetting(ExtendedBaseSettings):
static_path: str = "./git_ignore_folder/static"
trace_folder: str = "./traces"
trace_folder: str = "./git_ignore_folder/traces"
enable_cache: bool = True
+5 -4
View File
@@ -33,10 +33,11 @@ class WebStorage(Storage):
def log(self, obj: object, tag: str, timestamp: datetime | None = None, **kwargs: Any) -> str | Path:
timestamp = gen_datetime(timestamp)
if "pdf_image" in tag or "load_pdf_screenshot" in tag:
obj.save(f"{UI_SETTING.static_path}/{timestamp.isoformat()}.jpg")
Path(f"{UI_SETTING.static_path}/pdf_images").mkdir(parents=True, exist_ok=True)
obj.save(f"{UI_SETTING.static_path}/pdf_images/{timestamp.isoformat()}.jpg")
try:
data = self._obj_to_json(obj=obj, tag=tag, id=self.path, timestamp=timestamp.isoformat())
data = self._obj_to_json(obj=obj, tag=tag, id=str(self.path), timestamp=timestamp.isoformat())
if not data:
return "Normal log, skipped"
if isinstance(data, list):
@@ -48,7 +49,7 @@ class WebStorage(Storage):
resp = requests.post(f"{self.url}/receive", json=data, headers=headers, timeout=1)
return f"{resp.status_code} {resp.text}"
except (requests.ConnectionError, requests.Timeout) as e:
pass
print(f"Failed to connect to the web storage server at {self.url}: {e}")
def truncate(self, time: datetime) -> None:
self.msgs = [m for m in self.msgs if datetime.fromisoformat(m["msg"]["timestamp"]) <= time]
@@ -100,7 +101,7 @@ class WebStorage(Storage):
"tag": "research.pdf_image",
"timestamp": timestamp,
"loop_id": li,
"content": {"image": f"{timestamp}.jpg"},
"content": {"image": f"pdf_images/{timestamp}.jpg"},
},
}
elif "experiment generation" in tag or "load_experiment" in tag:
+1 -1
View File
@@ -92,7 +92,7 @@ def extract_loopid_func_name(tag: str) -> tuple[str, str] | tuple[None, None]:
def extract_evoid(tag: str) -> str | None:
"""extract evo id from the tag in Message"""
match = re.search(r"\.evo_loop_(\d+)\.", tag)
match = re.search(r"evo_loop_(\d+)\.", tag)
return cast(str, match.group(1)) if match else None
@@ -19,17 +19,6 @@ from rdagent.scenarios.qlib.experiment.model_experiment import QlibModelExperime
DIRNAME = Path(__file__).absolute().resolve().parent
DIRNAME_local = Path.cwd()
# class QlibFactorExpWorkspace:
# def prepare():
# # create a folder;
# # copy template
# # place data inside the folder `combined_factors`
# #
# def execute():
# de = DockerEnv()
# de.run(local_path=self.ws_path, entry="qrun conf_baseline.yaml")
# TODO: supporting multiprocessing and keep previous results
@@ -89,6 +78,8 @@ class QlibFactorRunner(CachedRunner[QlibFactorExperiment]):
"valid_start": fbps.valid_start,
"valid_end": fbps.valid_end,
"test_start": fbps.test_start,
"feature_names": str(list(exp.base_features.keys())),
"feature_expressions": str(list(exp.base_features.values())),
}
if fbps.test_end is not None:
env_to_use.update({"test_end": fbps.test_end})
@@ -103,8 +94,8 @@ class QlibFactorRunner(CachedRunner[QlibFactorExperiment]):
logger.info(f"SOTA factor processing ...")
SOTA_factor = process_factor_data(sota_factor_experiments_list)
logger.info(f"New factor processing ...")
# Process the new factors data
logger.info(f"New factor processing ...")
new_factors = process_factor_data(exp)
if new_factors.empty:
@@ -126,9 +117,10 @@ class QlibFactorRunner(CachedRunner[QlibFactorExperiment]):
combined_factors = combined_factors.loc[:, ~combined_factors.columns.duplicated(keep="last")]
new_columns = pd.MultiIndex.from_product([["feature"], combined_factors.columns])
combined_factors.columns = new_columns
num_features = RD_AGENT_SETTINGS.initial_fator_library_size + len(combined_factors.columns)
logger.info(f"Factor data processing completed.")
num_features = len(exp.base_features) + len(combined_factors.columns)
# Due to the rdagent and qlib docker image in the numpy version of the difference,
# the `combined_factors_df.pkl` file could not be loaded correctly in qlib dokcer,
# so we changed the file type of `combined_factors_df` from pkl to parquet.
@@ -175,19 +167,30 @@ class QlibFactorRunner(CachedRunner[QlibFactorExperiment]):
else:
# LGBM + combined factors
result, stdout = exp.experiment_workspace.execute(
qlib_config_name=(
f"conf_baseline.yaml" if len(exp.based_experiments) == 0 else "conf_combined_factors.yaml"
),
qlib_config_name="conf_combined_factors.yaml",
run_env=env_to_use,
)
else:
logger.info(f"Experiment execution ...")
result, stdout = exp.experiment_workspace.execute(
qlib_config_name=(
f"conf_baseline.yaml" if len(exp.based_experiments) == 0 else "conf_combined_factors.yaml"
),
run_env=env_to_use,
)
if exp.base_feature_codes:
factors = process_factor_data(exp)
factors = factors.sort_index()
factors = factors.loc[:, ~factors.columns.duplicated(keep="last")]
new_columns = pd.MultiIndex.from_product([["feature"], factors.columns])
factors.columns = new_columns
target_path = exp.experiment_workspace.workspace_path / "combined_factors_df.parquet"
# Save the combined factors to the workspace
factors.to_parquet(target_path, engine="pyarrow")
logger.info(f"Factor data processing completed.")
result, stdout = exp.experiment_workspace.execute(
qlib_config_name="conf_combined_factors.yaml",
run_env=env_to_use,
)
else:
result, stdout = exp.experiment_workspace.execute(
qlib_config_name="conf_baseline.yaml",
run_env=env_to_use,
)
if result is None:
logger.error(f"Failed to run this experiment, because {stdout}")
@@ -47,7 +47,7 @@ class QlibModelRunner(CachedRunner[QlibModelExperiment]):
combined_factors = combined_factors.loc[:, ~combined_factors.columns.duplicated(keep="last")]
new_columns = pd.MultiIndex.from_product([["feature"], combined_factors.columns])
combined_factors.columns = new_columns
num_features = str(RD_AGENT_SETTINGS.initial_fator_library_size + len(combined_factors.columns))
num_features = str(len(exp.base_features) + len(combined_factors.columns))
target_path = exp.experiment_workspace.workspace_path / "combined_factors_df.parquet"
@@ -67,6 +67,8 @@ class QlibModelRunner(CachedRunner[QlibModelExperiment]):
"valid_start": mbps.valid_start,
"valid_end": mbps.valid_end,
"test_start": mbps.test_start,
"feature_names": str(list(exp.base_features.keys())),
"feature_expressions": str(list(exp.base_features.values())),
}
if mbps.test_end is not None:
env_to_use.update({"test_end": mbps.test_end})
+142 -32
View File
@@ -3,6 +3,7 @@ from typing import List
import pandas as pd
from rdagent.components.coder.CoSTEER.evaluators import CoSTEERMultiFeedback
from rdagent.components.coder.factor_coder.factor import FactorFBWorkspace, FactorTask
from rdagent.core.conf import RD_AGENT_SETTINGS
from rdagent.core.exception import FactorEmptyError
from rdagent.core.utils import multiprocessing_wrapper
@@ -10,6 +11,123 @@ from rdagent.log import rdagent_logger as logger
from rdagent.scenarios.qlib.experiment.factor_experiment import QlibFactorExperiment
def _build_base_feature_workspaces(exp: QlibFactorExperiment) -> list[FactorFBWorkspace]:
workspaces: list[FactorFBWorkspace] = []
for file_name, code in exp.base_feature_codes.items():
workspace = FactorFBWorkspace(
target_task=FactorTask(
factor_name=file_name,
factor_description=f"Base feature from {file_name}",
factor_formulation="",
)
)
workspace.inject_files(**{"factor.py": code})
workspaces.append(workspace)
return workspaces
def _build_execute_calls(exp: QlibFactorExperiment, base_feature_workspaces: list[FactorFBWorkspace]) -> list[tuple]:
execute_calls = []
if exp.sub_tasks:
assert isinstance(exp.prop_dev_feedback, CoSTEERMultiFeedback)
execute_calls.extend(
(implementation.execute, ("All",))
for implementation, feedback in zip(exp.sub_workspace_list, exp.prop_dev_feedback)
if implementation and feedback
)
execute_calls.extend((workspace.execute, ("All",)) for workspace in base_feature_workspaces)
return execute_calls
def _resolve_index_level_values(df: pd.DataFrame, level_name: str) -> pd.Index | None:
matching_levels = [idx for idx, name in enumerate(df.index.names) if name == level_name]
if not matching_levels:
return None
if len(matching_levels) == 1:
return df.index.get_level_values(matching_levels[0])
candidate_values = [df.index.get_level_values(idx) for idx in matching_levels]
first_values = candidate_values[0]
if all(first_values.equals(values) for values in candidate_values[1:]):
logger.warning(
f"Factor dataframe has duplicated '{level_name}' index levels at positions {matching_levels}; "
"their values are identical, so the first one is used."
)
return first_values
logger.warning(
f"Skip factor dataframe because index has ambiguous duplicated '{level_name}' levels at positions "
f"{matching_levels}. index names={list(df.index.names)}"
)
return None
def _normalize_factor_index(df: pd.DataFrame) -> pd.DataFrame | None:
"""Normalize factor index to a 2-level MultiIndex: (datetime, instrument)."""
if df is None or df.empty:
return None
index_names = list(df.index.names)
if "datetime" not in index_names:
return None
if "instrument" not in index_names:
logger.warning(f"Skip factor dataframe because index misses 'instrument'. index names={index_names}")
return None
datetime_values = _resolve_index_level_values(df, "datetime")
instrument_values = _resolve_index_level_values(df, "instrument")
if datetime_values is None or instrument_values is None:
return None
normalized = df.copy()
normalized.index = pd.MultiIndex.from_arrays(
[datetime_values, instrument_values],
names=["datetime", "instrument"],
)
return normalized
def _format_index_info(df: pd.DataFrame | None) -> str:
if df is None:
return "df is None"
return f"index_type={type(df.index).__name__}, nlevels={df.index.nlevels}, names={list(df.index.names)}"
def _process_message_and_df(
source_name: str,
message: str,
df: pd.DataFrame | None,
factor_dfs: list[pd.DataFrame],
error_message: str,
) -> str:
index_info = _format_index_info(df)
if df is None or "datetime" not in df.index.names:
logger.warning(f"Factor data from {source_name} has invalid execution output or index: {index_info}")
logger.warning(f"Factor data from {source_name} is not generated because of {message}")
return (
f"{error_message}Factor data from {source_name} is not generated because of {message}. "
f"index_info={index_info}. "
)
normalized_df = _normalize_factor_index(df)
if normalized_df is None:
logger.warning(f"Factor data from {source_name} is skipped due to invalid index structure: {index_info}")
return f"{error_message}Factor data from {source_name} is skipped due to invalid index: {index_info}. "
time_diff = df.index.get_level_values("datetime").to_series().diff().dropna().unique()
if pd.Timedelta(minutes=1) in time_diff:
logger.warning(f"Factor data from {source_name} is not generated.")
return error_message
factor_dfs.append(normalized_df)
logger.info(f"Factor data from {source_name} is successfully generated.")
return error_message
def process_factor_data(exp_or_list: List[QlibFactorExperiment] | QlibFactorExperiment) -> pd.DataFrame:
"""
Process and combine factor data from experiment implementations.
@@ -23,44 +141,36 @@ def process_factor_data(exp_or_list: List[QlibFactorExperiment] | QlibFactorExpe
if isinstance(exp_or_list, QlibFactorExperiment):
exp_or_list = [exp_or_list]
factor_dfs = []
error_message = ""
# Collect all exp's dataframes
for exp in exp_or_list:
if isinstance(exp, QlibFactorExperiment):
if len(exp.sub_tasks) > 0:
# if it has no sub_tasks, the experiment is results from template project.
# otherwise, it is developed with designed task. So it should have feedback.
assert isinstance(exp.prop_dev_feedback, CoSTEERMultiFeedback)
# Iterate over sub-implementations and execute them to get each factor data
message_and_df_list = multiprocessing_wrapper(
[
(implementation.execute, ("All",))
for implementation, fb in zip(exp.sub_workspace_list, exp.prop_dev_feedback)
if implementation and fb
], # only execute successfully feedback
n=RD_AGENT_SETTINGS.multi_proc_n,
)
error_message = ""
for message, df in message_and_df_list:
# Check if factor generation was successful
if df is not None and "datetime" in df.index.names:
time_diff = df.index.get_level_values("datetime").to_series().diff().dropna().unique()
if pd.Timedelta(minutes=1) not in time_diff:
factor_dfs.append(df)
logger.info(
f"Factor data from {exp.hypothesis.concise_justification} is successfully generated."
)
else:
logger.warning(f"Factor data from {exp.hypothesis.concise_justification} is not generated.")
else:
error_message += f"Factor data from {exp.hypothesis.concise_justification} is not generated because of {message}"
logger.warning(
f"Factor data from {exp.hypothesis.concise_justification} is not generated because of {message}"
)
if not isinstance(exp, QlibFactorExperiment):
continue
source_name = exp.hypothesis.concise_justification if exp.hypothesis else "BASE factor files"
base_feature_workspaces = _build_base_feature_workspaces(exp)
execute_calls = _build_execute_calls(exp, base_feature_workspaces)
if not execute_calls:
continue
message_and_df_list = multiprocessing_wrapper(execute_calls, n=RD_AGENT_SETTINGS.multi_proc_n)
for message, df in message_and_df_list:
error_message = _process_message_and_df(source_name, message, df, factor_dfs, error_message)
# Combine all successful factor data
if factor_dfs:
return pd.concat(factor_dfs, axis=1)
try:
return pd.concat(factor_dfs, axis=1)
except Exception as concat_error:
concat_index_info = " | ".join([f"df#{i}: {_format_index_info(df)}" for i, df in enumerate(factor_dfs)])
logger.warning(
f"Failed to concat factor data due to index misalignment. concat_error={concat_error}; collected_index_info={concat_index_info}"
)
raise FactorEmptyError(
"Failed to concat factor data due to index misalignment or incompatible index structure. "
f"concat_error={concat_error}; collected_index_info={concat_index_info}; details={error_message}"
) from concat_error
else:
raise FactorEmptyError(
f"No valid factor data found to merge (in process_factor_data) because of {error_message}."
@@ -21,6 +21,10 @@ class QlibFactorExperiment(FactorExperiment[FactorTask, QlibFBWorkspace, FactorF
super().__init__(*args, **kwargs)
self.experiment_workspace = QlibFBWorkspace(template_folder_path=Path(__file__).parent / "factor_template")
self.stdout = ""
self.base_features: dict[str, str] = (
{}
) # Qlib features in operator form, e.g., "RESI5": "Resi($close, 5)/$close"
self.base_feature_codes: dict[str, str] = {} # Qlib features in code form
class QlibFactorScenario(Scenario):
@@ -8,30 +8,36 @@ benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
start_time: {{ train_start | default("2008-01-01", true) }}
end_time: {{ test_end | default("null", true) }}
fit_start_time: {{ train_start | default("2008-01-01", true) }}
fit_end_time: {{ train_end | default("2014-12-31", true) }}
instruments: *market
data_loader:
class: NestedDataLoader
kwargs:
dataloader_l:
- class: qlib.contrib.data.loader.Alpha158DL
kwargs:
config:
label:
- ["Ref($close, -2)/Ref($close, -1) - 1"]
- ["LABEL0"]
feature:
- {{ feature_expressions }}
- {{ feature_names }}
infer_processors:
- class: FilterCol
kwargs:
fields_group: feature
col_list: ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"
]
- class: RobustZScoreNorm
kwargs:
fields_group: feature
clip_outlier: true
fit_start_time: {{ train_start | default("2008-01-01", true) }}
fit_end_time: {{ train_end | default("2014-12-31", true) }}
- class: Fillna
kwargs:
fields_group: feature
learn_processors:
- class: DropnaLabel
- class: CSRankNorm
- class: CSZScoreNorm
kwargs:
fields_group: label
label: ["Ref($close, -2) / Ref($close, -1) - 1"]
port_analysis_config: &port_analysis_config
strategy:
@@ -52,6 +58,7 @@ port_analysis_config: &port_analysis_config
open_cost: 0.0005
close_cost: 0.0015
min_cost: 5
task:
model:
class: LGBModel
@@ -71,7 +78,7 @@ task:
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
class: DataHandlerLP
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
@@ -20,17 +20,8 @@ data_handler_config: &data_handler_config
- ["Ref($close, -2)/Ref($close, -1) - 1"]
- ["LABEL0"]
feature:
- ["Resi($close, 5)/$close", "Std(Abs($close/Ref($close, 1)-1)*$volume, 5)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 5)+1e-12)",
"Rsquare($close, 5)", "($high-$low)/$open", "Rsquare($close, 10)", "Corr($close, Log($volume+1), 5)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 5)", "Corr($close, Log($volume+1), 10)",
"Ref($close, 60)/$close", "Resi($close, 10)/$close", "Std($volume, 5)/($volume+1e-12)",
"Rsquare($close, 60)", "Corr($close, Log($volume+1), 60)", "Std(Abs($close/Ref($close, 1)-1)*$volume, 60)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 60)+1e-12)",
"Std($close, 5)/$close", "Rsquare($close, 20)", "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 60)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 10)", "Corr($close, Log($volume+1), 20)",
"(Less($open, $close)-$low)/$open"]
- ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"]
- {{ feature_expressions }}
- {{ feature_names }}
- class: qlib.data.dataset.loader.StaticDataLoader
kwargs:
config: "combined_factors_df.parquet"
@@ -20,17 +20,8 @@ data_handler_config: &data_handler_config
- ["Ref($close, -2)/Ref($close, -1) - 1"]
- ["LABEL0"]
feature:
- ["Resi($close, 5)/$close", "Std(Abs($close/Ref($close, 1)-1)*$volume, 5)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 5)+1e-12)",
"Rsquare($close, 5)", "($high-$low)/$open", "Rsquare($close, 10)", "Corr($close, Log($volume+1), 5)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 5)", "Corr($close, Log($volume+1), 10)",
"Ref($close, 60)/$close", "Resi($close, 10)/$close", "Std($volume, 5)/($volume+1e-12)",
"Rsquare($close, 60)", "Corr($close, Log($volume+1), 60)", "Std(Abs($close/Ref($close, 1)-1)*$volume, 60)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 60)+1e-12)",
"Std($close, 5)/$close", "Rsquare($close, 20)", "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 60)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 10)", "Corr($close, Log($volume+1), 20)",
"(Less($open, $close)-$low)/$open"]
- ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"]
- {{ feature_expressions }}
- {{ feature_names }}
- class: qlib.data.dataset.loader.StaticDataLoader
kwargs:
config: "combined_factors_df.parquet"
@@ -20,6 +20,7 @@ class QlibModelExperiment(ModelExperiment[ModelTask, QlibFBWorkspace, ModelFBWor
super().__init__(*args, **kwargs)
self.experiment_workspace = QlibFBWorkspace(template_folder_path=Path(__file__).parent / "model_template")
self.stdout = ""
self.base_features: dict[str, str] = {}
class QlibModelScenario(Scenario):
@@ -3,33 +3,40 @@ qlib_init:
region: cn
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
start_time: {{ train_start | default("2008-01-01", true) }}
end_time: {{ test_end | default("null", true) }}
fit_start_time: {{ train_start | default("2008-01-01", true) }}
fit_end_time: {{ train_end | default("2014-12-31", true) }}
instruments: *market
data_loader:
class: NestedDataLoader
kwargs:
dataloader_l:
- class: qlib.contrib.data.loader.Alpha158DL
kwargs:
config:
label:
- ["Ref($close, -2)/Ref($close, -1) - 1"]
- ["LABEL0"]
feature:
- {{ feature_expressions }}
- {{ feature_names }}
infer_processors:
- class: FilterCol
kwargs:
fields_group: feature
col_list: ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"
]
- class: RobustZScoreNorm
kwargs:
fields_group: feature
clip_outlier: true
fit_start_time: {{ train_start | default("2008-01-01", true) }}
fit_end_time: {{ train_end | default("2014-12-31", true) }}
- class: Fillna
kwargs:
fields_group: feature
learn_processors:
- class: DropnaLabel
- class: CSRankNorm
- class: CSZScoreNorm
kwargs:
fields_group: label
label: ["Ref($close, -2) / Ref($close, -1) - 1"]
port_analysis_config: &port_analysis_config
strategy:
@@ -74,7 +81,7 @@ task:
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
class: DataHandlerLP
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
@@ -20,17 +20,8 @@ data_handler_config: &data_handler_config
- ["Ref($close, -2)/Ref($close, -1) - 1"]
- ["LABEL0"]
feature:
- ["Resi($close, 5)/$close", "Std(Abs($close/Ref($close, 1)-1)*$volume, 5)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 5)+1e-12)",
"Rsquare($close, 5)", "($high-$low)/$open", "Rsquare($close, 10)", "Corr($close, Log($volume+1), 5)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 5)", "Corr($close, Log($volume+1), 10)",
"Ref($close, 60)/$close", "Resi($close, 10)/$close", "Std($volume, 5)/($volume+1e-12)",
"Rsquare($close, 60)", "Corr($close, Log($volume+1), 60)", "Std(Abs($close/Ref($close, 1)-1)*$volume, 60)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 60)+1e-12)",
"Std($close, 5)/$close", "Rsquare($close, 20)", "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 60)",
"Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 10)", "Corr($close, Log($volume+1), 20)",
"(Less($open, $close)-$low)/$open"]
- ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"]
- {{ feature_expressions }}
- {{ feature_names }}
- class: qlib.data.dataset.loader.StaticDataLoader
kwargs:
config: "combined_factors_df.parquet"
+208
View File
@@ -0,0 +1,208 @@
from rdagent.core.experiment import FBWorkspace
from rdagent.utils.env import QlibCondaConf, QlibCondaEnv
ALPHA20 = {
"RESI5": "Resi($close, 5)/$close",
"WVMA5": "Std(Abs($close/Ref($close, 1)-1)*$volume, 5)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 5)+1e-12)",
"RSQR5": "Rsquare($close, 5)",
"KLEN": "($high-$low)/$open",
"RSQR10": "Rsquare($close, 10)",
"CORR5": "Corr($close, Log($volume+1), 5)",
"CORD5": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 5)",
"CORR10": "Corr($close, Log($volume+1), 10)",
"ROC60": "Ref($close, 60)/$close",
"RESI10": "Resi($close, 10)/$close",
"VSTD5": "Std($volume, 5)/($volume+1e-12)",
"RSQR60": "Rsquare($close, 60)",
"CORR60": "Corr($close, Log($volume+1), 60)",
"WVMA60": "Std(Abs($close/Ref($close, 1)-1)*$volume, 60)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 60)+1e-12)",
"STD5": "Std($close, 5)/$close",
"RSQR20": "Rsquare($close, 20)",
"CORD60": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 60)",
"CORD10": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 10)",
"CORR20": "Corr($close, Log($volume+1), 20)",
"KLOW": "(Less($open, $close)-$low)/$open",
}
ALPHA158 = {
"KMID": "($close-$open)/$open",
"KLEN": "($high-$low)/$open",
"KMID2": "($close-$open)/($high-$low+1e-12)",
"KUP": "($high-Greater($open, $close))/$open",
"KUP2": "($high-Greater($open, $close))/($high-$low+1e-12)",
"KLOW": "(Less($open, $close)-$low)/$open",
"KLOW2": "(Less($open, $close)-$low)/($high-$low+1e-12)",
"KSFT": "(2*$close-$high-$low)/$open",
"KSFT2": "(2*$close-$high-$low)/($high-$low+1e-12)",
"OPEN0": "$open/$close",
"HIGH0": "$high/$close",
"LOW0": "$low/$close",
"VWAP0": "$vwap/$close",
"ROC5": "Ref($close, 5)/$close",
"ROC10": "Ref($close, 10)/$close",
"ROC20": "Ref($close, 20)/$close",
"ROC30": "Ref($close, 30)/$close",
"ROC60": "Ref($close, 60)/$close",
"MA5": "Mean($close, 5)/$close",
"MA10": "Mean($close, 10)/$close",
"MA20": "Mean($close, 20)/$close",
"MA30": "Mean($close, 30)/$close",
"MA60": "Mean($close, 60)/$close",
"STD5": "Std($close, 5)/$close",
"STD10": "Std($close, 10)/$close",
"STD20": "Std($close, 20)/$close",
"STD30": "Std($close, 30)/$close",
"STD60": "Std($close, 60)/$close",
"BETA5": "Slope($close, 5)/$close",
"BETA10": "Slope($close, 10)/$close",
"BETA20": "Slope($close, 20)/$close",
"BETA30": "Slope($close, 30)/$close",
"BETA60": "Slope($close, 60)/$close",
"RSQR5": "Rsquare($close, 5)",
"RSQR10": "Rsquare($close, 10)",
"RSQR20": "Rsquare($close, 20)",
"RSQR30": "Rsquare($close, 30)",
"RSQR60": "Rsquare($close, 60)",
"RESI5": "Resi($close, 5)/$close",
"RESI10": "Resi($close, 10)/$close",
"RESI20": "Resi($close, 20)/$close",
"RESI30": "Resi($close, 30)/$close",
"RESI60": "Resi($close, 60)/$close",
"MAX5": "Max($high, 5)/$close",
"MAX10": "Max($high, 10)/$close",
"MAX20": "Max($high, 20)/$close",
"MAX30": "Max($high, 30)/$close",
"MAX60": "Max($high, 60)/$close",
"MIN5": "Min($low, 5)/$close",
"MIN10": "Min($low, 10)/$close",
"MIN20": "Min($low, 20)/$close",
"MIN30": "Min($low, 30)/$close",
"MIN60": "Min($low, 60)/$close",
"QTLU5": "Quantile($close, 5, 0.8)/$close",
"QTLU10": "Quantile($close, 10, 0.8)/$close",
"QTLU20": "Quantile($close, 20, 0.8)/$close",
"QTLU30": "Quantile($close, 30, 0.8)/$close",
"QTLU60": "Quantile($close, 60, 0.8)/$close",
"QTLD5": "Quantile($close, 5, 0.2)/$close",
"QTLD10": "Quantile($close, 10, 0.2)/$close",
"QTLD20": "Quantile($close, 20, 0.2)/$close",
"QTLD30": "Quantile($close, 30, 0.2)/$close",
"QTLD60": "Quantile($close, 60, 0.2)/$close",
"RANK5": "Rank($close, 5)",
"RANK10": "Rank($close, 10)",
"RANK20": "Rank($close, 20)",
"RANK30": "Rank($close, 30)",
"RANK60": "Rank($close, 60)",
"RSV5": "($close-Min($low, 5))/(Max($high, 5)-Min($low, 5)+1e-12)",
"RSV10": "($close-Min($low, 10))/(Max($high, 10)-Min($low, 10)+1e-12)",
"RSV20": "($close-Min($low, 20))/(Max($high, 20)-Min($low, 20)+1e-12)",
"RSV30": "($close-Min($low, 30))/(Max($high, 30)-Min($low, 30)+1e-12)",
"RSV60": "($close-Min($low, 60))/(Max($high, 60)-Min($low, 60)+1e-12)",
"IMAX5": "IdxMax($high, 5)/5",
"IMAX10": "IdxMax($high, 10)/10",
"IMAX20": "IdxMax($high, 20)/20",
"IMAX30": "IdxMax($high, 30)/30",
"IMAX60": "IdxMax($high, 60)/60",
"IMIN5": "IdxMin($low, 5)/5",
"IMIN10": "IdxMin($low, 10)/10",
"IMIN20": "IdxMin($low, 20)/20",
"IMIN30": "IdxMin($low, 30)/30",
"IMIN60": "IdxMin($low, 60)/60",
"IMXD5": "(IdxMax($high, 5)-IdxMin($low, 5))/5",
"IMXD10": "(IdxMax($high, 10)-IdxMin($low, 10))/10",
"IMXD20": "(IdxMax($high, 20)-IdxMin($low, 20))/20",
"IMXD30": "(IdxMax($high, 30)-IdxMin($low, 30))/30",
"IMXD60": "(IdxMax($high, 60)-IdxMin($low, 60))/60",
"CORR5": "Corr($close, Log($volume+1), 5)",
"CORR10": "Corr($close, Log($volume+1), 10)",
"CORR20": "Corr($close, Log($volume+1), 20)",
"CORR30": "Corr($close, Log($volume+1), 30)",
"CORR60": "Corr($close, Log($volume+1), 60)",
"CORD5": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 5)",
"CORD10": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 10)",
"CORD20": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 20)",
"CORD30": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 30)",
"CORD60": "Corr($close/Ref($close,1), Log($volume/Ref($volume, 1)+1), 60)",
"CNTP5": "Mean($close>Ref($close, 1), 5)",
"CNTP10": "Mean($close>Ref($close, 1), 10)",
"CNTP20": "Mean($close>Ref($close, 1), 20)",
"CNTP30": "Mean($close>Ref($close, 1), 30)",
"CNTP60": "Mean($close>Ref($close, 1), 60)",
"CNTN5": "Mean($close<Ref($close, 1), 5)",
"CNTN10": "Mean($close<Ref($close, 1), 10)",
"CNTN20": "Mean($close<Ref($close, 1), 20)",
"CNTN30": "Mean($close<Ref($close, 1), 30)",
"CNTN60": "Mean($close<Ref($close, 1), 60)",
"CNTD5": "Mean($close>Ref($close, 1), 5)-Mean($close<Ref($close, 1), 5)",
"CNTD10": "Mean($close>Ref($close, 1), 10)-Mean($close<Ref($close, 1), 10)",
"CNTD20": "Mean($close>Ref($close, 1), 20)-Mean($close<Ref($close, 1), 20)",
"CNTD30": "Mean($close>Ref($close, 1), 30)-Mean($close<Ref($close, 1), 30)",
"CNTD60": "Mean($close>Ref($close, 1), 60)-Mean($close<Ref($close, 1), 60)",
"SUMP5": "Sum(Greater($close-Ref($close, 1), 0), 5)/(Sum(Abs($close-Ref($close, 1)), 5)+1e-12)",
"SUMP10": "Sum(Greater($close-Ref($close, 1), 0), 10)/(Sum(Abs($close-Ref($close, 1)), 10)+1e-12)",
"SUMP20": "Sum(Greater($close-Ref($close, 1), 0), 20)/(Sum(Abs($close-Ref($close, 1)), 20)+1e-12)",
"SUMP30": "Sum(Greater($close-Ref($close, 1), 0), 30)/(Sum(Abs($close-Ref($close, 1)), 30)+1e-12)",
"SUMP60": "Sum(Greater($close-Ref($close, 1), 0), 60)/(Sum(Abs($close-Ref($close, 1)), 60)+1e-12)",
"SUMN5": "Sum(Greater(Ref($close, 1)-$close, 0), 5)/(Sum(Abs($close-Ref($close, 1)), 5)+1e-12)",
"SUMN10": "Sum(Greater(Ref($close, 1)-$close, 0), 10)/(Sum(Abs($close-Ref($close, 1)), 10)+1e-12)",
"SUMN20": "Sum(Greater(Ref($close, 1)-$close, 0), 20)/(Sum(Abs($close-Ref($close, 1)), 20)+1e-12)",
"SUMN30": "Sum(Greater(Ref($close, 1)-$close, 0), 30)/(Sum(Abs($close-Ref($close, 1)), 30)+1e-12)",
"SUMN60": "Sum(Greater(Ref($close, 1)-$close, 0), 60)/(Sum(Abs($close-Ref($close, 1)), 60)+1e-12)",
"SUMD5": "(Sum(Greater($close-Ref($close, 1), 0), 5)-Sum(Greater(Ref($close, 1)-$close, 0), 5))/(Sum(Abs($close-Ref($close, 1)), 5)+1e-12)",
"SUMD10": "(Sum(Greater($close-Ref($close, 1), 0), 10)-Sum(Greater(Ref($close, 1)-$close, 0), 10))/(Sum(Abs($close-Ref($close, 1)), 10)+1e-12)",
"SUMD20": "(Sum(Greater($close-Ref($close, 1), 0), 20)-Sum(Greater(Ref($close, 1)-$close, 0), 20))/(Sum(Abs($close-Ref($close, 1)), 20)+1e-12)",
"SUMD30": "(Sum(Greater($close-Ref($close, 1), 0), 30)-Sum(Greater(Ref($close, 1)-$close, 0), 30))/(Sum(Abs($close-Ref($close, 1)), 30)+1e-12)",
"SUMD60": "(Sum(Greater($close-Ref($close, 1), 0), 60)-Sum(Greater(Ref($close, 1)-$close, 0), 60))/(Sum(Abs($close-Ref($close, 1)), 60)+1e-12)",
"VMA5": "Mean($volume, 5)/($volume+1e-12)",
"VMA10": "Mean($volume, 10)/($volume+1e-12)",
"VMA20": "Mean($volume, 20)/($volume+1e-12)",
"VMA30": "Mean($volume, 30)/($volume+1e-12)",
"VMA60": "Mean($volume, 60)/($volume+1e-12)",
"VSTD5": "Std($volume, 5)/($volume+1e-12)",
"VSTD10": "Std($volume, 10)/($volume+1e-12)",
"VSTD20": "Std($volume, 20)/($volume+1e-12)",
"VSTD30": "Std($volume, 30)/($volume+1e-12)",
"VSTD60": "Std($volume, 60)/($volume+1e-12)",
"WVMA5": "Std(Abs($close/Ref($close, 1)-1)*$volume, 5)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 5)+1e-12)",
"WVMA10": "Std(Abs($close/Ref($close, 1)-1)*$volume, 10)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 10)+1e-12)",
"WVMA20": "Std(Abs($close/Ref($close, 1)-1)*$volume, 20)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 20)+1e-12)",
"WVMA30": "Std(Abs($close/Ref($close, 1)-1)*$volume, 30)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 30)+1e-12)",
"WVMA60": "Std(Abs($close/Ref($close, 1)-1)*$volume, 60)/(Mean(Abs($close/Ref($close, 1)-1)*$volume, 60)+1e-12)",
"VSUMP5": "Sum(Greater($volume-Ref($volume, 1), 0), 5)/(Sum(Abs($volume-Ref($volume, 1)), 5)+1e-12)",
"VSUMP10": "Sum(Greater($volume-Ref($volume, 1), 0), 10)/(Sum(Abs($volume-Ref($volume, 1)), 10)+1e-12)",
"VSUMP20": "Sum(Greater($volume-Ref($volume, 1), 0), 20)/(Sum(Abs($volume-Ref($volume, 1)), 20)+1e-12)",
"VSUMP30": "Sum(Greater($volume-Ref($volume, 1), 0), 30)/(Sum(Abs($volume-Ref($volume, 1)), 30)+1e-12)",
"VSUMP60": "Sum(Greater($volume-Ref($volume, 1), 0), 60)/(Sum(Abs($volume-Ref($volume, 1)), 60)+1e-12)",
"VSUMN5": "Sum(Greater(Ref($volume, 1)-$volume, 0), 5)/(Sum(Abs($volume-Ref($volume, 1)), 5)+1e-12)",
"VSUMN10": "Sum(Greater(Ref($volume, 1)-$volume, 0), 10)/(Sum(Abs($volume-Ref($volume, 1)), 10)+1e-12)",
"VSUMN20": "Sum(Greater(Ref($volume, 1)-$volume, 0), 20)/(Sum(Abs($volume-Ref($volume, 1)), 20)+1e-12)",
"VSUMN30": "Sum(Greater(Ref($volume, 1)-$volume, 0), 30)/(Sum(Abs($volume-Ref($volume, 1)), 30)+1e-12)",
"VSUMN60": "Sum(Greater(Ref($volume, 1)-$volume, 0), 60)/(Sum(Abs($volume-Ref($volume, 1)), 60)+1e-12)",
"VSUMD5": "(Sum(Greater($volume-Ref($volume, 1), 0), 5)-Sum(Greater(Ref($volume, 1)-$volume, 0), 5))/(Sum(Abs($volume-Ref($volume, 1)), 5)+1e-12)",
"VSUMD10": "(Sum(Greater($volume-Ref($volume, 1), 0), 10)-Sum(Greater(Ref($volume, 1)-$volume, 0), 10))/(Sum(Abs($volume-Ref($volume, 1)), 10)+1e-12)",
"VSUMD20": "(Sum(Greater($volume-Ref($volume, 1), 0), 20)-Sum(Greater(Ref($volume, 1)-$volume, 0), 20))/(Sum(Abs($volume-Ref($volume, 1)), 20)+1e-12)",
"VSUMD30": "(Sum(Greater($volume-Ref($volume, 1), 0), 30)-Sum(Greater(Ref($volume, 1)-$volume, 0), 30))/(Sum(Abs($volume-Ref($volume, 1)), 30)+1e-12)",
"VSUMD60": "(Sum(Greater($volume-Ref($volume, 1), 0), 60)-Sum(Greater(Ref($volume, 1)-$volume, 0), 60))/(Sum(Abs($volume-Ref($volume, 1)), 60)+1e-12)",
}
_TFW = FBWorkspace() # test feature workspace
TEST_FEATURE_CODE = """
import qlib
from qlib.data import D
qlib.init()
expressions = {experessions}
df = D.features(["SH600000"], expressions, start_time="2008-01-01", end_time="2020-08-31")
"""
def validate_qlib_features(expressions: list[str]) -> bool:
_TFW.inject_files(**{"test_fea.py": TEST_FEATURE_CODE.format(experessions=str(expressions))})
qlib_env = QlibCondaEnv(conf=QlibCondaConf())
qlib_env.prepare()
res = _TFW.run(
env=qlib_env,
entry="python test_fea.py",
)
return res.exit_code == 0
+6 -2
View File
@@ -11,6 +11,7 @@ Postscripts:
import asyncio
import concurrent.futures
import copy
import multiprocessing.queues
import os
import pickle
from collections import defaultdict
@@ -528,8 +529,11 @@ class LoopBase:
def __getstate__(self) -> dict[str, Any]:
res = {}
for k, v in self.__dict__.items():
if k not in ["queue", "semaphores", "_pbar"]:
res[k] = v
if k in ["queue", "semaphores", "_pbar"]:
continue
if isinstance(v, multiprocessing.queues.Queue): # interaction queues are not picklable
continue
res[k] = v
return res
def __setstate__(self, state: dict[str, Any]) -> None:
+23
View File
@@ -0,0 +1,23 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
dist
node_modules
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+33
View File
@@ -0,0 +1,33 @@
# R&D-Agent
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run dev
```
### Compiles and minifies for production
```
npm run build
```
### API URL behavior after build
This project uses the current page origin as the API base URL.
If the built frontend is served by the same Flask server that also exposes `/upload`, `/trace`, `/control` and other APIs, no extra frontend configuration is needed. The frontend will automatically call the same host and port that served the page.
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended Setup
- [VS Code](https://code.visualstudio.com/) + [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously Volar) and disable Vetur
- Use [vue-tsc](https://github.com/vuejs/language-tools/tree/master/packages/tsc) for performing the same type checking from the command line, or for generating d.ts files for SFCs.
+10
View File
@@ -0,0 +1,10 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}
+46
View File
@@ -0,0 +1,46 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ChartBox: typeof import('./src/components/chartBox.vue')['default']
Code: typeof import('./src/components/code.vue')['default']
Development: typeof import('./src/components/development.vue')['default']
Dialog: typeof import('./src/components/dialog.vue')['default']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
Feedback: typeof import('./src/components/feedback.vue')['default']
Footer: typeof import('./src/components/footer.vue')['default']
KateX: typeof import('./src/components/kateX.vue')['default']
LineChart: typeof import('./src/components/lineChart.vue')['default']
LineChartOne: typeof import('./src/components/lineChartOne.vue')['default']
Loading: typeof import('./src/components/loading.vue')['default']
LoadingDot: typeof import('./src/components/loading-dot.vue')['default']
LoopComponent: typeof import('./src/components/loop-component.vue')['default']
Markdown: typeof import('./src/components/markdown.vue')['default']
MarkdownToHtml: typeof import('./src/components/markdownToHtml.vue')['default']
NavBar: typeof import('./src/components/navBar.vue')['default']
Research: typeof import('./src/components/research.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SaveImage: typeof import('./src/components/saveImage.vue')['default']
SelectComponent: typeof import('./src/components/select-component.vue')['default']
SmSelectComponent: typeof import('./src/components/sm-select-component.vue')['default']
StepComponent: typeof import('./src/components/step-component.vue')['default']
SvgIcon: typeof import('./src/components/svgIcon.vue')['default']
Swiper: typeof import('./src/components/swiper.vue')['default']
UploadProgress: typeof import('./src/components/upload-progress.vue')['default']
}
}
+19
View File
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="./src/assets/images/rd_icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs.min.css" />
<title>R&D-Agent</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+55
View File
@@ -0,0 +1,55 @@
<template>
<div id="app">
<Header />
<router-view v-slot="{ Component }" class="component">
<keep-alive>
<component
:is="Component"
:key="$route.name"
v-if="$route.meta.keepAlive"
/>
</keep-alive>
<component
:is="Component"
:key="$route.name"
v-if="!$route.meta.keepAlive"
/>
</router-view>
<Footer :color="color" />
</div>
</template>
<script setup>
import { provide, nextTick, ref, watch } from "vue";
import Header from "./components/navBar.vue";
import Footer from "./components/footer.vue";
import { useRoute } from "vue-router";
const isRouterActive = ref(true);
const route = useRoute();
const color = ref("#F6FAFF");
watch(
() => route.path,
(newValue, oldValue) => {
color.value = route.meta.footerBg;
}
);
provide("reload", () => {
isRouterActive.value = false;
nextTick(() => {
isRouterActive.value = true;
});
});
</script>
<style scoped>
#app {
width: 100%;
height: 100vh;
box-sizing: border-box;
background: #fff;
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
</style>
+5
View File
@@ -0,0 +1,5 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="healthicons:chart-line">
<path id="Vector" d="M10.7844 20.0026L5.83333 26.2742V29.667H30.625V31.1253H5.10417C4.91078 31.1253 4.72531 31.0485 4.58857 30.9118C4.45182 30.775 4.375 30.5895 4.375 30.3962V5.60449H5.83333V23.9212L9.71979 18.9986C9.56983 18.7056 9.48792 18.3825 9.48016 18.0535C9.4724 17.7244 9.53899 17.3978 9.67498 17.0981C9.81097 16.7984 10.0128 16.5332 10.2656 16.3223C10.5183 16.1114 10.8153 15.9603 11.1346 15.8802C11.4538 15.8001 11.787 15.793 12.1094 15.8596C12.4317 15.9261 12.7349 16.0646 12.9963 16.2646C13.2577 16.4646 13.4706 16.721 13.6191 17.0147C13.7677 17.3084 13.848 17.6319 13.8542 17.9609L18.6907 19.5724C18.9759 19.2052 19.3708 18.9386 19.8181 18.8113C20.2653 18.6841 20.7414 18.703 21.1772 18.8651L25.8278 13.2848C25.5641 12.8412 25.4658 12.3187 25.5501 11.8096C25.6344 11.3005 25.896 10.8376 26.2886 10.5027C26.6812 10.1678 27.1796 9.98253 27.6956 9.97958C28.2117 9.97662 28.7121 10.1562 29.1086 10.4866C29.505 10.8169 29.7719 11.2768 29.862 11.7849C29.9522 12.293 29.8598 12.8166 29.6012 13.2632C29.3426 13.7098 28.9345 14.0506 28.4489 14.2253C27.9634 14.4 27.4317 14.3975 26.9478 14.2181L22.2972 19.7992C22.4682 20.0872 22.5708 20.4106 22.5971 20.7446C22.6233 21.0785 22.5725 21.414 22.4486 21.7252C22.3247 22.0364 22.131 22.315 21.8824 22.5395C21.6338 22.764 21.337 22.9284 21.0148 23.0201C20.6926 23.1117 20.3537 23.1282 20.0242 23.0681C19.6946 23.0081 19.3833 22.8731 19.1141 22.6737C18.845 22.4744 18.6252 22.2158 18.4718 21.918C18.3183 21.6203 18.2353 21.2913 18.2292 20.9564L13.3926 19.3449C13.0936 19.7299 12.6744 20.0038 12.2018 20.123C11.7291 20.2422 11.2302 20.1998 10.7844 20.0026Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon-park-outline:finance">
<g id="Group">
<path id="Vector" d="M17.4998 32.5834C25.5542 32.5834 32.0832 26.0544 32.0832 18C32.0832 9.94565 25.5542 3.41669 17.4998 3.41669C9.44546 3.41669 2.9165 9.94565 2.9165 18C2.9165 26.0544 9.44546 32.5834 17.4998 32.5834Z" stroke="black" stroke-width="2" stroke-linejoin="round"/>
<path id="Vector_2" d="M13.125 16.5417H21.875M13.125 20.9167H21.875M17.5058 16.5417V25.2917M21.875 11.4375L17.5 15.8125L13.125 11.4375" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 657 B

+10
View File
@@ -0,0 +1,10 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="fluent-mdl2:medical" clip-path="url(#clip0_2237_3552)">
<path id="Vector" d="M29.5312 11.4375C30.2832 11.4375 30.9896 11.5799 31.6504 11.8647C32.3112 12.1496 32.8866 12.5426 33.3765 13.0439C33.8664 13.5452 34.2594 14.1263 34.5557 14.7871C34.8519 15.4479 35 16.1543 35 16.9062C35 17.5557 34.8918 18.1766 34.6753 18.769C34.4588 19.3615 34.1569 19.8913 33.7695 20.3584C33.3822 20.8255 32.9207 21.23 32.3853 21.5718C31.8498 21.9136 31.263 22.1471 30.625 22.2725V24.0156C30.625 25.0296 30.4997 26.0151 30.249 26.9722C29.9984 27.9292 29.6452 28.8407 29.1895 29.7065C28.7337 30.5724 28.1755 31.3529 27.5146 32.0479C26.8538 32.7428 26.119 33.3524 25.3101 33.8765C24.5011 34.4006 23.6182 34.7993 22.6611 35.0728C21.7041 35.3462 20.7129 35.4886 19.6875 35.5C18.6507 35.5 17.6595 35.3576 16.7139 35.0728C15.7682 34.7879 14.891 34.3892 14.082 33.8765C13.2731 33.3638 12.5382 32.7542 11.8774 32.0479C11.2166 31.3415 10.6584 30.561 10.2026 29.7065C9.74691 28.8521 9.38802 27.9463 9.12598 26.9893C8.86393 26.0322 8.73861 25.041 8.75 24.0156V20.1021C7.34863 19.9767 6.10677 19.6406 5.02441 19.0938C3.94206 18.5469 3.0249 17.8291 2.27295 16.9404C1.521 16.0518 0.957031 15.0207 0.581055 13.8472C0.205078 12.6737 0.0113932 11.4033 0 10.0361V0.5H5.46875C5.76497 0.5 6.02132 0.608236 6.23779 0.824707C6.45426 1.04118 6.5625 1.29753 6.5625 1.59375C6.5625 1.88997 6.45426 2.14632 6.23779 2.36279C6.02132 2.57926 5.76497 2.6875 5.46875 2.6875H2.1875V10.0361C2.1875 11.2438 2.3527 12.3376 2.68311 13.3174C3.01351 14.2972 3.50911 15.1346 4.16992 15.8296C4.83073 16.5246 5.62826 17.0601 6.5625 17.436C7.49674 17.812 8.5905 18 9.84375 18C10.9945 18 12.0426 17.8234 12.9883 17.4702C13.9339 17.117 14.7371 16.61 15.3979 15.9492C16.0588 15.2884 16.5771 14.4909 16.9531 13.5566C17.3291 12.6224 17.5114 11.5685 17.5 10.395V2.6875H14.2188C13.9225 2.6875 13.6662 2.57926 13.4497 2.36279C13.2332 2.14632 13.125 1.88997 13.125 1.59375C13.125 1.29753 13.2332 1.04118 13.4497 0.824707C13.6662 0.608236 13.9225 0.5 14.2188 0.5H19.6875V10.0361C19.6875 11.4033 19.4938 12.6737 19.1064 13.8472C18.7191 15.0207 18.1551 16.0518 17.4146 16.9404C16.674 17.8291 15.7625 18.5469 14.6802 19.0938C13.5978 19.6406 12.3503 19.9767 10.9375 20.1021V24.0156C10.9375 25.2347 11.154 26.4025 11.5869 27.519C12.0199 28.6356 12.6294 29.6268 13.4155 30.4927C14.2017 31.3586 15.1245 32.0422 16.1841 32.5435C17.2437 33.0448 18.4115 33.3011 19.6875 33.3125C20.9521 33.3125 22.1143 33.0562 23.1738 32.5435C24.2334 32.0308 25.1562 31.3472 25.9424 30.4927C26.7285 29.6382 27.3381 28.6527 27.771 27.5361C28.2039 26.4196 28.4261 25.2461 28.4375 24.0156V22.2725C27.7995 22.1357 27.2127 21.9022 26.6772 21.5718C26.1418 21.2414 25.6803 20.8426 25.293 20.3755C24.9056 19.9084 24.6037 19.3729 24.3872 18.769C24.1707 18.1652 24.0625 17.5443 24.0625 16.9062C24.0625 16.1543 24.2049 15.4479 24.4897 14.7871C24.7746 14.1263 25.1619 13.5509 25.6519 13.061C26.1418 12.5711 26.7228 12.1781 27.395 11.8818C28.0672 11.5856 28.7793 11.4375 29.5312 11.4375ZM29.5312 20.1875C29.987 20.1875 30.4142 20.1021 30.813 19.9312C31.2118 19.7603 31.5592 19.5267 31.8555 19.2305C32.1517 18.9342 32.3853 18.5868 32.5562 18.188C32.7271 17.7892 32.8125 17.362 32.8125 16.9062C32.8125 16.4505 32.7271 16.0233 32.5562 15.6245C32.3853 15.2257 32.1517 14.8783 31.8555 14.582C31.5592 14.2858 31.2118 14.0522 30.813 13.8813C30.4142 13.7104 29.987 13.625 29.5312 13.625C29.0755 13.625 28.6483 13.7104 28.2495 13.8813C27.8507 14.0522 27.5033 14.2858 27.207 14.582C26.9108 14.8783 26.6772 15.2257 26.5063 15.6245C26.3354 16.0233 26.25 16.4505 26.25 16.9062C26.25 17.362 26.3354 17.7892 26.5063 18.188C26.6772 18.5868 26.9108 18.9342 27.207 19.2305C27.5033 19.5267 27.8507 19.7603 28.2495 19.9312C28.6483 20.1021 29.0755 20.1875 29.5312 20.1875Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2237_3552">
<rect width="35" height="35" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg width="35" height="36" viewBox="0 0 35 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="arcticons:google-earth">
<path id="Vector" d="M17.4998 33.677C26.1581 33.677 33.1769 26.6582 33.1769 18C33.1769 9.34175 26.1581 2.32288 17.4998 2.32288C8.84162 2.32288 1.82275 9.34175 1.82275 18C1.82275 26.6582 8.84162 33.677 17.4998 33.677Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M3.25082 24.5355C2.70541 22.1059 4.13165 19.3409 6.8303 19.3409C13.3673 19.3409 14.8395 30.032 23.5282 30.032C27.8208 30.032 30.6544 26.5356 30.6544 26.5356" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M1.82604 18.0021C1.80826 17.1155 1.96848 16.2343 2.29722 15.4106C2.62596 14.587 3.11654 13.8376 3.73995 13.2068C4.36335 12.5761 5.10692 12.0768 5.92667 11.7384C6.74641 11.4001 7.62569 11.2295 8.5125 11.2369C17.4353 11.2369 17.9362 24.7622 27.1974 24.7622C30.4407 24.7622 32.1134 22.7971 32.968 20.5659" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M5.38428 8.05053C6.19433 7.18629 7.16845 6.49209 8.24976 6.00846C9.33106 5.52484 10.4979 5.26148 11.6821 5.23376C20.9542 5.23376 23.0476 18.8502 29.9368 18.8502C30.5506 18.8351 31.1546 18.6923 31.7101 18.4308C32.2656 18.1692 32.7606 17.7948 33.1633 17.3314" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_5" d="M32.5938 13.7475C32.1438 13.8854 31.6755 13.9545 31.2048 13.9524C26.0729 13.9524 25.9912 2.79395 15.6269 2.79395C14.476 2.80831 13.3308 2.95685 12.2144 3.23655" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="9" height="19" viewBox="0 0 9 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M0.77445 1.24971L1.31897 0.754717L0.77445 1.24971Z" fill="currentColor" stroke="currentColor" stroke-width="6"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="26" height="20" viewBox="0 0 26 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M25.6741 9.21699C25.8828 9.42475 26 9.70637 26 10C26 10.2936 25.8828 10.5753 25.6741 10.783L16.7595 19.6473C16.6575 19.7562 16.5344 19.8435 16.3978 19.9041C16.2611 19.9646 16.1135 19.9972 15.9639 19.9998C15.8143 20.0025 15.6656 19.9751 15.5269 19.9194C15.3881 19.8636 15.2621 19.7807 15.1563 19.6755C15.0505 19.5702 14.9671 19.4449 14.911 19.3069C14.855 19.169 14.8274 19.0212 14.8301 18.8724C14.8327 18.7236 14.8655 18.5769 14.9264 18.441C14.9873 18.3051 15.0751 18.1827 15.1846 18.0813L22.1974 11.108L1.11433 11.108C0.818788 11.108 0.535354 10.9913 0.326377 10.7835C0.117401 10.5757 -4.49959e-07 10.2939 -4.37114e-07 10C-4.24269e-07 9.70613 0.117401 9.4243 0.326377 9.2165C0.535354 9.0087 0.818788 8.89196 1.11433 8.89196L22.1974 8.89196L15.1846 1.91869C15.0751 1.81725 14.9873 1.69493 14.9264 1.55901C14.8655 1.42309 14.8327 1.27636 14.8301 1.12759C14.8274 0.97881 14.855 0.831028 14.911 0.693057C14.9671 0.555087 15.0505 0.429754 15.1563 0.324537C15.2621 0.219319 15.3881 0.136372 15.5269 0.0806432C15.6657 0.0249147 15.8143 -0.002453 15.9639 0.000172006C16.1135 0.00279701 16.2611 0.0353609 16.3978 0.0959219C16.5345 0.156483 16.6575 0.2438 16.7595 0.352664L25.6741 9.21699Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="22" height="28" viewBox="0 0 22 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M20.9622 8.65022L13.6451 0.984647C13.4591 0.789622 13.2069 0.67993 12.9438 0.679688H9.67554C8.71049 0.679688 7.78497 1.08131 7.10258 1.79619C6.42019 2.51108 6.03682 3.48068 6.03682 4.49168V6.2244H4.38286C3.41781 6.2244 2.49229 6.62602 1.8099 7.34091C1.1275 8.0558 0.744141 9.02539 0.744141 10.0364V23.8982C0.744141 24.9092 1.1275 25.8788 1.8099 26.5937C2.49229 27.3086 3.41781 27.7102 4.38286 27.7102H13.6451C14.6101 27.7102 15.5356 27.3086 16.218 26.5937C16.9004 25.8788 17.2838 24.9092 17.2838 23.8982V22.1655H17.6146C18.5796 22.1655 19.5051 21.7638 20.1875 21.049C20.8699 20.3341 21.2533 19.3645 21.2533 18.3535V9.34331C21.2429 9.08215 21.1389 8.8347 20.9622 8.65022ZM13.9758 4.22831L17.866 8.30367H13.9758V4.22831ZM15.299 23.8982C15.299 24.3577 15.1248 24.7985 14.8146 25.1234C14.5044 25.4484 14.0837 25.6309 13.6451 25.6309H4.38286C3.9442 25.6309 3.52351 25.4484 3.21333 25.1234C2.90315 24.7985 2.7289 24.3577 2.7289 23.8982V10.0364C2.7289 9.57685 2.90315 9.13612 3.21333 8.81117C3.52351 8.48623 3.9442 8.30367 4.38286 8.30367H6.03682V18.3535C6.03682 19.3645 6.42019 20.3341 7.10258 21.049C7.78497 21.7638 8.71049 22.1655 9.67554 22.1655H15.299V23.8982ZM17.6146 20.0862H9.67554C9.23688 20.0862 8.81619 19.9036 8.50601 19.5787C8.19584 19.2537 8.02158 18.813 8.02158 18.3535V4.49168C8.02158 4.03213 8.19584 3.59141 8.50601 3.26646C8.81619 2.94151 9.23688 2.75896 9.67554 2.75896H11.9911V9.34331C11.9945 9.61792 12.1002 9.88027 12.2855 10.0745C12.4709 10.2687 12.7213 10.3793 12.9835 10.3829H19.2685V18.3535C19.2685 18.813 19.0943 19.2537 18.7841 19.5787C18.4739 19.9036 18.0532 20.0862 17.6146 20.0862Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 175">
<circle id="Ellipse 7" cx="18.4742" cy="17.5259" r="17.5259" fill="#A9A9A9" fill-opacity="0.13"/>
<g id="Group 174">
<path id="Line 7" d="M11.7334 10.2777L25.556 24.1003" stroke="#A9A9A9" stroke-width="1.34815" stroke-linecap="round"/>
<path id="Line 8" d="M25.5557 10.2775L11.733 24.1001" stroke="#A9A9A9" stroke-width="1.34815" stroke-linecap="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 487 B

+5
View File
@@ -0,0 +1,5 @@
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="system-uicons:write">
<path id="Vector" d="M15.8334 29.1667H29.1667M25.8334 10.8333L27.5 12.5M28.3334 6.66667C28.6619 6.99482 28.9226 7.38453 29.1004 7.8135C29.2783 8.24247 29.3698 8.70229 29.3698 9.16667C29.3698 9.63104 29.2783 10.0909 29.1004 10.5198C28.9226 10.9488 28.6619 11.3385 28.3334 11.6667L12.5 27.5L5.83337 29.1667L7.50004 22.5933L23.34 6.67333C23.9644 6.04595 24.8018 5.67627 25.6861 5.63768C26.5703 5.59908 27.4368 5.8944 28.1134 6.465L28.3334 6.66667Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 671 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M25.7398 1.41794V8.36704C25.7389 9.25861 24.7733 9.81494 24.0016 9.36843C23.6441 9.16159 23.4238 8.78005 23.4234 8.36704V4.21351L17.2937 10.3446C16.6629 10.9754 15.5859 10.6868 15.355 9.82515C15.2478 9.42525 15.3622 8.99856 15.6549 8.70581L21.786 2.57613H17.6325C16.7409 2.57529 16.1846 1.60962 16.6311 0.83792C16.8379 0.480441 17.2195 0.260152 17.6325 0.259766H24.5816C25.2212 0.259796 25.7398 0.778324 25.7398 1.41794ZM8.70581 15.6549L2.57613 21.786V17.6325C2.57529 16.7409 1.60962 16.1846 0.83792 16.6311C0.480441 16.8379 0.260152 17.2195 0.259766 17.6325V24.5816C0.259766 25.2213 0.778283 25.7398 1.41794 25.7398H8.36704C9.25861 25.7389 9.81494 24.7733 9.36843 24.0016C9.16159 23.6441 8.78005 23.4238 8.36704 23.4234H4.21351L10.3446 17.2937C10.9754 16.6629 10.6868 15.5859 9.82515 15.355C9.42525 15.2478 8.99856 15.3622 8.70581 15.6549ZM24.5816 16.4743C23.9419 16.4743 23.4234 16.9928 23.4234 17.6325V21.786L17.2937 15.6549C16.6629 15.0241 15.5859 15.3127 15.355 16.1744C15.2478 16.5743 15.3622 17.001 15.6549 17.2937L21.786 23.4234H17.6325C16.7409 23.4242 16.1846 24.3899 16.6311 25.1616C16.8379 25.5191 17.2195 25.7394 17.6325 25.7398H24.5816C25.2212 25.7397 25.7398 25.2212 25.7398 24.5816V17.6325C25.7398 16.9929 25.2212 16.4743 24.5816 16.4743ZM4.21351 2.57613H8.36704C9.25861 2.57529 9.81494 1.60962 9.36843 0.83792C9.16159 0.480441 8.78005 0.260152 8.36704 0.259766H1.41794C0.778283 0.259735 0.259766 0.778283 0.259766 1.41794V8.36704C0.260598 9.25861 1.22628 9.81494 1.99798 9.36843C2.35546 9.16159 2.57575 8.78005 2.57613 8.36704V4.21351L8.70581 10.3446C9.33659 10.9754 10.4137 10.6868 10.6446 9.82515C10.7517 9.42525 10.6374 8.99856 10.3446 8.70581L4.21351 2.57613Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="34" height="18" viewBox="0 0 34 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M0.333008 8.90987C0.333008 4.32154 4.12634 0.666535 8.72467 0.666535C10.0648 0.663633 11.3863 0.979502 12.5803 1.58807C13.7742 2.19663 14.8063 3.08044 15.5913 4.16654L16.9997 6.1382L18.4097 4.16987C19.1932 3.0824 20.2247 2.19735 21.4186 1.58809C22.6124 0.978836 23.9343 0.66292 25.2747 0.666535C29.8747 0.666535 33.6663 4.32154 33.6663 8.90987V9.08987C33.6663 13.6782 29.873 17.3332 25.2747 17.3332C23.9343 17.3375 22.6123 17.0222 21.4181 16.4135C20.224 15.8048 19.1921 14.9203 18.408 13.8332L16.9997 11.8615L15.5897 13.8299C14.8061 14.9173 13.7747 15.8024 12.5808 16.4116C11.3869 17.0209 10.065 17.3368 8.72467 17.3332C4.12467 17.3332 0.333008 13.6782 0.333008 9.08987V8.90987ZM14.9497 8.99987L12.8797 6.1082C12.4044 5.45198 11.7796 4.91845 11.057 4.55181C10.3344 4.18517 9.53493 3.99596 8.72467 3.99987C5.89634 3.99987 3.66634 6.2332 3.66634 8.90987V9.08987C3.66634 11.7665 5.89634 13.9999 8.72467 13.9999C10.3913 13.9999 11.9413 13.2049 12.8797 11.8915L14.9497 8.99987ZM19.0497 8.99987L21.1197 11.8915C21.595 12.5478 22.2198 13.0813 22.9423 13.4479C23.6649 13.8146 24.4644 14.0038 25.2747 13.9999C28.103 13.9999 30.333 11.7665 30.333 9.08987V8.90987C30.333 6.2332 28.103 3.99987 25.2747 3.99987C23.608 3.99987 22.058 4.79487 21.1197 6.1082L19.0497 8.99987Z" fill="#2B2B2B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 177">
<circle id="Ellipse 6" cx="17.5259" cy="17.5259" r="17.5259" fill="#A9A9A9" fill-opacity="0.13"/>
<g id="Group 176">
<path id="Line 5" d="M12.8076 7.41479L12.8076 26.9629" stroke="#A9A9A9" stroke-width="1.34815" stroke-linecap="round"/>
<path id="Line 6" d="M21.5703 7.41504L21.5703 26.9632" stroke="#A9A9A9" stroke-width="1.34815" stroke-linecap="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 489 B

+8
View File
@@ -0,0 +1,8 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Union">
<path d="M18.6096 0H8.19863C7.98301 0 7.80822 0.174793 7.80822 0.390411C7.80822 1.10913 8.39086 1.69176 9.10957 1.69176H16.0068C16.7256 1.69176 17.3082 2.27441 17.3082 2.99313V9.8904C17.3082 10.6091 17.8909 11.1918 18.6096 11.1918C18.8252 11.1918 19 11.017 19 10.8014V0.390411C19 0.174793 18.8252 0 18.6096 0Z" fill="currentColor"/>
<path d="M14.7055 5.59587V12.4931C14.7055 13.2119 15.2881 13.7945 16.0068 13.7945C16.2225 13.7945 16.3973 13.6197 16.3973 13.4041V2.99315C16.3973 2.94396 16.3882 2.8969 16.3716 2.85356C16.3336 2.75438 16.2563 2.67465 16.1588 2.6334C16.1121 2.61365 16.0607 2.60272 16.0068 2.60272L5.59589 2.60274C5.38027 2.60274 5.20548 2.77753 5.20548 2.99315C5.20548 3.71187 5.78812 4.2945 6.50683 4.2945H13.4041C14.1228 4.2945 14.7055 4.87715 14.7055 5.59587Z" fill="currentColor"/>
<path d="M13.7882 5.52585C13.7831 5.49734 13.7748 5.4699 13.7638 5.44391C13.7217 5.34436 13.6395 5.26591 13.5374 5.22882C13.496 5.21382 13.4507 5.20546 13.4041 5.20546L2.99315 5.20548C2.77753 5.20548 2.60274 5.38027 2.60274 5.59589C2.60274 6.31461 3.18538 6.89724 3.90409 6.89724H10.8014C11.5201 6.89724 12.1027 7.47989 12.1027 8.19862V15.0959C12.1027 15.8146 12.6854 16.3973 13.4041 16.3973C13.6197 16.3973 13.7945 16.2225 13.7945 16.0068V5.59589C13.7945 5.57198 13.7924 5.54857 13.7882 5.52585Z" fill="currentColor"/>
<path d="M10.9395 7.83333C10.8965 7.81709 10.85 7.8082 10.8014 7.8082L0.390411 7.80822C0.174793 7.80822 0 7.98301 0 8.19863V18.6096C0 18.8252 0.174793 19 0.390411 19H10.8014C11.017 19 11.1918 18.8252 11.1918 18.6096V8.19863C11.1918 8.14472 11.1808 8.09336 11.1611 8.04665C11.1196 7.94865 11.0393 7.8711 10.9395 7.83333Z" fill="currentColor"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M4.29467 0C3.60844 0 2.94321 0.0627942 2.31922 0.132426C1.17029 0.260638 0.248466 1.18194 0.12516 2.33579C0.058702 2.95768 0 3.61839 0 4.29961C0 4.98085 0.0587021 5.64156 0.12516 6.26345C0.248466 7.4173 1.17029 8.3386 2.31922 8.46681C2.94321 8.53644 3.60844 8.59923 4.29467 8.59923C4.61581 8.59923 4.93235 8.58548 5.24221 8.56372C5.56376 7.84694 6.00624 7.18253 6.58892 6.59919C7.17274 6.01468 7.83786 5.57109 8.55544 5.24902C8.57625 4.93842 8.58934 4.6213 8.58934 4.29961C8.58934 3.61839 8.53063 2.95768 8.46418 2.33579C8.34088 1.18194 7.41904 0.26064 6.27012 0.132426C5.64613 0.0627942 4.9809 0 4.29467 0ZM4.29467 10.3946C4.42637 10.3946 4.5573 10.3969 4.68733 10.4012C4.59138 10.9474 4.54667 11.5078 4.54667 12.0726C4.54667 14.1054 5.12584 16.0811 6.58892 17.5459C6.88661 17.844 7.20544 18.1054 7.54158 18.3327C7.18399 18.6187 6.74658 18.8083 6.27012 18.8614C5.64613 18.9311 4.9809 18.9939 4.29467 18.9939C3.60844 18.9939 2.94321 18.9311 2.31922 18.8614C1.17029 18.7332 0.248466 17.8119 0.12516 16.6581C0.0587021 16.0362 0 15.3755 0 14.6943C0 14.013 0.058702 13.3523 0.12516 12.7304C0.248466 11.5766 1.17029 10.6553 2.31922 10.5271C2.94321 10.4574 3.60844 10.3946 4.29467 10.3946ZM18.8748 6.26345C18.8221 6.75727 18.623 7.20849 18.3225 7.57318C18.0923 7.22921 17.8268 6.90319 17.5231 6.59919C16.06 5.13442 14.0864 4.55458 12.056 4.55458C11.5023 4.55458 10.9528 4.59769 10.4168 4.69012C10.4128 4.5608 10.4107 4.43059 10.4107 4.29961C10.4107 3.61839 10.4694 2.95768 10.5358 2.33579C10.6591 1.18194 11.581 0.260638 12.7299 0.132426C13.3539 0.0627942 14.0191 0 14.7053 0C15.3916 0 16.0567 0.0627942 16.6808 0.132426C17.8298 0.260638 18.7515 1.18194 18.8748 2.33579C18.9413 2.95768 19 3.61839 19 4.29961C19 4.98085 18.9413 5.64156 18.8748 6.26345ZM9.24387 9.25719C8.67523 9.82648 8.30134 10.7303 8.30134 12.0726C8.30134 13.4148 8.67523 14.3186 9.24387 14.888C9.8125 15.4573 10.7153 15.8315 12.056 15.8315C13.3967 15.8315 14.2996 15.4573 14.8681 14.888C15.4368 14.3186 15.8107 13.4148 15.8107 12.0726C15.8107 10.7303 15.4368 9.82648 14.8681 9.25719C14.2996 8.6879 13.3967 8.31358 12.056 8.31358C10.7153 8.31358 9.8125 8.6879 9.24387 9.25719ZM7.79571 7.80737C8.85183 6.75004 10.3383 6.26322 12.056 6.26322C13.7736 6.26322 15.2602 6.75004 16.3163 7.80737C17.3724 8.8647 17.8587 10.3529 17.8587 12.0726C17.8587 13.3943 17.5715 14.5793 16.959 15.537L18.67 17.25C19.0699 17.6503 19.0699 18.2994 18.67 18.6997C18.2701 19.1001 17.6217 19.1001 17.2218 18.6997L15.5097 16.9856C14.5542 17.5957 13.373 17.8819 12.056 17.8819C10.3383 17.8819 8.85183 17.3951 7.79571 16.3377C6.7396 15.2804 6.25334 13.7923 6.25334 12.0726C6.25334 10.3529 6.7396 8.8647 7.79571 7.80737Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="prime:upload">
<path id="Vector" d="M26.5708 30.2604H8.42915C7.92342 30.2398 7.42672 30.1196 6.96747 29.9068C6.50822 29.694 6.09544 29.3928 5.75275 29.0203C5.41006 28.6478 5.14418 28.2114 4.97032 27.736C4.79647 27.2607 4.71805 26.7557 4.73956 26.25V21.875C4.73956 21.5849 4.8548 21.3067 5.05991 21.1016C5.26503 20.8965 5.54323 20.7812 5.83331 20.7812C6.12339 20.7812 6.40159 20.8965 6.60671 21.1016C6.81183 21.3067 6.92706 21.5849 6.92706 21.875V26.25C6.88941 26.683 7.01987 27.1139 7.2914 27.4533C7.56292 27.7927 7.95467 28.0146 8.3854 28.0729H26.5708C27.0015 28.0146 27.3933 27.7927 27.6648 27.4533C27.9363 27.1139 28.0668 26.683 28.0291 26.25V21.875C28.0291 21.5849 28.1444 21.3067 28.3495 21.1016C28.5546 20.8965 28.8328 20.7812 29.1229 20.7812C29.413 20.7812 29.6912 20.8965 29.8963 21.1016C30.1014 21.3067 30.2166 21.5849 30.2166 21.875V26.25C30.2603 27.2641 29.9018 28.2544 29.219 29.0054C28.5362 29.7565 27.5845 30.2075 26.5708 30.2604ZM23.3333 12.7604C23.1896 12.7611 23.0472 12.7331 22.9145 12.678C22.7818 12.6229 22.6614 12.5418 22.5604 12.4396L17.5 7.37916L12.4396 12.4396C12.2322 12.6328 11.958 12.738 11.6746 12.733C11.3913 12.728 11.1209 12.6132 10.9205 12.4128C10.7201 12.2124 10.6053 11.942 10.6003 11.6587C10.5953 11.3753 10.7005 11.1011 10.8937 10.8937L16.7271 5.06041C16.9321 4.85559 17.2101 4.74054 17.5 4.74054C17.7898 4.74054 18.0678 4.85559 18.2729 5.06041L24.1062 10.8937C24.3111 11.0988 24.4261 11.3768 24.4261 11.6667C24.4261 11.9565 24.3111 12.2345 24.1062 12.4396C24.0052 12.5418 23.8849 12.6229 23.7521 12.678C23.6194 12.7331 23.477 12.7611 23.3333 12.7604Z" fill="currentColor"/>
<path id="Vector_2" d="M17.5 22.9687C17.2111 22.965 16.9351 22.8485 16.7308 22.6442C16.5265 22.4399 16.41 22.1639 16.4062 21.875V5.83333C16.4062 5.54325 16.5215 5.26505 16.7266 5.05993C16.9317 4.85481 17.2099 4.73958 17.5 4.73958C17.7901 4.73958 18.0683 4.85481 18.2734 5.05993C18.4785 5.26505 18.5938 5.54325 18.5938 5.83333V21.875C18.59 22.1639 18.4735 22.4399 18.2692 22.6442C18.0649 22.8485 17.7889 22.965 17.5 22.9687Z" fill="currentColor"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="11" height="18" viewBox="0 0 11 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M10.2638 9.5296L1.77781 17.298C1.63622 17.4277 1.4481 17.5 1.25248 17.5C1.05686 17.5 0.868743 17.4277 0.72715 17.298L0.718013 17.2892C0.649133 17.2263 0.594286 17.1507 0.556807 17.0668C0.519327 16.9829 0.5 16.8926 0.5 16.8013C0.5 16.71 0.519327 16.6197 0.556807 16.5358C0.594286 16.4519 0.649133 16.3763 0.718013 16.3134L8.70915 8.99854L0.718012 1.68661C0.649132 1.62374 0.594285 1.54807 0.556806 1.46419C0.519326 1.38031 0.499999 1.28999 0.499999 1.19871C0.499999 1.10743 0.519326 1.01711 0.556806 0.933228C0.594285 0.849352 0.649132 0.773678 0.718012 0.710808L0.727149 0.702031C0.868742 0.572346 1.05686 0.5 1.25248 0.5C1.4481 0.5 1.63622 0.572346 1.77781 0.702031L10.2638 8.4704C10.3385 8.53872 10.3979 8.62089 10.4385 8.71192C10.4791 8.80296 10.5 8.90096 10.5 9C10.5 9.09904 10.4791 9.19705 10.4385 9.28808C10.3979 9.37911 10.3385 9.46128 10.2638 9.5296Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1730451372035" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1445" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M153 294.6l351.5 351.5c1.9 1.9 4.5 3.1 7.5 3.1s5.6-1.2 7.6-3.2L871 294.6c13.9-13.9 36.7-13.9 50.6 0 13.9 13.9 13.9 36.7 0 50.6L537.3 729.4c-13.9 13.9-36.7 13.9-50.6 0-0.1-0.1-0.1-0.1-0.1-0.2L102.4 345.1c-13.9-13.9-13.9-36.7 0-50.6 13.9-13.8 36.7-13.8 50.6 0.1z" p-id="1446"></path><path d="M501.8 641.2c0-0.2-0.1-0.3-0.1-0.5 0 0.2 0 0.3 0.1 0.5zM502.4 642.9c0-0.1-0.1-0.1-0.1-0.2 0 0.1 0 0.1 0.1 0.2zM501.4 638.6v0z" p-id="1447"></path></svg>

After

Width:  |  Height:  |  Size: 773 B

@@ -0,0 +1,10 @@
<svg width="61" height="73" viewBox="0 0 61 73" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M58.73 14.793L45.77 1.77757C45.2118 1.21366 44.548 0.766276 43.8169 0.461195C43.0858 0.156114 42.3017 -0.000628148 41.51 1.89184e-06H6.5C4.9087 1.89184e-06 3.38258 0.634845 2.25736 1.76487C1.13214 2.8949 0.5 4.42754 0.5 6.02564V66.2821C0.5 67.8802 1.13214 69.4128 2.25736 70.5428C3.38258 71.6729 4.9087 72.3077 6.5 72.3077H54.5C56.0913 72.3077 57.6174 71.6729 58.7426 70.5428C59.8679 69.4128 60.5 67.8802 60.5 66.2821V19.0712C60.5006 18.276 60.3446 17.4887 60.0408 16.7544C59.737 16.0201 59.2915 15.3535 58.73 14.793ZM27.08 57.2436C26.6543 57.6595 26.0839 57.8922 25.49 57.8922C24.8961 57.8922 24.3257 57.6595 23.9 57.2436L13.85 46.3071C13.4747 45.8959 13.2666 45.3584 13.2666 44.8006C13.2666 44.2429 13.4747 43.7054 13.85 43.2942L23.87 32.5083C24.2914 32.1999 24.8064 32.048 25.327 32.0786C25.8476 32.1092 26.3414 32.3205 26.724 32.6763C27.1066 33.0321 27.3543 33.5104 27.4247 34.0293C27.4951 34.5482 27.3839 35.0755 27.11 35.5212L19.07 44.2583C18.9414 44.3976 18.8699 44.5806 18.8699 44.7705C18.8699 44.9605 18.9414 45.1434 19.07 45.2827L27.14 53.9897C27.3578 54.2024 27.5299 54.4576 27.6455 54.7397C27.7611 55.0218 27.8179 55.3247 27.8123 55.6297C27.8067 55.9347 27.7388 56.2353 27.6128 56.5129C27.4869 56.7905 27.3055 57.0392 27.08 57.2436ZM47.15 46.4276L37.13 57.1833C36.7118 57.542 36.1799 57.739 35.63 57.739C35.0801 57.739 34.5482 57.542 34.13 57.1833C33.7086 56.7597 33.472 56.1853 33.472 55.5865C33.472 54.9877 33.7086 54.4134 34.13 53.9897L41.93 45.1923C42.0586 45.053 42.1301 44.8701 42.1301 44.6801C42.1301 44.4902 42.0586 44.3072 41.93 44.168L33.86 35.5513C33.4386 35.1276 33.202 34.5533 33.202 33.9545C33.202 33.3557 33.4386 32.7814 33.86 32.3577C34.2819 31.9345 34.8537 31.6969 35.45 31.6969C36.0462 31.6969 36.6181 31.9345 37.04 32.3577L47.03 43.1436C47.2458 43.3427 47.4201 43.5828 47.543 43.85C47.666 44.1172 47.735 44.4061 47.7461 44.7002C47.7573 44.9943 47.7104 45.2877 47.608 45.5635C47.5057 45.8393 47.35 46.092 47.15 46.3071V46.4276Z" fill="url(#paint0_linear_1044_4756)" fill-opacity="0.6"/>
<defs>
<linearGradient id="paint0_linear_1044_4756" x1="30.5" y1="0" x2="30.5" y2="72.3077" gradientUnits="userSpaceOnUse">
<stop stop-color="#3563FF"/>
<stop offset="0.51" stop-color="#6B52FF"/>
<stop offset="1" stop-color="#9146FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+10
View File
@@ -0,0 +1,10 @@
<svg width="60" height="73" viewBox="0 0 60 73" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M58.23 15.293L45.27 2.27757C44.7118 1.71366 44.048 1.26628 43.3169 0.961195C42.5858 0.656114 41.8017 0.499372 41.01 0.500002H6C4.4087 0.500002 2.88258 1.13484 1.75736 2.26487C0.632141 3.3949 0 4.92754 0 6.52564V66.7821C0 68.3802 0.632141 69.9128 1.75736 71.0428C2.88258 72.1729 4.4087 72.8077 6 72.8077H54C55.5913 72.8077 57.1174 72.1729 58.2426 71.0428C59.3679 69.9128 60 68.3802 60 66.7821V19.5712C60.0006 18.776 59.8446 17.9887 59.5408 17.2544C59.237 16.5201 58.7915 15.8535 58.23 15.293ZM26.58 57.7436C26.1543 58.1595 25.5839 58.3922 24.99 58.3922C24.3961 58.3922 23.8257 58.1595 23.4 57.7436L13.35 46.8071C12.9747 46.3959 12.7666 45.8584 12.7666 45.3006C12.7666 44.7429 12.9747 44.2054 13.35 43.7942L23.37 33.0083C23.7914 32.6999 24.3064 32.548 24.827 32.5786C25.3476 32.6092 25.8414 32.8205 26.224 33.1763C26.6066 33.5321 26.8543 34.0104 26.9247 34.5293C26.9951 35.0482 26.8839 35.5755 26.61 36.0212L18.57 44.7583C18.4414 44.8976 18.3699 45.0806 18.3699 45.2705C18.3699 45.4605 18.4414 45.6434 18.57 45.7827L26.64 54.4897C26.8578 54.7024 27.0299 54.9576 27.1455 55.2397C27.2611 55.5218 27.3179 55.8247 27.3123 56.1297C27.3067 56.4347 27.2388 56.7353 27.1128 57.0129C26.9869 57.2905 26.8055 57.5392 26.58 57.7436ZM46.65 46.9276L36.63 57.6833C36.2118 58.042 35.6799 58.239 35.13 58.239C34.5801 58.239 34.0482 58.042 33.63 57.6833C33.2086 57.2597 32.972 56.6853 32.972 56.0865C32.972 55.4877 33.2086 54.9134 33.63 54.4897L41.43 45.6923C41.5586 45.553 41.6301 45.3701 41.6301 45.1801C41.6301 44.9902 41.5586 44.8072 41.43 44.668L33.36 36.0513C32.9386 35.6276 32.702 35.0533 32.702 34.4545C32.702 33.8557 32.9386 33.2814 33.36 32.8577C33.7819 32.4345 34.3537 32.1969 34.95 32.1969C35.5462 32.1969 36.1181 32.4345 36.54 32.8577L46.53 43.6436C46.7458 43.8427 46.9201 44.0828 47.043 44.35C47.166 44.6172 47.235 44.9061 47.2461 45.2002C47.2573 45.4943 47.2104 45.7877 47.108 46.0635C47.0057 46.3393 46.85 46.592 46.65 46.8071V46.9276Z" fill="url(#paint0_linear_1111_511)"/>
<defs>
<linearGradient id="paint0_linear_1111_511" x1="30" y1="0.5" x2="30" y2="72.8077" gradientUnits="userSpaceOnUse">
<stop stop-color="#3563FF"/>
<stop offset="0.51" stop-color="#6B52FF"/>
<stop offset="1" stop-color="#9146FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg width="54" height="67" viewBox="0 0 54 67" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Description-Fill--Streamline-Sharp-Fill-Material-Symbols.svg" clip-path="url(#clip0_1171_4407)">
<path id="Vector" d="M15.9569 52.7402H38.0783C39.4873 52.7402 40.6145 51.6218 40.6145 50.2238C40.6145 48.8258 39.4873 47.7074 38.0783 47.7074H15.9569C14.5479 47.7074 13.4207 48.8258 13.4207 50.2238C13.4207 51.6218 14.5479 52.7402 15.9569 52.7402ZM15.9569 38.5154H38.0783C39.4873 38.5154 40.6145 37.397 40.6145 35.999C40.6145 34.6009 39.4873 33.4825 38.0783 33.4825H15.9569C14.5479 33.4825 13.4207 34.6009 13.4207 35.999C13.4207 37.397 14.5479 38.5154 15.9569 38.5154ZM0 64.4836V2.51643C0 1.11841 1.1272 0 2.5362 0H34.4853C35.1546 0 35.7887 0.279604 36.2818 0.733959L53.2955 17.615C53.7534 18.0694 54.0352 18.7334 54.0352 19.3975V64.4836C54.0352 65.8816 52.908 67 51.499 67H2.5362C1.1272 67 0 65.8816 0 64.4836ZM35.5421 20.5858H42.7632C45.0176 20.5858 46.1448 17.8597 44.5245 16.2869L37.3033 9.22692C35.7182 7.65415 33.0059 8.77256 33.0059 11.0094V18.0694C33.0059 19.4674 34.1331 20.5858 35.5421 20.5858Z" fill="url(#paint0_linear_1171_4407)" fill-opacity="0.6"/>
</g>
<defs>
<linearGradient id="paint0_linear_1171_4407" x1="27.0176" y1="0" x2="27.0176" y2="67" gradientUnits="userSpaceOnUse">
<stop stop-color="#3563FF"/>
<stop offset="0.5" stop-color="#6B52FF"/>
<stop offset="1" stop-color="#9146FF"/>
</linearGradient>
<clipPath id="clip0_1171_4407">
<rect width="54" height="67" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg width="54" height="67" viewBox="0 0 54 67" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Description-Fill--Streamline-Sharp-Fill-Material-Symbols.svg" clip-path="url(#clip0_1171_4422)">
<path id="Vector" d="M15.9569 52.7402H38.0783C39.4873 52.7402 40.6145 51.6218 40.6145 50.2238C40.6145 48.8258 39.4873 47.7074 38.0783 47.7074H15.9569C14.5479 47.7074 13.4207 48.8258 13.4207 50.2238C13.4207 51.6218 14.5479 52.7402 15.9569 52.7402ZM15.9569 38.5154H38.0783C39.4873 38.5154 40.6145 37.397 40.6145 35.999C40.6145 34.6009 39.4873 33.4825 38.0783 33.4825H15.9569C14.5479 33.4825 13.4207 34.6009 13.4207 35.999C13.4207 37.397 14.5479 38.5154 15.9569 38.5154ZM0 64.4836V2.51643C0 1.11841 1.1272 0 2.5362 0H34.4853C35.1546 0 35.7887 0.279604 36.2818 0.733959L53.2955 17.615C53.7534 18.0694 54.0352 18.7334 54.0352 19.3975V64.4836C54.0352 65.8816 52.908 67 51.499 67H2.5362C1.1272 67 0 65.8816 0 64.4836ZM35.5421 20.5858H42.7632C45.0176 20.5858 46.1448 17.8597 44.5245 16.2869L37.3033 9.22692C35.7182 7.65415 33.0059 8.77256 33.0059 11.0094V18.0694C33.0059 19.4674 34.1331 20.5858 35.5421 20.5858Z" fill="url(#paint0_linear_1171_4422)"/>
</g>
<defs>
<linearGradient id="paint0_linear_1171_4422" x1="27.0176" y1="0" x2="27.0176" y2="67" gradientUnits="userSpaceOnUse">
<stop stop-color="#3563FF"/>
<stop offset="0.5" stop-color="#6B52FF"/>
<stop offset="1" stop-color="#9146FF"/>
</linearGradient>
<clipPath id="clip0_1171_4422">
<rect width="54" height="67" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,4 @@
<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5 23.0002H22.5V25.0002H14.5V23.0002ZM10.5 23.0002H12.5V25.0002H10.5V23.0002ZM14.5 18.0002H22.5V20.0002H14.5V18.0002ZM10.5 18.0002H12.5V20.0002H10.5V18.0002ZM14.5 13.0002H22.5V15.0002H14.5V13.0002ZM10.5 13.0002H12.5V15.0002H10.5V13.0002Z" fill="black"/>
<path d="M25.5 5.00024H22.5V4.00024C22.5 3.46981 22.2893 2.9611 21.9142 2.58603C21.5391 2.21096 21.0304 2.00024 20.5 2.00024H12.5C11.9696 2.00024 11.4609 2.21096 11.0858 2.58603C10.7107 2.9611 10.5 3.46981 10.5 4.00024V5.00024H7.5C6.96957 5.00024 6.46086 5.21096 6.08579 5.58603C5.71071 5.9611 5.5 6.46981 5.5 7.00024V28.0002C5.5 28.5307 5.71071 29.0394 6.08579 29.4145C6.46086 29.7895 6.96957 30.0002 7.5 30.0002H25.5C26.0304 30.0002 26.5391 29.7895 26.9142 29.4145C27.2893 29.0394 27.5 28.5307 27.5 28.0002V7.00024C27.5 6.46981 27.2893 5.9611 26.9142 5.58603C26.5391 5.21096 26.0304 5.00024 25.5 5.00024ZM12.5 4.00024H20.5V8.00024H12.5V4.00024ZM25.5 28.0002H7.5V7.00024H10.5V10.0002H22.5V7.00024H25.5V28.0002Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,5 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ci:bulb">
<path id="Vector" d="M11.2501 26.25H18.7501M15.0001 3.75C13.6473 3.74968 12.3196 4.11525 11.1576 4.80799C9.99569 5.50074 9.04273 6.49486 8.39971 7.68506C7.7567 8.87526 7.44757 10.2172 7.50507 11.5688C7.56257 12.9204 7.98456 14.2312 8.72634 15.3625C9.91884 17.1775 10.5138 18.085 10.5926 18.22C11.2801 19.4263 11.1538 19.0012 11.2401 20.3875C11.2501 20.5425 11.2501 20.7787 11.2501 21.25C11.2501 21.5815 11.3818 21.8995 11.6162 22.1339C11.8506 22.3683 12.1686 22.5 12.5001 22.5H17.5001C17.8316 22.5 18.1496 22.3683 18.384 22.1339C18.6184 21.8995 18.7501 21.5815 18.7501 21.25C18.7501 20.7787 18.7501 20.5425 18.7601 20.3875C18.8476 19 18.7188 19.4263 19.4076 18.22C19.4851 18.085 20.0826 17.1775 21.2738 15.3612C22.0153 14.23 22.437 12.9193 22.4943 11.5679C22.5517 10.2165 22.2425 8.87476 21.5995 7.68477C20.9565 6.49477 20.0037 5.5008 18.8419 4.80812C17.6802 4.11543 16.3527 3.74982 15.0001 3.75Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,8 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="majesticons:eye-line">
<g id="Group">
<path id="Vector" d="M12.5 5C6.193 5 3.133 10.683 2.59 11.808C2.56098 11.8678 2.5459 11.9335 2.5459 12C2.5459 12.0665 2.56098 12.1322 2.59 12.192C3.132 13.317 6.192 19 12.5 19C18.808 19 21.867 13.317 22.41 12.192C22.439 12.1322 22.4541 12.0665 22.4541 12C22.4541 11.9335 22.439 11.8678 22.41 11.808C21.868 10.683 18.808 5 12.5 5Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M12.5 15C14.1569 15 15.5 13.6569 15.5 12C15.5 10.3431 14.1569 9 12.5 9C10.8431 9 9.5 10.3431 9.5 12C9.5 13.6569 10.8431 15 12.5 15Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 807 B

@@ -0,0 +1,5 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="fluent:search-24-regular">
<path id="Vector" d="M3.37238 9.74055C3.37238 7.91908 4.09598 6.17221 5.384 4.88424C6.67201 3.59626 8.41894 2.87269 10.2405 2.87269C12.062 2.87269 13.8089 3.59626 15.0969 4.88424C16.385 6.17221 17.1086 7.91908 17.1086 9.74055C17.1086 11.562 16.385 13.3089 15.0969 14.5969C13.8089 15.8848 12.062 16.6084 10.2405 16.6084C8.41894 16.6084 6.67201 15.8848 5.384 14.5969C4.09598 13.3089 3.37238 11.562 3.37238 9.74055ZM10.2405 0.999634C8.84271 0.999752 7.46536 1.33505 6.22396 1.9774C4.98256 2.61976 3.91331 3.55043 3.10589 4.69136C2.29848 5.83229 1.77645 7.15021 1.5836 8.53455C1.39075 9.91889 1.5327 11.3293 1.99754 12.6475C2.46238 13.9656 3.23656 15.1531 4.25513 16.1102C5.27371 17.0674 6.50698 17.7664 7.85148 18.1485C9.19599 18.5306 10.6125 18.5847 11.9823 18.3063C13.352 18.0279 14.635 17.4251 15.7237 16.5485L22.3782 23.2016C22.464 23.2936 22.5674 23.3674 22.6823 23.4186C22.7972 23.4697 22.9212 23.4973 23.0469 23.4995C23.1727 23.5017 23.2976 23.4786 23.4142 23.4315C23.5308 23.3844 23.6368 23.3143 23.7257 23.2253C23.8146 23.1364 23.8847 23.0305 23.9318 22.9139C23.9789 22.7972 24.0021 22.6723 23.9999 22.5466C23.9976 22.4208 23.9701 22.2968 23.9189 22.1819C23.8677 22.0671 23.7939 21.9637 23.7019 21.8779L17.0486 15.2236C18.083 13.9394 18.7331 12.3887 18.9237 10.7508C19.1143 9.11279 18.8376 7.45433 18.1257 5.96691C17.4137 4.47948 16.2956 3.22378 14.9003 2.34483C13.505 1.46587 11.8895 0.999522 10.2405 0.999634Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6875 17.0625V29.7812H13.3125V17.0625H0.5625V13.6562H13.3125V0.90625H16.6875V13.6562H29.4375V17.0625H16.6875Z" fill="black"/>
<path d="M16.6875 17.0625V29.7812H13.3125V17.0625H0.5625V13.6562H13.3125V0.90625H16.6875V13.6562H29.4375V17.0625H16.6875Z" fill="url(#paint0_linear_1994_1982)"/>
<defs>
<linearGradient id="paint0_linear_1994_1982" x1="-159.646" y1="55.0003" x2="177.383" y2="55.0003" gradientUnits="userSpaceOnUse">
<stop stop-color="#4CA9FF" stop-opacity="0"/>
<stop offset="0.108674" stop-color="#4CA9FF"/>
<stop offset="0.549673" stop-color="#2648FF"/>
<stop offset="0.859503" stop-color="#BE05FF"/>
<stop offset="1" stop-color="#BE05FF" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 810 B

@@ -0,0 +1,3 @@
<svg width="29" height="29" viewBox="0 0 29 29" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M14.2609 17.7183L3.93839 28.0408C3.55217 28.427 3.06063 28.6201 2.46375 28.6201C1.86687 28.6201 1.37533 28.427 0.989111 28.0408C0.602897 27.6546 0.40979 27.163 0.40979 26.5661C0.40979 25.9693 0.602897 25.4777 0.989111 25.0915L11.3116 14.769L0.989111 4.44657C0.602897 4.06035 0.40979 3.56881 0.40979 2.97193C0.40979 2.37505 0.602897 1.8835 0.989111 1.49729C1.37533 1.11108 1.86687 0.917969 2.46375 0.917969C3.06063 0.917969 3.55217 1.11108 3.93839 1.49729L14.2609 11.8198L24.5833 1.49729C24.9695 1.11108 25.4611 0.917969 26.058 0.917969C26.6548 0.917969 27.1464 1.11108 27.5326 1.49729C27.9188 1.8835 28.1119 2.37505 28.1119 2.97193C28.1119 3.56881 27.9188 4.06035 27.5326 4.44657L17.2101 14.769L27.5326 25.0915C27.9188 25.4777 28.1119 25.9693 28.1119 26.5661C28.1119 27.163 27.9188 27.6546 27.5326 28.0408C27.1464 28.427 26.6548 28.6201 26.058 28.6201C25.4611 28.6201 24.9695 28.427 24.5833 28.0408L14.2609 17.7183Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,9 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M0 15C0 7.92893 -1.70299e-07 4.39339 2.1967 2.1967C4.39339 -1.70299e-07 7.92893 0 15 0C22.071 0 25.6066 -1.70299e-07 27.8032 2.1967C30 4.39339 30 7.92893 30 15C30 22.071 30 25.6066 27.8032 27.8032C25.6066 30 22.071 30 15 30C7.92893 30 4.39339 30 2.1967 27.8032C-1.70299e-07 25.6066 0 22.071 0 15ZM15 6.375C15.6213 6.375 16.125 6.87868 16.125 7.5V15.2839L18.7046 12.7045C19.1439 12.2652 19.8561 12.2652 20.2954 12.7045C20.7348 13.1439 20.7348 13.8561 20.2954 14.2955L15.7955 18.7954C15.5846 19.0065 15.2984 19.125 15 19.125C14.7017 19.125 14.4155 19.0065 14.2045 18.7954L9.7045 14.2955C9.26517 13.8561 9.26517 13.1439 9.7045 12.7045C10.1438 12.2652 10.8562 12.2652 11.2955 12.7045L13.875 15.2839V7.5C13.875 6.87868 14.3787 6.375 15 6.375ZM9 21.375C8.37868 21.375 7.875 21.8787 7.875 22.5C7.875 23.1213 8.37868 23.625 9 23.625H21C21.6213 23.625 22.125 23.1213 22.125 22.5C22.125 21.8787 21.6213 21.375 21 21.375H9Z" fill="url(#paint0_linear_1654_11267)"/>
<defs>
<linearGradient id="paint0_linear_1654_11267" x1="15" y1="0" x2="15" y2="30" gradientUnits="userSpaceOnUse">
<stop stop-color="#3C61FF"/>
<stop offset="1" stop-color="#8749FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,3 @@
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.5 12.5V4.5H12.5M20.5 4.5H28.5V12.5M4.5 20.5V28.5H12.5M28.5 20.5V28.5H20.5" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

@@ -0,0 +1,11 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Sucess" clip-path="url(#clip0_1654_11326)">
<path id="Vector" d="M15 28.8466C22.647 28.8466 28.8461 22.6475 28.8461 15.0005C28.8461 7.35343 22.647 1.1543 15 1.1543C7.35294 1.1543 1.15381 7.35343 1.15381 15.0005C1.15381 22.6475 7.35294 28.8466 15 28.8466Z" fill="white" stroke="#16A427" stroke-width="2" stroke-linecap="round"/>
<path id="Vector_2" d="M21.2305 11.5391L13.5354 19.5391L9.23047 15.0715" stroke="#16A427" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1654_11326">
<rect width="30" height="30" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 703 B

@@ -0,0 +1,10 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Sucess" clip-path="url(#clip0_1654_10424)">
<path id="Vector" d="M15.0005 28.8461C22.6475 28.8461 28.8466 22.647 28.8466 15C28.8466 7.35294 22.6475 1.15381 15.0005 1.15381C7.35343 1.15381 1.1543 7.35294 1.1543 15C1.1543 22.647 7.35343 28.8461 15.0005 28.8461Z" fill="white" stroke="#C5D2E6" stroke-width="2" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_1654_10424">
<rect width="30" height="30" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 552 B

@@ -0,0 +1,11 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Property 1=Default" clip-path="url(#clip0_1206_1827)">
<path id="Vector" d="M15 28.8464C22.647 28.8464 28.8461 22.6473 28.8461 15.0002C28.8461 7.35322 22.647 1.15409 15 1.15409C7.35294 1.15409 1.15381 7.35322 1.15381 15.0002C1.15381 22.6473 7.35294 28.8464 15 28.8464Z" fill="white" stroke="#E4452C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M11 11L19.5 19.5M19.5 11L11 19.5" stroke="#E4452C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1206_1827">
<rect width="30" height="30" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

@@ -0,0 +1,20 @@
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Property 1=Default">
<g id="Vector">
<path d="M15.7311 29.4852C23.327 29.4852 29.4847 23.3275 29.4847 15.7316C29.4847 8.13572 23.327 1.97803 15.7311 1.97803C8.13523 1.97803 1.97754 8.13572 1.97754 15.7316C1.97754 23.3275 8.13523 29.4852 15.7311 29.4852Z" fill="white"/>
<path d="M15.7311 29.4852C23.327 29.4852 29.4847 23.3275 29.4847 15.7316C29.4847 8.13572 23.327 1.97803 15.7311 1.97803C8.13523 1.97803 1.97754 8.13572 1.97754 15.7316C1.97754 23.3275 8.13523 29.4852 15.7311 29.4852Z" stroke="#C5D2E6" stroke-width="2" stroke-linecap="round"/>
<path d="M15.7311 29.4852C23.327 29.4852 29.4847 23.3275 29.4847 15.7316C29.4847 8.13572 23.327 1.97803 15.7311 1.97803C8.13523 1.97803 1.97754 8.13572 1.97754 15.7316C1.97754 23.3275 8.13523 29.4852 15.7311 29.4852Z" stroke="url(#paint0_linear_1654_12180)" stroke-width="2" stroke-linecap="round"/>
</g>
<path id="Ellipse 52" d="M0.997471 15.465C1.14461 7.3279 7.86033 0.850721 15.9975 0.997856C24.1346 1.14499 30.6118 7.86072 30.4647 15.9979C30.3175 24.135 23.6018 30.6122 15.4647 30.465C7.32751 30.3179 0.850337 23.6022 0.997471 15.465ZM28.424 15.961C28.5507 8.95085 22.9707 3.16528 15.9606 3.03853C8.95047 2.91177 3.1649 8.49183 3.03814 15.5019C2.91139 22.512 8.49144 28.2976 15.5016 28.4244C22.5117 28.5511 28.2972 22.9711 28.424 15.961Z" fill="url(#paint1_linear_1654_12180)"/>
</g>
<defs>
<linearGradient id="paint0_linear_1654_12180" x1="4.43354" y1="4.43403" x2="27.5199" y2="27.0292" gradientUnits="userSpaceOnUse">
<stop stop-color="#2667FF"/>
<stop offset="1" stop-color="#9D41FF"/>
</linearGradient>
<linearGradient id="paint1_linear_1654_12180" x1="30.4913" y1="14.5245" x2="7.09515" y2="4.27585" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="liquidity_factors" clip-path="url(#clip0_2393_6607)">
<path id="Vector" d="M10.0003 19.2311C15.0983 19.2311 19.2311 15.0983 19.2311 10.0003C19.2311 4.90229 15.0983 0.769531 10.0003 0.769531C4.90229 0.769531 0.769531 4.90229 0.769531 10.0003C0.769531 15.0983 4.90229 19.2311 10.0003 19.2311Z" fill="#16A427" stroke="#16A427" stroke-width="1.33333" stroke-linecap="round"/>
<path id="Vector_2" d="M14.1543 7.69238L9.02424 13.0257L6.1543 10.0473" stroke="#EEEFFF" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_2393_6607">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 751 B

@@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="industry_high_correlation_factor" clip-path="url(#clip0_1946_1108)">
<path id="Vector" d="M10.0003 19.2311C15.0983 19.2311 19.2311 15.0983 19.2311 10.0003C19.2311 4.90229 15.0983 0.769531 10.0003 0.769531C4.90229 0.769531 0.769531 4.90229 0.769531 10.0003C0.769531 15.0983 4.90229 19.2311 10.0003 19.2311Z" fill="#E4452C" stroke="#EEEFFF" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M7.33301 7.33398L12.9997 13.0007M12.9997 7.33398L7.33301 13.0007" stroke="#EEEFFF" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1946_1108">
<rect width="20" height="20" fill="#E4452C"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 809 B

@@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="industry_high_correlation_factor" clip-path="url(#clip0_1946_1108)">
<path id="Vector" d="M10.0003 19.2311C15.0983 19.2311 19.2311 15.0983 19.2311 10.0003C19.2311 4.90229 15.0983 0.769531 10.0003 0.769531C4.90229 0.769531 0.769531 4.90229 0.769531 10.0003C0.769531 15.0983 4.90229 19.2311 10.0003 19.2311Z" fill="white" stroke="#E4452C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M7.33301 7.33398L12.9997 13.0007M12.9997 7.33398L7.33301 13.0007" stroke="#E4452C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1946_1108">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 805 B

@@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="liquidity_factors" clip-path="url(#clip0_1946_1096)">
<path id="Vector" d="M10.0003 19.2311C15.0983 19.2311 19.2311 15.0983 19.2311 10.0003C19.2311 4.90229 15.0983 0.769531 10.0003 0.769531C4.90229 0.769531 0.769531 4.90229 0.769531 10.0003C0.769531 15.0983 4.90229 19.2311 10.0003 19.2311Z" fill="white" stroke="#16A427" stroke-width="1.33333" stroke-linecap="round"/>
<path id="Vector_2" d="M14.1543 7.69238L9.02424 13.0257L6.1543 10.0473" stroke="#16A427" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1946_1096">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 749 B

+12
View File
@@ -0,0 +1,12 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon-park:full-screen-two">
<g id="Group">
<path id="Vector" d="M12.9224 2.73438H17.7676V7.57961" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M8.07717 2.73438H3.23193V7.57961" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M12.9224 17.27H17.7676V12.4248" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M8.07717 17.27H3.23193V12.4248" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_5" d="M17.7676 2.73438L12.5186 7.98338" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_6" d="M8.48094 12.0215L3.23193 17.2705" stroke="#2b2b2b" stroke-width="1.61508" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

+163
View File
@@ -0,0 +1,163 @@
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: "Source Code Pro", monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token {
/* background: transparent;
border: 0px;
color: inherit;
display: inline;
font-size: 1em;
line-height: inherit;
margin: 0px;
overflow-x: auto;
padding: 0px;
white-space: pre;
word-break: normal;
overflow-wrap: normal; */
font-family: "consolas", monospace;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: rgb(128, 132, 149);
font-style: italic;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: rgb(9, 171, 59);
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: rgb(237, 111, 19);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: rgb(28, 131, 225);
}
.token.function,
.token.class-name {
color: rgb(28, 131, 225);
font-weight: 700;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
+137
View File
@@ -0,0 +1,137 @@
/**
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/chriskempson/tomorrow-theme
* @author Rose Pritchard
*/
code[class*="language-"],
pre[class*="language-"] {
color: #333;
/* 更改为深灰色,便于白色背景下的阅读 */
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
font-weight: 500;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #ffffff;
/* 修改背景为白色 */
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #6a737d;
/* 调整注释为更深的灰色,增加可读性 */
}
.token.punctuation {
color: #555;
/* 调整标点符号为更深的灰色 */
}
.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
color: #e2777a;
/* 仍保留删除标签的红色 */
}
.token.function-name {
color: #3d5a80;
/* 修改函数名为蓝色系 */
}
.token.boolean,
.token.number,
.token.function {
color: #f08d49;
/* 保持橙色用于布尔值和数字 */
}
.token.property,
.token.class-name,
.token.constant,
.token.symbol {
color: #f8c555;
/* 修改为金黄色系,以便突出 */
}
.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
color: #6fa3f2;
/* 将关键词、选择器等修改为浅蓝色 */
}
.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
color: #7ec699;
/* 修改字符串为绿色 */
}
.token.operator,
.token.entity,
.token.url {
color: #67cdcc;
/* 将运算符和URL改为青绿色 */
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.inserted {
color: #28a745;
/* 插入内容为绿色 */
}
+197
View File
@@ -0,0 +1,197 @@
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video,
textarea,
input {
margin: 0;
padding: 0;
border: 0;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
blockquote,
q {
quotes: none;
}
blockquote::before,
blockquote::after,
q::before,
q::after {
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* custom */
a {
color: #7e8c8d;
text-decoration: none;
backface-visibility: hidden;
}
li {
list-style: none;
}
::-webkit-scrollbar {
width: 5px;
height: 5px;
/* background-color: rgba(211, 208, 255, 0); */
opacity: 0;
}
:hover::-webkit-scrollbar {
opacity: 1;
}
::-webkit-scrollbar-track {
background-color: rgba(211, 208, 255, 0);
/* 滚动条轨道颜色 */
}
::-webkit-scrollbar-track-piece {
/* 滚动条背景色 */
background-color: rgba(211, 208, 255, 0);
border-radius: 6px;
}
::-webkit-scrollbar-thumb:vertical {
height: 5px;
/* 滚动条颜色 */
background-color: #E4E7FF;
/* background: linear-gradient( to bottom, #8D9AFF, #9D42FF); */
border-radius: 6px;
}
::-webkit-scrollbar-thumb:horizontal {
width: 5px;
background-color: #E4E7FF;
border-radius: 6px;
}
::-webkit-scrollbar-corner {
/* background-color: rgba(211, 208, 255, 0); */
/* color: rgba(211, 208, 255, 0); */
}
::-webkit-scrollbar-button {
/* background-color: rgba(211, 208, 255, 0); */
/* color: rgba(211, 208, 255, 0); */
}
html,
body {
width: 100%;
height: 100%;
}
body {
/* -webkit-user-select: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-touch-callout: none; */
}
* {
-webkit-text-size-adjust: none;
}
+153
View File
@@ -0,0 +1,153 @@
<template>
<div class="chart-box">
<div
class="chart-item"
v-for="(item, index) in keyList"
:key="item"
:style="{ width: 100 / keyList.length + '%' }"
>
<div
class="zoom"
@click="zoom(colors[index], metricData[item], item)"
></div>
<lineChart
:color="colors[index]"
:data="metricData[item]"
:chartName="item"
:smallSize="true"
></lineChart>
</div>
<div class="dialog-box" v-if="showDialog">
<div class="dialog-content gradient-border">
<div class="close" @click="close"></div>
<lineChart
:color="dialogColor"
:data="dialogData"
:chartName="dialogName"
:smallSize="false"
></lineChart>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, defineProps, watch, ref } from "vue";
import lineChart from "../components/lineChartOne.vue";
const props = defineProps({
metricData: Object,
});
const metricData = ref(props.metricData);
const colors = ["red", "blue", "orange", "green"];
const keyList = ref([]);
const showDialog = ref(false);
const updateData = () => {
keyList.value = Object.keys(metricData.value);
};
const dialogColor = ref("");
const dialogData = ref(null);
const dialogName = ref("");
const zoom = (color, data, name) => {
dialogColor.value = color;
dialogData.value = data;
showDialog.value = true;
dialogName.value = name;
};
const close = () => {
showDialog.value = false;
dialogColor.value = "";
dialogData.value = null;
dialogName.value = "";
};
watch(
() => props.metricData,
(newValue, oldValue) => {
metricData.value = newValue;
updateData();
},
{
deep: true,
immediate: true,
}
);
onMounted(() => {
updateData();
});
</script>
<style scoped lang="scss">
.chart-box {
display: flex;
gap: 1.8em;
margin-bottom: 1.8em;
.chart-item {
background-color: var(--bg-white);
max-width: 500px;
min-width: 0;
border-radius: 35.5px;
position: relative;
box-shadow: 1px 1px 2px 0px rgba(255, 255, 255, 0.3) inset,
-1px -1px 2px 0px rgba(221, 221, 221, 0.5) inset,
-10px 10px 20px 0px rgba(221, 221, 221, 0.2),
10px -10px 20px 0px rgba(221, 221, 221, 0.2),
-10px -10px 20px 0px rgba(255, 255, 255, 0.9),
10px 10px 25px 0px rgba(221, 221, 221, 0.9);
.zoom {
position: absolute;
right: 1.125em;
top: 0.8em;
width: 1.125em;
height: 1.125em;
background: url(@/assets/playground-images/zoom.svg) no-repeat;
background-size: contain;
cursor: pointer;
z-index: 1;
&:hover {
opacity: 0.5;
}
}
}
.dialog-box {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
background: rgba(255, 255, 255, 0.29);
backdrop-filter: blur(4.599999904632568px);
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
.dialog-content {
width: 60%;
height: 498px;
background-color: #fff;
border-radius: 18px;
--border-radius: 20px;
--border-width: 2px;
// padding: 3em 4em;
padding-bottom: 2em;
margin-top: -4em;
position: relative;
.close {
position: absolute;
right: 1.35em;
top: 0.9em;
width: 1.125em;
height: 1.125em;
background: url(@/assets/playground-images/close.svg) no-repeat;
background-size: contain;
cursor: pointer;
z-index: 1;
&:hover {
opacity: 0.5;
}
}
}
}
}
</style>
+183
View File
@@ -0,0 +1,183 @@
<template>
<div class="code">
<div class="code-content">
<SvgIcon
@click="fullScreen"
class="expand-icon"
color="#2b2b2b"
name="fullscreen"
></SvgIcon>
<SvgIcon
@click="copy"
class="copy-icon"
color="#2b2b2b"
name="copy"
></SvgIcon>
<div
class="md-code"
:class="{
'full-dev': fullScreenFlag && developer,
'full-no-dev': fullScreenFlag && !developer,
'no-full-dev': !fullScreenFlag && developer,
'no-full-no-dev': !fullScreenFlag && !developer,
}"
>
<pre
class="code-display language-python"
><code v-html="highlightedCode"></code>
</pre>
</div>
</div>
</div>
</template>
<script setup>
import { ref, watch, onMounted, defineProps, defineEmits, nextTick } from "vue";
// main.js Vue
import "prismjs";
import "prismjs/components/prism-python.min.js"; // Python
import { ElMessage } from "element-plus";
const props = defineProps({
markdown: String,
developer: Boolean,
fullscreen: Boolean,
});
const emit = defineEmits(["fullScreen"]);
const markdown = ref(props.markdown);
const developer = ref(props.developer);
const highlightedCode = ref("");
const fullScreenFlag = ref(props.fullscreen);
watch(
() => [props.markdown, props.developer, props.fullscreen],
(newValue, oldValue) => {
markdown.value = newValue[0];
developer.value = newValue[1];
fullScreenFlag.value = newValue[2];
highlightCode();
}
);
const highlightCode = () => {
// 使 PrismJS Python
highlightedCode.value = Prism.highlight(
markdown.value,
Prism.languages.python,
"python"
);
};
const copy = () => {
navigator.clipboard.writeText(markdown.value);
ElMessage({
message: "Copy Success.",
type: "success",
plain: true,
});
};
const fullScreen = () => {
fullScreenFlag.value = !fullScreenFlag.value;
emit("fullScreen", fullScreenFlag.value);
};
onMounted(() => {
// const codeBlock = document.querySelector("pre code");
// hljs.highlightElement(codeBlock);
highlightCode();
});
</script>
<style lang="scss">
.code {
width: 100%;
.code-content {
border-radius: 11px;
background: var(--bg-white);
padding: 1.35em 0 0 0.9em;
box-sizing: border-box;
overflow-y: hidden;
position: relative;
.expand-icon {
position: absolute;
right: 3.6em;
top: 0.45em;
cursor: pointer;
opacity: 0.5;
width: 1.24em;
&:hover {
opacity: 0.8;
}
}
.copy-icon {
position: absolute;
right: 1.35em;
top: 0.45em;
cursor: pointer;
opacity: 0.5;
width: 1.24em;
&:hover {
opacity: 0.8;
}
}
.md-code {
height: calc(100vh - 28.35em);
max-width: 100%;
font-size: 0.9em;
line-height: 140%;
overflow: auto;
// &:hover {
// overflow: auto;
// }
&::-webkit-scrollbar-thumb {
background-color: #fff;
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: #e4e7ff;
}
}
&.full-dev {
height: calc(100vh - 26.13em);
}
&.full-no-dev {
height: calc(100vh - 19.98em);
}
&.no-full-dev {
height: calc(100vh - 32.8em);
}
&.no-full-no-dev {
height: calc(100vh - 26.1em);
}
pre {
background: transparent;
border: 0px;
display: inline;
font-size: 0.9em;
margin: 0px;
overflow: auto;
padding: 0px;
white-space: pre;
word-break: normal;
overflow-wrap: normal;
font-family: "consolas", monospace;
&::-webkit-scrollbar-thumb {
background-color: #fff;
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: #e4e7ff;
}
}
}
code {
font-family: "consolas", monospace;
}
}
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More