auto-coder 0.1.255__py3-none-any.whl → 0.1.256__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-coder
3
- Version: 0.1.255
3
+ Version: 0.1.256
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
@@ -26,7 +26,7 @@ Requires-Dist: tabulate
26
26
  Requires-Dist: jupyter-client
27
27
  Requires-Dist: prompt-toolkit
28
28
  Requires-Dist: tokenizers
29
- Requires-Dist: byzerllm[saas] >=0.1.163
29
+ Requires-Dist: byzerllm[saas] >=0.1.164
30
30
  Requires-Dist: patch
31
31
  Requires-Dist: diff-match-patch
32
32
  Requires-Dist: GitPython
@@ -1,5 +1,5 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder/auto_coder.py,sha256=uzNAtguu7O2m7vve1H2FQnWCmVuqT07RITxS5jgWz4U,64774
2
+ autocoder/auto_coder.py,sha256=obRx5lFu8P4M5mmLA717lwMso7Ei3Kx3i9kG7I_xrRY,65654
3
3
  autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
4
4
  autocoder/auto_coder_rag.py,sha256=DDAmqw36CO6phtdQuN8LYIbIR3YGdoZw5-pG0LjVxMc,29063
5
5
  autocoder/auto_coder_rag_client_mcp.py,sha256=WV7j5JUiQge0x4-B7Hp5-pSAFXLbvLpzQMcCovbauIM,6276
@@ -10,8 +10,8 @@ autocoder/chat_auto_coder.py,sha256=a1YEp6OPMzpLbRpr2hrbzF6pRnhVPTVxyZfBiQHFPIw,
10
10
  autocoder/chat_auto_coder_lang.py,sha256=1cJrjFGrcOQnuP2LdZpgGDSX4CNaIYI7KZGvEEtj6_Q,18242
11
11
  autocoder/command_args.py,sha256=9aYJ-AmPxP1sQh6ciw04FWHjSn31f2W9afXFwo8wgx4,30441
12
12
  autocoder/lang.py,sha256=U6AjVV8Rs1uLyjFCZ8sT6WWuNUxMBqkXXIOs4S120uk,14511
13
- autocoder/models.py,sha256=0f653gjpQN_JO5k7h6wmTF4bVd6CW3fpQOyHIZ3ZUv4,7558
14
- autocoder/version.py,sha256=vxd_TSbCxiXnBHQnfprB361BOJEhjQMPeDRseFI3YrY,23
13
+ autocoder/models.py,sha256=xwWPcegwx945g433UZXna-7HBdnHWCq8oEfHm-HKIDQ,8651
14
+ autocoder/version.py,sha256=Mlq4zYTZeRq2mquyM-8m1qr6sjxAHZpSDVyjrKqhayc,23
15
15
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  autocoder/agent/auto_demand_organizer.py,sha256=NWSAEsEk94vT3lGjfo25kKLMwYdPcpy9e-i21txPasQ,6942
17
17
  autocoder/agent/auto_filegroup.py,sha256=CW7bqp0FW1GIEMnl-blyAc2UGT7O9Mom0q66ITz1ckM,6635
@@ -29,20 +29,20 @@ autocoder/common/__init__.py,sha256=6maackdzrYnUPvpgVPl92JdMOnw7X4n3EnEQA9OnLGE,
29
29
  autocoder/common/anything2images.py,sha256=0ILBbWzY02M-CiWB-vzuomb_J1hVdxRcenAfIrAXq9M,25283
30
30
  autocoder/common/anything2img.py,sha256=4TREa-sOA-iargieUy7MpyCYVUE-9Mmq0wJtwomPqnE,7662
31
31
  autocoder/common/audio.py,sha256=Kn9nWKQddWnUrAz0a_ZUgjcu4VUU_IcZBigT7n3N3qc,7439
32
- autocoder/common/auto_coder_lang.py,sha256=nF8XrHpSbibk6ro8Oum-0V0FXcDS1lHP_hL-CnPJtT4,16974
32
+ autocoder/common/auto_coder_lang.py,sha256=x9Zjwvu9OZJjTmswwyimlMb1pvngUAF9_3oNQQut2i4,17634
33
33
  autocoder/common/buildin_tokenizer.py,sha256=L7d5t39ZFvUd6EoMPXUhYK1toD0FHlRH1jtjKRGokWU,1236
34
34
  autocoder/common/chunk_validation.py,sha256=BrR_ZWavW8IANuueEE7hS8NFAwEvm8TX34WnPx_1hs8,3030
35
35
  autocoder/common/cleaner.py,sha256=NU72i8C6o9m0vXExab7nao5bstBUsfJFcj11cXa9l4U,1089
36
36
  autocoder/common/code_auto_execute.py,sha256=4KXGmiGObr_B1d6tzV9dwS6MifCSc3Gm4j2d6ildBXQ,6867
37
- autocoder/common/code_auto_generate.py,sha256=N_kENWW4eVPKmihpIQ4Q2ivYkugAuCWIPLDCKiarRWg,10818
38
- autocoder/common/code_auto_generate_diff.py,sha256=QAm-BVJgGl_wbw0VjY2RZigVCwOBO-l1W-90PrYDdOQ,16741
39
- autocoder/common/code_auto_generate_editblock.py,sha256=FuVH-sP4_Ys2MJk9SkWgHHLAKp51bKSxTwFzd7voilg,18356
40
- autocoder/common/code_auto_generate_strict_diff.py,sha256=kieVUx2KuR0BGtQHE0Ll7i8e_3Lb4xfFXHIXDttQACE,15274
37
+ autocoder/common/code_auto_generate.py,sha256=E8r3VI88hPBPhU5t56qnmeL_fWtCWX1CJvaOachGa2Y,12014
38
+ autocoder/common/code_auto_generate_diff.py,sha256=dmMgN1yIOjJfiYFnzXZuktVFdj4_XR_Tavwx_ysm53U,17846
39
+ autocoder/common/code_auto_generate_editblock.py,sha256=NI_dFwy1VhvdjvARb04-B1AGfgW9z4P1BfWMm-blnaU,19447
40
+ autocoder/common/code_auto_generate_strict_diff.py,sha256=uf5P5B8ly0MP3jCK2PaYJiPLktd1cRRPouwkkaf-DfY,16457
41
41
  autocoder/common/code_auto_merge.py,sha256=-ksBjj4ZVcbY_tVH4JLXAMSRtsgaSxrSZ5-MOl9cAgE,7354
42
42
  autocoder/common/code_auto_merge_diff.py,sha256=qpEuHJEgX6sWK7EDFEKqcYkyI28wOyM4pytyl8BLohY,15350
43
43
  autocoder/common/code_auto_merge_editblock.py,sha256=sxgYMLMACRwJvw-bABkdDHezPelsDFrOCpGuhtT5Dzs,17504
44
44
  autocoder/common/code_auto_merge_strict_diff.py,sha256=P0nKNkBrFMybTSZ7kOdA_JixoVmLCZIhAP5q7ILJ9j0,9538
45
- autocoder/common/code_modification_ranker.py,sha256=qfadP9P-iiidCG2A_MjAf3Ca8cMz7YlnN08D_kH6uFc,6447
45
+ autocoder/common/code_modification_ranker.py,sha256=oG9rCekGsYwE9gNdkIKQ6uKt6uaXpwrC17-FV5Wo-fQ,8187
46
46
  autocoder/common/command_completer.py,sha256=IShrZJSpR-Q_MCj_aCVdVyscLYDKj5ZQK357QBcQ_oQ,9420
47
47
  autocoder/common/command_generator.py,sha256=-hmbD_AnCa5HxL4BznuEfYAf_l8AxU5fAG5F0sM_fuE,2116
48
48
  autocoder/common/command_templates.py,sha256=mnB3n8i0yjH1mqzyClEg8Wpr9VbZV44kxky66Zu6OJY,8557
@@ -76,10 +76,10 @@ autocoder/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  autocoder/db/store.py,sha256=tFT66bP2ZKIqZip-uhLkHRSLaaOAUUDZfozJwcqix3c,1908
77
77
  autocoder/dispacher/__init__.py,sha256=YoA64dIxnx4jcE1pwSfg81sjkQtjDkhddkfac1-cMWo,1230
78
78
  autocoder/dispacher/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- autocoder/dispacher/actions/action.py,sha256=AmckPmTHFKRPTWi4lcw0kAnFw8dyQ9KKoN40JGMuP2s,21971
79
+ autocoder/dispacher/actions/action.py,sha256=sfh3pCasy622Jm0_AIKU7xtR-tqY2tS2_9YJsEd0FJY,22753
80
80
  autocoder/dispacher/actions/copilot.py,sha256=iMh4ckj9hO5Q-iemF3CStXd7DatWai7Eci5zOlKxK9c,13072
81
81
  autocoder/dispacher/actions/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
- autocoder/dispacher/actions/plugins/action_regex_project.py,sha256=ckTbisMlvwMNHQbrt5WB7pBvf2XAhYQYGH8uyYrvGXU,6060
82
+ autocoder/dispacher/actions/plugins/action_regex_project.py,sha256=22EZL3mLFxgsEZ8ymPCGvaHCJFnrW6C_prp1ykYCuEY,6335
83
83
  autocoder/dispacher/actions/plugins/action_translate.py,sha256=nVAtRSQpdGNmZxg1R_9zXG3AuTv3CHf2v7ODgj8u65c,7727
84
84
  autocoder/index/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
85
  autocoder/index/entry.py,sha256=1KIGPCtxQN0OdErAco9OmGTd5hB8WJTpWGrxsGLsTcE,12634
@@ -89,8 +89,8 @@ autocoder/index/symbols_utils.py,sha256=CjcjUVajmJZB75Ty3a7kMv1BZphrm-tIBAdOJv6u
89
89
  autocoder/index/types.py,sha256=a2s_KV5FJlq7jqA2ELSo9E1sjuLwDB-JJYMhSpzBAhU,596
90
90
  autocoder/index/filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  autocoder/index/filter/normal_filter.py,sha256=APu34iSvWhtlLtWgkj8N3Vo4oW1TegtZQq2bwDX_cs4,8031
92
- autocoder/index/filter/quick_filter.py,sha256=Dsm23Z_RrJ_UwCypGUPN1BlKUMibae_9_D8jWD1UDFw,10518
93
- autocoder/pyproject/__init__.py,sha256=dQ2_7YZ7guybT9BhfxSGn43eLQJGQN2zgeKa6--JlaQ,14403
92
+ autocoder/index/filter/quick_filter.py,sha256=5toipv7XwLsmG_UaqrElpGNjKXq_0bcvFr8W80vT44g,15206
93
+ autocoder/pyproject/__init__.py,sha256=bRuGxFV4QyE85xVjDzeMFmlLVqGbbcFs09FI15Uss4Q,14423
94
94
  autocoder/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  autocoder/rag/api_server.py,sha256=dRbhAZVRAOlZ64Cnxf4_rKb4iJwHnrWS9Zr67IVORw0,7288
96
96
  autocoder/rag/doc_filter.py,sha256=ZCixxUXNBbz6UiGbgXvbDWdn5moLac3HnZEphpasTDc,6579
@@ -124,14 +124,14 @@ autocoder/rag/stream_event/event_writer.py,sha256=l7kq_LnDDE8E5dZ-73C7J2MgzSL7Wr
124
124
  autocoder/rag/stream_event/types.py,sha256=rtLwOE8rShmi1dJdxyBpAV5ZjLBGG9vptMiSzMxGuIA,318
125
125
  autocoder/regex_project/__init__.py,sha256=EBZeCL5ORyD_9_5u_UuG4s7XtpXOu0y1sWDmxWFtufE,6781
126
126
  autocoder/regexproject/__init__.py,sha256=cEr-ZOaQjLD5sx7T7F2DhD5ips03HcJ02rded9EpSXc,9693
127
- autocoder/suffixproject/__init__.py,sha256=VcXjUbGf3uQrpoqVCItDvGG9DoeHJ_qEmghKwrVNw9w,11058
128
- autocoder/tsproject/__init__.py,sha256=boNuRCHi94xI_y4tvL5LKgSZ4gYxcPqUUQTw9MU_STI,11751
127
+ autocoder/suffixproject/__init__.py,sha256=2dxh8vizDLiSqGpCx-V2VQ6cOfRZGxJMgosjwSlAsQM,11078
128
+ autocoder/tsproject/__init__.py,sha256=zGVSrxFo15Nh8GcSXHwdk4Fr-W7Bdb6IwVUX46PZKy4,11771
129
129
  autocoder/utils/__init__.py,sha256=KtcGElFNBgZPF7dEL8zF9JpXkCAjoyDrzaREJBhJrcs,994
130
130
  autocoder/utils/_markitdown.py,sha256=RU88qn4eZfYIy0GDrPxlI8oYXIypbi63VRJjdlnE0VU,47431
131
131
  autocoder/utils/coder.py,sha256=rK8e0svQBe0NOP26dIGToUXgha_hUDgxlWoC_p_r7oc,5698
132
132
  autocoder/utils/conversation_store.py,sha256=sz-hhY7sttPAUOAQU6Pze-5zJc3j0_Emj22dM_0l5ro,1161
133
133
  autocoder/utils/llm_client_interceptors.py,sha256=FEHNXoFZlCjAHQcjPRyX8FOMjo6rPXpO2AJ2zn2KTTo,901
134
- autocoder/utils/llms.py,sha256=RBOSzH6xhedISzmiQMGH_swmVfY-QSTe5Cm1ZZGBhNE,2948
134
+ autocoder/utils/llms.py,sha256=HM5K_v4AcuWo65lgcp66DEqaU9-fjoT7mcI1iv2Fopg,3839
135
135
  autocoder/utils/log_capture.py,sha256=I-bsJFLWoGUiX-GKoZsH9kWJCKSV7ZlUnRt7jh-fOL0,1548
136
136
  autocoder/utils/multi_turn.py,sha256=unK9OpqVRbK6uIcTKXgggX2wNmyj7s5eyEAQ2xUwHoM,88
137
137
  autocoder/utils/operate_config_api.py,sha256=99YAKsuUFLPwrRvj0CJal_bAPgyiXWMma6ZKMU56thw,5790
@@ -146,9 +146,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=xWXqICANbDOovH4wcFW1eSI7lB7TjXbk1mSU4bTKEW4,11434
148
148
  autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
- auto_coder-0.1.255.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
150
- auto_coder-0.1.255.dist-info/METADATA,sha256=2uB08jgGHyp3_DWMI2_vxoFoptVJO76Va-yek1umBac,2616
151
- auto_coder-0.1.255.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
152
- auto_coder-0.1.255.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
153
- auto_coder-0.1.255.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
154
- auto_coder-0.1.255.dist-info/RECORD,,
149
+ auto_coder-0.1.256.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
150
+ auto_coder-0.1.256.dist-info/METADATA,sha256=NrC0Y2oSS6lDTeKbXKk3F1QnZ7_3Kie7pho_i7JhwJk,2616
151
+ auto_coder-0.1.256.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
152
+ auto_coder-0.1.256.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
153
+ auto_coder-0.1.256.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
154
+ auto_coder-0.1.256.dist-info/RECORD,,
autocoder/auto_coder.py CHANGED
@@ -1389,11 +1389,25 @@ def main(input_args: Optional[List[str]] = None):
1389
1389
  elapsed_time = time.time() - start_time
1390
1390
  printer = Printer()
1391
1391
  speed = last_meta.generated_tokens_count / elapsed_time
1392
+
1393
+ # Get model info for pricing
1394
+ from autocoder.utils import llms as llm_utils
1395
+ model_info = llm_utils.get_model_info(model_name, args.product_mode) or {}
1396
+ input_price = model_info.get("input_price", 0.0) if model_info else 0.0
1397
+ output_price = model_info.get("output_price", 0.0) if model_info else 0.0
1398
+
1399
+ # Calculate costs
1400
+ input_cost = (last_meta.input_tokens_count * input_price) / 1000000 # Convert to millions
1401
+ output_cost = (last_meta.generated_tokens_count * output_price) / 1000000 # Convert to millions
1402
+
1392
1403
  printer.print_in_terminal("stream_out_stats",
1404
+ model_name=model_name,
1393
1405
  elapsed_time=elapsed_time,
1394
1406
  first_token_time=last_meta.first_token_time,
1395
1407
  input_tokens=last_meta.input_tokens_count,
1396
1408
  output_tokens=last_meta.generated_tokens_count,
1409
+ input_cost=round(input_cost, 4),
1410
+ output_cost=round(output_cost, 4),
1397
1411
  speed=round(speed, 2))
1398
1412
 
1399
1413
  chat_history["ask_conversation"].append(
@@ -57,7 +57,7 @@ MESSAGES = {
57
57
  "Paste the answer to the input box below, use '/break' to exit, '/clear' to clear the screen, '/eof' to submit."
58
58
  ),
59
59
  "code_generation_start": "Auto generate the code...",
60
- "code_generation_complete": "Code generation completed in {{ duration }} seconds, input_tokens_count: {{ input_tokens }}, generated_tokens_count: {{ output_tokens }}, speed: {{ speed }} tokens/s",
60
+ "code_generation_complete": "{{ model_names}} Code generation completed in {{ duration }} seconds, input_tokens_count: {{ input_tokens }}, generated_tokens_count: {{ output_tokens }}, input_cost: {{ input_cost }}, output_cost: {{ output_cost }}, speed: {{ speed }} tokens/s",
61
61
  "code_merge_start": "Auto merge the code...",
62
62
  "code_execution_warning": "Content(send to model) is {{ content_length }} tokens (you may collect too much files), which is larger than the maximum input length {{ max_length }}",
63
63
  "quick_filter_start": "{{ model_name }} Starting filter context(quick_filter)...",
@@ -75,12 +75,12 @@ MESSAGES = {
75
75
  "ranking_start": "Start ranking {{ count }} candidates using model {{ model_name }}",
76
76
  "ranking_failed_request": "Ranking request failed: {{ error }}",
77
77
  "ranking_all_failed": "All ranking requests failed",
78
- "ranking_complete": "Ranking completed in {{ elapsed }}s, total voters: {{ total_tasks }}, best candidate index: {{ best_candidate }}, scores: {{ scores }}, input_tokens: {{ input_tokens }}, output_tokens: {{ output_tokens }}",
78
+ "ranking_complete": "{{ model_names }} Ranking completed in {{ elapsed }}s, total voters: {{ total_tasks }}, best candidate index: {{ best_candidate }}, scores: {{ scores }}, input_tokens: {{ input_tokens }}, output_tokens: {{ output_tokens }}, input_cost: {{ input_cost }}, output_cost: {{ output_cost }}",
79
79
  "ranking_process_failed": "Ranking process failed: {{ error }}",
80
80
  "ranking_failed": "Ranking failed in {{ elapsed }}s, using original order",
81
81
  "begin_index_source_code": "🚀 Begin to index source code in {{ source_dir }}",
82
- "stream_out_stats": "Elapsed time {{ elapsed_time }} seconds, first token time: {{ first_token_time }} seconds, input tokens: {{ input_tokens }}, output tokens: {{ output_tokens }}, speed: {{ speed }} tokens/s",
83
- "quick_filter_stats": "快速过滤器完成,耗时 {{ elapsed_time }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}",
82
+ "stream_out_stats": "Model: {{ model_name }}, Total time: {{ elapsed_time }} seconds, First token time: {{ first_token_time }} seconds, Speed: {{ speed }} tokens/s, Input tokens: {{ input_tokens }}, Output tokens: {{ output_tokens }}, Input cost: {{ input_cost }}, Output cost: {{ output_cost }}",
83
+ "quick_filter_stats": "{{ model_names }} 快速过滤器完成,耗时 {{ elapsed_time }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}, 输入成本: {{ input_cost }}, 输出成本: {{ output_cost }}",
84
84
  "upsert_file": "✅ Updated file: {{ file_path }}",
85
85
  "unmerged_blocks_title": "Unmerged Blocks",
86
86
  "quick_filter_title": "{{ model_name }} is analyzing how to filter context...",
@@ -150,7 +150,7 @@ MESSAGES = {
150
150
  "将获得答案黏贴到下面的输入框,换行后,使用 '/break' 退出,'/clear' 清屏,'/eof' 提交。"
151
151
  ),
152
152
  "code_generation_start": "正在自动生成代码...",
153
- "code_generation_complete": "代码生成完成,耗时 {{ duration }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}, 速度: {{ speed }} tokens/秒",
153
+ "code_generation_complete": "{{ model_names}} 代码生成完成,耗时 {{ duration }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}, 输入成本: {{ input_cost }}, 输出成本: {{ output_cost }}, 速度: {{ speed }} tokens/秒",
154
154
  "code_merge_start": "正在自动合并代码...",
155
155
  "code_execution_warning": "发送给模型的内容长度为 {{ content_length }} tokens(您可能收集了太多文件),超过了最大输入长度 {{ max_length }}",
156
156
  "quick_filter_start": "{{ model_name }} 开始查找上下文(quick_filter)...",
@@ -179,11 +179,11 @@ MESSAGES = {
179
179
  "ranking_start": "开始对 {{ count }} 个候选项进行排序,使用模型 {{ model_name }} 打分",
180
180
  "ranking_failed_request": "排序请求失败: {{ error }}",
181
181
  "ranking_all_failed": "所有排序请求都失败",
182
- "ranking_complete": "排序完成,耗时 {{ elapsed }} 秒,总投票数: {{ total_tasks }},最佳候选索引: {{ best_candidate }},得分: {{ scores }},输入token数: {{ input_tokens }},输出token数: {{ output_tokens }}",
182
+ "ranking_complete": "{{ model_names }} 排序完成,耗时 {{ elapsed }} 秒,总投票数: {{ total_tasks }},最佳候选索引: {{ best_candidate }},得分: {{ scores }},输入token数: {{ input_tokens }},输出token数: {{ output_tokens }} 输入成本: {{ input_cost }}, 输出成本: {{ output_cost }}",
183
183
  "ranking_process_failed": "排序过程失败: {{ error }}",
184
184
  "ranking_failed": "排序失败,耗时 {{ elapsed }} 秒,使用原始顺序",
185
- "stream_out_stats": "总耗时 {{ elapsed_time }} 秒,首token时间: {{ first_token_time }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}, 速度: {{ speed }} tokens/秒",
186
- "quick_filter_stats": "Quick filter completed in {{ elapsed_time }} seconds, input tokens: {{ input_tokens }}, output tokens: {{ output_tokens }}",
185
+ "stream_out_stats": "模型: {{ model_name }},总耗时 {{ elapsed_time }} 秒,首token时间: {{ first_token_time }} 秒, 速度: {{ speed }} tokens/秒, 输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}, 输入成本: {{ input_cost }}, 输出成本: {{ output_cost }}",
186
+ "quick_filter_stats": "{{ model_names }} Quick filter completed in {{ elapsed_time }} seconds, input tokens: {{ input_tokens }}, output tokens: {{ output_tokens }}, input cost: {{ input_cost }}, output cost: {{ output_cost }}",
187
187
  "quick_filter_title": "{{ model_name }} 正在分析如何筛选上下文...",
188
188
  "quick_filter_failed": "❌ 快速过滤器失败: {{ error }}. ",
189
189
  "estimated_chat_input_tokens": "对话输入token预估为: {{ estimated_input_tokens }}",
@@ -10,6 +10,7 @@ from autocoder.common.utils_code_auto_generate import chat_with_continue
10
10
  import json
11
11
  from autocoder.common.printer import Printer
12
12
  from autocoder.rag.token_counter import count_tokens
13
+ from autocoder.utils import llms as llm_utils
13
14
 
14
15
 
15
16
  class CodeAutoGenerate:
@@ -193,6 +194,9 @@ class CodeAutoGenerate:
193
194
  results = []
194
195
  input_tokens_count = 0
195
196
  generated_tokens_count = 0
197
+ input_tokens_cost = 0
198
+ generated_tokens_cost = 0
199
+ model_names = []
196
200
 
197
201
  printer = Printer()
198
202
  estimated_input_tokens = count_tokens(json.dumps(conversations, ensure_ascii=False))
@@ -206,13 +210,27 @@ class CodeAutoGenerate:
206
210
  futures = []
207
211
  for llm in self.llms:
208
212
  for _ in range(self.generate_times_same_model):
209
- futures.append(executor.submit(
210
- chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
213
+
214
+ model_names_list = llm_utils.get_llm_names(llm)
215
+ model_name = None
216
+ if model_names_list:
217
+ model_name = model_names_list[0]
218
+
219
+ for _ in range(self.generate_times_same_model):
220
+ model_names.append(model_name)
221
+ futures.append(executor.submit(
222
+ chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
223
+
211
224
  temp_results = [future.result() for future in futures]
212
225
  for result in temp_results:
213
226
  results.append(result.content)
214
227
  input_tokens_count += result.input_tokens_count
215
228
  generated_tokens_count += result.generated_tokens_count
229
+ model_info = llm_utils.get_model_info(model_name, self.args.product_mode)
230
+ input_cost = model_info.get("input_price", 0) if model_info else 0
231
+ output_cost = model_info.get("output_price", 0) if model_info else 0
232
+ input_tokens_cost += input_cost * result.input_tokens_count / 1000000
233
+ generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
216
234
 
217
235
  for result in results:
218
236
  conversations_list.append(
@@ -227,7 +245,9 @@ class CodeAutoGenerate:
227
245
 
228
246
  statistics = {
229
247
  "input_tokens_count": input_tokens_count,
230
- "generated_tokens_count": generated_tokens_count
248
+ "generated_tokens_count": generated_tokens_count,
249
+ "input_tokens_cost": input_tokens_cost,
250
+ "generated_tokens_cost": generated_tokens_cost
231
251
  }
232
252
 
233
253
  if self.args.request_id and not self.args.skip_events:
@@ -9,6 +9,7 @@ import json
9
9
  from autocoder.common.utils_code_auto_generate import chat_with_continue
10
10
  from autocoder.common.printer import Printer
11
11
  from autocoder.rag.token_counter import count_tokens
12
+ from autocoder.utils import llms as llm_utils
12
13
 
13
14
 
14
15
  class CodeAutoGenerateDiff:
@@ -341,6 +342,9 @@ class CodeAutoGenerateDiff:
341
342
  results = []
342
343
  input_tokens_count = 0
343
344
  generated_tokens_count = 0
345
+ input_tokens_cost = 0
346
+ generated_tokens_cost = 0
347
+ model_names = []
344
348
 
345
349
  printer = Printer()
346
350
  estimated_input_tokens = count_tokens(json.dumps(conversations, ensure_ascii=False))
@@ -354,13 +358,26 @@ class CodeAutoGenerateDiff:
354
358
  futures = []
355
359
  for llm in self.llms:
356
360
  for _ in range(self.generate_times_same_model):
357
- futures.append(executor.submit(
358
- chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
361
+ model_names_list = llm_utils.get_llm_names(llm)
362
+ model_name = None
363
+ if model_names_list:
364
+ model_name = model_names_list[0]
365
+
366
+ for _ in range(self.generate_times_same_model):
367
+ model_names.append(model_name)
368
+ futures.append(executor.submit(
369
+ chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
370
+
359
371
  temp_results = [future.result() for future in futures]
360
372
  for result in temp_results:
361
373
  results.append(result.content)
362
374
  input_tokens_count += result.input_tokens_count
363
375
  generated_tokens_count += result.generated_tokens_count
376
+ model_info = llm_utils.get_model_info(model_name, self.args.product_mode)
377
+ input_cost = model_info.get("input_price",0) if model_info else 0
378
+ output_cost = model_info.get("output_price",0) if model_info else 0
379
+ input_tokens_cost += input_cost * result.input_tokens_count / 1000000
380
+ generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
364
381
 
365
382
  for result in results:
366
383
  conversations_list.append(
@@ -376,7 +393,9 @@ class CodeAutoGenerateDiff:
376
393
 
377
394
  statistics = {
378
395
  "input_tokens_count": input_tokens_count,
379
- "generated_tokens_count": generated_tokens_count
396
+ "generated_tokens_count": generated_tokens_count,
397
+ "input_tokens_cost": input_tokens_cost,
398
+ "generated_tokens_cost": generated_tokens_cost
380
399
  }
381
400
 
382
401
  if self.args.request_id and not self.args.skip_events:
@@ -13,6 +13,7 @@ from concurrent.futures import ThreadPoolExecutor
13
13
  from autocoder.common.utils_code_auto_generate import chat_with_continue
14
14
  from autocoder.common.printer import Printer
15
15
  from autocoder.rag.token_counter import count_tokens
16
+ from autocoder.utils import llms as llm_utils
16
17
 
17
18
 
18
19
  class CodeAutoGenerateEditBlock:
@@ -424,6 +425,11 @@ class CodeAutoGenerateEditBlock:
424
425
  input_tokens_count = 0
425
426
  generated_tokens_count = 0
426
427
 
428
+ input_tokens_cost = 0
429
+ generated_tokens_cost = 0
430
+
431
+ model_names = []
432
+
427
433
  printer = Printer()
428
434
  estimated_input_tokens = count_tokens(
429
435
  json.dumps(conversations, ensure_ascii=False))
@@ -437,14 +443,28 @@ class CodeAutoGenerateEditBlock:
437
443
  with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
438
444
  futures = []
439
445
  for llm in self.llms:
446
+
447
+ model_names_list = llm_utils.get_llm_names(llm)
448
+ model_name = None
449
+ if model_names_list:
450
+ model_name = model_names_list[0]
451
+
440
452
  for _ in range(self.generate_times_same_model):
453
+ model_names.append(model_name)
441
454
  futures.append(executor.submit(
442
455
  chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
456
+
443
457
  temp_results = [future.result() for future in futures]
444
- for result in temp_results:
458
+
459
+ for result,model_name in zip(temp_results,model_names):
445
460
  results.append(result.content)
446
461
  input_tokens_count += result.input_tokens_count
447
462
  generated_tokens_count += result.generated_tokens_count
463
+ model_info = llm_utils.get_model_info(model_name,self.args.product_mode)
464
+ input_cost = model_info.get("input_price", 0) if model_info else 0
465
+ output_cost = model_info.get("output_price", 0) if model_info else 0
466
+ input_tokens_cost += input_cost * result.input_tokens_count / 1000000
467
+ generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
448
468
 
449
469
  for result in results:
450
470
  conversations_list.append(
@@ -461,7 +481,9 @@ class CodeAutoGenerateEditBlock:
461
481
 
462
482
  statistics = {
463
483
  "input_tokens_count": input_tokens_count,
464
- "generated_tokens_count": generated_tokens_count
484
+ "generated_tokens_count": generated_tokens_count,
485
+ "input_tokens_cost": input_tokens_cost,
486
+ "generated_tokens_cost": generated_tokens_cost
465
487
  }
466
488
 
467
489
  if self.args.request_id and not self.args.skip_events:
@@ -9,6 +9,7 @@ import json
9
9
  from autocoder.common.utils_code_auto_generate import chat_with_continue
10
10
  from autocoder.common.printer import Printer
11
11
  from autocoder.rag.token_counter import count_tokens
12
+ from autocoder.utils import llms as llm_utils
12
13
 
13
14
  class CodeAutoGenerateStrictDiff:
14
15
  def __init__(
@@ -311,6 +312,9 @@ class CodeAutoGenerateStrictDiff:
311
312
  results = []
312
313
  input_tokens_count = 0
313
314
  generated_tokens_count = 0
315
+ input_tokens_cost = 0
316
+ generated_tokens_cost = 0
317
+ model_names = []
314
318
 
315
319
  printer = Printer()
316
320
  estimated_input_tokens = count_tokens(json.dumps(conversations, ensure_ascii=False))
@@ -324,14 +328,27 @@ class CodeAutoGenerateStrictDiff:
324
328
  futures = []
325
329
  for llm in self.llms:
326
330
  for _ in range(self.generate_times_same_model):
327
- futures.append(executor.submit(
328
- chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
331
+
332
+ model_names_list = llm_utils.get_llm_names(llm)
333
+ model_name = None
334
+ if model_names_list:
335
+ model_name = model_names_list[0]
336
+
337
+ for _ in range(self.generate_times_same_model):
338
+ model_names.append(model_name)
339
+ futures.append(executor.submit(
340
+ chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
341
+
329
342
  temp_results = [future.result() for future in futures]
330
343
  for result in temp_results:
331
344
  results.append(result.content)
332
345
  input_tokens_count += result.input_tokens_count
333
346
  generated_tokens_count += result.generated_tokens_count
334
-
347
+ model_info = llm_utils.get_model_info(model_name, self.args.product_mode)
348
+ input_cost = model_info.get("input_price", 0) if model_info else 0
349
+ output_cost = model_info.get("output_price", 0) if model_info else 0
350
+ input_tokens_cost += input_cost * result.input_tokens_count / 1000000
351
+ generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
335
352
  for result in results:
336
353
  conversations_list.append(
337
354
  conversations + [{"role": "assistant", "content": result}])
@@ -345,7 +362,9 @@ class CodeAutoGenerateStrictDiff:
345
362
 
346
363
  statistics = {
347
364
  "input_tokens_count": input_tokens_count,
348
- "generated_tokens_count": generated_tokens_count
365
+ "generated_tokens_count": generated_tokens_count,
366
+ "input_tokens_cost": input_tokens_cost,
367
+ "generated_tokens_cost": generated_tokens_cost
349
368
  }
350
369
 
351
370
  if self.args.request_id and not self.args.skip_events:
@@ -8,8 +8,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
8
8
  import traceback
9
9
  from autocoder.common.utils_code_auto_generate import chat_with_continue
10
10
  from byzerllm.utils.str2model import to_model
11
+ from autocoder.utils.llms import get_llm_names, get_model_info
11
12
 
12
- from autocoder.utils.llms import get_llm_names
13
13
  class RankResult(BaseModel):
14
14
  rank_result: List[int]
15
15
 
@@ -97,13 +97,42 @@ class CodeModificationRanker:
97
97
 
98
98
  # Collect all results
99
99
  results = []
100
- for future in as_completed(futures):
100
+ # 获取模型名称列表
101
+ model_names = []
102
+ for llm in self.llms:
103
+ # 获取当前llm实例对应的模型名称
104
+ names = get_llm_names(llm)
105
+ model_names.extend(names)
106
+
107
+ # 获取模型价格信息
108
+ model_info_map = {}
109
+ for name in model_names:
110
+ # 第二个参数是产品模式,从args中获取
111
+ info = get_model_info(name, self.args.product_mode)
112
+ if info:
113
+ model_info_map[name] = {
114
+ "input_cost": info.get("input_price", 0.0), # 每百万tokens成本
115
+ "output_cost": info.get("output_price", 0.0) # 每百万tokens成本
116
+ }
117
+
118
+ # 计算总成本
119
+ total_input_cost = 0.0
120
+ total_output_cost = 0.0
121
+
122
+ for future, model_name in zip(futures, model_names):
101
123
  try:
102
124
  result = future.result()
103
125
  input_tokens_count += result.input_tokens_count
104
126
  generated_tokens_count += result.generated_tokens_count
105
127
  v = to_model(result.content,RankResult)
106
128
  results.append(v.rank_result)
129
+
130
+ # 计算成本
131
+ info = model_info_map.get(model_name, {})
132
+ # 计算公式:token数 * 单价 / 1000000
133
+ total_input_cost += (result.input_tokens_count * info.get("input_cost", 0.0)) / 1000000
134
+ total_output_cost += (result.generated_tokens_count * info.get("output_cost", 0.0)) / 1000000
135
+
107
136
  except Exception as e:
108
137
  self.printer.print_in_terminal(
109
138
  "ranking_failed_request", style="yellow", error=str(e))
@@ -113,6 +142,10 @@ class CodeModificationRanker:
113
142
  raise Exception(
114
143
  self.printer.get_message_from_key("ranking_all_failed"))
115
144
 
145
+ # 四舍五入到4位小数
146
+ total_input_cost = round(total_input_cost, 4)
147
+ total_output_cost = round(total_output_cost, 4)
148
+
116
149
  # Calculate scores for each candidate
117
150
  candidate_scores = defaultdict(float)
118
151
  for rank_result in results:
@@ -137,7 +170,10 @@ class CodeModificationRanker:
137
170
  best_candidate=sorted_candidates[0],
138
171
  scores=score_details,
139
172
  input_tokens=input_tokens_count,
140
- output_tokens=generated_tokens_count
173
+ output_tokens=generated_tokens_count,
174
+ input_cost=total_input_cost,
175
+ output_cost=total_output_cost,
176
+ model_names=", ".join(model_names)
141
177
  )
142
178
 
143
179
  rerank_contents = [generate_result.contents[i]
@@ -125,13 +125,17 @@ class ActionTSProject(BaseAction):
125
125
  query=args.query, source_content=content
126
126
  )
127
127
  elapsed_time = time.time() - start_time
128
- speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
129
- model_names = ",".join(get_llm_names(self.llm))
128
+ speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
129
+ input_tokens_cost = generate_result.metadata.get('input_tokens_cost', 0)
130
+ generated_tokens_cost = generate_result.metadata.get('generated_tokens_cost', 0)
131
+ model_names = ",".join(get_llm_names(generate.llms))
130
132
  self.printer.print_in_terminal(
131
133
  "code_generation_complete",
132
134
  duration=elapsed_time,
133
135
  input_tokens=generate_result.metadata.get('input_tokens_count', 0),
134
136
  output_tokens=generate_result.metadata.get('generated_tokens_count', 0),
137
+ input_cost=input_tokens_cost,
138
+ output_cost=generated_tokens_cost,
135
139
  speed=round(speed, 2),
136
140
  model_names=model_names
137
141
  )
@@ -221,12 +225,16 @@ class ActionPyScriptProject(BaseAction):
221
225
 
222
226
  elapsed_time = time.time() - start_time
223
227
  speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
224
- model_names = ",".join(get_llm_names(self.llm))
228
+ model_names = ",".join(get_llm_names(generate.llms))
229
+ input_tokens_cost = generate_result.metadata.get('input_tokens_cost', 0)
230
+ generated_tokens_cost = generate_result.metadata.get('generated_tokens_cost', 0)
225
231
  self.printer.print_in_terminal(
226
232
  "code_generation_complete",
227
233
  duration=elapsed_time,
228
234
  input_tokens=generate_result.metadata.get('input_tokens_count', 0),
229
235
  output_tokens=generate_result.metadata.get('generated_tokens_count', 0),
236
+ input_cost=input_tokens_cost,
237
+ output_cost=generated_tokens_cost,
230
238
  speed=round(speed, 2),
231
239
  model_names=model_names
232
240
  )
@@ -264,13 +272,7 @@ class ActionPyScriptProject(BaseAction):
264
272
  model=self.llm.default_model_name,
265
273
  )
266
274
 
267
- end_time = time.time()
268
- self.printer.print_in_terminal(
269
- "code_generation_complete",
270
- duration=end_time - start_time,
271
- input_tokens=generate_result.metadata.get('input_tokens_count', 0),
272
- output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
273
- )
275
+ end_time = time.time()
274
276
  with open(self.args.target_file, "w") as file:
275
277
  file.write(content)
276
278
 
@@ -348,12 +350,16 @@ class ActionPyProject(BaseAction):
348
350
  )
349
351
  elapsed_time = time.time() - start_time
350
352
  speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
351
- model_names = ",".join(get_llm_names(self.llm))
353
+ model_names = ",".join(get_llm_names(generate.llms))
354
+ input_tokens_cost = generate_result.metadata.get('input_tokens_cost', 0)
355
+ generated_tokens_cost = generate_result.metadata.get('generated_tokens_cost', 0)
352
356
  self.printer.print_in_terminal(
353
357
  "code_generation_complete",
354
358
  duration=elapsed_time,
355
359
  input_tokens=generate_result.metadata.get('input_tokens_count', 0),
356
360
  output_tokens=generate_result.metadata.get('generated_tokens_count', 0),
361
+ input_cost=input_tokens_cost,
362
+ output_cost=generated_tokens_cost,
357
363
  speed=round(speed, 2),
358
364
  model_names=model_names
359
365
  )
@@ -458,12 +464,16 @@ class ActionSuffixProject(BaseAction):
458
464
 
459
465
  elapsed_time = time.time() - start_time
460
466
  speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
461
- model_names = ",".join(get_llm_names(self.llm))
467
+ model_names = ",".join(get_llm_names(generate.llms))
468
+ input_tokens_cost = generate_result.metadata.get('input_tokens_cost', 0)
469
+ generated_tokens_cost = generate_result.metadata.get('generated_tokens_cost', 0)
462
470
  self.printer.print_in_terminal(
463
471
  "code_generation_complete",
464
472
  duration=elapsed_time,
465
473
  input_tokens=generate_result.metadata.get('input_tokens_count', 0),
466
474
  output_tokens=generate_result.metadata.get('generated_tokens_count', 0),
475
+ input_cost=input_tokens_cost,
476
+ output_cost=generated_tokens_cost,
467
477
  speed=round(speed, 2),
468
478
  model_names=model_names
469
479
  )
@@ -88,11 +88,15 @@ class ActionRegexProject:
88
88
  elapsed_time = time.time() - start_time
89
89
  speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
90
90
  model_names = ",".join(get_llm_names(self.llm))
91
+ input_tokens_cost = generate_result.metadata.get('input_tokens_cost', 0)
92
+ generated_tokens_cost = generate_result.metadata.get('generated_tokens_cost', 0)
91
93
  self.printer.print_in_terminal(
92
94
  "code_generation_complete",
93
95
  duration=elapsed_time,
94
96
  input_tokens=generate_result.metadata.get('input_tokens_count', 0),
95
97
  output_tokens=generate_result.metadata.get('generated_tokens_count', 0),
98
+ input_cost=input_tokens_cost,
99
+ output_cost=generated_tokens_cost,
96
100
  speed=round(speed, 2),
97
101
  model_names=model_names
98
102
  )
@@ -4,21 +4,21 @@ from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
4
4
  from autocoder.common.utils_code_auto_generate import stream_chat_with_continue
5
5
  from byzerllm.utils.str2model import to_model
6
6
  from autocoder.index.types import IndexItem
7
- from autocoder.common import AutoCoderArgs,SourceCode
7
+ from autocoder.common import AutoCoderArgs, SourceCode
8
8
  import byzerllm
9
9
  import time
10
10
  from autocoder.index.index import IndexManager
11
11
  from autocoder.index.types import (
12
12
  IndexItem,
13
- TargetFile,
13
+ TargetFile,
14
14
  FileNumberList
15
15
  )
16
16
  from autocoder.rag.token_counter import count_tokens
17
17
  from autocoder.common.printer import Printer
18
18
  from concurrent.futures import ThreadPoolExecutor
19
- import threading
19
+ from byzerllm import MetaHolder
20
20
 
21
- from autocoder.utils.llms import get_llm_names
21
+ from autocoder.utils.llms import get_llm_names, get_model_info
22
22
 
23
23
 
24
24
  def get_file_path(file_path):
@@ -32,8 +32,9 @@ class QuickFilterResult(BaseModel):
32
32
  has_error: bool
33
33
  error_message: Optional[str] = None
34
34
 
35
+
35
36
  class QuickFilter():
36
- def __init__(self, index_manager: IndexManager,stats:Dict[str,Any],sources:List[SourceCode]):
37
+ def __init__(self, index_manager: IndexManager, stats: Dict[str, Any], sources: List[SourceCode]):
37
38
  self.index_manager = index_manager
38
39
  self.args = index_manager.args
39
40
  self.stats = stats
@@ -41,72 +42,142 @@ class QuickFilter():
41
42
  self.printer = Printer()
42
43
  self.max_tokens = self.args.index_filter_model_max_input_length
43
44
 
44
-
45
45
  def big_filter(self, index_items: List[IndexItem],) -> QuickFilterResult:
46
46
  chunks = []
47
47
  current_chunk = []
48
-
48
+
49
49
  # 将 index_items 切分成多个 chunks,第一个chunk尽可能接近max_tokens
50
50
  for item in index_items:
51
51
  # 使用 quick_filter_files.prompt 生成文本再统计
52
52
  temp_chunk = current_chunk + [item]
53
- prompt_text = self.quick_filter_files.prompt(temp_chunk, self.args.query)
54
- temp_size = count_tokens(prompt_text)
53
+ prompt_text = self.quick_filter_files.prompt(
54
+ temp_chunk, self.args.query)
55
+ temp_size = count_tokens(prompt_text)
55
56
  # 如果当前chunk为空,或者添加item后不超过max_tokens,就添加到当前chunk
56
57
  if not current_chunk or temp_size <= self.max_tokens:
57
- current_chunk.append(item)
58
+ current_chunk.append(item)
58
59
  else:
59
60
  # 当前chunk已满,创建新chunk
60
61
  chunks.append(current_chunk)
61
- current_chunk = [item]
62
-
62
+ current_chunk = [item]
63
+
63
64
  if current_chunk:
64
65
  chunks.append(current_chunk)
65
-
66
- tokens_len = count_tokens(self.quick_filter_files.prompt(index_items, self.args.query))
66
+
67
+ tokens_len = count_tokens(
68
+ self.quick_filter_files.prompt(index_items, self.args.query))
67
69
  self.printer.print_in_terminal(
68
- "quick_filter_too_long",
69
- style="yellow",
70
- tokens_len=tokens_len,
71
- max_tokens=self.max_tokens,
72
- split_size=len(chunks)
73
- )
70
+ "quick_filter_too_long",
71
+ style="yellow",
72
+ tokens_len=tokens_len,
73
+ max_tokens=self.max_tokens,
74
+ split_size=len(chunks)
75
+ )
74
76
 
75
77
  def process_chunk(chunk_index: int, chunk: List[IndexItem]) -> QuickFilterResult:
76
78
  try:
77
- model_name = ",".join(get_llm_names(self.index_manager.index_filter_llm))
79
+ # 获取模型名称列表
80
+ model_names = get_llm_names(
81
+ self.index_manager.index_filter_llm)
82
+ model_name = ",".join(model_names)
78
83
  files: Dict[str, TargetFile] = {}
79
-
84
+
85
+ # 获取模型价格信息
86
+ model_info_map = {}
87
+ for name in model_names:
88
+ # 第二个参数是产品模式,从args中获取
89
+ info = get_model_info(name, self.args.product_mode)
90
+ if info:
91
+ model_info_map[name] = {
92
+ # 每百万tokens成本
93
+ "input_price": info.get("input_price", 0.0),
94
+ # 每百万tokens成本
95
+ "output_price": info.get("output_price", 0.0)
96
+ }
97
+
80
98
  if chunk_index == 0:
81
99
  # 第一个chunk使用流式输出
82
100
  stream_generator = stream_chat_with_continue(
83
101
  self.index_manager.index_filter_llm,
84
- [{"role": "user", "content": self.quick_filter_files.prompt(chunk, self.args.query)}],
102
+ [{"role": "user", "content": self.quick_filter_files.prompt(
103
+ chunk, self.args.query)}],
85
104
  {}
86
105
  )
87
- full_response, _ = stream_out(
106
+ full_response, last_meta = stream_out(
88
107
  stream_generator,
89
108
  model_name=model_name,
90
- title=self.printer.get_message_from_key_with_format("quick_filter_title", model_name=model_name),
109
+ title=self.printer.get_message_from_key_with_format(
110
+ "quick_filter_title", model_name=model_name),
91
111
  args=self.args
92
112
  )
93
113
  file_number_list = to_model(full_response, FileNumberList)
114
+
115
+ # 计算总成本
116
+ total_input_cost = 0.0
117
+ total_output_cost = 0.0
118
+
119
+ for name in model_names:
120
+ info = model_info_map.get(name, {})
121
+ # 计算公式:token数 * 单价 / 1000000
122
+ total_input_cost += (last_meta.input_tokens_count *
123
+ info.get("input_price", 0.0)) / 1000000
124
+ total_output_cost += (last_meta.generated_tokens_count *
125
+ info.get("output_price", 0.0)) / 1000000
126
+
127
+ # 四舍五入到4位小数
128
+ total_input_cost = round(total_input_cost, 4)
129
+ total_output_cost = round(total_output_cost, 4)
130
+
131
+ # 打印 token 统计信息和成本
132
+ self.printer.print_in_terminal(
133
+ "quick_filter_stats",
134
+ style="blue",
135
+ input_tokens=last_meta.input_tokens_count,
136
+ output_tokens=last_meta.generated_tokens_count,
137
+ input_cost=total_input_cost,
138
+ output_cost=total_output_cost,
139
+ model_names=model_name
140
+ )
94
141
  else:
95
142
  # 其他chunks直接使用with_llm
96
- file_number_list = self.quick_filter_files.with_llm(self.index_manager.index_filter_llm).with_return_type(FileNumberList).run(chunk, self.args.query)
97
-
143
+ meta_holder = MetaHolder()
144
+ start_time = time.monotonic()
145
+ file_number_list = self.quick_filter_files.with_llm(self.index_manager.index_filter_llm).with_meta(
146
+ meta_holder).with_return_type(FileNumberList).run(chunk, self.args.query)
147
+ end_time = time.monotonic()
148
+
149
+ total_input_cost = 0.0
150
+ total_output_cost = 0.0
151
+ if meta_holder.get_meta():
152
+ meta_dict = meta_holder.get_meta()
153
+ total_input_cost = meta_dict.get("input_tokens_count", 0) * model_info_map.get(model_name, {}).get("input_price", 0.0) / 1000000
154
+ total_output_cost = meta_dict.get("generated_tokens_count", 0) * model_info_map.get(model_name, {}).get("output_price", 0.0) / 1000000
155
+
156
+ self.printer.print_in_terminal(
157
+ "quick_filter_stats",
158
+ style="blue",
159
+ input_tokens=meta_dict.get("input_tokens_count", 0),
160
+ output_tokens=meta_dict.get("generated_tokens_count", 0),
161
+ input_cost=total_input_cost,
162
+ output_cost=total_output_cost,
163
+ model_names=model_name,
164
+ elapsed_time=f"{end_time - start_time:.2f}"
165
+ )
166
+
98
167
  if file_number_list:
99
168
  for file_number in file_number_list.file_list:
100
- file_path = get_file_path(chunk[file_number].module_name)
169
+ file_path = get_file_path(
170
+ chunk[file_number].module_name)
101
171
  files[file_path] = TargetFile(
102
172
  file_path=chunk[file_number].module_name,
103
- reason=self.printer.get_message_from_key("quick_filter_reason")
173
+ reason=self.printer.get_message_from_key(
174
+ "quick_filter_reason")
104
175
  )
105
176
  return QuickFilterResult(
106
177
  files=files,
107
178
  has_error=False
108
179
  )
109
-
180
+
110
181
  except Exception as e:
111
182
  self.printer.print_in_terminal(
112
183
  "quick_filter_failed",
@@ -123,25 +194,25 @@ class QuickFilter():
123
194
  if chunks:
124
195
  with ThreadPoolExecutor() as executor:
125
196
  # 提交所有chunks到线程池并收集结果
126
- futures = [executor.submit(process_chunk, i, chunk)
127
- for i, chunk in enumerate(chunks)]
128
-
197
+ futures = [executor.submit(process_chunk, i, chunk)
198
+ for i, chunk in enumerate(chunks)]
199
+
129
200
  # 等待所有任务完成并收集结果
130
201
  for future in futures:
131
202
  results.append(future.result())
132
-
203
+
133
204
  # 合并所有结果
134
205
  final_files: Dict[str, TargetFile] = {}
135
206
  has_error = False
136
207
  error_messages: List[str] = []
137
-
208
+
138
209
  for result in results:
139
210
  if result.has_error:
140
211
  has_error = True
141
212
  if result.error_message:
142
213
  error_messages.append(result.error_message)
143
214
  final_files.update(result.files)
144
-
215
+
145
216
  return QuickFilterResult(
146
217
  files=final_files,
147
218
  has_error=has_error,
@@ -149,7 +220,7 @@ class QuickFilter():
149
220
  )
150
221
 
151
222
  @byzerllm.prompt()
152
- def quick_filter_files(self,file_meta_list:List[IndexItem],query:str) -> str:
223
+ def quick_filter_files(self, file_meta_list: List[IndexItem], query: str) -> str:
153
224
  '''
154
225
  当用户提一个需求的时候,我们需要找到相关的文件,然后阅读这些文件,并且修改其中部分文件。
155
226
  现在,给定下面的索引文件:
@@ -160,7 +231,7 @@ class QuickFilter():
160
231
 
161
232
  索引文件包含文件序号(##[]括起来的部分),文件路径,文件符号信息等。
162
233
  下面是用户的查询需求:
163
-
234
+
164
235
  <query>
165
236
  {{ query }}
166
237
  </query>
@@ -182,63 +253,101 @@ class QuickFilter():
182
253
  2. 如果 query 里是一段历史对话,那么对话里的内容提及的文件路径必须要返回。
183
254
  3. json格式数据不允许有注释
184
255
  '''
185
- file_meta_str = "\n".join([f"##[{index}]{item.module_name}\n{item.symbols}" for index,item in enumerate(file_meta_list)])
256
+ file_meta_str = "\n".join(
257
+ [f"##[{index}]{item.module_name}\n{item.symbols}" for index, item in enumerate(file_meta_list)])
186
258
  context = {
187
259
  "content": file_meta_str,
188
260
  "query": query
189
261
  }
190
- return context
262
+ return context
191
263
 
192
264
  def filter(self, index_items: List[IndexItem], query: str) -> QuickFilterResult:
193
265
  final_files: Dict[str, TargetFile] = {}
194
- start_time = time.monotonic()
266
+ start_time = time.monotonic()
267
+
268
+ prompt_str = self.quick_filter_files.prompt(index_items, query)
269
+
270
+ tokens_len = count_tokens(prompt_str)
195
271
 
196
- prompt_str = self.quick_filter_files.prompt(index_items,query)
197
-
198
- tokens_len = count_tokens(prompt_str)
199
-
200
272
  # Print current index size
201
273
  self.printer.print_in_terminal(
202
274
  "quick_filter_tokens_len",
203
275
  style="blue",
204
276
  tokens_len=tokens_len
205
277
  )
206
-
207
- if tokens_len > self.max_tokens:
278
+
279
+ if tokens_len > self.max_tokens:
208
280
  return self.big_filter(index_items)
209
-
281
+
210
282
  try:
211
- model_name = ",".join(get_llm_names(self.index_manager.index_filter_llm))
212
-
283
+ # 获取模型名称
284
+ model_names = get_llm_names(self.index_manager.index_filter_llm)
285
+ model_name = ",".join(model_names)
286
+
287
+ # 获取模型价格信息
288
+ model_info_map = {}
289
+ for name in model_names:
290
+ # 第二个参数是产品模式,从args中获取
291
+ info = get_model_info(name, self.args.product_mode)
292
+ if info:
293
+ model_info_map[name] = {
294
+ # 每百万tokens成本
295
+ "input_price": info.get("input_price", 0.0),
296
+ # 每百万tokens成本
297
+ "output_price": info.get("output_price", 0.0)
298
+ }
299
+
213
300
  # 渲染 Prompt 模板
214
- query = self.quick_filter_files.prompt(index_items, self.args.query)
215
-
301
+ query = self.quick_filter_files.prompt(
302
+ index_items, self.args.query)
303
+
216
304
  # 使用流式输出处理
217
305
  stream_generator = stream_chat_with_continue(
218
306
  self.index_manager.index_filter_llm,
219
307
  [{"role": "user", "content": query}],
220
308
  {}
221
309
  )
222
-
310
+
223
311
  # 获取完整响应
224
312
  full_response, last_meta = stream_out(
225
313
  stream_generator,
226
314
  model_name=model_name,
227
- title=self.printer.get_message_from_key_with_format("quick_filter_title", model_name=model_name),
315
+ title=self.printer.get_message_from_key_with_format(
316
+ "quick_filter_title", model_name=model_name),
228
317
  args=self.args
229
- )
318
+ )
230
319
  # 解析结果
231
320
  file_number_list = to_model(full_response, FileNumberList)
232
- end_time = time.monotonic()
233
- # 打印 token 统计信息
321
+ end_time = time.monotonic()
322
+
323
+ # 计算总成本
324
+ total_input_cost = 0.0
325
+ total_output_cost = 0.0
326
+
327
+ for name in model_names:
328
+ info = model_info_map.get(name, {})
329
+ # 计算公式:token数 * 单价 / 1000000
330
+ total_input_cost += (last_meta.input_tokens_count *
331
+ info.get("input_price", 0.0)) / 1000000
332
+ total_output_cost += (last_meta.generated_tokens_count *
333
+ info.get("output_price", 0.0)) / 1000000
334
+
335
+ # 四舍五入到4位小数
336
+ total_input_cost = round(total_input_cost, 4)
337
+ total_output_cost = round(total_output_cost, 4)
338
+
339
+ # 打印 token 统计信息和成本
234
340
  self.printer.print_in_terminal(
235
- "quick_filter_stats",
341
+ "quick_filter_stats",
236
342
  style="blue",
237
343
  elapsed_time=f"{end_time - start_time:.2f}",
238
344
  input_tokens=last_meta.input_tokens_count,
239
- output_tokens=last_meta.generated_tokens_count
345
+ output_tokens=last_meta.generated_tokens_count,
346
+ input_cost=total_input_cost,
347
+ output_cost=total_output_cost,
348
+ model_names=model_name
240
349
  )
241
-
350
+
242
351
  except Exception as e:
243
352
  self.printer.print_in_terminal(
244
353
  "quick_filter_failed",
@@ -250,16 +359,17 @@ class QuickFilter():
250
359
  has_error=True,
251
360
  error_message=str(e)
252
361
  )
253
-
362
+
254
363
  if file_number_list:
255
364
  for file_number in file_number_list.file_list:
256
365
  final_files[get_file_path(index_items[file_number].module_name)] = TargetFile(
257
366
  file_path=index_items[file_number].module_name,
258
- reason=self.printer.get_message_from_key("quick_filter_reason")
367
+ reason=self.printer.get_message_from_key(
368
+ "quick_filter_reason")
259
369
  )
260
- end_time = time.monotonic()
261
- self.stats["timings"]["quick_filter"] = end_time - start_time
370
+ end_time = time.monotonic()
371
+ self.stats["timings"]["quick_filter"] = end_time - start_time
262
372
  return QuickFilterResult(
263
373
  files=final_files,
264
374
  has_error=False
265
- )
375
+ )
autocoder/models.py CHANGED
@@ -127,11 +127,23 @@ def update_model_input_price(name: str, price: float) -> bool:
127
127
  """更新模型输入价格
128
128
 
129
129
  Args:
130
- name: 模型名称
131
- price: 输入价格(M/百万input tokens)
130
+ name (str): 要更新的模型名称,必须与models.json中的记录匹配
131
+ price (float): 新的输入价格,单位:美元/百万tokens。必须大于等于0
132
132
 
133
133
  Returns:
134
- bool: 是否更新成功
134
+ bool: 是否成功找到并更新了模型价格
135
+
136
+ Raises:
137
+ ValueError: 如果price为负数时抛出
138
+
139
+ Example:
140
+ >>> update_model_input_price("gpt-4", 3.0)
141
+ True
142
+
143
+ Notes:
144
+ 1. 价格设置后会立即生效并保存到models.json
145
+ 2. 实际费用计算时会按实际使用量精确到小数点后6位
146
+ 3. 设置价格为0表示该模型当前不可用
135
147
  """
136
148
  if price < 0:
137
149
  raise ValueError("Price cannot be negative")
@@ -151,11 +163,23 @@ def update_model_output_price(name: str, price: float) -> bool:
151
163
  """更新模型输出价格
152
164
 
153
165
  Args:
154
- name: 模型名称
155
- price: 输出价格(M/百万output tokens)
166
+ name (str): 要更新的模型名称,必须与models.json中的记录匹配
167
+ price (float): 新的输出价格,单位:美元/百万tokens。必须大于等于0
156
168
 
157
169
  Returns:
158
- bool: 是否更新成功
170
+ bool: 是否成功找到并更新了模型价格
171
+
172
+ Raises:
173
+ ValueError: 如果price为负数时抛出
174
+
175
+ Example:
176
+ >>> update_model_output_price("gpt-4", 6.0)
177
+ True
178
+
179
+ Notes:
180
+ 1. 输出价格通常比输入价格高30%-50%
181
+ 2. 对于按token计费的API,实际收费按(input_tokens * input_price + output_tokens * output_price)计算
182
+ 3. 价格变更会影响所有依赖模型计费的功能(如成本预测、用量监控等)
159
183
  """
160
184
  if price < 0:
161
185
  raise ValueError("Price cannot be negative")
@@ -116,6 +116,7 @@ class PyProject:
116
116
  "actions",
117
117
  ".vscode",
118
118
  ".idea",
119
+ "venv",
119
120
  ]
120
121
 
121
122
  @byzerllm.prompt()
@@ -56,6 +56,7 @@ class SuffixProject:
56
56
  ".vscode",
57
57
  "actions",
58
58
  ".idea",
59
+ "venv",
59
60
  ]
60
61
 
61
62
  @byzerllm.prompt()
@@ -48,6 +48,7 @@ class TSProject:
48
48
  "actions",
49
49
  ".vscode",
50
50
  ".idea",
51
+ "venv",
51
52
  ]
52
53
 
53
54
  @byzerllm.prompt()
autocoder/utils/llms.py CHANGED
@@ -3,9 +3,15 @@ from typing import Union,Optional
3
3
 
4
4
  def get_llm_names(llm: Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM,str],target_model_type:Optional[str]=None):
5
5
  if target_model_type is None:
6
+ if isinstance(llm,list):
7
+ return [_llm.default_model_name for _llm in llm]
6
8
  return [llm.default_model_name for llm in [llm] if llm.default_model_name]
9
+
7
10
  llms = llm.get_sub_client(target_model_type)
11
+
8
12
  if llms is None:
13
+ if isinstance(llm,list):
14
+ return [_llm.default_model_name for _llm in llm]
9
15
  return [llm.default_model_name for llm in [llm] if llm.default_model_name]
10
16
  elif isinstance(llms, list):
11
17
  return [llm.default_model_name for llm in llms if llm.default_model_name]
@@ -14,6 +20,27 @@ def get_llm_names(llm: Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM,str],tar
14
20
  else:
15
21
  return [llm.default_model_name for llm in [llms] if llm.default_model_name]
16
22
 
23
+ def get_model_info(model_names: str, product_mode: str):
24
+ from autocoder import models as models_module
25
+ def get_model_by_name(model_name: str):
26
+ try:
27
+ return models_module.get_model_by_name(model_name)
28
+ except Exception as e:
29
+ return None
30
+
31
+ if product_mode == "pro":
32
+ return None
33
+
34
+ if product_mode == "lite":
35
+ if "," in model_names:
36
+ # Multiple code models specified
37
+ model_names = model_names.split(",")
38
+ for _, model_name in enumerate(model_names):
39
+ return get_model_by_name(model_name)
40
+ else:
41
+ # Single code model
42
+ return get_model_by_name(model_names)
43
+
17
44
  def get_single_llm(model_names: str, product_mode: str):
18
45
  from autocoder import models as models_module
19
46
  if product_mode == "pro":
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.255"
1
+ __version__ = "0.1.256"