Skip to content

Commit aeebd1c

Browse files
authored
Merge pull request #63 from led-mirage/feature/v1.35.0
Feature/v1.35.0
2 parents b1fb176 + 8d269de commit aeebd1c

File tree

16 files changed

+248
-89
lines changed

16 files changed

+248
-89
lines changed

Readme.en.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ The following values can be configured:
6868
- Windows 11 Pro 23H2, 24H2, 25H2
6969
- Raspberry Pi OS Bookworm 64bit
7070
- Linux Mint 22.1 Cinnamon Edition
71-
- Python 3.10–3.13 (development environment: 3.12.0)
71+
- Python 3.10–3.12 (development environment: 3.12.0)
7272
- VOICEVOX 0.25.0
7373
- A.I.VOICE Editor 1.4.10.0
7474
- COEIROINK v.2.3.4

Readme.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Raspberry Pi、Linuxへの導入に関しても[Zennの記事](https://zenn.dev/
5959
- Windows 11 Pro 23H2、24H2、25H2
6060
- Raspberry Pi OS Bookworm 64bit
6161
- Linux Mint 22.1 Cinnamon Edition
62-
- Python 3.10-3.13(開発環境は 3.12.0)
62+
- Python 3.10-3.12(開発環境は 3.12.0)
6363
- VOICEVOX 0.25.0
6464
- A.I.VOICE Editor 1.4.10.0
6565
- COEIROINK v.2.3.4
@@ -70,8 +70,12 @@ Raspberry Pi、Linuxへの導入に関しても[Zennの記事](https://zenn.dev/
7070

7171
動作確認済みのモデルは以下の通りなのだ。
7272

73-
<details><summary>OpenAI(2025/10/19現在)</summary>
73+
<details><summary>OpenAI(2025/11/23現在)</summary>
7474

75+
- GPT-5.1 (モデル名:gpt-5.1)
76+
- GPT-5.1 Chat (モデル名:gpt-5.1-chat-latest)
77+
- GPT-5.1 Codex (モデル名:gpt-5.1-codex)
78+
- GPT-5.1 Codex mini(モデル名:gpt-5.1-codex-mini)
7579
- GPT-5 (モデル名:gpt-5)
7680
- GPT-5 pro (モデル名:gpt-5-pro)
7781
- GPT-5 mini (モデル名:gpt-5-mini)
@@ -206,7 +210,7 @@ Windowsの場合は、Windowsの検索窓で「環境変数を編集」で検索
206210

207211
以下のリンクから ZundaGPT2.ZIP をダウンロードして、作成したフォルダに展開するのだ。
208212

209-
https://github.com/led-mirage/ZundaGPT2/releases/tag/v1.34.0
213+
https://github.com/led-mirage/ZundaGPT2/releases/tag/v1.35.0
210214

211215
#### 3. 実行
212216

@@ -354,11 +358,11 @@ CSSを知らない人はなんのことかわからないかもしれないけ
354358

355359
VirusTotalでのチェック結果はこちらなのだ。
356360

357-
- Windows版: [72個中2個のアンチウィルスエンジンで検出 :2025/11/02 v1.34.0](https://www.virustotal.com/gui/file/ee47b5a5c9c70fca1c3d080bf4f63356bf86d38a5000a375e8a8db910f6e3754/detection)
358-
- Raspberry Pi版: [60個中0個のアンチウィルスエンジンで検出 :2025/11/02 v1.34.0](https://www.virustotal.com/gui/file/8d8cdb96624cdf83da439297b762e5ae2595486d799142ad8457cfd8071bddf3/detection)
359-
- Linux版: [62個中0個のアンチウィルスエンジンで検出 :2025/11/02 v1.34.0](https://www.virustotal.com/gui/file/23315c375d2badf83a31c84dfb986fc9addb250d69bb68b33d36780f0e39e2ff/detection)
361+
- Windows版: [72個中2個のアンチウィルスエンジンで検出 :2025/11/23 v1.35.0](https://www.virustotal.com/gui/file/0c8f0151ca9ce5b351f00841e4523ba526b3e989f09a867f25097688e5617205/detection)
362+
- Raspberry Pi版: [62個中0個のアンチウィルスエンジンで検出 :2025/11/23 v1.35.0](https://www.virustotal.com/gui/file/dff03e4818e882e379ecff35b7b9e38cc0e4396891e5a8c62378624e5010178a/detection)
363+
- Linux版: [61個中0個のアンチウィルスエンジンで検出 :2025/11/23 v1.35.0](https://www.virustotal.com/gui/file/1f7e6c47a81f6d3d86515bcc6bbbb813586b6e36575664706d54f72e288fab12/detection)
360364

361-
<img src="doc/images/virustotal_1.34.0.png" width="600">
365+
<img src="doc/images/virustotal_1.35.0.png" width="600">
362366

363367
### ⚡ ご利用について
364368

@@ -494,6 +498,17 @@ VirusTotalでのチェック結果はこちらなのだ。
494498

495499
## 💎 バージョン履歴
496500

501+
### 1.35.0 (2025/11/23)
502+
503+
- キャラ設定の削除機能を追加
504+
- 送信画像のサイズ調整機能を追加または調整
505+
- AI応答メッセージ表示ロジックの改善
506+
- Fix: GTP-5 Codex系のモデルを使用した際にレスポンスを処理できない問題を修正
507+
- Fix: タイムアウト時などにメッセージを再送した際、ユーザーの発言が重複して残ってしまう問題を修正
508+
- Fix: カスタムCSSが有効なとき、background_imageが設定されていないとエラーになる問題を修正
509+
- Fix: A.I.VOICEの起動制御を修正
510+
- Doc: 対応環境からPython 3.13を外した(将来的に修正予定)
511+
497512
### 1.34.0 (2025/11/02)
498513

499514
- 画像送信機能の追加(実験的機能)
@@ -519,6 +534,8 @@ VirusTotalでのチェック結果はこちらなのだ。
519534
- google-genaiライブラリを1.45.0に更新
520535
- anthropicライブラリを0.71.0に更新
521536

537+
<details><summary>それ以前のバージョンアップの履歴はこちらなのだ</summary>
538+
522539
### 1.30.2 (2025/10/05)
523540

524541
- タスクバーに表示されるアイコンをアプリのアイコンに変更(Linux、ラズパイ向け)
@@ -527,8 +544,6 @@ VirusTotalでのチェック結果はこちらなのだ。
527544

528545
- fix: ウィンドウの最小化、最大化状態から元に戻す際にウィンドウサイズが固定化されるバグを修正
529546

530-
<details><summary>それ以前のバージョンアップの履歴はこちらなのだ</summary>
531-
532547
### 1.30.0 (2025/09/14)
533548

534549
- ウィンドウサイズの自動保存・復元機能を追加

app/api/api_router.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,14 @@ def move_to_settings(self):
107107
def get_settings_files(self):
108108
return self.settings_service.get_settings_files()
109109

110-
# 設定画面編集イベントハンドラ(UI)
110+
# 設定画面・設定編集イベントハンドラ(UI)
111111
def edit_settings(self, settings_file):
112112
return self.settings_service.edit_settings(settings_file)
113113

114+
# 設定画面・設定削除イベントハンドラ(UI)
115+
def delete_settings(self, settings_file):
116+
return self.settings_service.delete_settings(settings_file)
117+
114118
# 設定画面確定イベントハンドラ(UI)
115119
def submit_settings(self, settings_file):
116120
return self.settings_service.submit_settings(settings_file)

app/character/character.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,18 @@ def __init__(self, speaker_id, aivoice_path= DEFAULT_INSTALL_PATH):
201201
# 話す
202202
def talk(self, text):
203203
CharacterAIVoice.run_aivoice(self.aivoice_path)
204-
try:
205-
tts_control = CharacterAIVoice._tts_control
206-
tts_control.Connect()
207-
tts_control.CurrentVoicePresetName = self.speaker_id
208-
tts_control.Text = text
209-
play_time = tts_control.GetPlayTime()
210-
tts_control.Play()
211-
time.sleep((play_time + 500) / 1000)
212-
except Exception as err:
213-
CharacterAIVoice._tts_control = None
214-
print(err)
215-
raise
204+
if CharacterAIVoice._tts_control is not None:
205+
try:
206+
tts_control = CharacterAIVoice._tts_control
207+
tts_control.Connect()
208+
tts_control.CurrentVoicePresetName = self.speaker_id
209+
tts_control.Text = text
210+
play_time = tts_control.GetPlayTime()
211+
tts_control.Play()
212+
time.sleep((play_time + 500) / 1000)
213+
except Exception as err:
214+
CharacterAIVoice._tts_control = None
215+
print(err)
216216

217217
# A.I.VOICEが起動していなかったら起動して接続する
218218
@classmethod

app/chat/chat_claude.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
# Anthropic Claude チャットクラス
2222
class ChatClaude(Chat):
23+
MAX_IMAGE_SIZE_MB = 4.0
24+
2325
def __init__(self, model: str, instruction: str, bad_response: str, history_size: int, history_char_limit: int,
2426
api_key_envvar: str=None, claude_options: dict=None):
2527

@@ -78,7 +80,7 @@ def send_message(
7880

7981
for image in images:
8082
media_type, image_format, b64 = parse_data_url(image)
81-
b64 = resize_base64_image(b64, max_size_mb=3.0, output_format=image_format)
83+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=image_format)
8284
content.append(
8385
{"type": "image", "source": {"type": "base64", "media_type": media_type, "data": b64}}
8486
)

app/chat/chat_gemini.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
# Google Gemini チャットクラス
2424
class ChatGemini(Chat):
25+
MAX_IMAGE_SIZE_MB = 10.0
26+
2527
def __init__(self, model: str, instruction: str, bad_response: str, history_size: int, history_char_limit: int,
2628
api_key_envvar: str=None, gemini_option: dict=None):
2729

@@ -66,7 +68,7 @@ def send_message(
6668
user_parts = [{"text": text}]
6769
for img_dataurl in images or []:
6870
media_type, image_format, b64 = parse_data_url(img_dataurl)
69-
b64 = resize_base64_image(b64, max_size_mb=15.0, output_format=image_format)
71+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=image_format)
7072
user_parts.append({
7173
"inline_data": {
7274
"mime_type": media_type,

app/chat/chat_openai_base.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313

1414
from openai import APITimeoutError, AuthenticationError, NotFoundError, BadRequestError
1515

16+
from utility.utils import parse_data_url, resize_base64_image
1617
from .chat import Chat
1718
from .listener import SendMessageListener
1819
from .error import StreamNotAllowedError, ResponsesApiRequiredError
1920

21+
2022
class ChatOpenAIBase(Chat):
23+
MAX_IMAGE_SIZE_MB = 10.0
24+
2125
# メッセージを送信して回答を得る(同期処理、一度きりの質問)
2226
def send_onetime_message(self, text:str):
2327
messages = []
@@ -67,10 +71,11 @@ def send_message_completions_streaming(
6771
if text:
6872
content.append({"type": "text", "text": text})
6973

70-
for b64 in images:
71-
if not b64.startswith("data:"):
72-
b64 = f"data:image/png;base64,{b64}"
73-
content.append({"type": "image_url", "image_url": {"url": b64}})
74+
for image in images:
75+
media_type, subtype, b64 = parse_data_url(image)
76+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=subtype)
77+
data_url = f"data:{media_type};base64,{b64}"
78+
content.append({"type": "image_url", "image_url": {"url": data_url}})
7479

7580
messages.append({"role": "user", "content": content})
7681

@@ -169,10 +174,11 @@ def send_message_completions_not_streaming(
169174
if text:
170175
content.append({"type": "text", "text": text})
171176

172-
for b64 in images:
173-
if not b64.startswith("data:"):
174-
b64 = f"data:image/png;base64,{b64}"
175-
content.append({"type": "image_url", "image_url": {"url": b64}})
177+
for image in images:
178+
media_type, subtype, b64 = parse_data_url(image)
179+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=subtype)
180+
data_url = f"data:{media_type};base64,{b64}"
181+
content.append({"type": "image_url", "image_url": {"url": data_url}})
176182

177183
messages.append({"role": "user", "content": content})
178184

@@ -269,7 +275,10 @@ def convert_message(m):
269275
if images and len(images) > 0:
270276
last_message = responses_input[-1]
271277
for image in images:
272-
last_message["content"].append({"type": "input_image", "image_url": image})
278+
media_type, subtype, b64 = parse_data_url(image)
279+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=subtype)
280+
data_url = f"data:{media_type};base64,{b64}"
281+
last_message["content"].append({"type": "input_image", "image_url": data_url})
273282

274283
content = ""
275284
sentence = ""
@@ -327,10 +336,14 @@ def convert_message(m):
327336
listener.on_end_response(self.bad_response)
328337
return self.bad_response
329338

330-
final_response = stream.get_final_response()
331-
if final_response and final_response.output:
332-
# Responses API は output 内に role が入っている
333-
role = final_response.output[0].role or "assistant"
339+
# final_response.output配列には複数のタイプのコンテンツが含まれる可能性があるため、
340+
# エラーになる場合があるためコメントアウト
341+
# roleはassistantで固定で問題ないが、参考のために残しておく
342+
#
343+
#final_response = stream.get_final_response()
344+
#if final_response and final_response.output:
345+
# # Responses API は output 内に role が入っている
346+
# role = final_response.output[0].role or "assistant"
334347

335348
if sentence:
336349
listener.on_receive_sentence(sentence)
@@ -400,7 +413,10 @@ def convert_message(m):
400413
if images and len(images) > 0:
401414
last_message = responses_input[-1]
402415
for image in images:
403-
last_message["content"].append({"type": "input_image", "image_url": image})
416+
media_type, subtype, b64 = parse_data_url(image)
417+
b64 = resize_base64_image(b64, max_size_mb=self.MAX_IMAGE_SIZE_MB, output_format=subtype)
418+
data_url = f"data:{media_type};base64,{b64}"
419+
last_message["content"].append({"type": "input_image", "image_url": data_url})
404420

405421
response = self.client.responses.create(
406422
model=self.model,

app/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
# ライセンスの詳細については、このプロジェクトのLICENSEファイルを参照してください。
88

99
APP_NAME = "ZundaGPT2"
10-
APP_VERSION = "1.34.0"
10+
APP_VERSION = "1.35.0"
1111
COPYRIGHT = "© 2024-2025 led-mirage"

0 commit comments

Comments
 (0)