  def testContainsWildcardNoMatches(self, mock_CreateWildcardIterator,
                                    mock_gsutil_api):
    mock_CreateWildcardIterator.return_value = iter([])
    with self.assertRaises(CommandException):
      ExpandUrlToSingleBlr('gs://test/hello*/', mock_gsutil_api, 'project_id',
                           False, CreateOrGetGsutilLogger('copy_test'))


    def __repr__(self):
        return '[%s] %s %s' % (self.name, self.type, ' '.join(self.value))


def test__xla_dist_model_create_from_context():
    # without spawn
    model = _XlaDistModel.create_from_context()

    assert model.backend() == "xla-tpu"

    import torch_xla.core.xla_model as xm

    _assert_model(
        model,
        {
            "device": xm.xla_device(),
            "local_rank": 0,
            "rank": 0,
            "world_size": 1,
            "node_index": 0,
            "nnodes": 1,
            "nproc_per_node": 1,
        },
    )


def main():
    parser = argparse.ArgumentParser(description="Generate a tutorial for a GitHub codebase or local directory.")

    # Create mutually exclusive group for source
    source_group = parser.add_mutually_exclusive_group(required=True)
    source_group.add_argument("--repo", help="URL of the public GitHub repository.")
    source_group.add_argument("--dir", help="Path to local directory.")

    parser.add_argument("-n", "--name", help="Project name (optional, derived from repo/directory if omitted).")
    parser.add_argument("-t", "--token", help="GitHub personal access token (optional, reads from GITHUB_TOKEN env var if not provided).")
    parser.add_argument("-o", "--output", default="output", help="Base directory for output (default: ./output).")
    parser.add_argument("-i", "--include", nargs="+", help="Include file patterns (e.g. '*.py' '*.js'). Defaults to common code files if not specified.")
    parser.add_argument("-e", "--exclude", nargs="+", help="Exclude file patterns (e.g. 'tests/*' 'docs/*'). Defaults to test/build directories if not specified.")
    parser.add_argument("-s", "--max-size", type=int, default=100000, help="Maximum file size in bytes (default: 100000, about 100KB).")
    # Add language parameter for multi-language support
    parser.add_argument("--language", default="english", help="Language for the generated tutorial (default: english)")
    # Add use_cache parameter to control LLM caching
    parser.add_argument("--no-cache", action="store_true", help="Disable LLM response caching (default: caching enabled)")
    # Add max_abstraction_num parameter to control the number of abstractions
    parser.add_argument("--max-abstractions", type=int, default=10, help="Maximum number of abstractions to identify (default: 10)")

    args = parser.parse_args()

    # Get GitHub token from argument or environment variable if using repo
    github_token = None
    if args.repo:
        github_token = args.token or os.environ.get('GITHUB_TOKEN')
        if not github_token:
            print("Warning: No GitHub token provided. You might hit rate limits for public repositories.")

    # Initialize the shared dictionary with inputs
    shared = {
        "repo_url": args.repo,
        "local_dir": args.dir,
        "project_name": args.name, # Can be None, FetchRepo will derive it
        "github_token": github_token,
        "output_dir": args.output, # Base directory for CombineTutorial output

        # Add include/exclude patterns and max file size
        "include_patterns": set(args.include) if args.include else DEFAULT_INCLUDE_PATTERNS,
        "exclude_patterns": set(args.exclude) if args.exclude else DEFAULT_EXCLUDE_PATTERNS,
        "max_file_size": args.max_size,

        # Add language for multi-language support
        "language": args.language,

        # Add use_cache flag (inverse of no-cache flag)
        "use_cache": not args.no_cache,

        # Add max_abstraction_num parameter
        "max_abstraction_num": args.max_abstractions,

        # Outputs will be populated by the nodes
        "files": [],
        "abstractions": [],
        "relationships": {},
        "chapter_order": [],
        "chapters": [],
        "final_output_dir": None
    }

    # Display starting message with repository/directory and language
    print(f"Starting tutorial generation for: {args.repo or args.dir} in {args.language.capitalize()} language")
    print(f"LLM caching: {'Disabled' if args.no_cache else 'Enabled'}")

    # Create the flow instance
    tutorial_flow = create_tutorial_flow()

    # Run the flow
    tutorial_flow.run(shared)


    def append(self, value):
        """Detect list add events and emit change events."""
        list.append(self, value)
        self.changed()


    async def start(self, callback=None):
        def default_callback(self, *args, **kwargs):
            pass

        self.update_progress = callback or default_callback
        self.run_ui = True if callback else False
        if self.run_ui:
            self.update_progress(f"正在检查网络是否支持IPv6", 0)
        self.ipv6_support = config.ipv6_support or check_ipv6_support()
        if not os.getenv("GITHUB_ACTIONS") and config.update_interval:
            await self.scheduler(asyncio.Event())
        else:
            await self.main()


    def register_multicall_functions(self):
        """Registers the XML-RPC multicall method in the system
        namespace.

        see http://www.xmlrpc.com/discuss/msgReader$1208"""

        self.funcs.update({'system.multicall' : self.system_multicall})


def main():
    # Get database path
    config = Config.from_env()
    db_path = config.database.db_file

    print(f"Database path: {db_path}")

    # Create migration manager
    manager = MigrationManager(db_path)

    # Get applied migrations
    applied = manager.get_applied_migrations()
    print(f"Applied migrations: {', '.join(applied) if applied else 'none'}")

    if not applied:
        print("No migrations to downgrade")
        return

    # Check command line arguments
    if len(sys.argv) > 1:
        target_version = sys.argv[1]
        if target_version not in applied:
            print(f"Error: Version {target_version} is not applied, cannot downgrade to this version")
            return

        print(f"Downgrading to version {target_version}...")
        downgraded = manager.downgrade_to_version(target_version)
    else:
        print("Downgrading all migrations...")
        downgraded = manager.downgrade_to_version()

    if downgraded:
        print(f"Successfully downgraded migrations: {', '.join(downgraded)}")
    else:
        print("No migrations were downgraded")


    def digest(self):
        return mysql41.encrypt(self._data[:64])[1:].decode('hex')


def interactive_image_generator():
    print("Welcome to the interactive image generator!")

    # Ask for the number of images at the start of the session
    while True:
        num_images_input = input("How many images would you like to generate per prompt? (Enter a positive integer): ")
        if num_images_input.isdigit() and int(num_images_input) > 0:
            parallel_size = int(num_images_input)
            break
        else:
            print("Invalid input. Please enter a positive integer.")

    while True:
        user_input = input("Please describe the image you'd like to generate (or type 'exit' to quit): ")

        if user_input.lower() == 'exit':
            print("Exiting the image generator. Goodbye!")
            break

        prompt = create_prompt(user_input)

        # Create a sanitized version of user_input for the filename
        short_prompt = re.sub(r'\W+', '_', user_input)[:50]

        print(f"Generating {parallel_size} image(s) for: '{user_input}'")
        generate(
            mmgpt=vl_gpt,
            vl_chat_processor=vl_chat_processor,
            prompt=prompt,
            short_prompt=short_prompt,
            parallel_size=parallel_size  # Pass the user-specified number of images
        )

        print("Image generation complete! Check the 'generated_samples' folder for the output.\n")


    def testGen(self, mock_init, mock_gen):
        # Test with constraints
        modelbridge = RandomModelBridge()
        modelbridge.parameters = ["x", "y", "z"]
        modelbridge.transforms = OrderedDict()
        modelbridge.model = RandomModel()
        observation_features, weights, best_obsf, _ = modelbridge._gen(
            n=3,
            search_space=self.search_space,
            pending_observations={},
            fixed_features=ObservationFeatures({"z": 3.0}),
            optimization_config=None,
            model_gen_options=self.model_gen_options,
        )
        gen_args = mock_gen.mock_calls[0][2]
        self.assertEqual(gen_args["n"], 3)
        self.assertEqual(gen_args["bounds"], [(0.0, 1.0), (1.0, 2.0), (0.0, 5.0)])
        self.assertTrue(
            np.array_equal(
                gen_args["linear_constraints"][0],
                np.array([[1.0, -1, 0.0], [-1.0, 0.0, -1.0]]),
            )
        )
        self.assertTrue(
            np.array_equal(gen_args["linear_constraints"][1], np.array([[0.0], [-3.5]]))
        )
        self.assertEqual(gen_args["fixed_features"], {2: 3.0})
        self.assertEqual(gen_args["model_gen_options"], {"option": "yes"})
        self.assertEqual(
            observation_features[0].parameters, {"x": 1.0, "y": 2.0, "z": 3.0}
        )
        self.assertEqual(
            observation_features[1].parameters, {"x": 3.0, "y": 4.0, "z": 3.0}
        )
        self.assertTrue(np.array_equal(weights, np.array([1.0, 2.0])))

        # Test with no constraints, no fixed feature, no pending observations
        search_space = SearchSpace(self.parameters[:2])
        modelbridge.parameters = ["x", "y"]
        modelbridge._gen(
            n=3,
            search_space=search_space,
            pending_observations={},
            fixed_features=ObservationFeatures({}),
            optimization_config=None,
            model_gen_options=self.model_gen_options,
        )
        gen_args = mock_gen.mock_calls[1][2]
        self.assertEqual(gen_args["bounds"], [(0.0, 1.0), (1.0, 2.0)])
        self.assertIsNone(gen_args["linear_constraints"])
        self.assertIsNone(gen_args["fixed_features"])


    def __init__(self, open, high, low, close):
        pass


    def get(
            self, resource_group_name, ip_groups_name, expand=None, custom_headers=None, raw=False, **operation_config):
        """Gets the specified ipGroups.

        :param resource_group_name: The name of the resource group.
        :type resource_group_name: str
        :param ip_groups_name: The name of the ipGroups.
        :type ip_groups_name: str
        :param expand: Expands resourceIds (of Firewalls/Network Security
         Groups etc.) back referenced by the IpGroups resource.
        :type expand: str
        :param dict custom_headers: headers that will be added to the request
        :param bool raw: returns the direct response alongside the
         deserialized response
        :param operation_config: :ref:`Operation configuration
         overrides<msrest:optionsforoperations>`.
        :return: IpGroup or ClientRawResponse if raw=true
        :rtype: ~azure.mgmt.network.v2019_09_01.models.IpGroup or
         ~msrest.pipeline.ClientRawResponse
        :raises:
         :class:`ErrorException<azure.mgmt.network.v2019_09_01.models.ErrorException>`
        """
        # Construct URL
        url = self.get.metadata['url']
        path_format_arguments = {
            'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'),
            'ipGroupsName': self._serialize.url("ip_groups_name", ip_groups_name, 'str'),
            'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str')
        }
        url = self._client.format_url(url, **path_format_arguments)

        # Construct parameters
        query_parameters = {}
        query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str')
        if expand is not None:
            query_parameters['$expand'] = self._serialize.query("expand", expand, 'str')

        # Construct headers
        header_parameters = {}
        header_parameters['Accept'] = 'application/json'
        if self.config.generate_client_request_id:
            header_parameters['x-ms-client-request-id'] = str(uuid.uuid1())
        if custom_headers:
            header_parameters.update(custom_headers)
        if self.config.accept_language is not None:
            header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str')

        # Construct and send request
        request = self._client.get(url, query_parameters, header_parameters)
        response = self._client.send(request, stream=False, **operation_config)

        if response.status_code not in [200]:
            raise models.ErrorException(self._deserialize, response)

        deserialized = None
        if response.status_code == 200:
            deserialized = self._deserialize('IpGroup', response)

        if raw:
            client_raw_response = ClientRawResponse(deserialized, response)
            return client_raw_response

        return deserialized


    def _execute_command_internal(self, command):
        """Internal command execution with proper context"""
        cmd_type = command.get("type")
        params = command.get("params", {})

        # Add a handler for checking PolyHaven status
        if cmd_type == "get_polyhaven_status":
            return {"status": "success", "result": self.get_polyhaven_status()}

        # Base handlers that are always available
        handlers = {
            "get_scene_info": self.get_scene_info,
            "get_object_info": self.get_object_info,
            "get_viewport_screenshot": self.get_viewport_screenshot,
            "execute_code": self.execute_code,
            "get_polyhaven_status": self.get_polyhaven_status,
            "get_hyper3d_status": self.get_hyper3d_status,
            "get_sketchfab_status": self.get_sketchfab_status,
        }

        # Add Polyhaven handlers only if enabled
        if bpy.context.scene.blendermcp_use_polyhaven:
            polyhaven_handlers = {
                "get_polyhaven_categories": self.get_polyhaven_categories,
                "search_polyhaven_assets": self.search_polyhaven_assets,
                "download_polyhaven_asset": self.download_polyhaven_asset,
                "set_texture": self.set_texture,
            }
            handlers.update(polyhaven_handlers)

        # Add Hyper3d handlers only if enabled
        if bpy.context.scene.blendermcp_use_hyper3d:
            polyhaven_handlers = {
                "create_rodin_job": self.create_rodin_job,
                "poll_rodin_job_status": self.poll_rodin_job_status,
                "import_generated_asset": self.import_generated_asset,
            }
            handlers.update(polyhaven_handlers)

        # Add Sketchfab handlers only if enabled
        if bpy.context.scene.blendermcp_use_sketchfab:
            sketchfab_handlers = {
                "search_sketchfab_models": self.search_sketchfab_models,
                "download_sketchfab_model": self.download_sketchfab_model,
            }
            handlers.update(sketchfab_handlers)

        handler = handlers.get(cmd_type)
        if handler:
            try:
                print(f"Executing handler for {cmd_type}")
                result = handler(**params)
                print(f"Handler execution complete")
                return {"status": "success", "result": result}
            except Exception as e:
                print(f"Error in handler: {str(e)}")
                traceback.print_exc()
                return {"status": "error", "message": str(e)}
        else:
            return {"status": "error", "message": f"Unknown command type: {cmd_type}"}


    def __init__(self, real, timeperiod=30):
        pass


    def target_temperature_low(self):
        """Return the lowbound target temperature we try to reach."""
        return self._target_temperature_low


def main():
    cosyvoice = CosyVoice2('pretrained_models/CosyVoice2-0.5B', load_jit=True, load_trt=True, load_vllm=True, fp16=True)
    prompt_speech_16k = load_wav('./asset/zero_shot_prompt.wav', 16000)
    for i in tqdm(range(100)):
        set_all_random_seed(i)
        for _, _ in enumerate(cosyvoice.inference_zero_shot('收到好友从远方寄来的生日礼物，那份意外的惊喜与深深的祝福让我心中充满了甜蜜的快乐，笑容如花儿般绽放。', '希望你以后能够做的比我还好呦。', prompt_speech_16k, stream=False)):
            continue


    def testSmallPage(self):
        local_pdf_path = os.path.join(os.path.dirname(__file__), "gnarly_pdfs", "small_page_size.pdf")

        report = _pdf_report(local_pdf_path, 1)

        print(report)

        print(get_anchor_text(local_pdf_path, 1, pdf_engine="pdfreport"))


	def test_get_prompt_description_no_filters(self):
		"""Test that system prompt only includes actions with no filters"""
		registry = ActionRegistry()

		# Add actions with and without filters
		no_filter_action = RegisteredAction(
			name='no_filter_action',
			description='Action with no filters',
			function=lambda: None,
			param_model=EmptyParamModel,
			domains=None,
			page_filter=None,
		)

		page_filter_action = RegisteredAction(
			name='page_filter_action',
			description='Action with page filter',
			function=lambda: None,
			param_model=EmptyParamModel,
			domains=None,
			page_filter=lambda page: True,
		)

		domain_filter_action = RegisteredAction(
			name='domain_filter_action',
			description='Action with domain filter',
			function=lambda: None,
			param_model=EmptyParamModel,
			domains=['example.com'],
			page_filter=None,
		)

		registry.actions = {
			'no_filter_action': no_filter_action,
			'page_filter_action': page_filter_action,
			'domain_filter_action': domain_filter_action,
		}

		# System prompt (no page) should only include actions with no filters
		system_description = registry.get_prompt_description()
		assert 'no_filter_action' in system_description
		assert 'page_filter_action' not in system_description
		assert 'domain_filter_action' not in system_description


    def _add_frag_write_service(self, count, ioi, write_data, data_type):
        """
        Add the fragmented write command stuff to the tagIOI
        """
        path_size = int(len(ioi)/2)
        service = 0x53
        request = pack('<BB', service, path_size)
        request += ioi

        if data_type == 160:
            request += pack('<BB', data_type, 0x02)
            request += pack('<H', self.StructIdentifier)
        else:
            request += pack('<H', data_type)
        request += pack('<H', count)
        request += pack('<I', self.Offset)

        for v in write_data:
            try:
                for i in range(len(v)):
                    el = v[i]
                    request += pack(self.CIPTypes[data_type][2], el)
            except Exception:
                request += pack(self.CIPTypes[data_type][2], v)

        return request


    def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
        super(RSU6, self).__init__()

        self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)

        self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
        self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=1)

        self.rebnconv6 = REBNCONV(mid_ch, mid_ch, dirate=2)

        self.rebnconv5d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)


  def testContainsWildcardMatchesNotObject(self, mock_CreateWildcardIterator,
                                           mock_gsutil_api):
    storage_url = StorageUrlFromString('gs://test/helloworld')
    mock_CreateWildcardIterator.return_value = iter(
        [BucketListingPrefix(storage_url)])
    (exp_url, have_existing_dst_container) = ExpandUrlToSingleBlr(
        'gs://test/hello*/', mock_gsutil_api, 'project_id', False,
        CreateOrGetGsutilLogger('copy_test'))

    self.assertTrue(have_existing_dst_container)
    self.assertEqual(exp_url, storage_url)


    def on_profile_status_changed(self, *a):
        "Invoked when the profile's status changes."

        self.show_status(profile.status)


def add_env_var(key, value, from_frontend=True):
    """Add or update a single environment variable

    Args:
        key: Environment variable name
        value: Environment variable value
        from_frontend: Whether it's from frontend configuration, default is True
    """
    try:
        if not key or not key.strip():
            return False, "Variable name cannot be empty"

        key = key.strip()
        value = value.strip()

        # If from frontend, add to frontend environment variable dictionary
        if from_frontend:
            WEB_FRONTEND_ENV_VARS[key] = value
            # Directly update system environment variables
            os.environ[key] = value

        # Also update .env file
        dotenv_path = init_env_file()
        set_key(dotenv_path, key, value)
        load_dotenv(dotenv_path, override=True)

        return True, f"Environment variable {key} has been successfully added/updated!"
    except Exception as e:
        return False, f"Error adding environment variable: {str(e)}"


    def flush(self):
        if self.linebuf != '':
            self.logger.log(self.log_level, self.linebuf.rstrip())
        self.linebuf = ''


    def should_continue_social(self, state: AgentState):
        """Determine if social media analysis should continue."""
        messages = state["messages"]
        last_message = messages[-1]
        if last_message.tool_calls:
            return "tools_social"
        return "Msg Clear Social"


    def test_start_handshake(self, mock_share, mock_timer, *_):
        self.server.start_handshake(
            key_id=self.key_id,
            task_id=self.task_id,
        )
        self.assertIn(
            self.key_id,
            self.server.resource_handshakes,
        )
        mock_timer.assert_called_once_with(self.key_id)
        mock_share.assert_called_once_with(self.key_id)


def get_stats(ids, counts=None):
    """
    Given a list of integers, return a dictionary of counts of consecutive pairs
    Example: [1, 2, 3, 1, 2] -> {(1, 2): 2, (2, 3): 1, (3, 1): 1}
    Optionally allows to update an existing dictionary of counts
    """
    counts = {} if counts is None else counts
    for pair in zip(ids, ids[1:]): # iterate consecutive elements
        counts[pair] = counts.get(pair, 0) + 1
    return counts


    def key_id(self):
        return self.public_key[2:]


    def _get_extension_path(self,exname='turnstilePatch'):
        """获取插件路径"""
        root_dir = os.getcwd()
        extension_path = os.path.join(root_dir, exname)

        if hasattr(sys, "_MEIPASS"):
            extension_path = os.path.join(sys._MEIPASS, exname)

        if not os.path.exists(extension_path):
            raise FileNotFoundError(f"插件不存在: {extension_path}")

        return extension_path


    def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
        super(RSU5, self).__init__()

        self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)

        self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
        self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)

        self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=2)

        self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)


def _parse_args():
    parser = argparse.ArgumentParser(
        description="Generate a image or video from a text prompt or image using Wan"
    )
    parser.add_argument(
        "--task",
        type=str,
        default="t2v-14B",
        choices=list(WAN_CONFIGS.keys()),
        help="The task to run.")
    parser.add_argument(
        "--size",
        type=str,
        default="1280*720",
        choices=list(SIZE_CONFIGS.keys()),
        help="The area (width*height) of the generated video. For the I2V task, the aspect ratio of the output video will follow that of the input image."
    )
    parser.add_argument(
        "--frame_num",
        type=int,
        default=None,
        help="How many frames to sample from a image or video. The number should be 4n+1"
    )
    parser.add_argument(
        "--ckpt_dir",
        type=str,
        default=None,
        help="The path to the checkpoint directory.")
    parser.add_argument(
        "--offload_model",
        type=str2bool,
        default=None,
        help="Whether to offload the model to CPU after each model forward, reducing GPU memory usage."
    )
    parser.add_argument(
        "--ulysses_size",
        type=int,
        default=1,
        help="The size of the ulysses parallelism in DiT.")
    parser.add_argument(
        "--ring_size",
        type=int,
        default=1,
        help="The size of the ring attention parallelism in DiT.")
    parser.add_argument(
        "--t5_fsdp",
        action="store_true",
        default=False,
        help="Whether to use FSDP for T5.")
    parser.add_argument(
        "--t5_cpu",
        action="store_true",
        default=False,
        help="Whether to place T5 model on CPU.")
    parser.add_argument(
        "--dit_fsdp",
        action="store_true",
        default=False,
        help="Whether to use FSDP for DiT.")
    parser.add_argument(
        "--save_file",
        type=str,
        default=None,
        help="The file to save the generated image or video to.")
    parser.add_argument(
        "--src_video",
        type=str,
        default=None,
        help="The file of the source video. Default None.")
    parser.add_argument(
        "--src_mask",
        type=str,
        default=None,
        help="The file of the source mask. Default None.")
    parser.add_argument(
        "--src_ref_images",
        type=str,
        default=None,
        help="The file list of the source reference images. Separated by ','. Default None."
    )
    parser.add_argument(
        "--prompt",
        type=str,
        default=None,
        help="The prompt to generate the image or video from.")
    parser.add_argument(
        "--use_prompt_extend",
        action="store_true",
        default=False,
        help="Whether to use prompt extend.")
    parser.add_argument(
        "--prompt_extend_method",
        type=str,
        default="local_qwen",
        choices=["dashscope", "local_qwen"],
        help="The prompt extend method to use.")
    parser.add_argument(
        "--prompt_extend_model",
        type=str,
        default=None,
        help="The prompt extend model to use.")
    parser.add_argument(
        "--prompt_extend_target_lang",
        type=str,
        default="zh",
        choices=["zh", "en"],
        help="The target language of prompt extend.")
    parser.add_argument(
        "--base_seed",
        type=int,
        default=-1,
        help="The seed to use for generating the image or video.")
    parser.add_argument(
        "--image",
        type=str,
        default=None,
        help="[image to video] The image to generate the video from.")
    parser.add_argument(
        "--first_frame",
        type=str,
        default=None,
        help="[first-last frame to video] The image (first frame) to generate the video from."
    )
    parser.add_argument(
        "--last_frame",
        type=str,
        default=None,
        help="[first-last frame to video] The image (last frame) to generate the video from."
    )
    parser.add_argument(
        "--sample_solver",
        type=str,
        default='unipc',
        choices=['unipc', 'dpm++'],
        help="The solver used to sample.")
    parser.add_argument(
        "--sample_steps", type=int, default=None, help="The sampling steps.")
    parser.add_argument(
        "--sample_shift",
        type=float,
        default=None,
        help="Sampling shift factor for flow matching schedulers.")
    parser.add_argument(
        "--sample_guide_scale",
        type=float,
        default=5.0,
        help="Classifier free guidance scale.")

    args = parser.parse_args()

    _validate_args(args)

    return args


def ocr_error_predictor() -> OCRErrorPredictor:
    ocr_error_predictor = OCRErrorPredictor()
    yield ocr_error_predictor
    del ocr_error_predictor


    def test_get_signal_signal_wrong_data_shape(self):
        s = self.signal
        s = s.transpose(signal_axes=1)
        with pytest.raises(ValueError):
            s._get_signal_signal(data=np.zeros((3, 2)))


def format_time(milliseconds):
    """将毫秒转换为时:分:秒.毫秒格式"""
    total_seconds = milliseconds / 1000
    hours = int(total_seconds // 3600)
    minutes = int((total_seconds % 3600) // 60)
    seconds = int(total_seconds % 60)
    ms = int((total_seconds * 1000) % 1000)

    if hours > 0:
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}.{ms:03d}"
    else:
        return f"{minutes:02d}:{seconds:02d}.{ms:03d}"


    def reset(self):
        self.kill_process()
        self.log.reset()
        self.agent0 = Agent(0, self.config, self)
        self.streaming_agent = None
        self.paused = False


def get_logger(name: str, lv=logging.INFO, remove_exist=False, format_root=False):
    logger = logging.getLogger(name)
    logger.setLevel(lv)
    if remove_exist and logger.hasHandlers():
        logger.handlers.clear()
    if not logger.hasHandlers():
        syslog = logging.StreamHandler()
        syslog.setFormatter(Formatter())
        logger.addHandler(syslog)
    else:
        for h in logger.handlers:
            h.setFormatter(Formatter())
    if format_root:
        for h in logger.root.handlers:
            h.setFormatter(Formatter())
    return logger


def test_encoder_stats():
    """Test encoder statistics"""
    encoder = MemvidEncoder()
    chunks = ["short", "medium length chunk", "this is a longer chunk with more text"]
    encoder.add_chunks(chunks)

    stats = encoder.get_stats()
    assert stats["total_chunks"] == 3
    assert stats["total_characters"] == sum(len(c) for c in chunks)
    assert stats["avg_chunk_size"] > 0


def Logger(content):
    if not ddp or dist.get_rank() == 0:
        print(content)


    def test_atomic_compare_and_swap(self):
        n = 100
        res = [-99] * (n // 2) + [-1] * (n // 2)
        random.shuffle(res)
        res = np.asarray(res, dtype=np.int32)
        out = np.zeros_like(res)
        ary = np.random.randint(1, 10, size=res.size).astype(res.dtype)

        fill_mask = res == -99
        unfill_mask = res == -1

        expect_res = np.zeros_like(res)
        expect_res[fill_mask] = ary[fill_mask]
        expect_res[unfill_mask] = -1

        expect_out = np.zeros_like(out)
        expect_out[fill_mask] = res[fill_mask]
        expect_out[unfill_mask] = -1

        cuda_func = cuda.jit(atomic_compare_and_swap)
        cuda_func[10, 10](res, out, ary)

        np.testing.assert_array_equal(expect_res, res)
        np.testing.assert_array_equal(expect_out, out)


    def generate(self, messages, tools_to_call_from=None, stop_sequences=None):
        if len(messages) < 3:
            return ChatMessage(
                role=MessageRole.ASSISTANT,
                content="",
                tool_calls=[
                    ChatMessageToolCall(
                        id="call_0",
                        type="function",
                        function=ChatMessageToolCallFunction(
                            name="fake_image_generation_tool",
                            arguments={"prompt": "An image of a cat"},
                        ),
                    )
                ],
            )
        else:
            return ChatMessage(
                role=MessageRole.ASSISTANT,
                content="",
                tool_calls=[
                    ChatMessageToolCall(
                        id="call_1",
                        type="function",
                        function=ChatMessageToolCallFunction(name="final_answer", arguments="image.png"),
                    )
                ],
            )


    def test_get_signal_signal_given_data(self):
        s = self.signal
        s = s.transpose(signal_axes=2)
        data = np.zeros(s.axes_manager._signal_shape_in_array)
        ns = s._get_signal_signal(data=data)
        assert ns.data is data


	def get_ClientToken(self):
		return self.get_query_params().get('ClientToken')


def build_logger(logger_name, logger_filename):
    global handler

    formatter = logging.Formatter(
        fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Set the format of root handlers
    if not logging.getLogger().handlers:
        logging.basicConfig(level=logging.INFO)
    logging.getLogger().handlers[0].setFormatter(formatter)

    # Redirect stdout and stderr to loggers
    stdout_logger = logging.getLogger("stdout")
    stdout_logger.setLevel(logging.INFO)
    sl = StreamToLogger(stdout_logger, logging.INFO)
    sys.stdout = sl

    stderr_logger = logging.getLogger("stderr")
    stderr_logger.setLevel(logging.ERROR)
    sl = StreamToLogger(stderr_logger, logging.ERROR)
    sys.stderr = sl

    # Get logger
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.INFO)

    # Add a file handler for all loggers
    if handler is None:
        os.makedirs(LOGDIR, exist_ok=True)
        filename = os.path.join(LOGDIR, logger_filename)
        handler = logging.handlers.TimedRotatingFileHandler(
            filename, when='D', utc=True, encoding='UTF-8')
        handler.setFormatter(formatter)

        for name, item in logging.root.manager.loggerDict.items():
            if isinstance(item, logging.Logger):
                item.addHandler(handler)

    return logger


def test_teleoperate():
    robot_cfg = MockRobotConfig()
    teleop_cfg = MockTeleopConfig()
    cfg = TeleoperateConfig(
        robot=robot_cfg,
        teleop=teleop_cfg,
        teleop_time_s=0.1,
    )
    teleoperate(cfg)


    def fetch_ticker(self, symbol, params={}):
        self.load_markets()
        market = self.market(symbol)
        method = 'publicGet'
        request = {
            'symbol': market['id'],
        }
        if market['future']:
            method += 'Future'
            request['contract_type'] = 'this_week'  # next_week, quarter
        method += 'Ticker'
        response = getattr(self, method)(self.extend(request, params))
        ticker = self.safe_value(response, 'ticker')
        if ticker is None:
            raise ExchangeError(self.id + ' fetchTicker returned an empty response: ' + self.json(response))
        timestamp = self.safe_integer(response, 'date')
        if timestamp is not None:
            timestamp *= 1000
            ticker = self.extend(ticker, {'timestamp': timestamp})
        return self.parse_ticker(ticker, market)


def load_config(config_path: str) -> List[TaskConfig]:
    with open(config_path, "r") as f:
        config_data = yaml.safe_load(f)

    configs = []
    for idx, entry in enumerate(config_data.get("tasks", [])):
        if not isinstance(entry, dict):
            raise ValueError(f"Invalid entry at index {idx}")

        config = TaskConfig(
            server_cmd=entry.get("server_cmd"),
            client_cmd=entry.get("client_cmd"),
            name=entry.get("name", f"task-{idx+1}"),
            server_type=entry.get("server_type"),
        )

        if not config.server_cmd or not config.client_cmd:
            raise ValueError(f"Missing commands in {config.name}")

        configs.append(config)

    return configs


def test_basic_crawl(tester: Crawl4AiTester):
    print("\n=== Testing Basic Crawl ===")
    request = {
        "urls": ["https://www.nbcnews.com/business"],
        "priority": 10,
        "session_id": "test",
    }

    result = tester.submit_and_wait(request)
    print(f"Basic crawl result length: {len(result['result']['markdown'])}")
    assert result["result"]["success"]
    assert len(result["result"]["markdown"]) > 0


def check_samples(samples=()):
    """
      Check script output for all samples. Sample is a two element list, where the first is input and
      the second is output.
    """
    for sample in samples:
        if len(sample) == 2:
            output = get_file_output(arg_string=str(sample[0]))
            if "\n".join(output) != sample[1]:
                failed(
                    "Test from samples failed: \n \n"
                    "Input:\n{}"
                    "\n \n"
                    "Expected:\n{}"
                    "\n \n"
                    "Your result:\n{}".format(str.strip(sample[0]), str.strip(sample[1]), "\n".join(output)))
                return
        set_congratulation_message("All test from samples passed. Now we are checking your solution on Stepic server.")

    passed()


    def test_delitem_with_2_invalid_keys(self):
        d = {
            'a': {
                'b': 1,
            }
        }
        b = KeypathDict(d)
        with self.assertRaises(KeyError):
            del b['a.c']
        self.assertEqual(b.get('a'), { 'b': 1 })


    def recomputeConvexHullDelayed(self) -> None:
        """The same as recomputeConvexHull, but using a timer if it was set."""
        if self._recompute_convex_hull_timer is not None:
            self._recompute_convex_hull_timer.start()
        else:
            from cura.CuraApplication import CuraApplication
            if not self._timer_scheduled_to_be_created:
                # The timer is not created and we never scheduled it. Time to create it now!
                CuraApplication.getInstance().callLater(self.createRecomputeConvexHullTimer)
            # Now we know for sure that the timer has been scheduled for creation, so we can try this again.
            CuraApplication.getInstance().callLater(self.recomputeConvexHullDelayed)


    def __len__(self):
        if self.batch is not None:
            return self.batch.batch_size[0]
        elif self.non_tensor_batch is not None and len(self.non_tensor_batch) > 0:
            random_key = list(self.non_tensor_batch.keys())[0]
            return self.non_tensor_batch[random_key].shape[0]
        else:
            return 0


def init_log():
    logger.remove()
    _lvl = "DEBUG"

    def format_record(record):
        # 获取日志记录中的文件全路径
        file_path = record["file"].path
        # 将绝对路径转换为相对于项目根目录的路径
        relative_path = os.path.relpath(file_path, root_dir)
        # 更新记录中的文件路径
        record["file"].path = f"./{relative_path}"
        # 返回修改后的格式字符串
        # 您可以根据需要调整这里的格式
        record["message"] = record["message"].replace(root_dir, ".")

        _format = (
            "<green>{time:%Y-%m-%d %H:%M:%S}</> | "
            + "<level>{level}</> | "
            + '"{file.path}:{line}":<blue> {function}</> '
            + "- <level>{message}</>"
            + "\n"
        )
        return _format

    logger.add(
        sys.stdout,
        level=_lvl,
        format=format_record,
        colorize=True,
    )


    def extract_tracks(self, tracks):
        """
        Extracts results from the provided data.

        Args:
            tracks (list): List of tracks obtained from the object tracking process.
        """
        self.boxes = tracks[0].boxes.xyxy.cpu()
        self.clss = tracks[0].boxes.cls.cpu().tolist()
        self.trk_ids = tracks[0].boxes.id.int().cpu().tolist()


def mixer():
    from mixer.backend.marshmallow import Mixer
    return Mixer(required=True)


    def getConvexHullBoundary(self) -> Optional[Polygon]:
        """Get convex hull of the node

        In case of printing all at once this None??
        For one at the time this is the area without the head.
        """
        if self._node is None:
            return None

        if self._node.callDecoration("isNonPrintingMesh"):
            return None

        if self._isSingularOneAtATimeNode():
            # Printing one at a time and it's not an object in a group
            return self._compute2DConvexHull()
        return None


def test_structured_extraction(tester: Crawl4AiTester):
    print("\n=== Testing Structured Extraction ===")
    schema = {
        "name": "Coinbase Crypto Prices",
        "baseSelector": ".cds-tableRow-t45thuk",
        "fields": [
            {
                "name": "crypto",
                "selector": "td:nth-child(1) h2",
                "type": "text",
            },
            {
                "name": "symbol",
                "selector": "td:nth-child(1) p",
                "type": "text",
            },
            {
                "name": "price",
                "selector": "td:nth-child(2)",
                "type": "text",
            },
        ],
    }

    request = {
        "urls": ["https://www.coinbase.com/explore"],
        "priority": 9,
        "extraction_config": {"type": "json_css", "params": {"schema": schema}},
    }

    result = tester.submit_and_wait(request)
    extracted = json.loads(result["result"]["extracted_content"])
    print(f"Extracted {len(extracted)} items")
    print("Sample item:", json.dumps(extracted[0], indent=2))
    assert result["result"]["success"]
    assert len(extracted) > 0


    def __init__(self, lam_over_diam=None, lam=None, diam=None, obscuration=0., flux=1.,
                 scale_unit=None, gsparams=None):
        from .angle import arcsec, radians, AngleUnit

        self._obscuration = float(obscuration)
        self._flux = float(flux)
        self._gsparams = GSParams.check(gsparams)

        # Parse arguments: either lam_over_diam in arbitrary units, or lam in nm and diam in m.
        # If the latter, then get lam_over_diam in units of scale_unit, as specified in
        # docstring.
        if lam_over_diam is not None:
            if lam is not None or diam is not None:
                raise GalSimIncompatibleValuesError(
                    "If specifying lam_over_diam, then do not specify lam or diam",
                    lam_over_diam=lam_over_diam, lam=lam, diam=diam)
            self._lod = float(lam_over_diam)
        else:
            if lam is None or diam is None:
                raise GalSimIncompatibleValuesError(
                    "If not specifying lam_over_diam, then specify lam AND diam",
                    lam_over_diam=lam_over_diam, lam=lam, diam=diam)
            # In this case we're going to use scale_unit, so parse it in case of string input:
            if isinstance(scale_unit, str):
                scale_unit = AngleUnit.from_name(scale_unit)
            elif scale_unit is None:
                scale_unit = arcsec
            self._lod = (1.e-9*float(lam)/float(diam))*(radians/scale_unit)


    def test_1d_slicing6(self, flags=enable_pyobj_flags):
        pyfunc = slicing_1d_usecase6
        self.check_1d_slicing_with_arg(pyfunc, flags)


    def check_file_matches_md5(checksum, fpath):
        if not os.path.exists(fpath):
            return False
        with open(fpath, 'rb') as f:
            current_md5checksum = hashlib.md5(f.read()).hexdigest()
        return current_md5checksum == checksum


    def is_enabled(cls, filename, syntax):
        if syntax == 'text.tex.latex.haskell':  # Literate Haskell.tmLanguage
            return True
        return filename.endswith('.lhs')


def __truediv__(self, name: str) -> URL: ...


    def parse_trade(self, trade, market=None):
        symbol = None
        if market:
            symbol = market['symbol']
        return {
            'info': trade,
            'timestamp': trade['date_ms'],
            'datetime': self.iso8601(trade['date_ms']),
            'symbol': symbol,
            'id': str(trade['tid']),
            'order': None,
            'type': None,
            'side': trade['type'],
            'price': self.safe_float(trade, 'price'),
            'amount': self.safe_float(trade, 'amount'),
        }


    def should_continue_fundamentals(self, state: AgentState):
        """Determine if fundamentals analysis should continue."""
        messages = state["messages"]
        last_message = messages[-1]
        if last_message.tool_calls:
            return "tools_fundamentals"
        return "Msg Clear Fundamentals"


    def assert_create_called_with(self, **kwargs):
        self.chat.completions.create.assert_called_with(**kwargs)


    def export_item(self, item):
        print(json.dumps(item))


    def delete(self, child=False):
        """Delete the filter documents

        if child is True then delete nested collection and documents also
        """
        transaction_or_batch = self.query_transaction if self.query_transaction else self.query_batch
        q = self.query()
        DeleteQuery(self.model, query=q, child=child).exec(transaction_or_batch)


async def run_flow():
    agents = {
        "manus": Manus(),
    }
    if config.run_flow_config.use_data_analysis_agent:
        agents["data_analysis"] = DataAnalysis()
    try:
        prompt = input("Enter your prompt: ")

        if prompt.strip().isspace() or not prompt:
            logger.warning("Empty prompt provided.")
            return

        flow = FlowFactory.create_flow(
            flow_type=FlowType.PLANNING,
            agents=agents,
        )
        logger.warning("Processing your request...")

        try:
            start_time = time.time()
            result = await asyncio.wait_for(
                flow.execute(prompt),
                timeout=3600,  # 60 minute timeout for the entire execution
            )
            elapsed_time = time.time() - start_time
            logger.info(f"Request processed in {elapsed_time:.2f} seconds")
            logger.info(result)
        except asyncio.TimeoutError:
            logger.error("Request processing timed out after 1 hour")
            logger.info(
                "Operation terminated due to timeout. Please try a simpler request."
            )

    except KeyboardInterrupt:
        logger.info("Operation cancelled by user.")
    except Exception as e:
        logger.error(f"Error: {str(e)}")


    def handle_close(self):
        raise Exception("handle_close not supposed to be called")


def progress_bar(progress, total, prefix="", length=50):
    filled = int(length * progress // total)
    bar = "█" * filled + "░" * (length - filled)
    percent = f"{100 * progress / total:.1f}"
    print(f"\r{prefix} |{bar}| {percent}% Complete", end="", flush=True)
    if progress == total:
        print()


    def restore_dtype(self, x):
        if x.dtype != self.original_run_dtype and self.original_run_dtype is not None:
            x = x.to(self.original_run_dtype)
        return x


    def reset(self, count=10):
        self.logger.info('Facedancer resetting...')
        for i in range(count):
            self.halt()
            self.serialport.setDTR(0)
            rsp_data = self.read(1024)
            if len(rsp_data) < 4:
                continue
            app, verb, n = struct.unpack('<BBH', rsp_data[:4])
            if verb == 0x7f and n == (len(rsp_data) - 4):
                self.logger.debug("No buffer any more")
                self.logger.info("Facedancer reset")
                return
        raise Exception("Facedancer reset fault.")


def get_all_fonts():
    fonts = []
    for root, dirs, files in os.walk(font_dir):
        for file in files:
            if file.endswith(".ttf") or file.endswith(".ttc"):
                fonts.append(file)
    fonts.sort()
    return fonts


def main():
  """Configures and runs a pipeline."""
  args = parse_arguments(sys.argv)
  config = parse_config(
      "CLOUD" if args.cloud else "LOCAL",
      get_relative_path("config.ini"))
  set_logging(config.get("log_level"))
  options = get_pipeline_options(args, config)
  runner = str(config.get("runner"))

  with beam.Pipeline(runner, options=options) as pipeline:
    with beam_impl.Context(
        temp_dir=os.path.join(args.tft_dir, constants.TMP_DIR)):
      preprocess.run(pipeline, args)


def split_line(text: str) -> List[str]:
    """Split text into lines based on terminal width."""
    term_width = shutil.get_terminal_size().columns or 80
    if not text.strip():
        return []
    # Split by explicit newlines and wrap long lines
    lines = []
    for line in text.split('\n'):
        while len(line) > term_width:
            lines.append(line[:term_width])
            line = line[term_width:]
        if line:
            lines.append(line)
    return lines


def setbufsize(size):
    """
    Set the size of the buffer used in ufuncs.

    Parameters
    ----------
    size : int
        Size of buffer.

    """
    if size > 10e6:
        raise ValueError("Buffer size, %s, is too big." % size)
    if size < 5:
        raise ValueError("Buffer size, %s, is too small." % size)
    if size % 16 != 0:
        raise ValueError("Buffer size, %s, is not a multiple of 16." % size)

    pyvals = umath.geterrobj()
    old = getbufsize()
    pyvals[0] = size
    umath.seterrobj(pyvals)
    return old


def test_add_chunks():
    """Test adding chunks"""
    encoder = MemvidEncoder()
    chunks = ["chunk1", "chunk2", "chunk3"]

    encoder.add_chunks(chunks)
    assert len(encoder.chunks) == 3
    assert encoder.chunks == chunks


def sidebar_config():
    with st.sidebar:
        st.title("🔑 Configuration")
        st.markdown("---")

        st.session_state.qdrant_url = st.text_input(
            "Qdrant URL",
            value=st.session_state.qdrant_url,
            type="password"
        )
        st.session_state.qdrant_api_key = st.text_input(
            "Qdrant API Key",
            value=st.session_state.qdrant_api_key,
            type="password"
        )
        st.session_state.firecrawl_api_key = st.text_input(
            "Firecrawl API Key",
            value=st.session_state.firecrawl_api_key,
            type="password"
        )
        st.session_state.openai_api_key = st.text_input(
            "OpenAI API Key",
            value=st.session_state.openai_api_key,
            type="password"
        )

        st.markdown("---")
        st.session_state.doc_url = st.text_input(
            "Documentation URL",
            value=st.session_state.doc_url,
            placeholder="https://docs.example.com"
        )

        st.markdown("---")
        st.markdown("### 🎤 Voice Settings")
        voices = ["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"]
        st.session_state.selected_voice = st.selectbox(
            "Select Voice",
            options=voices,
            index=voices.index(st.session_state.selected_voice),
            help="Choose the voice for the audio response"
        )

        if st.button("Initialize System", type="primary"):
            if all([
                st.session_state.qdrant_url,
                st.session_state.qdrant_api_key,
                st.session_state.firecrawl_api_key,
                st.session_state.openai_api_key,
                st.session_state.doc_url
            ]):
                progress_placeholder = st.empty()
                with progress_placeholder.container():
                    try:
                        st.markdown("🔄 Setting up Qdrant connection...")
                        client, embedding_model = setup_qdrant_collection(
                            st.session_state.qdrant_url,
                            st.session_state.qdrant_api_key
                        )
                        st.session_state.client = client
                        st.session_state.embedding_model = embedding_model
                        st.markdown("✅ Qdrant setup complete!")

                        st.markdown("🔄 Crawling documentation pages...")
                        pages = crawl_documentation(
                            st.session_state.firecrawl_api_key,
                            st.session_state.doc_url
                        )
                        st.markdown(f"✅ Crawled {len(pages)} documentation pages!")

                        store_embeddings(
                            client,
                            embedding_model,
                            pages,
                            "docs_embeddings"
                        )

                        processor_agent, tts_agent = setup_agents(
                            st.session_state.openai_api_key
                        )
                        st.session_state.processor_agent = processor_agent
                        st.session_state.tts_agent = tts_agent

                        st.session_state.setup_complete = True
                        st.success("✅ System initialized successfully!")

                    except Exception as e:
                        st.error(f"Error during setup: {str(e)}")
            else:
                st.error("Please fill in all the required fields!")


def home():
    return render_template('index.html')


def punc_norm(text: str) -> str:
    """
        Quick cleanup func for punctuation from LLMs or
        containing chars not seen often in the dataset
    """
    if len(text) == 0:
        return "You need to add some text for me to talk."

    # Capitalise first letter
    if text[0].islower():
        text = text[0].upper() + text[1:]

    # Remove multiple space chars
    text = " ".join(text.split())

    # Replace uncommon/llm punc
    punc_to_replace = [
        ("...", ", "),
        ("…", ", "),
        (":", ","),
        (" - ", ", "),
        (";", ", "),
        ("—", "-"),
        ("–", "-"),
        (" ,", ","),
        ("“", "\""),
        ("”", "\""),
        ("‘", "'"),
        ("’", "'"),
    ]
    for old_char_sequence, new_char in punc_to_replace:
        text = text.replace(old_char_sequence, new_char)

    # Add full stop if no ending punc
    text = text.rstrip(" ")
    sentence_enders = {".", "!", "?", "-", ","}
    if not any(text.endswith(p) for p in sentence_enders):
        text += "."

    return text


    async def create_llm_artifact(self, *args, **kwargs):
        return None


def test_gpt4_tiktoken_equality_special_tokens():
    tokenizer = GPT4Tokenizer()
    enc = tiktoken.get_encoding("cl100k_base")
    tiktoken_ids = enc.encode(specials_string, allowed_special="all")
    gpt4_tokenizer_ids = tokenizer.encode(specials_string, allowed_special="all")
    assert gpt4_tokenizer_ids == tiktoken_ids


async def main():
    pretty_print("Initializing...", color="status")
    stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
    personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
    languages = config["MAIN"]["languages"].split(' ')

    provider = Provider(provider_name=config["MAIN"]["provider_name"],
                        model=config["MAIN"]["provider_model"],
                        server_address=config["MAIN"]["provider_server_address"],
                        is_local=config.getboolean('MAIN', 'is_local'))

    browser = Browser(
        create_driver(headless=config.getboolean('BROWSER', 'headless_browser'), stealth_mode=stealth_mode, lang=languages[0]),
        anticaptcha_manual_install=stealth_mode
    )

    agents = [
        CasualAgent(name=config["MAIN"]["agent_name"],
                    prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
                    provider=provider, verbose=False),
        CoderAgent(name="coder",
                   prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
                   provider=provider, verbose=False),
        FileAgent(name="File Agent",
                  prompt_path=f"prompts/{personality_folder}/file_agent.txt",
                  provider=provider, verbose=False),
        BrowserAgent(name="Browser",
                     prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
                     provider=provider, verbose=False, browser=browser),
        PlannerAgent(name="Planner",
                     prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
                     provider=provider, verbose=False, browser=browser),
        #McpAgent(name="MCP Agent",
        #            prompt_path=f"prompts/{personality_folder}/mcp_agent.txt",
        #            provider=provider, verbose=False), # NOTE under development
    ]

    interaction = Interaction(agents,
                              tts_enabled=config.getboolean('MAIN', 'speak'),
                              stt_enabled=config.getboolean('MAIN', 'listen'),
                              recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
                              langs=languages
                            )
    try:
        while interaction.is_active:
            interaction.get_user()
            if await interaction.think():
                interaction.show_answer()
                interaction.speak_answer()
    except Exception as e:
        if config.getboolean('MAIN', 'save_session'):
            interaction.save_session()
        raise e
    finally:
        if config.getboolean('MAIN', 'save_session'):
            interaction.save_session()


def main(config_path):
    config = load_config(config_path)
    task_instances = initialize_tasks_and_models(config)

    # get input and output path from config
    input_data = config.get('inputs', None)
    result_path = config.get('outputs', 'outputs'+'/'+TASK_NAME)

    # formula_detection_task
    model_formula_detection = task_instances[TASK_NAME]

    # for image detection
    detection_results = model_formula_detection.predict_images(input_data, result_path)

    # for pdf detection
    # detection_results = model_formula_detection.predict_pdfs(input_data, result_path)

    # print(detection_results)
    print(f'The predicted results can be found at {result_path}')


    def check_edges(self):
        """Return True if alien is at edge of screen."""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <= 0:
            return True


    def __init__(self, in_ch=3, mid_ch=12, out_ch=3, img_size=512):
        super(RSU7, self).__init__()

        self.in_ch = in_ch
        self.mid_ch = mid_ch
        self.out_ch = out_ch

        self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)  ## 1 -> 1/2

        self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
        self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=1)
        self.pool5 = nn.MaxPool2d(2, stride=2, ceil_mode=True)

        self.rebnconv6 = REBNCONV(mid_ch, mid_ch, dirate=1)

        self.rebnconv7 = REBNCONV(mid_ch, mid_ch, dirate=2)

        self.rebnconv6d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv5d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
        self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)


    def __init__(
        self,
        agent: Callable,
        tickers: list[str],
        start_date: str,
        end_date: str,
        initial_capital: float,
        model_name: str = "gpt-4.1",
        model_provider: str = "OpenAI",
        selected_analysts: list[str] = [],
        initial_margin_requirement: float = 0.0,
    ):
        """
        :param agent: The trading agent (Callable).
        :param tickers: List of tickers to backtest.
        :param start_date: Start date string (YYYY-MM-DD).
        :param end_date: End date string (YYYY-MM-DD).
        :param initial_capital: Starting portfolio cash.
        :param model_name: Which LLM model name to use (gpt-4, etc).
        :param model_provider: Which LLM provider (OpenAI, etc).
        :param selected_analysts: List of analyst names or IDs to incorporate.
        :param initial_margin_requirement: The margin ratio (e.g. 0.5 = 50%).
        """
        self.agent = agent
        self.tickers = tickers
        self.start_date = start_date
        self.end_date = end_date
        self.initial_capital = initial_capital
        self.model_name = model_name
        self.model_provider = model_provider
        self.selected_analysts = selected_analysts

        # Initialize portfolio with support for long/short positions
        self.portfolio_values = []
        self.portfolio = {
            "cash": initial_capital,
            "margin_used": 0.0,  # total margin usage across all short positions
            "margin_requirement": initial_margin_requirement,  # The margin ratio required for shorts
            "positions": {ticker: {"long": 0, "short": 0, "long_cost_basis": 0.0, "short_cost_basis": 0.0, "short_margin_used": 0.0} for ticker in tickers},  # Number of shares held long  # Number of shares held short  # Average cost basis per share (long)  # Average cost basis per share (short)  # Dollars of margin used for this ticker's short
            "realized_gains": {
                ticker: {
                    "long": 0.0,  # Realized gains from long positions
                    "short": 0.0,  # Realized gains from short positions
                }
                for ticker in tickers
            },
        }


def test_tool_calling_agents_raises_agent_execution_error_when_tool_raises():
    @tool
    def _sample_tool(_: str) -> float:
        """Tool that fails

        Args:
            _: The pointless string
        Returns:
            Some number
        """

        return 1 / 0

    agent = ToolCallingAgent(model=FakeToolCallModel(), tools=[_sample_tool])
    with pytest.raises(AgentExecutionError):
        agent.execute_tool_call(_sample_tool.name, "sample")


def get_db_path():
    """Get the database path from environment or use default"""
    config = Config.from_env()
    db_path = config.get("SQLITE_DB_PATH", os.path.join(project_root, "data", "sqlite", "lpm.db"))
    return db_path


def main():
    install_package("requests", "rich", "ruamel.yaml", "InquirerPy")
    from rich.console import Console
    from rich.panel import Panel
    from rich.box import DOUBLE
    from InquirerPy import inquirer
    from translations.translations import translate as t
    from translations.translations import DISPLAY_LANGUAGES
    from core.utils.config_utils import load_key, update_key
    from core.utils.decorator import except_handler

    console = Console()

    width = max(len(line) for line in ascii_logo.splitlines()) + 4
    welcome_panel = Panel(
        ascii_logo,
        width=width,
        box=DOUBLE,
        title="[bold green]🌏[/bold green]",
        border_style="bright_blue"
    )
    console.print(welcome_panel)
    # Language selection
    current_language = load_key("display_language")
    # Find the display name for current language code
    current_display = next((k for k, v in DISPLAY_LANGUAGES.items() if v == current_language), "🇬🇧 English")
    selected_language = DISPLAY_LANGUAGES[inquirer.select(
        message="Select language / 选择语言 / 選擇語言 / 言語を選択 / Seleccionar idioma / Sélectionner la langue / Выберите язык:",
        choices=list(DISPLAY_LANGUAGES.keys()),
        default=current_display
    ).execute()]
    update_key("display_language", selected_language)

    console.print(Panel.fit(t("🚀 Starting Installation"), style="bold magenta"))

    # Configure mirrors
    # add a check to ask user if they want to configure mirrors
    if inquirer.confirm(
        message=t("Do you need to auto-configure PyPI mirrors? (Recommended if you have difficulty accessing pypi.org)"),
        default=True
    ).execute():
        from core.utils.pypi_autochoose import main as choose_mirror
        choose_mirror()

    # Detect system and GPU
    has_gpu = platform.system() != 'Darwin' and check_nvidia_gpu()
    if has_gpu:
        console.print(Panel(t("🎮 NVIDIA GPU detected, installing CUDA version of PyTorch..."), style="cyan"))
        subprocess.check_call([sys.executable, "-m", "pip", "install", "torch==2.0.0", "torchaudio==2.0.0", "--index-url", "https://download.pytorch.org/whl/cu118"])
    else:
        system_name = "🍎 MacOS" if platform.system() == 'Darwin' else "💻 No NVIDIA GPU"
        console.print(Panel(t(f"{system_name} detected, installing CPU version of PyTorch... Note: it might be slow during whisperX transcription."), style="cyan"))
        subprocess.check_call([sys.executable, "-m", "pip", "install", "torch==2.1.2", "torchaudio==2.1.2"])

    @except_handler("Failed to install project")
    def install_requirements():
        console.print(Panel(t("Installing project in editable mode using `pip install -e .`"), style="cyan"))
        subprocess.check_call([sys.executable, "-m", "pip", "install", "-e", "."], env={**os.environ, "PIP_NO_CACHE_DIR": "0", "PYTHONIOENCODING": "utf-8"})

    @except_handler("Failed to install Noto fonts")
    def install_noto_font():
        # Detect Linux distribution type
        if os.path.exists('/etc/debian_version'):
            # Debian/Ubuntu systems
            cmd = ['sudo', 'apt-get', 'install', '-y', 'fonts-noto']
            pkg_manager = "apt-get"
        elif os.path.exists('/etc/redhat-release'):
            # RHEL/CentOS/Fedora systems
            cmd = ['sudo', 'yum', 'install', '-y', 'google-noto*']
            pkg_manager = "yum"
        else:
            console.print("Warning: Unrecognized Linux distribution, please install Noto fonts manually", style="yellow")
            return

        subprocess.run(cmd, check=True)
        console.print(f"✅ Successfully installed Noto fonts using {pkg_manager}", style="green")

    if platform.system() == 'Linux':
        install_noto_font()

    install_requirements()
    check_ffmpeg()

    # First panel with installation complete and startup command
    panel1_text = (
        t("Installation completed") + "\n\n" +
        t("Now I will run this command to start the application:") + "\n" +
        "[bold]streamlit run st.py[/bold]\n" +
        t("Note: First startup may take up to 1 minute")
    )
    console.print(Panel(panel1_text, style="bold green"))

    # Second panel with troubleshooting tips
    panel2_text = (
        t("If the application fails to start:") + "\n" +
        "1. " + t("Check your network connection") + "\n" +
        "2. " + t("Re-run the installer: [bold]python install.py[/bold]")
    )
    console.print(Panel(panel2_text, style="yellow"))

    # start the application
    subprocess.Popen(["streamlit", "run", "st.py"])


    def __init__(self, settings):
        self.topic_todo = settings.get('SPIDER_FEED_TOPIC')
        self.topic_done = settings.get('SPIDER_LOG_TOPIC')
        self.topic_scoring = settings.get('SCORING_LOG_TOPIC')
        self.topic_stats = settings.get('STATS_LOG_TOPIC')

        self.spiderlog_dbw_group = settings.get('SPIDER_LOG_DBW_GROUP')
        self.spiderlog_sw_group = settings.get('SPIDER_LOG_SW_GROUP')
        self.scoringlog_dbw_group = settings.get('SCORING_LOG_DBW_GROUP')
        self.statslog_reader_group = settings.get('STATS_LOG_READER_GROUP')
        self.spider_feed_group = settings.get('SPIDER_FEED_GROUP')
        self.spider_partition_id = settings.get('SPIDER_PARTITION_ID')
        self.max_next_requests = settings.MAX_NEXT_REQUESTS
        self.hostname_partitioning = settings.get('QUEUE_HOSTNAME_PARTITIONING')
        self.codec = settings.get('KAFKA_CODEC')
        self.kafka_location = settings.get('KAFKA_LOCATION')
        self.enable_ssl = settings.get('KAFKA_ENABLE_SSL')
        self.cert_path = settings.get('KAFKA_CERT_PATH')
        self.spider_log_partitions = settings.get('SPIDER_LOG_PARTITIONS')
        self.spider_feed_partitions = settings.get('SPIDER_FEED_PARTITIONS')


    def fetch(self, limit=None):
        """Fetch the result from firestore

        Parameters
        ---------
        limit : optional
            Apply limit to firestore documents, how much documents you want to retrieve
        """
        # save the Limit in cursor for next fetch
        self.cursor_dict['limit'] = limit

        if limit:
            self.n_limit = limit
        return QueryIterator(self)


def requires_cuda_initialized() -> pytest.MarkDecorator:
    if not torch.cuda.is_available():
        return pytest.mark.skip(reason="CUDA is not available")

    if not torch.cuda.is_initialized():
        torch.cuda.init()

    return pytest.mark.skipif(
        not torch.cuda.is_initialized(), reason="CUDA is not initialized"
    )


def run_tts(
    text,
    model,
    prompt_text=None,
    prompt_speech=None,
    gender=None,
    pitch=None,
    speed=None,
    save_dir="example/results",
):
    """Perform TTS inference and save the generated audio."""
    logging.info(f"Saving audio to: {save_dir}")

    if prompt_text is not None:
        prompt_text = None if len(prompt_text) <= 1 else prompt_text

    # Ensure the save directory exists
    os.makedirs(save_dir, exist_ok=True)

    # Generate unique filename using timestamp
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    save_path = os.path.join(save_dir, f"{timestamp}.wav")

    logging.info("Starting inference...")

    # Perform inference and save the output audio
    with torch.no_grad():
        wav = model.inference(
            text,
            prompt_speech,
            prompt_text,
            gender,
            pitch,
            speed,
        )

        sf.write(save_path, wav, samplerate=16000)

    logging.info(f"Audio saved at: {save_path}")

    return save_path


def init_sv_cn():
    global hifigan_model, bigvgan_model, sv_cn_model
    sv_cn_model = SV(device, is_half)


    def test_delitem_with_2_valid_keys(self):
        d = {
            'a': {
                'b': 1,
            }
        }
        b = KeypathDict(d)

        del b['a.b']
        with self.assertRaises(KeyError):
            del b['a.b']
        self.assertEqual(b.get('a'), {})

        del b['a']
        with self.assertRaises(KeyError):
            del b['a']
        self.assertEqual(b.get('a'), None)


def validate_input(question: str) -> bool:
    """Validate if user input is valid

    Args:
        question: User question

    Returns:
        bool: Whether the input is valid
    """
    # Check if input is empty or contains only spaces
    if not question or question.strip() == "":
        return False
    return True


    def _tokenize_audio(self, audio: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        assert audio.ndim == 1, "Audio must be single channel"

        frame_tokens = []
        frame_masks = []

        # (K, T)
        audio = audio.to(self.device)
        audio_tokens = self._audio_tokenizer.encode(audio.unsqueeze(0).unsqueeze(0))[0]
        # add EOS frame
        eos_frame = torch.zeros(audio_tokens.size(0), 1).to(self.device)
        audio_tokens = torch.cat([audio_tokens, eos_frame], dim=1)

        audio_frame = torch.zeros(audio_tokens.size(1), 33).long().to(self.device)
        audio_frame_mask = torch.zeros(audio_tokens.size(1), 33).bool().to(self.device)
        audio_frame[:, :-1] = audio_tokens.transpose(0, 1)
        audio_frame_mask[:, :-1] = True

        frame_tokens.append(audio_frame)
        frame_masks.append(audio_frame_mask)

        return torch.cat(frame_tokens, dim=0), torch.cat(frame_masks, dim=0)


def audio_volume_normalize(audio: np.ndarray, coeff: float = 0.2) -> np.ndarray:
    """
    Normalize the volume of an audio signal.

    Parameters:
        audio (numpy array): Input audio signal array.
        coeff (float): Target coefficient for normalization, default is 0.2.

    Returns:
        numpy array: The volume-normalized audio signal.
    """
    # Sort the absolute values of the audio signal
    temp = np.sort(np.abs(audio))

    # If the maximum value is less than 0.1, scale the array to have a maximum of 0.1
    if temp[-1] < 0.1:
        scaling_factor = max(
            temp[-1], 1e-3
        )  # Prevent division by zero with a small constant
        audio = audio / scaling_factor * 0.1

    # Filter out values less than 0.01 from temp
    temp = temp[temp > 0.01]
    L = temp.shape[0]  # Length of the filtered array

    # If there are fewer than or equal to 10 significant values, return the audio without further processing
    if L <= 10:
        return audio

    # Compute the average of the top 10% to 1% of values in temp
    volume = np.mean(temp[int(0.9 * L) : int(0.99 * L)])

    # Normalize the audio to the target coefficient level, clamping the scale factor between 0.1 and 10
    audio = audio * np.clip(coeff / volume, a_min=0.1, a_max=10)

    # Ensure the maximum absolute value in the audio does not exceed 1
    max_value = np.max(np.abs(audio))
    if max_value > 1:
        audio = audio / max_value

    return audio


def load_model():
    model = ChatterboxTTS.from_pretrained(DEVICE)
    return model


    def get(id: str):
        return AgentContext._contexts.get(id, None)


async def test_read_bytes_with_offset_and_length(computer):
    """Test read_bytes with offset and length parameters."""
    tmp_path = "test_read_bytes_offset.bin"
    test_data = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    # Write test data
    await computer.interface.write_text(tmp_path, test_data.decode('latin-1'))

    # Test reading with offset only
    read_data = await computer.interface.read_bytes(tmp_path, offset=5)
    expected = test_data[5:]
    assert read_data == expected, f"Data from offset 5 should match. Got: {read_data}, Expected: {expected}"

    # Test reading with offset and length
    read_data = await computer.interface.read_bytes(tmp_path, offset=10, length=5)
    expected = test_data[10:15]
    assert read_data == expected, f"Data from offset 10, length 5 should match. Got: {read_data}, Expected: {expected}"

    # Test reading from beginning with length
    read_data = await computer.interface.read_bytes(tmp_path, offset=0, length=10)
    expected = test_data[:10]
    assert read_data == expected, f"Data from beginning, length 10 should match. Got: {read_data}, Expected: {expected}"

    await computer.interface.delete_file(tmp_path)


  def testUpdateCloudStorageDependenciesMissingDependency(
      self, uploader_cs_mock):
    self.fs.CreateFile(self.file_path,
                       contents='\n'.join(self.expected_file_lines))
    config = dependency_manager.BaseConfig(self.file_path, writable=True)
    self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob,
                      'dep', 'plat', 'path')
    self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob,
                      'dep', 'plat', 'path', version='1.2.3')
    self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob,
                      'dep', 'plat', 'path', execute_job=False)
    self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob,
                      'dep', 'plat', 'path', version='1.2.3', execute_job=False)


def quantized_resize_bilinear_handler(converter: TensorFlowConverter, tf_op: "tf.Operation"):
    raise NotImplementedError(f"[TensorFlowConverter] {tf_op.type} is not supported yet.")


    def init_browser(self, user_agent=None):
        """初始化浏览器"""
        co = self._get_browser_options(user_agent)
        self.browser = Chromium(co)
        return self.browser


def main():
  if getattr(sys, "frozen", False):
    scriptpath = os.path.dirname(sys.executable)
  else:
    scriptpath = os.path.realpath(__file__)

  if "steam.exe" not in get_processes():
    print("WARNING: Steam is not running. Build will most likely fail.\n")

  print("{} Binarizer".format(PROJECTNAME))
  print("Authors: {}".format(", ".join(AUTHORS)))
  b = Binarizer(scriptpath)

  try:
    b.check_paths()
  except:
    print(" Failed to get tool paths. ".center(79, "="))
    print("")
    raise

  print("")
  print(" Tools found, binarizing. ".center(79, "="))
  print("")

  b.remove_obsolete()
  attempted = b.binarize()

  failed = b.verify()
  succeeded = attempted - failed

  result = " {} / {} modules binarized. ".format(succeeded, attempted)
  print("")

  try:
    import colorama
  except ImportError:
    print(result.center(79, "="))
  else:
    colorama.init()
    result = result.center(79, "=")
    if succeeded == attempted:
      result = "\33[32m" + result + "\33[39m"
    else:
      result = "\33[31m" + result + "\33[39m"
    print(result)
  print("")
  print("[Finished at {}]".format(time.ctime()))

  if getattr(sys, "frozen", False):
    input("\nPress any key to exit...\n")

  if failed > 0:
    sys.exit(1)


   def init(self):
      self.DATALEN = 256 * 2**10
      self.PAYLOAD = "\x00\xfe\x23\xfa\xf0"
      self.WAITSECS = 10
      self.reportTime = True


    def any(self):
        return len(self._rx_buffer)


def data():
    project = manager.get_project_list()
    models = LLM().list_models()
    search_engines = ["Bing", "Google", "DuckDuckGo"]
    return jsonify({"projects": project, "models": models, "search_engines": search_engines})


async def test_take_full_page_screenshot():
	browser_session = BrowserSession(browser_profile=BrowserProfile(headless=True, disable_security=True))
	await browser_session.start()
	try:
		page = await browser_session.get_current_page()
		# Go to a test page
		await page.goto('https://example.com')

		await asyncio.sleep(3)
		# Take full page screenshot
		screenshot_b64 = await browser_session.take_screenshot(full_page=True)
		await asyncio.sleep(3)
		# Verify screenshot is not empty and is valid base64
		assert screenshot_b64 is not None
		assert isinstance(screenshot_b64, str)
		assert len(screenshot_b64) > 0

		# Test we can decode the base64 string
		try:
			base64.b64decode(screenshot_b64)
		except Exception as e:
			pytest.fail(f'Failed to decode base64 screenshot: {str(e)}')
	finally:
		await browser_session.stop()


    def encode(self, input, final=False):
        return codecs.charmap_encode(input,self.errors,encoding_table)[0]


    def test_valid_json_object(self):
        """Test with valid JSON object"""
        content = '{"key": "value", "number": 123}'
        result = repair_json_output(content)
        expected = json.dumps({"key": "value", "number": 123}, ensure_ascii=False)
        assert result == expected


def pytest_addoption(parser):
    parser.addoption(
        "--base-url",
        action="store",
        help="Base URL for OpenAI compatible API",
    )
    parser.addoption(
        "--api-key",
        action="store",
        help="API key to use for the provider",
    )
    parser.addoption(
        "--provider",
        action="store",
        help="Provider to use for testing",
    )
    parser.addoption(
        "--model",
        action="store",
        help="Model to use for testing",
    )


        def update_visibility(input_type):
            image = gr.update(visible=True) if input_type == "Image" else gr.update(visible=False)
            video = gr.update(visible=False) if input_type == "Image" else gr.update(visible=True)
            output_image = gr.update(visible=True) if input_type == "Image" else gr.update(visible=False)
            output_video = gr.update(visible=False) if input_type == "Image" else gr.update(visible=True)

            return image, video, output_image, output_video


def write_in_github_step_summary(results: List[TaskResult]):
    """Write formatted results to GitHub step summary."""
    if not os.environ.get("GITHUB_STEP_SUMMARY"):
        logging.warning("GITHUB_STEP_SUMMARY environment variable not set")
        return

    formatted_content = format_results(results)
    with open(os.environ["GITHUB_STEP_SUMMARY"], "a") as f:
        f.write(formatted_content)


def generate(
    model: Transformer,
    prompt_tokens: List[List[int]],
    max_new_tokens: int,
    eos_id: int,
    temperature: float = 1.0
) -> List[List[int]]:
    """
    Generates new tokens based on the given prompt tokens using the specified model.

    Args:
        model (Transformer): The transformer model used for token generation.
        prompt_tokens (List[List[int]]): A list of lists containing the prompt tokens for each sequence.
        max_new_tokens (int): The maximum number of new tokens to generate.
        eos_id (int): The end-of-sequence token ID.
        temperature (float, optional): The temperature value for sampling. Defaults to 1.0.

    Returns:
        List[List[int]]: A list of lists containing the generated tokens for each sequence.
    """
    prompt_lens = [len(t) for t in prompt_tokens]
    assert max(prompt_lens) <= model.max_seq_len, f"Prompt length exceeds model maximum sequence length (max_seq_len={model.max_seq_len})"
    total_len = min(model.max_seq_len, max_new_tokens + max(prompt_lens))
    tokens = torch.full((len(prompt_tokens), total_len), -1, dtype=torch.long, device="cuda")
    for i, t in enumerate(prompt_tokens):
        tokens[i, :len(t)] = torch.tensor(t, dtype=torch.long, device="cuda")
    prev_pos = 0
    finished = torch.tensor([False] * len(prompt_tokens), device="cuda")
    prompt_mask = tokens != -1
    for cur_pos in range(min(prompt_lens), total_len):
        logits = model.forward(tokens[:, prev_pos:cur_pos], prev_pos)
        if temperature > 0:
            next_token = sample(logits, temperature)
        else:
            next_token = logits.argmax(dim=-1)
        next_token = torch.where(prompt_mask[:, cur_pos], tokens[:, cur_pos], next_token)
        tokens[:, cur_pos] = next_token
        finished |= torch.logical_and(~prompt_mask[:, cur_pos], next_token == eos_id)
        prev_pos = cur_pos
        if finished.all():
            break
    completion_tokens = []
    for i, toks in enumerate(tokens.tolist()):
        toks = toks[prompt_lens[i]:prompt_lens[i]+max_new_tokens]
        if eos_id in toks:
            toks = toks[:toks.index(eos_id)]
        completion_tokens.append(toks)
    return completion_tokens


    def testCrossValidate(self, mock_init):
        modelbridge = RandomModelBridge()
        modelbridge.transforms = OrderedDict()
        modelbridge.parameters = ["x", "y", "z"]
        with self.assertRaises(NotImplementedError):
            modelbridge._cross_validate([], [], [])


    def cmd_next_screen(self):
        """Move to next screen"""
        return self.focus_screen(
            (self.screens.index(self.current_screen) + 1) % len(self.screens)
        )


def stream_requests(ques, output_file):
    base_url = "http://0.0.0.0:8777"
    URL = base_url + "/api/local_doc_qa/local_doc_chat" #流式
    data = {
            "kb_ids": [
            "KBf46828db208c4289a120a34f0fc96147",
            "KBc2440f13e98f4736b5ef81cfaebef3a9",
            "KBb78af28c73f74fb4ae6ad44b3c53302f",
            "KB6c2b097d83be430ab809e361fa8dcc8b",
            "KB69331d593f5b4b5bb555a0ea1b145e5b",
            "KB3cdc79f8c8d24a14bffd27e6570c33da"
            ],
            "question": ques,
            "user_id": "liujx_265",
            "streaming": False,
            "rerank": True,
            "history": []
    }
    response = requests.post(
        URL,
        json=data,
        timeout=60,
        stream=True
    )
    print("response", response)
    print(response.iter_lines)
    for line in response.iter_lines(decode_unicode=False, delimiter=b"\n\n"):
    # for line in response.iter_lines():
        if line:
            yield line


    def test_setitem_override_existing_item(self):
        d = {}
        b = KeypathDict(d)
        b['a.b.c'] = 1
        r = {
            'a': {
                'b': {
                    'c': 1
                }
            }
        }
        b['a.b.c'] = 2
        r = {
            'a': {
                'b': {
                    'c': 2
                }
            }
        }
        self.assertEqual(b, r)
        b['a.b.c.d'] = 3
        r = {
            'a': {
                'b': {
                    'c': {
                        'd': 3
                    }
                }
            }
        }
        self.assertEqual(b, r)


def restore(
    checkpoint_path: str,
    state_shapes: Any,
    mesh,
    between_hosts_config,
    params_only,
    state_sharding,
    init_state: Optional[Any] = None,
) -> Any:
    ckpt_path = os.path.join(checkpoint_path, "ckpt-0")

    rank_logger.info("Loading checkpoint at {}".format(ckpt_path))
    ckpt_shapes = state_shapes
    ckpt_shapes_with_path, structure = jax.tree_util.tree_flatten_with_path(ckpt_shapes)

    ckpt_shapes_flat = [elem[1] for elem in ckpt_shapes_with_path]
    loaded_tensors = load_tensors(ckpt_shapes_flat, ckpt_path, between_hosts_config)

    state = jax.tree_util.tree_unflatten(structure, loaded_tensors)

    # Sanity check to give a better error message.
    ckpt_keys = set(state.params.keys())
    code_keys = set(state_sharding.params.keys())

    if ckpt_keys != code_keys and init_state is None:
        missing_in_ckpt = code_keys - ckpt_keys
        missing_locally = ckpt_keys - code_keys
        raise ValueError(
            "Parameters in the code are not matching checkpoint parameters.\n"
            "Params missing in checkpoint: {}\nParams missing in code: {}".format(
                missing_in_ckpt, missing_locally
            )
        )
    state_sharding = jax.tree_util.tree_map(
        lambda x: jax.sharding.PartitionSpec() if x is None else x,
        state_sharding,
        is_leaf=lambda x: x is None,
    )
    state = multihost_utils.host_local_array_to_global_array(state, mesh, state_sharding)
    if params_only:
        state = state.params
    return state


    def setUp(self):
        self.tool_manager = Tools()


def _drawReciboCaixa(self, boletoDados):
        """Imprime o Recibo do Caixa

        :param boletoDados: Objeto com os dados do boleto a ser preenchido.
            Deve ser subclasse de :class:`pyboleto.data.BoletoData`
        :type boletoDados: :class:`pyboleto.data.BoletoData`

        """
        tpl = string.Template(self._load_template('recibo_caixa.html'))
        tpl_data = {}

        # Cabeçalho
        tpl_data['logo_img'] = ''
        if boletoDados.logo_image:
            tpl_data['logo_img'] = self._load_image(boletoDados.logo_image)
        tpl_data['codigo_dv_banco'] = boletoDados.codigo_dv_banco
        tpl_data['linha_digitavel'] = boletoDados.linha_digitavel

        # Corpo
        data_vencimento = boletoDados.data_vencimento
        tpl_data['data_vencimento'] = data_vencimento.strftime('%d/%m/%Y')

        # value em unicode em data.py
        if isinstance(boletoDados.local_pagamento, unicode):
            tpl_data['local_pagamento'] = boletoDados.local_pagamento.encode
            ('utf-8')
        else:
            tpl_data['local_pagamento'] = boletoDados.local_pagamento
        tpl_data['cedente'] = boletoDados.cedente
        tpl_data['agencia_conta_cedente'] = boletoDados.agencia_conta_cedente

        data_documento = boletoDados.data_documento
        tpl_data['data_documento'] = data_documento.strftime('%d/%m/%Y')
        tpl_data['numero_documento'] = boletoDados.numero_documento
        tpl_data['especie_documento'] = boletoDados.especie_documento
        tpl_data['aceite'] = boletoDados.aceite

        data_process = boletoDados.data_processamento
        tpl_data['data_processamento'] = data_process.strftime('%d/%m/%Y')
        tpl_data['nosso_numero_format'] = boletoDados.format_nosso_numero()
        tpl_data['carteira'] = boletoDados.carteira
        tpl_data['especie'] = boletoDados.especie
        tpl_data['quantidade'] = boletoDados.quantidade

        valor = self._formataValorParaExibir(boletoDados.valor)
        tpl_data['valor'] = valor

        valor_doc = self._formataValorParaExibir(boletoDados.valor_documento)
        tpl_data['valor_documento'] = valor_doc

        # Instruções
        tpl_data['instrucoes'] = ''
        for instrucao in boletoDados.instrucoes:
            tpl_data['instrucoes'] += '
{0}
'.format(instrucao)

        # Rodapé
        tpl_data['sacado_info'] = ''
        for linha_sacado in boletoDados.sacado:
            tpl_data['sacado_info'] += '
{0}
'.format(linha_sacado)

        # Código de barras
        tpl_data['barcode'] = self._codigoBarraI25(boletoDados.barcode)

        self.html += tpl.substitute(tpl_data)


        def noop_no_sync():
            yield


    def accept_encodings(self):
        r = {}
        ae = self.headers.get("Accept-Encoding", "")
        for e in ae.split(","):
            match = self.aepattern.match(e)
            if match:
                v = match.group(3)
                v = float(v) if v else 1.0
                r[match.group(1)] = v
        return r


def weight_dequant(x: torch.Tensor, s: torch.Tensor, block_size: int = 128) -> torch.Tensor:
    """
    Dequantizes the given weight tensor using the provided scale tensor.

    Args:
        x (torch.Tensor): The quantized weight tensor of shape (M, N).
        s (torch.Tensor): The scale tensor of shape (M//block_size, N//block_size).
        block_size (int, optional): The block size to use for dequantization. Defaults to 128.

    Returns:
        torch.Tensor: The dequantized weight tensor of the same shape as `x`.

    Raises:
        AssertionError: If `x` or `s` are not contiguous or if their dimensions are not 2.
    """
    assert x.is_contiguous() and s.is_contiguous(), 'Input tensors must be contiguous'
    assert x.dim() == 2 and s.dim() == 2, 'Input tensors must have 2 dimensions'
    M, N = x.size()
    y = torch.empty_like(x, dtype=torch.get_default_dtype())
    grid = lambda meta: (triton.cdiv(M, meta['BLOCK_SIZE']), triton.cdiv(N, meta['BLOCK_SIZE']))
    weight_dequant_kernel[grid](x, s, y, M, N, BLOCK_SIZE=block_size)
    return y


    def __init__(self, open, high, low, close):
        pass


async def test_directory_exists(computer):
    tmp_dir = "test_directory_exists"
    if await computer.interface.directory_exists(tmp_dir):
        # Remove all files in directory before removing directory
        files = await computer.interface.list_dir(tmp_dir)
        for fname in files:
            await computer.interface.delete_file(f"{tmp_dir}/{fname}")
        # Remove the directory itself
        await computer.interface.delete_dir(tmp_dir)
    exists = await computer.interface.directory_exists(tmp_dir)
    assert exists is False, f"Directory {tmp_dir} should not exist"
    await computer.interface.create_dir(tmp_dir)
    exists = await computer.interface.directory_exists(tmp_dir)
    assert exists is True, f"Directory {tmp_dir} should exist"
    # Cleanup: remove files and directory
    files = await computer.interface.list_dir(tmp_dir)
    for fname in files:
        await computer.interface.delete_file(f"{tmp_dir}/{fname}")
    await computer.interface.delete_dir(tmp_dir)


  def testLocalFileNotDirectory(self, mock_StorageUrlFromString,
                                mock_gsutil_api):
    mock_storage_url = mock.Mock()
    mock_storage_url.isFileUrl.return_value = True
    mock_storage_url.IsDirectory.return_value = False
    mock_StorageUrlFromString.return_value = mock_storage_url
    (exp_url, have_existing_dst_container) = ExpandUrlToSingleBlr(
        '/home/test', mock_gsutil_api, 'project_id', False,
        CreateOrGetGsutilLogger('copy_test'))

    self.assertFalse(have_existing_dst_container)
    self.assertEqual(exp_url, mock_storage_url)


  def get_observation_model(self, times):
    """Observe level but not slope.

    See StateSpaceModel.get_observation_model.

    Args:
      times: Unused. See the parent class for details.
    Returns:
      A static, univariate observation model for later broadcasting.
    """
    del times  # Does not rely on times. Uses broadcasting from the parent.
    return constant_op.constant([1., 0.], dtype=self.dtype)


def end_session(req: gr.Request):
    user_dir = os.path.join(TMP_DIR, str(req.session_hash))
    shutil.rmtree(user_dir)


    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id')
        display_id = mobj.group('display_id') or video_id

        video = self._download_json(
            'https://api.byutv.org/api3/catalog/getvideosforcontent',
            display_id, query={
                'contentid': video_id,
                'channel': 'byutv',
                'x-byutv-context': 'web$US',
            }, headers={
                'x-byutv-context': 'web$US',
                'x-byutv-platformkey': 'xsaaw9c7y5',
            })

        ep = video.get('ooyalaVOD')
        if ep:
            return {
                '_type': 'url_transparent',
                'ie_key': 'Ooyala',
                'url': 'ooyala:%s' % ep['providerId'],
                'id': video_id,
                'display_id': display_id,
                'title': ep.get('title'),
                'description': ep.get('description'),
                'thumbnail': ep.get('imageThumbnail'),
            }

        info = {}
        formats = []
        for format_id, ep in video.items():
            if not isinstance(ep, dict):
                continue
            video_url = url_or_none(ep.get('videoUrl'))
            if not video_url:
                continue
            ext = determine_ext(video_url)
            if ext == 'm3u8':
                formats.extend(self._extract_m3u8_formats(
                    video_url, video_id, 'mp4', entry_protocol='m3u8_native',
                    m3u8_id='hls', fatal=False))
            elif ext == 'mpd':
                formats.extend(self._extract_mpd_formats(
                    video_url, video_id, mpd_id='dash', fatal=False))
            else:
                formats.append({
                    'url': video_url,
                    'format_id': format_id,
                })
            merge_dicts(info, {
                'title': ep.get('title'),
                'description': ep.get('description'),
                'thumbnail': ep.get('imageThumbnail'),
                'duration': parse_duration(ep.get('length')),
            })
        self._sort_formats(formats)

        return merge_dicts(info, {
            'id': video_id,
            'display_id': display_id,
            'title': display_id,
            'formats': formats,
        })


    def __isub__(self, other):
        return self + (-other)


    def log_to_all(
        type: Log.Type,
        heading: str | None = None,
        content: str | None = None,
        kvps: dict | None = None,
        temp: bool | None = None,
        update_progress: Log.ProgressUpdate | None = None,
        id: str | None = None,  # Add id parameter
        **kwargs,
    ) -> list[Log.LogItem]:
        items: list[Log.LogItem] = []
        for context in AgentContext.all():
            items.append(
                context.log.log(
                    type, heading, content, kvps, temp, update_progress, id, **kwargs
                )
            )
        return items


def initialize_model(model_path):
    args = parse_args()
    models_root_path = Path(model_path)
    if not models_root_path.exists():
        raise ValueError(f"`models_root` not exists: {models_root_path}")

    hunyuan_video_sampler = HunyuanVideoSampler.from_pretrained(models_root_path, args=args)
    return hunyuan_video_sampler


    def test_repo_rename_noargs(self, shell):
        """
        Test do_repo_rename no arguments.

        :param shell:
        :return:
        """
        shell.help_repo_rename = MagicMock()
        shell.client.channel.software.getRepoDetails = MagicMock()
        shell.do_repo_list = MagicMock()
        mprint = MagicMock()
        logger = MagicMock()

        with patch("spacecmd.repo.print", mprint) as prn, \
                patch("spacecmd.repo.logging", logger) as lgr:
            out = spacecmd.repo.do_repo_rename(shell, "")

        assert out is 1
        assert not mprint.called
        assert not logger.error.called
        assert not shell.client.channel.software.getRepoDetails.called
        assert shell.help_repo_rename.called


    def __rmul__(self, other):
        return self.__class__(other) * self


    def __init__(self, **kwargs):
        """Behaviour can be customized by overriding attributes in a subclass or setting them in the constructor.

        :param string kill_xpath: XPath expression for tags to remove along with their contents.
        :param string strip_xpath: XPath expression for tags to replace with their contents.
        :param string allow_xpath: XPath expression for tags to except from strip_xpath.
        :param bool fix_whitespace: Normalize whitespace to a single space and ensure newlines around block elements.
        :param dict namespaces: Namespace prefixes to register for the XPaths.
        """
        # TODO: This is weird. Why don't we change to proper individual keyword arguments with class attribs as default
        for name, value in kwargs.items():
            if not hasattr(self, name):
                raise TypeError('Unknown parameter: %s=%r' % (name, value))
            setattr(self, name, value)


    def action_execution_server_url(self):
        return self.api_url


    def test_reasoning_steps_reward(self):
        """Test reasoning_steps_reward with various formats."""
        test_cases = [
            # Full credit cases (3 or more steps)
            ("Step 1: First step\nStep 2: Second step\nStep 3: Third step", 1.0),
            ("First, we do this.\nSecond, we do that.\nFinally, we conclude.", 1.0),
            # Partial credit cases (less than 3 steps)
            ("Step 1: Only step", 1 / 3),
            ("First, we do this.\nFinally, we conclude.", 2 / 3),
            # No credit case
            ("Just plain text without any clear steps", 0.0),
        ]

        for content, expected_reward in test_cases:
            completion = [[{"content": content}]]
            rewards = reasoning_steps_reward(completion)
            self.assertAlmostEqual(rewards[0], expected_reward)