mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-24 21:34:24 +00:00
Compare commits
No commits in common. "04ad8ca58e355b022bb01737ae3007d90d1cb4db" and "e72e191b3566dfcc0afd0e188cb89df2384882f1" have entirely different histories.
04ad8ca58e
...
e72e191b35
8 changed files with 32 additions and 133 deletions
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
# Copy source files
|
# Copy source files
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN bun run generateVersionTag
|
|
||||||
# Build the application
|
# Build the application
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Vars for translating stuff
|
// Translate stuff
|
||||||
interface translateInterfaceText {
|
interface translateInterfaceText {
|
||||||
translateText: string;
|
translateText: string;
|
||||||
}
|
}
|
||||||
const translateItem: Record<string, translateInterfaceText> = {};
|
const translateItems: Record<string, translateInterfaceText> = {};
|
||||||
|
|
||||||
const translateLoading = ref(false);
|
|
||||||
const displayTranslateContent = ref(false);
|
|
||||||
const traslateFailed = ref(false);
|
|
||||||
const translatedBefore = ref(false);
|
|
||||||
|
|
||||||
// Imports
|
// Imports
|
||||||
import { ScanEyeIcon, RefreshCcwIcon } from "lucide-vue-next";
|
import { ScanEyeIcon, RefreshCcwIcon } from "lucide-vue-next";
|
||||||
|
@ -37,10 +32,18 @@ const emit = defineEmits([
|
||||||
"windowopener",
|
"windowopener",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps({
|
||||||
applyForTranslation: Boolean;
|
applyForTranslation: {
|
||||||
windowTranslateState: Boolean;
|
type: Boolean,
|
||||||
}>();
|
required: true,
|
||||||
|
},
|
||||||
|
windowTranslateState: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { applyForTranslation, windowTranslateState } = props;
|
||||||
|
|
||||||
const openNewWindow = (itemId: string) => {
|
const openNewWindow = (itemId: string) => {
|
||||||
emit("windowopener", "aboutNewsOrg");
|
emit("windowopener", "aboutNewsOrg");
|
||||||
|
@ -50,7 +53,7 @@ const contentArray = ref([]);
|
||||||
const errorr = ref(false);
|
const errorr = ref(false);
|
||||||
const switchTabs = ref(false);
|
const switchTabs = ref(false);
|
||||||
const tabs = ref([]);
|
const tabs = ref([]);
|
||||||
const primary = ref<string>("domestic"); // Hard code default value as top is just pure garbage.
|
const primary = ref<string>("top"); // Hard code value fn
|
||||||
const canNotLoadTabUI = ref(false);
|
const canNotLoadTabUI = ref(false);
|
||||||
const isDataCached = ref(false);
|
const isDataCached = ref(false);
|
||||||
const pullTabsData = async () => {
|
const pullTabsData = async () => {
|
||||||
|
@ -81,7 +84,6 @@ const updateContent = async (url: string, tabAction: boolean) => {
|
||||||
contentArray.value = [...data.uuidData, ...(data.nuuiddata?.items || [])];
|
contentArray.value = [...data.uuidData, ...(data.nuuiddata?.items || [])];
|
||||||
switchTabs.value = false;
|
switchTabs.value = false;
|
||||||
isDataCached.value = data.cached || false;
|
isDataCached.value = data.cached || false;
|
||||||
translatedBefore.value = false;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -213,64 +215,15 @@ const openPublisher = (slug: string, title: string) => {
|
||||||
emit("openNewsSourcePage", slug, title);
|
emit("openNewsSourcePage", slug, title);
|
||||||
};
|
};
|
||||||
const isLoading = computed(() => contentArray.value.length === 0);
|
const isLoading = computed(() => contentArray.value.length === 0);
|
||||||
|
const testmessage = await translate("嗨", { from: "zh", to: "en" });
|
||||||
const shouldHideItem = (item) => {
|
const shouldHideItem = (item) => {
|
||||||
return (
|
return (
|
||||||
item.contentType !== "GENERAL" ||
|
item.contentType !== "GENERAL" ||
|
||||||
item.publisher?.toLowerCase().includes("line")
|
item.publisher?.toLowerCase().includes("line")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Translate (Selective content)
|
|
||||||
const startTranslating = async (text: string) => {
|
|
||||||
try {
|
|
||||||
translateItem[text] = {
|
|
||||||
translateText: await translate(text, { from: "zh", to: "en" }),
|
|
||||||
};
|
|
||||||
console.log(translateItem[text]);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Translation failed:", error);
|
|
||||||
traslateFailed.value = true;
|
|
||||||
translateItem[text] = { translateText: text }; // fallback
|
|
||||||
}
|
|
||||||
};
|
|
||||||
watch(
|
|
||||||
() => props.applyForTranslation,
|
|
||||||
(value) => {
|
|
||||||
if (value === true || translatedBefore.value === false) {
|
|
||||||
if (translatedBefore.value === true) {
|
|
||||||
displayTranslateContent.value = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
translateFunction();
|
|
||||||
// NOT retranslating AGAIN when disabling the feat
|
|
||||||
translatedBefore.value = true;
|
|
||||||
} else {
|
|
||||||
displayTranslateContent.value = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const translateFunction = () => {
|
|
||||||
if (canNotLoadTabUI.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
translateLoading.value = true;
|
|
||||||
// Translate tabs
|
|
||||||
for (const tab of tabs.value) {
|
|
||||||
startTranslating(tab.text);
|
|
||||||
}
|
|
||||||
// Translate news titles & news org
|
|
||||||
for (const articleBlock of contentArray.value) {
|
|
||||||
startTranslating(articleBlock.title);
|
|
||||||
startTranslating(articleBlock.publisher);
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
displayTranslateContent.value = true;
|
|
||||||
translateLoading.value = false;
|
|
||||||
}, 3000);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-if="translateLoading">Loading...</div>
|
|
||||||
<div class="justify-center align-center text-center">
|
<div class="justify-center align-center text-center">
|
||||||
<!--Tabs-->
|
<!--Tabs-->
|
||||||
<div
|
<div
|
||||||
|
@ -299,16 +252,13 @@ const translateFunction = () => {
|
||||||
class="disabled:cursor-not-allowed"
|
class="disabled:cursor-not-allowed"
|
||||||
:disabled="isPrimary(item.url, true) || switchTabs"
|
:disabled="isPrimary(item.url, true) || switchTabs"
|
||||||
>
|
>
|
||||||
<span>{{
|
<span>{{ true ? item.text : testmessage }}</span>
|
||||||
displayTranslateContent
|
|
||||||
? translateItem[item.text].translateText
|
|
||||||
: item.text
|
|
||||||
}}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<button v-if="canNotLoadTabUI"><RefreshCcwIcon /></button>
|
<button v-if="canNotLoadTabUI"><RefreshCcwIcon /></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Content Area -->
|
<!-- Content Area -->
|
||||||
<div>
|
<div>
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
|
@ -375,19 +325,11 @@ const translateFunction = () => {
|
||||||
<button
|
<button
|
||||||
@click="openPublisher(item.publisherId, item.publisher)"
|
@click="openPublisher(item.publisherId, item.publisher)"
|
||||||
>
|
>
|
||||||
{{
|
{{ item.publisher }}
|
||||||
displayTranslateContent
|
|
||||||
? translateItem[item.publisher].translateText
|
|
||||||
: item.publisher
|
|
||||||
}}
|
|
||||||
</button>
|
</button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent class="rounded">
|
<TooltipContent class="rounded">
|
||||||
{{ t("news.articleopenpart1") }}({{
|
會打開關於媒體({{ item.publisher }})的視窗
|
||||||
displayTranslateContent
|
|
||||||
? translateItem[item.publisher].translateText
|
|
||||||
: item.publisher
|
|
||||||
}}){{ t("news.articleopenpart2") }}
|
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
@ -413,20 +355,18 @@ const translateFunction = () => {
|
||||||
@click="openNews(item.url.hash, item.title)"
|
@click="openNews(item.url.hash, item.title)"
|
||||||
class="flex flex-row p-1 bg-sky-300/50 hover:bg-sky-400/50 shadow-lg backdrop-blur-sm rounded transition-all duration-200"
|
class="flex flex-row p-1 bg-sky-300/50 hover:bg-sky-400/50 shadow-lg backdrop-blur-sm rounded transition-all duration-200"
|
||||||
>
|
>
|
||||||
<ScanEyeIcon class="w-6 h-6 p-1" /><span>{{
|
<ScanEyeIcon class="w-6 h-6 p-1" /><span>觀看文章</span>
|
||||||
t("news.open")
|
|
||||||
}}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent class="rounded">
|
<TooltipContent class="rounded">
|
||||||
{{ t("news.opennewwindow") }}
|
會打開新的視窗
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg">{{ t("news.similararticles") }}</h3>
|
<h3 class="text-lg">類似文章</h3>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div
|
<div
|
||||||
v-for="similar in useArgFindRel(item.title, item.publisher)"
|
v-for="similar in useArgFindRel(item.title, item.publisher)"
|
||||||
|
@ -436,13 +376,8 @@ const translateFunction = () => {
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ similar.title }}</div>
|
<div class="font-medium">{{ similar.title }}</div>
|
||||||
<div class="text-gray-500 text-xs">
|
<div class="text-gray-500 text-xs">
|
||||||
{{ t("news.similarity") }}:
|
相似度: {{ (similar.similarity * 100).toFixed(1) }}% |
|
||||||
{{ (similar.similarity * 100).toFixed(1) }}% |
|
{{ similar.item.publisher }}
|
||||||
{{
|
|
||||||
displayTranslateContent
|
|
||||||
? translateItem[similar.item.publisher].translateText
|
|
||||||
: similar.item.publisher
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -450,7 +385,7 @@ const translateFunction = () => {
|
||||||
v-if="checkIfEmpty(item.title)"
|
v-if="checkIfEmpty(item.title)"
|
||||||
class="text-gray-500 text-sm"
|
class="text-gray-500 text-sm"
|
||||||
>
|
>
|
||||||
{{ t("news.nosimilararticles") }}
|
找不到類似文章
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import getVersionTag from "~/versionTag";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const user = ref("");
|
const user = ref("");
|
||||||
|
@ -282,20 +281,20 @@ const submitChangeAction = async (action: string) => {
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="bg-sky-400 p-1 rounded hover:bg-sky-600 transition-all duration-200 w-32"
|
class="bg-sky-400 p-1 rounded hover:bg-sky-600 transition-all duration-200 w-32"
|
||||||
@click="() => emit('windowopener', 'privacypolicy')"
|
@click="emit('windowopener', 'privacypolicy')"
|
||||||
>
|
>
|
||||||
Privacy Policy
|
Privacy Policy
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="bg-sky-400 p-1 rounded hover:bg-sky-600 transition-all duration-200 w-32"
|
class="bg-sky-400 p-1 rounded hover:bg-sky-600 transition-all duration-200 w-32"
|
||||||
@click="() => emit('windowopener', 'tos')"
|
@click="emit('windowopener', 'tos')"
|
||||||
>
|
>
|
||||||
TOS
|
TOS
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="justiy-center align-center text-center">
|
<div class="justiy-center align-center text-center">
|
||||||
{{ t("app.settings") }} v0.0.3 || Version: {{ getVersionTag() }}
|
{{ t("app.settings") }} v0.0.3
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -128,14 +128,5 @@
|
||||||
"contactEmailStarter": "聯絡信箱:"
|
"contactEmailStarter": "聯絡信箱:"
|
||||||
},
|
},
|
||||||
"copyrightInfo": "版權資訊"
|
"copyrightInfo": "版權資訊"
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"open": "觀看文章",
|
|
||||||
"opennewwindow": "會打開新的視窗",
|
|
||||||
"similararticles": "類似文章",
|
|
||||||
"similarity": "相似度",
|
|
||||||
"nosimilararticles": "找不到類似文章",
|
|
||||||
"articleopenpart1": "會打開關於媒體",
|
|
||||||
"articleopenpart2": "的視窗"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
"docs:dev": "vitepress dev docs",
|
"docs:dev": "vitepress dev docs",
|
||||||
"docs:build": "vitepress build docs",
|
"docs:build": "vitepress build docs",
|
||||||
"docs:preview": "vitepress preview docs",
|
"docs:preview": "vitepress preview docs",
|
||||||
"wipedev": "./clean-dev-env.sh",
|
"wipedev": "./clean-dev-env.sh"
|
||||||
"generateVersionTag": "bun run versionTagGenerate.ts"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/noto-sans-tc": "^5.2.5",
|
"@fontsource-variable/noto-sans-tc": "^5.2.5",
|
||||||
|
@ -64,4 +63,4 @@
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@vercel/nft": "^0.27.4"
|
"@vercel/nft": "^0.27.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
import versionTag from "~/versionTag";
|
|
||||||
export default defineEventHandler(() => {
|
|
||||||
return {
|
|
||||||
version: versionTag(),
|
|
||||||
};
|
|
||||||
});
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function versionTag() {
|
|
||||||
return "value";
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { $ } from "bun";
|
|
||||||
const characters =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
||||||
function generateVersionTag() {
|
|
||||||
let slug = "";
|
|
||||||
let length = 8;
|
|
||||||
for (let times = 0; times < length; times++) {
|
|
||||||
slug += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
||||||
}
|
|
||||||
return slug;
|
|
||||||
}
|
|
||||||
const tag = generateVersionTag();
|
|
||||||
// Command
|
|
||||||
await $`echo 'export default function versionTag() {return "${tag}";}' > ./versionTag.ts`;
|
|
||||||
|
|
||||||
console.log("Version Tag:", tag);
|
|
Loading…
Add table
Add a link
Reference in a new issue