diff --git a/.idea/misc.xml b/.idea/misc.xml index b2c751a..7e4f6ee 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,4 +6,11 @@ + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fc922ac..68454df 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,6 +51,16 @@ dependencies { implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.material3) implementation("androidx.recyclerview:recyclerview:1.3.2") + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-simplexml:2.9.0") + dependencies { + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-simplexml:2.9.0") + implementation("com.squareup.okhttp3:okhttp:4.11.0") + implementation("com.squareup.moshi:moshi-kotlin:1.15.0") + + } + testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 96e4581..d4dde1b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/curation_train_app/AkaneReponder.kt b/app/src/main/java/com/example/curation_train_app/AkaneReponder.kt new file mode 100644 index 0000000..446c71b --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/AkaneReponder.kt @@ -0,0 +1,23 @@ +package com.example.curation_train_app + +class AkaneResponder : CharacterResponder { + + override val profile = CharacterProfiles.akane + + override fun respond(info: String, type: InfoType): String { + return when (type) { + + InfoType.DELAY -> + "えっ!?遅延!? 急ぐなら別ルートも考えたほうがいいかもだよっ!!" + + InfoType.REVISION -> + "うわーっ!ダイヤ改正だって!? 新しい運用とかワクワクするじゃんっ!" + + InfoType.EVENT -> + "イベント列車!? こういうのめっちゃ楽しみだよねっ!!" + + else -> + "なんか気になる情報があるよねっ!気をつけていこーっ!" + } + } +} diff --git a/app/src/main/java/com/example/curation_train_app/CharacterProfile.kt b/app/src/main/java/com/example/curation_train_app/CharacterProfile.kt new file mode 100644 index 0000000..ee0f6f3 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/CharacterProfile.kt @@ -0,0 +1,136 @@ +package com.example.curation_train_app + +object CharacterProfiles { + + data class CharacterProfile( + val id: String, + val name: String, + val speakingStyle: String, // 話し方・口調の説明 + val personality: String, // 性格・立ち位置 + val knowledgeLevel: String // 鉄道知識レベル + ) + + // ─────────────────────────────── + // 🔴1. 霊夢(メイン進行・解説) + // ─────────────────────────────── + val reimu = CharacterProfile( + id = "reimu", + name = "霊夢", + speakingStyle = + "落ち着いた女言葉。断定を避け、やわらかい表現。敬語は使わない。" + + "語尾は自然な範囲で「〜よ」「〜わよ」「〜よね」を用いる。", + personality = + "穏やか、冷静、全体進行役。説明整理が得意で、視聴者に安心感を与える。優しい。", + knowledgeLevel = "中程度の鉄道知識" + ) + + // ─────────────────────────────── + // 🟡2. 魔理沙(補足・深掘り担当) + // ─────────────────────────────── + val marisa = CharacterProfile( + id = "marisa", + name = "魔理沙", + speakingStyle = + "元気な口調。「〜だぜ」は乱発せず、強調・納得・気付きの場面でだけ自然に使う。", + personality = + "深掘り・解説の補足、技術寄りの説明が得意。少しテンション高めで勢いがある。", + knowledgeLevel = "高い鉄道知識" + ) + + // ─────────────────────────────── + // 🟠3. フラン(明るく元気) + // ─────────────────────────────── + val flan = CharacterProfile( + id = "flan", + name = "フラン", + speakingStyle = + "明るく元気。テンションが高いときだけ「なのだー」「のだー」が出る。" + + "普段は普通の話し方で語尾を毎回つけない。", + personality = + "ムードメーカー。感情表現が大きく、明るい。盛り上げ役。", + knowledgeLevel = "中〜低の鉄道知識(感覚派)" + ) + + // ─────────────────────────────── + // 🟢4. 早苗(丁寧で落ち着いた補足役) + // ─────────────────────────────── + val sanae = CharacterProfile( + id = "sanae", + name = "早苗", + speakingStyle = + "丁寧で落ち着いた語り。霊夢寄りの柔らかい話し方。敬語あり。", + personality = + "冷静な補足役。情景や背景知識を丁寧に伝える。視点が穏やか。", + knowledgeLevel = "中程度の鉄道知識" + ) + + // ─────────────────────────────── + // 🟨5. あかね(テンション高い・視聴者代表) + // ─────────────────────────────── + val akane = CharacterProfile( + id = "akane", + name = "あかね", + speakingStyle = + "元気で明るい。テンション高め。語尾に小さい「っ」が入ることがある。" + + "自分のことを「HN君」と呼ぶ。", + personality = + "視聴者代表。リアクション担当。疑問を素直に口に出す。場を明るくする。", + knowledgeLevel = "低〜中の鉄道知識。難しい話は苦手。" + ) + + // ─────────────────────────────── + // 🟦6. さやか(冷静・整理役) + // ─────────────────────────────── + val sayaka = CharacterProfile( + id = "sayaka", + name = "さやか", + speakingStyle = + "落ち着いた女言葉。霊夢寄りの丁寧な話し方。語尾は崩れない。敬語は使わない", + personality = + "冷静な説明・整理役。感情を抑えめに、的確に指摘する。", + knowledgeLevel = "中程度の鉄道知識" + ) + + // ─────────────────────────────── + // 🟧7. ひより(穏やか・控えめ) + // ─────────────────────────────── + val hiyori = CharacterProfile( + id = "hiyori", + name = "ひより", + speakingStyle = + "やわらかく、控えめな話し方。語彙は優しめ。崩れすぎない。", + personality = + "優しく控えめで、聞き役になることもある。しっかり者だが遠慮がち。", + knowledgeLevel = "中〜低の鉄道知識" + ) + + // ─────────────────────────────── + // 🍑8. ももか(甘めの口調・テンション高め) + // ─────────────────────────────── + val momoka = CharacterProfile( + id = "momoka", + name = "ももか", + speakingStyle = + "かわいめの語尾・柔らかい話し方。テンション高めの時だけ「っ」が入る。", + personality = + "甘めの雰囲気で明るい。感情が前に出るタイプ。", + knowledgeLevel = "低〜中の鉄道知識" + ) + + // ─────────────────────────────── + // ID → キャラ検索 + // ─────────────────────────────── + fun getProfile(id: String): CharacterProfile? { + return when (id.lowercase()) { + "reimu" -> reimu + "marisa" -> marisa + "flan" -> flan + "sanae" -> sanae + "akane" -> akane + "sayaka" -> sayaka + "hiyori" -> hiyori + "momoka" -> momoka + else -> null + } + } +} diff --git a/app/src/main/java/com/example/curation_train_app/CharacterReplyManager.kt b/app/src/main/java/com/example/curation_train_app/CharacterReplyManager.kt new file mode 100644 index 0000000..88378f6 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/CharacterReplyManager.kt @@ -0,0 +1,39 @@ +package com.example.curation_train_app + +import com.example.curation_train_app.ai.PromptBuilder +import com.example.curation_train_app.ai.AiClient +private const val API_KEY = "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" + + + +class CharacterReplyManager { + + private val responders = mapOf( + "reimu" to ReimuResponder(), + "akane" to AkaneResponder(), + "marisa" to MarisaResponder(), + "sayaka" to SayakResponder(), + "sanae" to SanaeResponder(), + "momoka" to MomokaResponder(), + "flandre" to flandreResponder(), + "hiyori" to HiyoriResponder() + // ← 6人追加予定 + ) + + fun reply(characterId: String, info: String, type: InfoType): String { + val responder = responders[characterId] + ?: return "キャラが見つかりません。" + return responder.respond(info, type) + } + fun replyWithAI(characterId: String, info: String, type: InfoType): String { + val character = CharacterProfiles.getProfile(characterId) + ?: return "(エラー:キャラが不明です)" + + + val prompt = PromptBuilder.buildPrompt(character, info, type) + + val ai = AiClient(API_KEY) + return ai.requestCharacterReply(prompt) + } + +} diff --git a/app/src/main/java/com/example/curation_train_app/CharacterResponder.kt b/app/src/main/java/com/example/curation_train_app/CharacterResponder.kt new file mode 100644 index 0000000..0f544bf --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/CharacterResponder.kt @@ -0,0 +1,6 @@ +package com.example.curation_train_app + +interface CharacterResponder { + val profile: CharacterProfiles.CharacterProfile + fun respond(info: String, type: InfoType): String +} diff --git a/app/src/main/java/com/example/curation_train_app/DummyLines.kt b/app/src/main/java/com/example/curation_train_app/DummyLines.kt new file mode 100644 index 0000000..f304527 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/DummyLines.kt @@ -0,0 +1,18 @@ +package com.example.curation_train_app + +object DummyLines { + + fun linesOf(region: String): List { + return when (region) { + "北海道" -> listOf("JR北海道全線", "札幌市営地下鉄", "道南いさりび鉄道") + "東北" -> listOf("JR東日本(東北)", "仙台市地下鉄", "青い森鉄道") + "関東" -> listOf("JR東日本(関東)", "東京メトロ", "京急", "東急", "小田急", "京王") + "中部" -> listOf("JR東海", "名鉄", "近鉄(名古屋)") + "関西" -> listOf("JR西日本(関西)", "大阪メトロ", "阪急", "阪神", "京阪", "南海", "近鉄(関西)") + "中国" -> listOf("JR西日本(中国)", "広島電鉄", "一畑電車") + "四国" -> listOf("JR四国") + "九州" -> listOf("JR九州", "西鉄") + else -> listOf("該当する路線がありません") + } + } +} diff --git a/app/src/main/java/com/example/curation_train_app/FillterSettingActivity.kt b/app/src/main/java/com/example/curation_train_app/FillterSettingActivity.kt new file mode 100644 index 0000000..c2f82da --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/FillterSettingActivity.kt @@ -0,0 +1,12 @@ +package com.example.curation_train_app + +import android.os.Bundle +import androidx.activity.ComponentActivity + +class FilterSettingActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_filter_setting) + } +} diff --git a/app/src/main/java/com/example/curation_train_app/HiyoriResponder.kt b/app/src/main/java/com/example/curation_train_app/HiyoriResponder.kt new file mode 100644 index 0000000..cc05ad7 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/HiyoriResponder.kt @@ -0,0 +1,23 @@ +package com.example.curation_train_app + +class HiyoriResponder : CharacterResponder { + + override val profile = CharacterProfiles.hiyori + + override fun respond(info: String, type: InfoType): String { + return when (type) { + + InfoType.DELAY -> + "遅延しているみたい…焦らずに、少し余裕を持って動けるといいね。" + + InfoType.REVISION -> + "ダイヤが変わるんだね…。知らないと戸惑うから、確認しておくと安心だよ。" + + InfoType.EVENT -> + "イベント列車…!楽しそうだね。時間が合えば、ちょっと見に行ってみたいな。" + + else -> + "気になったことがあるの?よかったら教えてね。いっしょに見てみるよ。" + } + } +} diff --git a/app/src/main/java/com/example/curation_train_app/InfoClassifier.kt b/app/src/main/java/com/example/curation_train_app/InfoClassifier.kt new file mode 100644 index 0000000..d7afbe5 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/InfoClassifier.kt @@ -0,0 +1,28 @@ +package com.example.curation_train_app + +object InfoClassifier { + + fun classify(text: String): InfoType { + + val t = text.lowercase() + + return when { + // 遅延系 + t.contains("遅延") || t.contains("遅れ") || t.contains("delay") -> + InfoType.DELAY + + // ダイヤ改正 / 運転変更 + t.contains("ダイヤ") || t.contains("時刻表") || t.contains("運転変更") -> + InfoType.REVISION + + // 注意報・警報・天候・安全 + t.contains("強風") || t.contains("大雨") || + t.contains("警報") || t.contains("注意喚起") || + t.contains("事故") || t.contains("運休") -> + InfoType.WEATHER + + // その他 + else -> InfoType.OTHER + } + } +} diff --git a/app/src/main/java/com/example/curation_train_app/InfoType.kt b/app/src/main/java/com/example/curation_train_app/InfoType.kt new file mode 100644 index 0000000..143bf68 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/InfoType.kt @@ -0,0 +1,12 @@ +package com.example.curation_train_app + +enum class InfoType { + DELAY, // 遅延 + SUSPENSION, // 運休 + REVISION, // ダイヤ改正 + CONSTRUCTION, // 工事 + EVENT, // イベント・臨時列車 + WEATHER, // 天候影響 + NEW_TRAIN, // 新型車両関連 + OTHER // 分類できない場合 +} diff --git a/app/src/main/java/com/example/curation_train_app/LinePriorityActivity.kt b/app/src/main/java/com/example/curation_train_app/LinePriorityActivity.kt new file mode 100644 index 0000000..0666d23 --- /dev/null +++ b/app/src/main/java/com/example/curation_train_app/LinePriorityActivity.kt @@ -0,0 +1,52 @@ +package com.example.curation_train_app + +import android.os.Bundle +import android.widget.TextView +import androidx.activity.ComponentActivity +import android.content.Intent +import android.widget.Button + +class LinePriorityActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_line_priority) + + val btnOpenFilter = findViewById